[Checkins] SVN: z3c.pt/trunk/ Added symbol_mapping attribute to code stream such that function dependencies can be registered at compile-time.

Malthe Borch mborch at gmail.com
Sun Aug 31 17:14:32 EDT 2008


Log message for revision 90632:
  Added symbol_mapping attribute to code stream such that function dependencies can be registered at compile-time.

Changed:
  U   z3c.pt/trunk/CHANGES.txt
  U   z3c.pt/trunk/benchmark/benchmark/tests.py
  U   z3c.pt/trunk/src/z3c/pt/clauses.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/pagetemplate.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

-=-
Modified: z3c.pt/trunk/CHANGES.txt
===================================================================
--- z3c.pt/trunk/CHANGES.txt	2008-08-31 16:15:26 UTC (rev 90631)
+++ z3c.pt/trunk/CHANGES.txt	2008-08-31 21:14:30 UTC (rev 90632)
@@ -4,6 +4,9 @@
 Version 1.0dev
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+- Added ``symbol_mapping`` attribute to code streams such that
+  function dependencies can be registered at compile-time. [malthe]
+
 - Allow BaseTemplate-derived classes (PageTemplate, PageTemplateFile, 
   et. al) to accept a ``doctype`` argument, which will override the
   doctype supplied by the source of the template if specified. [chrism]

Modified: z3c.pt/trunk/benchmark/benchmark/tests.py
===================================================================
--- z3c.pt/trunk/benchmark/benchmark/tests.py	2008-08-31 16:15:26 UTC (rev 90631)
+++ z3c.pt/trunk/benchmark/benchmark/tests.py	2008-08-31 21:14:30 UTC (rev 90632)
@@ -302,8 +302,10 @@
 
         # In order to have a fair comparision, we need real zope.i18n handling
         zopefile.pt_getEngineContext = _pt_getEngineContext
+
+        assert config.SYMBOLS.i18n_context=='_i18n_context'
         
-        t_z3c = timing(z3cfile, table=table, context=self.env)
+        t_z3c = timing(z3cfile, table=table, _i18n_context=self.env)
         t_zope = timing(zopefile, table=table, env=self.env)
 
         print "z3c.pt:            %.2f" % t_z3c

Modified: z3c.pt/trunk/src/z3c/pt/clauses.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/clauses.py	2008-08-31 16:15:26 UTC (rev 90631)
+++ z3c.pt/trunk/src/z3c/pt/clauses.py	2008-08-31 21:14:30 UTC (rev 90632)
@@ -87,7 +87,7 @@
     def __init__(self, parts, variable=None):
         if not isinstance(parts, types.parts):
             parts = types.parts((parts,))
-        
+
         self.parts = parts
         self.variable = variable
         
@@ -114,6 +114,9 @@
     def _assign(self, variable, value, stream):
         stream.annotate(value)
         symbols = stream.symbols.as_dict()
+
+        if value.symbol_mapping:
+            stream.symbol_mapping.update(value.symbol_mapping)
         
         if isinstance(value, types.template):
             value = types.value(value % symbols)
@@ -743,11 +746,7 @@
     value = assign = None
     
     def __init__(self, value):
-        if isinstance(value, types.parts):
-            self.assign = Assign(value)
-        else:
-            self.value = value
-
+        self.assign = Assign(value)
         self.structure = not isinstance(value, types.escape)
         
     def begin(self, stream):
@@ -791,11 +790,12 @@
         # validate XML if enabled
         if config.VALIDATION:
             try:
-                etree.import_elementtree()
+                _et = etree.import_elementtree()
             except ImportError:
                 raise ImportError(
                     "ElementTree (required when XML validation is enabled).")
 
+            stream.symbol_mapping[stream.symbols.elementtree] = _et
             write("%(elementtree)s.fromstring('<div>%%s</div>' %% %(tmp)s)")
 
     def end(self, stream):

Modified: z3c.pt/trunk/src/z3c/pt/expressions.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/expressions.py	2008-08-31 16:15:26 UTC (rev 90631)
+++ z3c.pt/trunk/src/z3c/pt/expressions.py	2008-08-31 21:14:30 UTC (rev 90632)
@@ -9,6 +9,7 @@
 
 import interfaces
 import types
+import config
 
 _marker = object()
 
@@ -604,42 +605,7 @@
         r'^((nocall|not):\s*)*([A-Za-z_][A-Za-z0-9_]*)'+
         r'(/[A-Za-z_ at -][A-Za-z0-9_ at -\\.]*)*$')
 
-    @classmethod
-    def traverse(cls, base, request, call, *path_items):
-        """See ``zope.app.pagetemplate.engine``."""
 
