[Checkins] SVN: z3c.pt/trunk/ Engine now expects all strings to be unicode or contain ASCII

Malthe Borch mborch at gmail.com
Wed Sep 10 12:38:28 EDT 2008


Log message for revision 91033:
  Engine now expects all strings to be unicode or contain ASCII
    characters only, unless an encoding is provided.

Changed:
  U   z3c.pt/trunk/CHANGES.txt
  U   z3c.pt/trunk/src/z3c/pt/clauses.py
  U   z3c.pt/trunk/src/z3c/pt/codegen.py
  U   z3c.pt/trunk/src/z3c/pt/expressions.py
  U   z3c.pt/trunk/src/z3c/pt/generation.py
  U   z3c.pt/trunk/src/z3c/pt/genshi.txt
  U   z3c.pt/trunk/src/z3c/pt/template.py
  U   z3c.pt/trunk/src/z3c/pt/testing.py
  U   z3c.pt/trunk/src/z3c/pt/translation.py
  U   z3c.pt/trunk/src/z3c/pt/types.py
  U   z3c.pt/trunk/src/z3c/pt/utils.py
  U   z3c.pt/trunk/src/z3c/pt/zpt.py
  U   z3c.pt/trunk/src/z3c/pt/zpt.txt

-=-
Modified: z3c.pt/trunk/CHANGES.txt
===================================================================
--- z3c.pt/trunk/CHANGES.txt	2008-09-10 14:33:08 UTC (rev 91032)
+++ z3c.pt/trunk/CHANGES.txt	2008-09-10 16:38:26 UTC (rev 91033)
@@ -6,6 +6,9 @@
 
   Backwards incompatibilities
 
+- Engine now expects all strings to be unicode or contain ASCII
+  characters only, unless an encoding is provided. [malthe]
+  
 - The default path traverser no longer proxies objects. [malthe]
   
 - Template output is now always converted to unicode. [malthe]

Modified: z3c.pt/trunk/src/z3c/pt/clauses.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/clauses.py	2008-09-10 14:33:08 UTC (rev 91032)
+++ z3c.pt/trunk/src/z3c/pt/clauses.py	2008-09-10 16:38:26 UTC (rev 91033)
@@ -14,7 +14,6 @@
     >>> bad_float = types.value("float('abc')")
     >>> abc = types.value("'abc'")
     >>> ghi = types.value("'ghi'")
-    >>> utf8_encoded = types.value("'La Pe\xc3\xb1a'")
     >>> exclamation = types.value("'!'")
         
     Simple value assignment:
@@ -61,25 +60,6 @@
     >>> b == 'abcghi'
     True
     >>> assign.end(stream)
