"Fossies" - the Fresh Open Source Software Archive

Member "roundup-2.0.0/roundup/cgi/PageTemplates/Expressions.py" (26 Aug 2019, 11128 Bytes) of package /linux/www/roundup-2.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "Expressions.py": 1.6.1_vs_2.0.0.

    1 ##############################################################################
    2 #
    3 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
    4 #
    5 # This software is subject to the provisions of the Zope Public License,
    6 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
    7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
    8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
   10 # FOR A PARTICULAR PURPOSE
   11 #
   12 ##############################################################################
   13 # Modified for Roundup:
   14 # 
   15 # 1. removed all Zope-specific code (doesn't even try to import that stuff now)
   16 # 2. removed all Acquisition
   17 # 3. removed blocking of leading-underscore URL components
   18 
   19 """Page Template Expression Engine
   20 
   21 Page Template-specific implementation of TALES, with handlers
   22 for Python expressions, string literals, and paths.
   23 """
   24 
   25 import re, sys
   26 try:
   27     from collections.abc import Callable
   28 except ImportError:
   29     from collections import Callable
   30 
   31 from .TALES import Engine, CompilerError, _valid_name, NAME_RE, \
   32      Undefined, Default, _parse_expr
   33 
   34 
   35 _engine = None
   36 def getEngine():
   37     global _engine
   38     if _engine is None:
   39         from .PathIterator import Iterator
   40         _engine = Engine(Iterator)
   41         installHandlers(_engine)
   42     return _engine
   43 
   44 def installHandlers(engine):
   45     reg = engine.registerType
   46     pe = PathExpr
   47     for pt in ('standard', 'path', 'exists', 'nocall'):
   48         reg(pt, pe)
   49     reg('string', StringExpr)
   50     reg('python', PythonExpr)
   51     reg('not', NotExpr)
   52     reg('defer', DeferExpr)
   53 
   54 from .PythonExpr import getSecurityManager, PythonExpr
   55 guarded_getattr = getattr
   56 try:
   57     from zExceptions import Unauthorized
   58 except ImportError:
   59     class Unauthorized(BaseException):
   60         pass
   61 
   62 def acquisition_security_filter(orig, inst, name, v, real_validate):
   63     if real_validate(orig, inst, name, v):
   64         return 1
   65     raise Unauthorized(name)
   66 
   67 def call_with_ns(f, ns, arg=1):
   68     if arg==2:
   69         return f(None, ns)
   70     else:
   71         return f(ns)
   72 
   73 class _SecureModuleImporter:
   74     """Simple version of the importer for use with trusted code."""
   75     __allow_access_to_unprotected_subobjects__ = 1
   76     def __getitem__(self, module):
   77         __import__(module)
   78         return sys.modules[module]
   79 
   80 SecureModuleImporter = _SecureModuleImporter()
   81 
   82 Undefs = (Undefined, AttributeError, KeyError,
   83           TypeError, IndexError, Unauthorized)
   84 
   85 def render(ob, ns):
   86     """
   87     Calls the object, possibly a document template, or just returns it if
   88     not callable.  (From DT_Util.py)
   89     """
   90     if hasattr(ob, '__render_with_namespace__'):
   91         ob = call_with_ns(ob.__render_with_namespace__, ns)
   92     else:
   93         base = ob
   94         if isinstance(base, Callable):
   95             try:
   96                 if getattr(base, 'isDocTemp', 0):
   97                     ob = call_with_ns(ob, ns, 2)
   98                 else:
   99                     ob = ob()
  100             except AttributeError as n:
  101                 if str(n) != '__call__':
  102                     raise
  103     return ob
  104 
  105 class SubPathExpr:
  106     def __init__(self, path):
  107         self._path = path = path.strip().split('/')
  108         self._base = base = path.pop(0)
  109         if base and not _valid_name(base):
  110             raise CompilerError('Invalid variable name "%s"' % base)
  111         # Parse path
  112         self._dp = dp = []
  113         for i in range(len(path)):
  114             e = path[i]
  115             if e[:1] == '?' and _valid_name(e[1:]):
  116                 dp.append((i, e[1:]))
  117         dp.reverse()
  118 
  119     def _eval(self, econtext,
  120               list=list, isinstance=isinstance, StringType=type('')):
  121         vars = econtext.vars
  122         path = self._path
  123         if self._dp:
  124             path = list(path) # Copy!
  125             for i, varname in self._dp:
  126                 val = vars[varname]
  127                 if isinstance(val, StringType):
  128                     path[i] = val
  129                 else:
  130                     # If the value isn't a string, assume it's a sequence
  131                     # of path names.
  132                     path[i:i+1] = list(val)
  133         base = self._base
  134         __traceback_info__ = 'path expression "%s"'%('/'.join(self._path))
  135         if base == 'CONTEXTS' or not base:
  136             ob = econtext.contexts
  137         else:
  138             ob = vars[base]
  139         if isinstance(ob, DeferWrapper):
  140             ob = ob()
  141         if path:
  142             ob = restrictedTraverse(ob, path, getSecurityManager())
  143         return ob
  144 
  145 class PathExpr:
  146     def __init__(self, name, expr, engine):
  147         self._s = expr
  148         self._name = name
  149         self._hybrid = 0
  150         paths = expr.split('|')
  151         self._subexprs = []
  152         add = self._subexprs.append
  153         for i in range(len(paths)):
  154             path = paths[i].lstrip()
  155             if _parse_expr(path):
  156                 # This part is the start of another expression type,
  157                 # so glue it back together and compile it.
  158                 add(engine.compile(('|'.join(paths[i:]).lstrip())))
  159                 self._hybrid = 1
  160                 break
  161             add(SubPathExpr(path)._eval)
  162 
  163     def _exists(self, econtext):
  164         for expr in self._subexprs:
  165             try:
  166                 expr(econtext)
  167             except Undefs:
  168                 pass
  169             else:
  170                 return 1
  171         return 0
  172 
  173     def _eval(self, econtext,
  174               isinstance=isinstance, StringType=type(''), render=render):
  175         for expr in self._subexprs[:-1]:
  176             # Try all but the last subexpression, skipping undefined ones.
  177             try:
  178                 ob = expr(econtext)
  179             except Undefs:
  180                 pass
  181             else:
  182                 break
  183         else:
  184             # On the last subexpression allow exceptions through, and
  185             # don't autocall if the expression was not a subpath.
  186             ob = self._subexprs[-1](econtext)
  187             if self._hybrid:
  188                 return ob
  189 
  190         if self._name == 'nocall' or isinstance(ob, StringType):
  191             return ob
  192         # Return the rendered object
  193         return render(ob, econtext.vars)
  194 
  195     def __call__(self, econtext):
  196         if self._name == 'exists':
  197             return self._exists(econtext)
  198         return self._eval(econtext)
  199 
  200     def __str__(self):
  201         return '%s expression %s' % (self._name, repr(self._s))
  202 
  203     def __repr__(self):
  204         return '%s:%s' % (self._name, repr(self._s))
  205 
  206 
  207 _interp = re.compile(r'\$(%(n)s)|\${(%(n)s(?:/[^}]*)*)}' % {'n': NAME_RE})
  208 
  209 class StringExpr:
  210     def __init__(self, name, expr, engine):
  211         self._s = expr
  212         if '%' in expr:
  213             expr = expr.replace('%', '%%')
  214         self._vars = vars = []
  215         if '$' in expr:
  216             parts = []
  217             for exp in expr.split('$$'):
  218                 if parts: parts.append('$')
  219                 m = _interp.search(exp)
  220                 while m is not None:
  221                     parts.append(exp[:m.start()])
  222                     parts.append('%s')
  223                     vars.append(PathExpr('path', m.group(1) or m.group(2),
  224                                          engine))
  225                     exp = exp[m.end():]
  226                     m = _interp.search(exp)
  227                 if '$' in exp:
  228                     raise CompilerError(
  229                         '$ must be doubled or followed by a simple path')
  230                 parts.append(exp)
  231             expr = ''.join(parts)
  232         self._expr = expr
  233 
  234     def __call__(self, econtext):
  235         vvals = []
  236         for var in self._vars:
  237             v = var(econtext)
  238             # I hope this isn't in use anymore.
  239             ## if isinstance(v, Exception):
  240             ##     raise v
  241             vvals.append(v)
  242         return self._expr % tuple(vvals)
  243 
  244     def __str__(self):
  245         return 'string expression %s' % repr(self._s)
  246 
  247     def __repr__(self):
  248         return 'string:%s' % repr(self._s)
  249 
  250 class NotExpr:
  251     def __init__(self, name, expr, compiler):
  252         self._s = expr = expr.lstrip()
  253         self._c = compiler.compile(expr)
  254 
  255     def __call__(self, econtext):
  256         # We use the (not x) and 1 or 0 formulation to avoid changing
  257         # the representation of the result in Python 2.3, where the
  258         # result of "not" becomes an instance of bool.
  259         return (not econtext.evaluateBoolean(self._c)) and 1 or 0
  260 
  261     def __repr__(self):
  262         return 'not:%s' % repr(self._s)
  263 
  264 class DeferWrapper:
  265     def __init__(self, expr, econtext):
  266         self._expr = expr
  267         self._econtext = econtext
  268 
  269     def __str__(self):
  270         return str(self())
  271 
  272     def __call__(self):
  273         return self._expr(self._econtext)
  274 
  275 class DeferExpr:
  276     def __init__(self, name, expr, compiler):
  277         self._s = expr = expr.lstrip()
  278         self._c = compiler.compile(expr)
  279 
  280     def __call__(self, econtext):
  281         return DeferWrapper(self._c, econtext)
  282 
  283     def __repr__(self):
  284         return 'defer:%s' % repr(self._s)
  285 
  286 class TraversalError:
  287     def __init__(self, path, name):
  288         self.path = path
  289         self.name = name
  290 
  291 
  292 
  293 def restrictedTraverse(object, path, securityManager,
  294                        get=getattr, has=hasattr, N=None, M=[],
  295                        TupleType=type(()) ):
  296 
  297     REQUEST = {'path': path}
  298     REQUEST['TraversalRequestNameStack'] = path = path[:] # Copy!
  299     path.reverse()
  300     validate = securityManager.validate
  301     __traceback_info__ = REQUEST
  302     done = []
  303     while path:
  304         name = path.pop()
  305         __traceback_info__ = TraversalError(done, name)
  306 
  307         if isinstance(name, TupleType):
  308             object = object(*name)
  309             continue
  310 
  311         if not name:
  312             # Skip directly to item access
  313             o = object[name]
  314             # Check access to the item.
  315             if not validate(object, object, name, o):
  316                 raise Unauthorized(name)
  317             object = o
  318             continue
  319 
  320         # Try an attribute.
  321         o = guarded_getattr(object, name, M)
  322         if o is M:
  323             # Try an item.
  324             try:
  325                 # XXX maybe in Python 2.2 we can just check whether
  326                 # the object has the attribute "__getitem__"
  327                 # instead of blindly catching exceptions.
  328                 o = object[name]
  329             except AttributeError as exc:
  330                 if str(exc).find('__getitem__') >= 0:
  331                     # The object does not support the item interface.
  332                     # Try to re-raise the original attribute error.
  333                     # XXX I think this only happens with
  334                     # ExtensionClass instances.
  335                     guarded_getattr(object, name)
  336                 raise
  337             except TypeError as exc:
  338                 if str(exc).find('unsubscriptable') >= 0:
  339                     # The object does not support the item interface.
  340                     # Try to re-raise the original attribute error.
  341                     # XXX This is sooooo ugly.
  342                     guarded_getattr(object, name)
  343                 raise
  344         done.append((name, o))
  345         object = o
  346 
  347     return object