Logo Search packages:      
Sourcecode: zope-loginmanager version File versions

Expressions.py

00001 """Utilties for computing DTML (restricted Python) Expressions

  This module exports everything you need to set up and call DTML expressions,
  including pickle-able (but not Persistent) Expression and Name lookup
  classes.  The general usage pattern looks like this::

   from Products.ZPatterns.Expressions import *
   
   md = NamespaceStack()             # make a namespace stack
   i = InstanceDict(object, md)      # prepare an object for pushing onto stack
  
   md._push(i)                             # push it on the stack
   getSecurityManager().addContext(self)   # add owner mask/proxy roles
        
   try:
       # compute the result 
       result = Expression(someString).eval(md)
       
   finally:
       getSecurityManager().removeContext(self)   # remove security context
       md._pop()                                  # remove pushed object

  Of course, if you need to place other data on the stack, your actual code
  will vary.  Also, it is more likely that you will store
  'Expression(someString)' as an attribute of your own objects, and simply
  call its '.eval()' method when you need it, in order to avoid excessive
  recompiling of the same expression.

  Note: The 'pushProxy(ob)' and 'popProxy(ob)' routines are simple synonyms for
  'getSecurityManager().addContext(ob)' and
  'getSecurityManager().removeContext(ob)', respectively.  They were originally
  created to mask the differences between Zope 2.1.x and 2.2.x, and so should
  be avoided when writing new code.
"""

from ExtensionClass import Base
from ComputedAttribute import ComputedAttribute
from DocumentTemplate.DT_Util import Eval, expr_globals, TemplateDict, \
    InstanceDict
from AccessControl import getSecurityManager

00042 class NamespaceStack(TemplateDict):
    """A DTML-style namespace stack, complete with Zope security
    
    To use, just create one with 'NamespaceStack()', then use its '_push()' and
    '_pop()' methods to add/remove mapping objects.  If you need to push a
    regular object instance (ala DTML's "with" tag), use::
    
      stack._push(InstanceDict(object,stack))"""

    # Called by Zope only
    def validate(self, inst, parent, name, value, md):
        return getSecurityManager().validate(inst, parent, name, value)


00056 def pushProxy(ob):

    """Push an object onto the security manager context stack
    
       DEPRECATED - use 'getSecurityManager().addContext(ob)' instead"""
        
    getSecurityManager().addContext(ob)


00065 def popProxy(ob):

    """Pop an object from the security manager context stack

       DEPRECATED - use 'getSecurityManager().removeContext(ob)' instead"""
        
    getSecurityManager().removeContext(ob)











00083 class Expression(Base):
    """DTML (restricted Python) Expression object that can be pickled

    To use, create with 'Expression("some string")'.  You can then save the
    created object as an attribute of any 'Persistent' object, and it will be
    properly pickled, without writing any actual Python bytecode to the ZODB.

    The secret is that the '_v_expr' computed attribute automatically recompiles
    the expression whenever it's needed, but caches it while the 'Expression' is
    in memory to avoid unnecessary re-compiling.

    To compute the result of the expression, call its 'eval()' method, passing
    in a 'NamespaceStack' object."""

00097     def __init__(self, expr):
        """Create the expression object.  'expr' is a string."""
        self.expr = expr

    # Private: computed attribute for compiled form of expression
    def _v_expr(self, expr_globals=expr_globals, Eval=Eval):
        self._v_expr = Eval(self.expr, expr_globals)
        return self._v_expr

    _v_expr = ComputedAttribute(_v_expr)

    # Private: returns pickle-able state, minus compiled expression
    def __getstate__(self):
        d = self.__dict__.copy()
        if d.has_key('_v_expr'):
            del d['_v_expr']
        return d

    # Private: load pickle state
    def __setstate__(self, state):
        d = self.__dict__
        d.clear(); d.update(state)
        
00120     def eval(self,mapping):
        """Return the result of computing the expression in the context of 'mapping'"""
        return self._v_expr.eval(mapping)

00124 class Name:
    """Object that does a DTML-style name lookup, with optional call of the
retrieved object"""
    
00128     def __init__(self,name,call=1):
        """Create an object with the same interface as an 'Expression', but
which just looks up a name, and calls it if 'call==1'."""
        self.name, self.call = name, call

00133     def eval(self,mapping):
        """Return the result of looking up/calling the name from 'mapping'.
If the object was created with 'call==1', call it before returning it."""
        return md.getitem(self.name,self.call)


del Eval, expr_globals, TemplateDict, Base, ComputedAttribute


Generated by  Doxygen 1.6.0   Back to index