-
-    UTF-8 coercing:
-
-    >>> assign = Assign(types.join((utf8_encoded, exclamation)))
-    >>> assign.begin(stream, 'b')
-    >>> exec stream.getvalue()
-    >>> b == 'La Pe\xc3\xb1a!'
-    True
-    >>> assign.end(stream)
-
-    UTF-8 coercing with unicode:
-    
-    >>> assign = Assign(types.join((utf8_encoded, u"!")))
-    >>> assign.begin(stream, 'b')
-    >>> exec stream.getvalue()
-    >>> b == 'La Pe\xc3\xb1a!'
-    True
-    >>> assign.end(stream)
-
     """
 
     def __init__(self, parts, variable=None):
@@ -137,7 +117,10 @@
                 elif isinstance(part, types.value):
                     parts.append(part)
                 elif isinstance(part, unicode):
-                    parts.append(repr(part.encode('utf-8')))
+                    if stream.encoding:
+                        parts.append(repr(part.encode(stream.encoding)))
+                    else:
+                        parts.append(repr(part))
                 elif isinstance(part, str):
                     parts.append(repr(part))
                 else:
@@ -510,33 +493,41 @@
         
         if self.expression:
             self.expression.begin(stream, stream.symbols.tmp)
+            # loop over all attributes
             stream.write("for %s, %s in %s.items():" % \
                          (temp, temp2, stream.symbols.tmp))            
             stream.indent()
-            if utils.unicode_required_flag:
-                stream.write(
-                    "if isinstance(%s, unicode) or isinstance(%s, unicode):" % (temp, temp2))
-                stream.indent()
+
+            # only include attribute if expression is not None
+            stream.write("if %s is not None:" % temp2)                
+            stream.indent()
+
+            # if an encoding is specified, we need to check
+            # whether we're dealing with unicode strings or not,
+            # before writing out the attribute
+            if stream.encoding is not None:
                 for t in (temp, temp2):
                     stream.write("if isinstance(%s, unicode):" % t)
                     stream.indent()
-                    stream.write("%s = %s.encode('utf-8')" % (t, t))
+                    stream.write("%s = %s.encode('%s')" % (t, t, stream.encoding))
                     stream.outdent()
-                stream.escape(temp2)
-                stream.write("%s(' %%s=\"%%s\"' %% (%s, %s))" % \
-                             (stream.symbols.write, temp, temp2))
+
+                # make sure this is a string
+                stream.write("if not isinstance(%s, (str, unicode)):" % temp2)
+                stream.indent()
+                stream.write("%s = str(%s)" % (temp2, temp2))
                 stream.outdent()
-                stream.write("elif %s is not None:" % temp2)
-            else:
-                stream.write("if %s is not None:" % temp2)
-            stream.indent()
-            stream.write("%s = str(%s)" % (temp2, temp2))
+                
+            # escape expression
             stream.escape(temp2)
+
+            # write out
             stream.write("%s(' %%s=\"%%s\"' %% (%s, %s))" % \
                          (stream.symbols.write, temp, temp2))
+
             stream.outdent()
             stream.outdent()
-
+            
         for attribute, value in dynamic:
             assign = Assign(value)
             assign.begin(stream, temp)
@@ -555,55 +546,60 @@
             toggle = ( (self.tag == 'option' and attribute == 'selected') or
                        (self.tag == 'input' and attribute == 'checked') )
 
-            if utils.unicode_required_flag:
+
+            # only include attribute if expression is not None
+            stream.write("if %s not in (False, None):" % temp)
+            stream.indent()
+
+            # print the attribute name
+            stream.write("%s(' %s=\"')" % (stream.symbols.write, attribute))
+
+            # if an encoding is specified, we need to check
+            # whether we're dealing with unicode strings or not,
+            # before writing out the attribute
+            if stream.encoding is not None:
                 stream.write("if isinstance(%s, unicode):" % temp)
                 stream.indent()
-                if toggle:
-                    stream.write('if %s:' % temp)
-                    stream.indent()
-                stream.write("%s(' %s=\"')" % (stream.symbols.write, attribute))
-                stream.write("%s = %s.encode('utf-8')" % (stream.symbols.tmp, temp))
-                stream.escape(stream.symbols.tmp)
-                stream.write("%s(%s)" % (stream.symbols.write, stream.symbols.tmp))
-                stream.write("%s('\"')" % stream.symbols.write)
+                stream.write("%s = %s.encode('%s')" % (temp, temp, stream.encoding))
                 stream.outdent()
-                if toggle:
-                    stream.outdent()
-                stream.write("elif %s is not None:" % temp)
-            else:
-                stream.write("if %s is not None:" % temp)
+
+            # make sure this is a string
+            stream.write("if not isinstance(%s, (str, unicode)):" % temp)
             stream.indent()
-            if toggle:
-                stream.write('if %s:' % temp)
-                stream.indent()
-            stream.write("%s(' %s=\"')" % (stream.symbols.write, attribute))
-            stream.write("%s = str(%s)" % (stream.symbols.tmp, temp))
-            stream.escape(stream.symbols.tmp)
-            stream.write("%s(%s)" % (stream.symbols.write, stream.symbols.tmp))
+            stream.write("%s = str(%s)" % (temp, temp))
+            stream.outdent()
+
+            # escape expression
+            stream.escape(temp)
+
+            stream.write("%s(%s)" % (stream.symbols.write, temp))
             stream.write("%s('\"')" % stream.symbols.write)
+
             stream.outdent()
-            if toggle:
-                stream.outdent()
             assign.end(stream)
 
         stream.restore()
         stream.restore()
-        
-        if self.expression:
-            for attribute, expression in static:
+
+        for attribute, expression in static:
+            if isinstance(expression, unicode) and stream.encoding:
+                expression = expression.encode(stream.encoding)
+
+            # escape expression
+            expression = utils.escape(expression, '"', stream.encoding)
+
+            # if there are dynamic expressions, we only want to write
+            # out static attributes if they're not in the dynamic
+            # expression dictionary
+            if self.expression:
                 stream.write("if '%s' not in %s:" % (attribute, stream.symbols.tmp))
                 stream.indent()
-                stream.write(
-                    "%s(' %s=\"%s\"')" % (
-                    stream.symbols.write, attribute, utils.escape(expression, '"')))
-                stream.outdent()
-        else:
-            for attribute, expression in static:
-                if isinstance(expression, unicode):
-                    expression = expression.encode('utf-8')
-                stream.out(
-                    ' %s="%s"' % (attribute, utils.escape(expression, '"')))
+                
+            stream.out(' %s="%s"' % (attribute, expression))
 
+            if self.expression:
+                stream.outdent()
+                
         if self.selfclosing:
             stream.out(" />")
         else:
@@ -756,8 +752,8 @@
 
     Unicode:
 
-    >>> _out, _write, stream = testing.setup_stream()
-    >>> write = Write(types.value("unicode('La Pe\xc3\xb1a', 'utf-8')"))
+    >>> _out, _write, stream = testing.setup_stream('utf-8')
+    >>> write = Write(types.value(repr('La Pe\xc3\xb1a'.decode('utf-8'))))
     >>> write.begin(stream)
     >>> write.end(stream)
     >>> exec stream.getvalue()
@@ -794,22 +790,25 @@
         stream.write("%s = %s" % (stream.symbols.tmp, expr))
         write("if %(tmp)s is not None:")
         stream.indent()
-        if utils.unicode_required_flag:
+
+        if stream.encoding is not None:
             write("if isinstance(%(tmp)s, unicode):")
             stream.indent()
-            write("%(tmp)s = %(tmp)s.encode('utf-8')")
+            write("%%(tmp)s = %%(tmp)s.encode('%s')" % stream.encoding)
             stream.outdent()
-            write("else:")
-            stream.indent()
-            write("%(tmp)s = str(%(tmp)s)")
-            stream.outdent()
-        else:
-            write("%(tmp)s = str(%(tmp)s)")
+
+        # make sure this is a string
+        write("if not isinstance(%(tmp)s, (str, unicode)):")
+        stream.indent()
+        write("%(tmp)s = str(%(tmp)s)")
+        stream.outdent()
+
         if self.structure:
             write("%(write)s(%(tmp)s)")
         else:
             stream.escape(stream.symbols.tmp)
             write("%(write)s(%(tmp)s)")
+
         stream.outdent()
 
         # validate XML if enabled
@@ -844,8 +843,8 @@
 
     Unicode:
 
-    >>> _out, _write, stream = testing.setup_stream()
-    >>> write = Write(types.value("unicode('La Pe\xc3\xb1a', 'utf-8')"))
+    >>> _out, _write, stream = testing.setup_stream('utf-8')
+    >>> write = Write(types.value(repr(unicode('La Pe\xc3\xb1a', 'utf-8'))))
     >>> write.begin(stream)
     >>> write.end(stream)
     >>> exec stream.getvalue()

Modified: z3c.pt/trunk/src/z3c/pt/codegen.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/codegen.py	2008-09-10 14:33:08 UTC (rev 91032)
+++ z3c.pt/trunk/src/z3c/pt/codegen.py	2008-09-10 16:38:26 UTC (rev 91033)
@@ -70,8 +70,8 @@
         self.names.update(globals)
 
     def visitConst(self, node):
-        if isinstance(node.value, unicode):
-            return ast.Const(node.value.encode('utf-8'))
+        #if isinstance(node.value, unicode):
+        #    return ast.Const(node.value.encode('utf-8'))
         return node
 
     def visitAssName(self, node):
@@ -166,6 +166,9 @@
     def __init__(self, source, globals=()):
         """Create the code object from a string."""
 
+        if isinstance(source, unicode):
+            source = source.encode('utf-8')
+            
         node = parse(source, self.mode)
 
         # build tree

Modified: z3c.pt/trunk/src/z3c/pt/expressions.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/expressions.py	2008-09-10 14:33:08 UTC (rev 91032)
+++ z3c.pt/trunk/src/z3c/pt/expressions.py	2008-09-10 16:38:26 UTC (rev 91033)
@@ -501,13 +501,16 @@
     def validate(self, string):
         """We use the ``parser`` module to determine if
         an expression is a valid python expression."""
-        
-        parser.expr(string.encode('utf-8').strip())
 
-    def translate(self, string):
         if isinstance(string, unicode):
             string = string.encode('utf-8')
+            
+        parser.expr(string.strip())
 
+    def translate(self, string):
+        if isinstance(string, str):
+            string = string.decode('utf-8')
+
         return types.value(string.strip())
 
 python_translation = PythonTranslation()
@@ -521,10 +524,10 @@
     def validate(self, string):
         self.interpolate(string)
         self.split(string)
-
+            
     def translate(self, string):
         return types.join(self.split(string))
-        
+            
     def split(self, string):
         """Split up an interpolation string expression into parts that
         are either unicode strings or ``value``-tuples.
