annotate roundup/cgi/PageTemplates/Expressions.py @ 5548:fea11d05110e

Avoid errors from selecting "no selection" on multilink (issue2550722). As discussed in issue 2550722 there are various cases where selecting "no selection" on a multilink can result in inappropriate errors from Roundup: * If selecting "no selection" produces a null edit (a value was set in the multilink in an edit with an error, then removed again, along with all other changes, in the next form submission), so the page is rendered from the form contents including the "-<id>" value for "no selection" for the multilink. * If creating an item with a nonempty value for a multilink has an error, and the resubmission changes that multilink to "no selection" (and this in turn has subcases, according to whether the creation then succeeds or fails on the resubmission, which need fixes in different places in the Roundup code). All of these cases have in common that it is expected and OK to have a "-<id>" value for a submission for a multilink when <id> is not set in that multilink in the database (because the original attempt to set <id> in that multilink had an error), so the hyperdb.py logic to give an error in that case is thus removed. In the subcase of the second case where the resubmission with "no selection" has an error, the templating code tries to produce a menu entry for the "-<id>" multilink value, which also results in an error, hence the templating.py change to ignore such values in the list for a multilink.
author Joseph Myers <jsm@polyomino.org.uk>
date Thu, 27 Sep 2018 11:33:01 +0000
parents 5a871a250670
children 33b25e51e127
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
1 ##############################################################################
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
2 #
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
3 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
4 #
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
5 # This software is subject to the provisions of the Zope Public License,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
6 # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
10 # FOR A PARTICULAR PURPOSE
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
11 #
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
12 ##############################################################################
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
13 # Modified for Roundup:
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
14 #
2663
5f9e00836006 update comment
Richard Jones <richard@users.sourceforge.net>
parents: 2351
diff changeset
15 # 1. removed all Zope-specific code (doesn't even try to import that stuff now)
5f9e00836006 update comment
Richard Jones <richard@users.sourceforge.net>
parents: 2351
diff changeset
16 # 2. removed all Acquisition
5f9e00836006 update comment
Richard Jones <richard@users.sourceforge.net>
parents: 2351
diff changeset
17 # 3. removed blocking of leading-underscore URL components
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
18
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
19 """Page Template Expression Engine
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
20
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
21 Page Template-specific implementation of TALES, with handlers
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
22 for Python expressions, string literals, and paths.
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
23 """
1071
c08b3820edd1 Adhering to ZPL
Richard Jones <richard@users.sourceforge.net>
parents: 1065
diff changeset
24
5406
5a871a250670 Python 3 preparation: use isinstance(x, collections.Callable) instead of callable(x).
Joseph Myers <jsm@polyomino.org.uk>
parents: 5388
diff changeset
25 import collections, re, sys
5388
d26921b851c3 Python 3 preparation: make relative imports explicit.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5378
diff changeset
26 from .TALES import Engine, CompilerError, _valid_name, NAME_RE, \
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
27 Undefined, Default, _parse_expr
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
28
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
29
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
30 _engine = None
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
31 def getEngine():
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
32 global _engine
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
33 if _engine is None:
5388
d26921b851c3 Python 3 preparation: make relative imports explicit.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5378
diff changeset
34 from .PathIterator import Iterator
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
35 _engine = Engine(Iterator)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
36 installHandlers(_engine)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
37 return _engine
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
38
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
39 def installHandlers(engine):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
40 reg = engine.registerType
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
41 pe = PathExpr
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
42 for pt in ('standard', 'path', 'exists', 'nocall'):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
43 reg(pt, pe)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
44 reg('string', StringExpr)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
45 reg('python', PythonExpr)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
46 reg('not', NotExpr)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
47 reg('defer', DeferExpr)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
48
5388
d26921b851c3 Python 3 preparation: make relative imports explicit.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5378
diff changeset
49 from .PythonExpr import getSecurityManager, PythonExpr
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
50 guarded_getattr = getattr
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
51 try:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
52 from zExceptions import Unauthorized
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
53 except ImportError:
5265
63868084b8bb Python 2 and 3 support. Convert Exception to BaseException. TAL and
John Rouillard <rouilj@ieee.org>
parents: 5248
diff changeset
54 class Unauthorized(BaseException):
4238
445e1bc8b1df remove use of string exception
Richard Jones <richard@users.sourceforge.net>
parents: 2663
diff changeset
55 pass
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
56
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
57 def acquisition_security_filter(orig, inst, name, v, real_validate):
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
58 if real_validate(orig, inst, name, v):
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
59 return 1
5378
35ea9b1efc14 Python 3 preparation: "raise" syntax.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5377
diff changeset
60 raise Unauthorized(name)
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
61
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
62 def call_with_ns(f, ns, arg=1):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
63 if arg==2:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
64 return f(None, ns)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
65 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
66 return f(ns)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
67
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
68 class _SecureModuleImporter:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
69 """Simple version of the importer for use with trusted code."""
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
70 __allow_access_to_unprotected_subobjects__ = 1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
71 def __getitem__(self, module):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
72 __import__(module)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
73 return sys.modules[module]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
74
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
75 SecureModuleImporter = _SecureModuleImporter()
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
76
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
77 Undefs = (Undefined, AttributeError, KeyError,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
78 TypeError, IndexError, Unauthorized)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
79
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
80 def render(ob, ns):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
81 """
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
82 Calls the object, possibly a document template, or just returns it if
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
83 not callable. (From DT_Util.py)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
84 """
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
85 if hasattr(ob, '__render_with_namespace__'):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
86 ob = call_with_ns(ob.__render_with_namespace__, ns)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
87 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
88 base = ob
5406
5a871a250670 Python 3 preparation: use isinstance(x, collections.Callable) instead of callable(x).
Joseph Myers <jsm@polyomino.org.uk>
parents: 5388
diff changeset
89 if isinstance(base, collections.Callable):
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
90 try:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
91 if getattr(base, 'isDocTemp', 0):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
92 ob = call_with_ns(ob, ns, 2)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
93 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
94 ob = ob()
5248
198b6e810c67 Use Python-3-compatible 'as' syntax for except statements
Eric S. Raymond <esr@thyrsus.com>
parents: 4570
diff changeset
95 except AttributeError as n:
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
96 if str(n) != '__call__':
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
97 raise
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
98 return ob
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
99
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
100 class SubPathExpr:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
101 def __init__(self, path):
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
102 self._path = path = path.strip().split('/')
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
103 self._base = base = path.pop(0)
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
104 if base and not _valid_name(base):
5378
35ea9b1efc14 Python 3 preparation: "raise" syntax.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5377
diff changeset
105 raise CompilerError('Invalid variable name "%s"' % base)
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
106 # Parse path
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
107 self._dp = dp = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
108 for i in range(len(path)):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
109 e = path[i]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
110 if e[:1] == '?' and _valid_name(e[1:]):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
111 dp.append((i, e[1:]))
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
112 dp.reverse()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
113
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
114 def _eval(self, econtext,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
115 list=list, isinstance=isinstance, StringType=type('')):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
116 vars = econtext.vars
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
117 path = self._path
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
118 if self._dp:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
119 path = list(path) # Copy!
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
120 for i, varname in self._dp:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
121 val = vars[varname]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
122 if isinstance(val, StringType):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
123 path[i] = val
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
124 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
125 # If the value isn't a string, assume it's a sequence
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
126 # of path names.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
127 path[i:i+1] = list(val)
1065
0f9aa62917bd much nicer error messages when there's a templating error
Richard Jones <richard@users.sourceforge.net>
parents: 1049
diff changeset
128 base = self._base
1136
7e193bbda38e added generic item editing
Richard Jones <richard@users.sourceforge.net>
parents: 1101
diff changeset
129 __traceback_info__ = 'path expression "%s"'%('/'.join(self._path))
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
130 if base == 'CONTEXTS' or not base:
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
131 ob = econtext.contexts
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
132 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
133 ob = vars[base]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
134 if isinstance(ob, DeferWrapper):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
135 ob = ob()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
136 if path:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
137 ob = restrictedTraverse(ob, path, getSecurityManager())
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
138 return ob
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
139
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
140 class PathExpr:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
141 def __init__(self, name, expr, engine):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
142 self._s = expr
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
143 self._name = name
1233
69bf0d381fd7 Zope Collector fixes.
Richard Jones <richard@users.sourceforge.net>
parents: 1181
diff changeset
144 self._hybrid = 0
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
145 paths = expr.split('|')
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
146 self._subexprs = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
147 add = self._subexprs.append
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
148 for i in range(len(paths)):
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
149 path = paths[i].lstrip()
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
150 if _parse_expr(path):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
151 # This part is the start of another expression type,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
152 # so glue it back together and compile it.
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
153 add(engine.compile(('|'.join(paths[i:]).lstrip())))
1233
69bf0d381fd7 Zope Collector fixes.
Richard Jones <richard@users.sourceforge.net>
parents: 1181
diff changeset
154 self._hybrid = 1
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
155 break
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
156 add(SubPathExpr(path)._eval)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
157
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
158 def _exists(self, econtext):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
159 for expr in self._subexprs:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
160 try:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
161 expr(econtext)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
162 except Undefs:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
163 pass
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
164 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
165 return 1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
166 return 0
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
167
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
168 def _eval(self, econtext,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
169 isinstance=isinstance, StringType=type(''), render=render):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
170 for expr in self._subexprs[:-1]:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
171 # Try all but the last subexpression, skipping undefined ones.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
172 try:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
173 ob = expr(econtext)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
174 except Undefs:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
175 pass
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
176 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
177 break
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
178 else:
1233
69bf0d381fd7 Zope Collector fixes.
Richard Jones <richard@users.sourceforge.net>
parents: 1181
diff changeset
179 # On the last subexpression allow exceptions through, and
69bf0d381fd7 Zope Collector fixes.
Richard Jones <richard@users.sourceforge.net>
parents: 1181
diff changeset
180 # don't autocall if the expression was not a subpath.
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
181 ob = self._subexprs[-1](econtext)
1233
69bf0d381fd7 Zope Collector fixes.
Richard Jones <richard@users.sourceforge.net>
parents: 1181
diff changeset
182 if self._hybrid:
69bf0d381fd7 Zope Collector fixes.
Richard Jones <richard@users.sourceforge.net>
parents: 1181
diff changeset
183 return ob
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
184
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
185 if self._name == 'nocall' or isinstance(ob, StringType):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
186 return ob
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
187 # Return the rendered object
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
188 return render(ob, econtext.vars)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
189
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
190 def __call__(self, econtext):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
191 if self._name == 'exists':
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
192 return self._exists(econtext)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
193 return self._eval(econtext)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
194
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
195 def __str__(self):
5377
12fe83f90f0d Python 3 preparation: use repr() instead of ``.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5265
diff changeset
196 return '%s expression %s' % (self._name, repr(self._s))
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
197
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
198 def __repr__(self):
5377
12fe83f90f0d Python 3 preparation: use repr() instead of ``.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5265
diff changeset
199 return '%s:%s' % (self._name, repr(self._s))
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
200
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
201
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
202 _interp = re.compile(r'\$(%(n)s)|\${(%(n)s(?:/[^}]*)*)}' % {'n': NAME_RE})
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
203
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
204 class StringExpr:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
205 def __init__(self, name, expr, engine):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
206 self._s = expr
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
207 if '%' in expr:
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
208 expr = expr.replace('%', '%%')
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
209 self._vars = vars = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
210 if '$' in expr:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
211 parts = []
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
212 for exp in expr.split('$$'):
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
213 if parts: parts.append('$')
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
214 m = _interp.search(exp)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
215 while m is not None:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
216 parts.append(exp[:m.start()])
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
217 parts.append('%s')
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
218 vars.append(PathExpr('path', m.group(1) or m.group(2),
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
219 engine))
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
220 exp = exp[m.end():]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
221 m = _interp.search(exp)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
222 if '$' in exp:
5378
35ea9b1efc14 Python 3 preparation: "raise" syntax.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5377
diff changeset
223 raise CompilerError(
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
224 '$ must be doubled or followed by a simple path')
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
225 parts.append(exp)
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
226 expr = ''.join(parts)
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
227 self._expr = expr
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
228
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
229 def __call__(self, econtext):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
230 vvals = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
231 for var in self._vars:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
232 v = var(econtext)
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
233 # I hope this isn't in use anymore.
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
234 ## if isinstance(v, Exception):
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
235 ## raise v
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
236 vvals.append(v)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
237 return self._expr % tuple(vvals)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
238
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
239 def __str__(self):
5377
12fe83f90f0d Python 3 preparation: use repr() instead of ``.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5265
diff changeset
240 return 'string expression %s' % repr(self._s)
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
241
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
242 def __repr__(self):
5377
12fe83f90f0d Python 3 preparation: use repr() instead of ``.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5265
diff changeset
243 return 'string:%s' % repr(self._s)
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
244
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
245 class NotExpr:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
246 def __init__(self, name, expr, compiler):
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
247 self._s = expr = expr.lstrip()
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
248 self._c = compiler.compile(expr)
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
249
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
250 def __call__(self, econtext):
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
251 # We use the (not x) and 1 or 0 formulation to avoid changing
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
252 # the representation of the result in Python 2.3, where the
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
253 # result of "not" becomes an instance of bool.
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
254 return (not econtext.evaluateBoolean(self._c)) and 1 or 0
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
255
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
256 def __repr__(self):
5377
12fe83f90f0d Python 3 preparation: use repr() instead of ``.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5265
diff changeset
257 return 'not:%s' % repr(self._s)
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
258
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
259 class DeferWrapper:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
260 def __init__(self, expr, econtext):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
261 self._expr = expr
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
262 self._econtext = econtext
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
263
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
264 def __str__(self):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
265 return str(self())
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
266
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
267 def __call__(self):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
268 return self._expr(self._econtext)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
269
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
270 class DeferExpr:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
271 def __init__(self, name, expr, compiler):
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
272 self._s = expr = expr.lstrip()
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
273 self._c = compiler.compile(expr)
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
274
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
275 def __call__(self, econtext):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
276 return DeferWrapper(self._c, econtext)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
277
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
278 def __repr__(self):
5377
12fe83f90f0d Python 3 preparation: use repr() instead of ``.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5265
diff changeset
279 return 'defer:%s' % repr(self._s)
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
280
2351
97fae0466d97 more ZPT porting tweaks
Richard Jones <richard@users.sourceforge.net>
parents: 2349
diff changeset
281 class TraversalError:
97fae0466d97 more ZPT porting tweaks
Richard Jones <richard@users.sourceforge.net>
parents: 2349
diff changeset
282 def __init__(self, path, name):
97fae0466d97 more ZPT porting tweaks
Richard Jones <richard@users.sourceforge.net>
parents: 2349
diff changeset
283 self.path = path
97fae0466d97 more ZPT porting tweaks
Richard Jones <richard@users.sourceforge.net>
parents: 2349
diff changeset
284 self.name = name
97fae0466d97 more ZPT porting tweaks
Richard Jones <richard@users.sourceforge.net>
parents: 2349
diff changeset
285
97fae0466d97 more ZPT porting tweaks
Richard Jones <richard@users.sourceforge.net>
parents: 2349
diff changeset
286
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
287
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
288 def restrictedTraverse(object, path, securityManager,
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
289 get=getattr, has=hasattr, N=None, M=[],
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
290 TupleType=type(()) ):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
291
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
292 REQUEST = {'path': path}
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
293 REQUEST['TraversalRequestNameStack'] = path = path[:] # Copy!
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
294 path.reverse()
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
295 validate = securityManager.validate
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
296 __traceback_info__ = REQUEST
2351
97fae0466d97 more ZPT porting tweaks
Richard Jones <richard@users.sourceforge.net>
parents: 2349
diff changeset
297 done = []
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
298 while path:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
299 name = path.pop()
2351
97fae0466d97 more ZPT porting tweaks
Richard Jones <richard@users.sourceforge.net>
parents: 2349
diff changeset
300 __traceback_info__ = TraversalError(done, name)
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
301
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
302 if isinstance(name, TupleType):
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
303 object = object(*name)
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
304 continue
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
305
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
306 if not name:
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
307 # Skip directly to item access
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
308 o = object[name]
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
309 # Check access to the item.
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
310 if not validate(object, object, name, o):
5378
35ea9b1efc14 Python 3 preparation: "raise" syntax.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5377
diff changeset
311 raise Unauthorized(name)
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
312 object = o
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
313 continue
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
314
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
315 # Try an attribute.
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
316 o = guarded_getattr(object, name, M)
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
317 if o is M:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
318 # Try an item.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
319 try:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
320 # XXX maybe in Python 2.2 we can just check whether
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
321 # the object has the attribute "__getitem__"
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
322 # instead of blindly catching exceptions.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
323 o = object[name]
5248
198b6e810c67 Use Python-3-compatible 'as' syntax for except statements
Eric S. Raymond <esr@thyrsus.com>
parents: 4570
diff changeset
324 except AttributeError as exc:
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
325 if str(exc).find('__getitem__') >= 0:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
326 # The object does not support the item interface.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
327 # Try to re-raise the original attribute error.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
328 # XXX I think this only happens with
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
329 # ExtensionClass instances.
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
330 guarded_getattr(object, name)
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
331 raise
5248
198b6e810c67 Use Python-3-compatible 'as' syntax for except statements
Eric S. Raymond <esr@thyrsus.com>
parents: 4570
diff changeset
332 except TypeError as exc:
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
333 if str(exc).find('unsubscriptable') >= 0:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
334 # The object does not support the item interface.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
335 # Try to re-raise the original attribute error.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
336 # XXX This is sooooo ugly.
2349
b43efe461b3e update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
337 guarded_getattr(object, name)
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
338 raise
2351
97fae0466d97 more ZPT porting tweaks
Richard Jones <richard@users.sourceforge.net>
parents: 2349
diff changeset
339 done.append((name, o))
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
340 object = o
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
341
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
342 return object

Roundup Issue Tracker: http://roundup-tracker.org/