-        _callable = callable(base)
-
-        for i in range(len(path_items)):
-            name = path_items[i]
-
-            next = getattr(base, name, _marker)
-            if next is not _marker:
-                _callable = callable(next)
-
-                if _callable:
-                    base = next()
-                else:
-                    base = next
-                    continue
-            else:
-                # special-case dicts for performance reasons        
-                if getattr(base, '__class__', None) == dict:
-                    base = base[name]
-                else:
-                    base = zope.traversing.adapters.traversePathElement(
-                        base, name, path_items[i+1:], request=request)
-
-            _callable = callable(base)
-
-            if not isinstance(base, (basestring, tuple, list)):
-                base = zope.security.proxy.ProxyFactory(base)
-
-        if call and _callable:
-            base = base()
-                
-        return base
-
     def validate(self, string):
         if not self.path_regex.match(string):
             raise SyntaxError("Not a valid path-expression.")
@@ -691,11 +657,49 @@
             components = ()
 
         value = types.value(
-            '_path(%s, request, %s, %s)' % (base, not nocall, ', '.join(components)))
+            '%s(%s, request, %s, %s)' % \
+            (config.SYMBOLS.path, base, not nocall, ', '.join(components)))
 
         if negate:
             value = types.value('not(%s)' % value)
 
+        value.symbol_mapping[config.SYMBOLS.path] = path_traverse
+
         return value
 
+def path_traverse(base, request, call, *path_items):
+    """See ``zope.app.pagetemplate.engine``."""
+
+    _callable = callable(base)
+
+    for i in range(len(path_items)):
+        name = path_items[i]
+
+        next = getattr(base, name, _marker)
+        if next is not _marker:
+            _callable = callable(next)
+
+            if _callable:
+                base = next()
+            else:
+                base = next
+                continue
+        else:
+            # special-case dicts for performance reasons        
+            if getattr(base, '__class__', None) == dict:
+                base = base[name]
+            else:
+                base = zope.traversing.adapters.traversePathElement(
+                    base, name, path_items[i+1:], request=request)
+
+        _callable = callable(base)
+
+        if not isinstance(base, (basestring, tuple, list)):
+            base = zope.security.proxy.ProxyFactory(base)
+
+    if call and _callable:
+        base = base()
+
+    return base
+
 path_translation = PathTranslation()

Modified: z3c.pt/trunk/src/z3c/pt/generation.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/generation.py	2008-08-31 16:15:26 UTC (rev 90631)
+++ z3c.pt/trunk/src/z3c/pt/generation.py	2008-08-31 21:14:30 UTC (rev 90632)
@@ -10,10 +10,6 @@
 def render(%(init)s, %(args)s%(extra)s%(language)s=None):
 \t%(out)s, %(write)s = %(init)s.initialize_stream()
 \t%(attributes)s, %(repeat)s = %(init)s.initialize_tal()
-\t%(marker)s = %(init)s.initialize_helpers()
-\t%(path)s = %(init)s.initialize_traversal()
-\t%(translate)s = %(init)s.fast_translate
-\t%(elementtree)s = %(init)s.initialize_elementtree()
 \t%(scope)s = {}
 
 %(body)s
@@ -23,13 +19,12 @@
 macro_wrapper = """\
 def render(%(init)s, %(kwargs)s%(extra)s):
 \t%(attributes)s, %(repeat)s = %(init)s.initialize_tal()
-\t%(marker)s = %(init)s.initialize_helpers()
-\t%(path)s = %(init)s.initialize_traversal()
-\t%(translate)s = %(init)s.fast_translate
-\t%(elementtree)s = %(init)s.initialize_elementtree()
 %(body)s
 """
 