@@ -562,8 +565,8 @@
         >>> split("abc${def | ghi}")
         ('abc', parts(value('def '), value(' ghi')))
 
-        >>> print split("abc${La Pe\xc3\xb1a}")
-        ('abc', value('La Pe\\xc3\\xb1a'))
+        >>> print split(u"abc${ghi}")
+        (u'abc', value('ghi'))
         
         """
 

Modified: z3c.pt/trunk/src/z3c/pt/generation.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/generation.py	2008-09-10 14:33:08 UTC (rev 91032)
+++ z3c.pt/trunk/src/z3c/pt/generation.py	2008-09-10 16:38:26 UTC (rev 91033)
@@ -70,10 +70,12 @@
     t_prefix = '_tmp'
     v_prefix = '_var'
 
-    def __init__(self, symbols=None, indentation=0, indentation_string="\t"):
+    def __init__(self, symbols=None, encoding=None,
+                 indentation=0, indentation_string="\t"):
         BufferIO.__init__(self)
         self.symbols = symbols or object
         self.symbol_mapping = {}
+        self.encoding = encoding
         self.indentation = indentation
         self.indentation_string = indentation_string
         self.queue = ''
@@ -114,12 +116,12 @@
             queue = self.queue
             self.queue = ''
             self.write(
-                "%s('%s')" %
-                (self.symbols.write, queue.replace('\n', '\\n').replace("'", "\\'")))
+                "%s(%s)" %
+                (self.symbols.write, repr(queue)))
 
     def write(self, string):
-        if isinstance(string, unicode):
-            string = string.encode('utf-8')
+        if isinstance(string, unicode) and self.encoding:
+            string = string.encode(self.encoding)
 
         self.l_counter += len(string.split('\n'))-1
 

Modified: z3c.pt/trunk/src/z3c/pt/genshi.txt
===================================================================
--- z3c.pt/trunk/src/z3c/pt/genshi.txt	2008-09-10 14:33:08 UTC (rev 91032)
+++ z3c.pt/trunk/src/z3c/pt/genshi.txt	2008-09-10 16:38:26 UTC (rev 91033)
@@ -256,7 +256,7 @@
   ...   ${unicode('La Pe\xc3\xb1a', 'utf-8').encode('utf-8')}
   ...   <img alt="${unicode('La Pe\xc3\xb1a', 'utf-8').encode('utf-8')}" />
   ...   <img alt="Hello ${unicode('La Pe\xc3\xb1a', 'utf-8').encode('utf-8')}!" />
-  ... </div>""")
+  ... </div>""", encoding='utf-8')
     <div xmlns="http://www.w3.org/1999/xhtml">
       <img alt="La Peña" />
       <img alt="Hello La Peña" />

Modified: z3c.pt/trunk/src/z3c/pt/template.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/template.py	2008-09-10 14:33:08 UTC (rev 91032)
+++ z3c.pt/trunk/src/z3c/pt/template.py	2008-09-10 16:38:26 UTC (rev 91033)
@@ -10,7 +10,8 @@
     defined by ``parser`` (``ZopePageTemplateParser`` or
     ``GenshiParser`` as of this writing). Must be passed an input
     string as ``body``. The ``format`` parameter supports values 'xml'
-    and 'text'."""
+    and 'text'. Pass a value for ``encoding`` if you need to allow
+    strings that are not unicode or plain ASCII."""
 
     compilers = {
         'xml': translation.Compiler,
@@ -20,12 +21,13 @@
     implicit_doctype = doctypes.xhtml
     explicit_doctype = None
     
-    def __init__(self, body, parser, format=None, doctype=None):
+    def __init__(self, body, parser, format=None, doctype=None, encoding=None):
         self.body = body
         self.parser = parser        
         self.signature = hash(body)
         self.registry = {}
-
+        self.encoding = encoding
+        
         if format is not None:
             self.format = format
 
@@ -45,7 +47,8 @@
         return self.compilers[self.format](
             self.body, self.parser,
             implicit_doctype=self.implicit_doctype,
-            explicit_doctype=self.explicit_doctype)
+            explicit_doctype=self.explicit_doctype,
+            encoding=self.encoding)
 
     def cook(self, **kwargs):
         return self.compiler(**kwargs)
@@ -56,7 +59,6 @@
         if template is None:
             template = self.cook(macro=macro, params=params)
             self.registry[key] = template
-            
         return template
 
     def prepare(self, kwargs):
@@ -66,8 +68,7 @@
         self.prepare(kwargs)
         template = self.cook_check(macro, tuple(kwargs))
         kwargs.update(template.selectors)
-        result = template.render(**kwargs) or ""
-        return result.decode('utf-8')
+        return template.render(**kwargs)
 
     def __repr__(self):
         return u"<%s %d>" % (self.__class__.__name__, id(self))

Modified: z3c.pt/trunk/src/z3c/pt/testing.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/testing.py	2008-09-10 14:33:08 UTC (rev 91032)
+++ z3c.pt/trunk/src/z3c/pt/testing.py	2008-09-10 16:38:26 UTC (rev 91033)
@@ -22,14 +22,14 @@
 def pyexp(string):
     return expressions.python_translation.expression(string)
 
-def setup_stream():
+def setup_stream(encoding=None):
     class symbols(translation.Node.symbols):
         out = '_out'
         write = '_write'
 
     out = StringIO()
     write = out.write
-    stream = generation.CodeIO(symbols)
+    stream = generation.CodeIO(symbols, encoding=encoding)
     return out, write, stream
 
 def compile_xhtml(body, **kwargs):
@@ -53,9 +53,10 @@
     template = compiler(params=sorted(kwargs.keys()))
     return template.render(**kwargs)    
 
-def render_genshi(body, **kwargs):
+def render_genshi(body, encoding=None, **kwargs):
     compiler = TestCompiler(
-        body, genshi.GenshiParser(), implicit_doctype=doctypes.xhtml)
+        body, genshi.GenshiParser(),
+        encoding=encoding, implicit_doctype=doctypes.xhtml)
     template = compiler(params=sorted(kwargs.keys()))
     kwargs.update(template.selectors)
     return template.render(**kwargs)    

Modified: z3c.pt/trunk/src/z3c/pt/translation.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/translation.py	2008-09-10 14:33:08 UTC (rev 91032)
+++ z3c.pt/trunk/src/z3c/pt/translation.py	2008-09-10 16:38:26 UTC (rev 91033)
@@ -112,8 +112,8 @@
         # tag tail (deferred)
         tail = self.element.tail
         if tail and not self.fill_slot:
-            if isinstance(tail, unicode):
-                tail = tail.encode('utf-8')
+            if isinstance(tail, unicode) and self.stream.encoding:
+                tail = tail.encode(self.stream.encoding)
             _.append(clauses.Out(tail, defer=True))
 
         # condition
@@ -201,8 +201,8 @@
 
         # tag text (if we're not replacing tag body)
         if text and not dynamic:
-            if isinstance(text, unicode):
-                text = text.encode('utf-8')
+            if isinstance(text, unicode) and self.stream.encoding:
+                text = text.encode(self.stream.encoding)
             _.append(clauses.Out(text))
 
         # dynamic content
@@ -530,7 +530,8 @@
     doctype = None
     implicit_doctype = ""
     
-    def __init__(self, body, parser, implicit_doctype=None, explicit_doctype=None):
+    def __init__(self, body, parser, implicit_doctype=None,
+                 explicit_doctype=None, encoding=None):
         # if no doctype is defined, prepend the implicit doctype to
         # the document source
         no_doctype_declaration = '<!DOCTYPE' not in body
@@ -554,11 +555,15 @@
             
         self.parser = parser
 
+        if utils.coerces_gracefully(encoding):
+            self.encoding = None
+        else:
+            self.encoding = encoding
+        
     @classmethod
-    def from_text(cls, body, parser, implicit_doctype=None, explicit_doctype=None):
+    def from_text(cls, body, parser, **kwargs):
         compiler = Compiler(
-            "<html xmlns='%s'></html>" % config.XHTML_NS, parser,
-            implicit_doctype, explicit_doctype)
+            "<html xmlns='%s'></html>" % config.XHTML_NS, parser, **kwargs)
         compiler.root.text = body
         compiler.root.attrib[utils.meta_attr('omit-tag')] = ""
         return compiler
@@ -595,7 +600,8 @@
 
         # initialize code stream object
         stream = generation.CodeIO(
-            self.root.node.symbols, indentation=1, indentation_string="\t")
+            self.root.node.symbols, encoding=self.encoding,
+            indentation=1, indentation_string="\t")
 
         # initialize variable scope
         stream.scope.append(set(
@@ -604,7 +610,9 @@
 
         # output doctype if any
         if self.doctype and isinstance(self.doctype, (str, unicode)):
-            doctype = (self.doctype +'\n').encode('utf-8')
+            doctype = self.doctype + '\n'
+            if self.encoding:
+                doctype = doctype.encode(self.encoding)
             out = clauses.Out(doctype)
             stream.scope.append(set())
             stream.begin([out])
@@ -704,12 +712,14 @@
         self.code = marshal.dumps(template.func.func_code)
         self.defaults = len(template.func.func_defaults or ())
         self.symbols = template.symbols
+        self.source = template.source
         self.xmldoc = template.xmldoc
         self.parser = template.parser
         
     @classmethod
     def rebuild(cls, state):
         symbols = state['symbols']
+        source = state['source']
         xmldoc = state['xmldoc']
         parser = state['parser']
         tree, doctype = parser.parse(xmldoc)        
@@ -726,6 +736,7 @@
         return dict(
             func=func,
             symbols=symbols,
+            source=source,
             xmldoc=xmldoc,
             parser=parser,
             tree=tree)

Modified: z3c.pt/trunk/src/z3c/pt/types.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/types.py	2008-09-10 14:33:08 UTC (rev 91032)
+++ z3c.pt/trunk/src/z3c/pt/types.py	2008-09-10 16:38:26 UTC (rev 91033)
@@ -7,13 +7,18 @@
     def __repr__(self):
         return 'parts'+tuple.__repr__(self)
 
-class value(str, expression):
+class value(unicode, expression):
     def __init__(self, *args):
         super(value, self).__init__(*args)
         self.symbol_mapping = {}
 
     def __repr__(self):
-        return 'value(%s)' % str.__repr__(self)
+        try:
+            r = repr(self.encode())
+        except UnicodeEncodeError:
+            r = unicode.__repr__(self)
+            
+        return "value(%s)" % r        
 
 class template(value):
     def __repr__(self):

Modified: z3c.pt/trunk/src/z3c/pt/utils.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/utils.py	2008-09-10 14:33:08 UTC (rev 91032)
+++ z3c.pt/trunk/src/z3c/pt/utils.py	2008-09-10 16:38:26 UTC (rev 91033)
@@ -21,6 +21,11 @@
              "an encoding that coerces gracefully to "
              "unicode is used ('utf-8' recommended)." % sys.getdefaultencoding())
 
+def coerces_gracefully(encoding):
+    if encoding != sys.getdefaultencoding() and unicode_required_flag:
+        return False
+    return True
+
 s_counter = 0
 
 def handler(key=None):
@@ -33,10 +38,12 @@
         return g
     return decorate
 
-def attribute(ns, factory=None, default=None):
+def attribute(ns, factory=None, default=None, encoding=None):
     def get(self):
         value = self.attrib.get(ns)
         if value is not None:
+            if encoding or self.stream.encoding:
+                value = value.encode(encoding or self.stream.encoding)
             if factory is None:
                 return value
             f = factory(self.translator)
@@ -47,9 +54,8 @@
         self.attrib[ns] = value
     return property(get, set)
 
-def escape(string, quote=None):
-    if not isinstance(string, unicode):
-        encoding = 'utf-8'
+def escape(string, quote=None, encoding=None):
+    if not isinstance(string, unicode) and encoding:
         string = string.decode(encoding)
     else:
         encoding = None

Modified: z3c.pt/trunk/src/z3c/pt/zpt.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/zpt.py	2008-09-10 14:33:08 UTC (rev 91032)
+++ z3c.pt/trunk/src/z3c/pt/zpt.py	2008-09-10 16:38:26 UTC (rev 91033)
@@ -132,7 +132,7 @@
     tal_omit = utils.attribute(
         utils.tal_attr('omit-tag'), lambda p: p.expression)
     tal_default_expression = utils.attribute(
-        utils.tal_attr('default-expression'))
+        utils.tal_attr('default-expression'), encoding='ascii')
     metal_define = utils.attribute(
         utils.metal_attr('define-macro'), lambda p: p.method)
     metal_use = utils.attribute(
@@ -211,7 +211,6 @@
 
     def parse(self, body):
         root, doctype = super(ZopePageTemplateParser, self).parse(body)
-
         # if a default expression is not set explicitly in the
         # template, use the TAL-attribute ``default-expression``
         # to set it

Modified: z3c.pt/trunk/src/z3c/pt/zpt.txt
===================================================================
--- z3c.pt/trunk/src/z3c/pt/zpt.txt	2008-09-10 14:33:08 UTC (rev 91032)
+++ z3c.pt/trunk/src/z3c/pt/zpt.txt	2008-09-10 16:38:26 UTC (rev 91033)
@@ -44,7 +44,7 @@
   ... <div xmlns="http://www.w3.org/1999/xhtml"
   ...      xmlns:tal="http://xml.zope.org/namespaces/tal">
   ...   <option tal:attributes="selected True"/>
-  ...   <option tal:attributes="selected False"/>
+  ...   <option tal:attributes="selected None"/>
   ...   <input tal:attributes="checked True"/>
   ...   <input tal:attributes="checked False"/>
   ... </div>""")



More information about the Checkins mailing list