+class marker(object):
+    pass
+
 def fast_translate(msgid, domain=None, mapping=None, context=None,
                    target_language=None, default=None):
     """This translation function does not attempt to negotiate a
@@ -55,22 +50,10 @@
 def initialize_tal():
     return ({}, utils.repeatdict())
 
-def initialize_helpers():
-    return (object(), )
-
 def initialize_stream():
     out = BufferIO()
     return (out, out.write)
 
-def initialize_traversal():
-    return expressions.path_translation.traverse
-
-def initialize_elementtree():
-    try:
-        return etree.import_elementtree()
-    except ImportError:
-        return None
-    
 class BufferIO(list):
     write = list.append
 
@@ -88,6 +71,7 @@
     def __init__(self, symbols=None, indentation=0, indentation_string="\t"):
         BufferIO.__init__(self)
         self.symbols = symbols or object
+        self.symbol_mapping = {}
         self.indentation = indentation
         self.indentation_string = indentation_string
         self.queue = ''

Modified: z3c.pt/trunk/src/z3c/pt/pagetemplate.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/pagetemplate.py	2008-08-31 16:15:26 UTC (rev 90631)
+++ z3c.pt/trunk/src/z3c/pt/pagetemplate.py	2008-08-31 21:14:30 UTC (rev 90632)
@@ -74,7 +74,7 @@
     """If ``filename`` is a relative path, the module path of the
     class where the instance is used to get an absolute path."""
     
-    def __init__(self, filename, **kwargs):
+    def __init__(self, filename, content_type=None, **kwargs):
         if not os.path.isabs(filename):	       
             for depth in (1, 2):	       
                 frame = sys._getframe(depth)	 

Modified: z3c.pt/trunk/src/z3c/pt/translation.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/translation.py	2008-08-31 16:15:26 UTC (rev 90631)
+++ z3c.pt/trunk/src/z3c/pt/translation.py	2008-08-31 21:14:30 UTC (rev 90632)
@@ -280,6 +280,7 @@
             # write translation to output if successful, otherwise
             # fallback to default rendition; 
             result = types.value(self.symbols.result)
+            result.symbol_mapping[self.symbols.marker] = generation.marker
             condition = types.template('%(result)s is not %(marker)s')
             _.append(clauses.Condition(condition,
                         [clauses.UnicodeWrite(result)]))
@@ -330,11 +331,17 @@
         return msgid
 
     def translate_expression(self, value, mapping=None, default=None):
-        format = "_translate(%s, domain=%%(domain)s, mapping=%s, " \
+        format = "%%(translate)s(%s, domain=%%(domain)s, mapping=%s, " \
                  "target_language=%%(language)s, default=%s)"
-        return types.template(
+        template = types.template(
             format % (value, mapping, default))
 
+        # add translate-method to symbol mapping
+        translate = generation.fast_translate
+        template.symbol_mapping[config.SYMBOLS.translate] = translate
+
+        return template
+    
 class Element(etree.ElementBase):
     """Template element class.
 
@@ -486,6 +493,7 @@
 
         # start generation
         self.root.start(stream)
+        body = stream.getvalue()
 
         # prepare args
         ignore = 'target_language',
@@ -504,21 +512,25 @@
             extra += '%s=None, ' % selector
 
         # wrap generated Python-code in function definition
-        body = stream.getvalue()
         mapping = dict(
             args=args, kwargs=kwargs, extra=extra, body=body)
         mapping.update(stream.symbols.__dict__)
         source = wrapper % mapping
         
+        # set symbol mappings as globals
+        _globals = stream.symbol_mapping
+        
         # compile code
-        suite = codegen.Suite(source)
+        suite = codegen.Suite(source, globals=_globals)
+        suite._globals.update(_globals)
+        
+        # execute code
         _locals = {}
-        _globals = {}
         exec suite.code in suite._globals, _locals
+        render = _locals['render']
+        
+        return ByteCodeTemplate(render, self.root, self.parser, stream)
 
-        return ByteCodeTemplate(
-            _locals['render'], self.root, self.parser, stream)
-
 class ByteCodeTemplate(object):
     """Template compiled to byte-code."""
 

Modified: z3c.pt/trunk/src/z3c/pt/types.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/types.py	2008-08-31 16:15:26 UTC (rev 90631)
+++ z3c.pt/trunk/src/z3c/pt/types.py	2008-08-31 21:14:30 UTC (rev 90632)
@@ -1,11 +1,17 @@
+from utils import emptydict
+
 class expression:
-    pass
+    symbol_mapping = emptydict()
 
 class parts(tuple, expression):
     def __repr__(self):
         return 'parts'+tuple.__repr__(self)
 
-class value(str, expression):            
+class value(str, expression):
+    def __init__(self, *args):
+        super(value, self).__init__(*args)
+        self.symbol_mapping = {}
+
     def __repr__(self):
         return 'value(%s)' % str.__repr__(self)
 

Modified: z3c.pt/trunk/src/z3c/pt/utils.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/utils.py	2008-08-31 16:15:26 UTC (rev 90631)
+++ z3c.pt/trunk/src/z3c/pt/utils.py	2008-08-31 21:14:30 UTC (rev 90632)
@@ -49,6 +49,10 @@
     def __hash__(self):
         return self.hash
 
+class emptydict(dict):
+    def __setitem__(self, key, value):
+        raise TypeError("Read-only dictionary does not support assignment.")
+    
 class repeatitem(object):
     def __init__(self, iterator, length):
         self.length = length

Modified: z3c.pt/trunk/src/z3c/pt/zpt.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/zpt.py	2008-08-31 16:15:26 UTC (rev 90631)
+++ z3c.pt/trunk/src/z3c/pt/zpt.py	2008-08-31 21:14:30 UTC (rev 90632)
@@ -195,6 +195,10 @@
 
     default_expression = 'python'
 
+    def __init__(self, default_expression=None):
+        if default_expression is not None:
+            self.default_expression = default_expression
+
     @classmethod
     def parse(cls, body):
         root, doctype = super(ZopePageTemplateParser, cls).parse(body)



More information about the Checkins mailing list