Mercurial > p > roundup > code
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 |
| rev | line source |
|---|---|
| 1049 | 1 ############################################################################## |
| 2 # | |
| 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 | 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 | |
|
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 | 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 | 18 |
| 19 """Page Template Expression Engine | |
| 20 | |
| 21 Page Template-specific implementation of TALES, with handlers | |
| 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 | 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 | 29 |
| 30 _engine = None | |
| 31 def getEngine(): | |
| 32 global _engine | |
| 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 | 35 _engine = Engine(Iterator) |
| 36 installHandlers(_engine) | |
| 37 return _engine | |
| 38 | |
| 39 def installHandlers(engine): | |
| 40 reg = engine.registerType | |
| 41 pe = PathExpr | |
| 42 for pt in ('standard', 'path', 'exists', 'nocall'): | |
| 43 reg(pt, pe) | |
| 44 reg('string', StringExpr) | |
| 45 reg('python', PythonExpr) | |
| 46 reg('not', NotExpr) | |
| 47 reg('defer', DeferExpr) | |
| 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 | 51 try: |
| 52 from zExceptions import Unauthorized | |
| 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 | 62 def call_with_ns(f, ns, arg=1): |
| 63 if arg==2: | |
| 64 return f(None, ns) | |
| 65 else: | |
| 66 return f(ns) | |
| 67 | |
| 68 class _SecureModuleImporter: | |
| 69 """Simple version of the importer for use with trusted code.""" | |
| 70 __allow_access_to_unprotected_subobjects__ = 1 | |
| 71 def __getitem__(self, module): | |
| 72 __import__(module) | |
| 73 return sys.modules[module] | |
| 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 | 77 Undefs = (Undefined, AttributeError, KeyError, |
| 78 TypeError, IndexError, Unauthorized) | |
| 79 | |
| 80 def render(ob, ns): | |
| 81 """ | |
| 82 Calls the object, possibly a document template, or just returns it if | |
| 83 not callable. (From DT_Util.py) | |
| 84 """ | |
| 85 if hasattr(ob, '__render_with_namespace__'): | |
| 86 ob = call_with_ns(ob.__render_with_namespace__, ns) | |
| 87 else: | |
| 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 | 90 try: |
| 91 if getattr(base, 'isDocTemp', 0): | |
| 92 ob = call_with_ns(ob, ns, 2) | |
| 93 else: | |
| 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 | 96 if str(n) != '__call__': |
| 97 raise | |
| 98 return ob | |
| 99 | |
| 100 class SubPathExpr: | |
| 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 | 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 | 106 # Parse path |
| 107 self._dp = dp = [] | |
| 108 for i in range(len(path)): | |
| 109 e = path[i] | |
| 110 if e[:1] == '?' and _valid_name(e[1:]): | |
| 111 dp.append((i, e[1:])) | |
| 112 dp.reverse() | |
| 113 | |
| 114 def _eval(self, econtext, | |
| 115 list=list, isinstance=isinstance, StringType=type('')): | |
| 116 vars = econtext.vars | |
| 117 path = self._path | |
| 118 if self._dp: | |
| 119 path = list(path) # Copy! | |
| 120 for i, varname in self._dp: | |
| 121 val = vars[varname] | |
| 122 if isinstance(val, StringType): | |
| 123 path[i] = val | |
| 124 else: | |
| 125 # If the value isn't a string, assume it's a sequence | |
| 126 # of path names. | |
| 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 | 131 ob = econtext.contexts |
| 132 else: | |
| 133 ob = vars[base] | |
| 134 if isinstance(ob, DeferWrapper): | |
| 135 ob = ob() | |
| 136 if path: | |
| 137 ob = restrictedTraverse(ob, path, getSecurityManager()) | |
| 138 return ob | |
| 139 | |
| 140 class PathExpr: | |
| 141 def __init__(self, name, expr, engine): | |
| 142 self._s = expr | |
| 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 | 146 self._subexprs = [] |
| 147 add = self._subexprs.append | |
| 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 | 150 if _parse_expr(path): |
| 151 # This part is the start of another expression type, | |
| 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 | 155 break |
| 156 add(SubPathExpr(path)._eval) | |
| 157 | |
| 158 def _exists(self, econtext): | |
| 159 for expr in self._subexprs: | |
| 160 try: | |
| 161 expr(econtext) | |
| 162 except Undefs: | |
| 163 pass | |
| 164 else: | |
| 165 return 1 | |
| 166 return 0 | |
| 167 | |
| 168 def _eval(self, econtext, | |
| 169 isinstance=isinstance, StringType=type(''), render=render): | |
| 170 for expr in self._subexprs[:-1]: | |
| 171 # Try all but the last subexpression, skipping undefined ones. | |
| 172 try: | |
| 173 ob = expr(econtext) | |
| 174 except Undefs: | |
| 175 pass | |
| 176 else: | |
| 177 break | |
| 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 | 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 | 184 |
| 185 if self._name == 'nocall' or isinstance(ob, StringType): | |
| 186 return ob | |
| 187 # Return the rendered object | |
| 188 return render(ob, econtext.vars) | |
| 189 | |
| 190 def __call__(self, econtext): | |
| 191 if self._name == 'exists': | |
| 192 return self._exists(econtext) | |
| 193 return self._eval(econtext) | |
| 194 | |
| 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 | 197 |
| 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 | 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 | 203 |
| 204 class StringExpr: | |
| 205 def __init__(self, name, expr, engine): | |
| 206 self._s = expr | |
| 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 | 209 self._vars = vars = [] |
| 210 if '$' in expr: | |
| 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 | 213 if parts: parts.append('$') |
| 214 m = _interp.search(exp) | |
| 215 while m is not None: | |
| 216 parts.append(exp[:m.start()]) | |
| 217 parts.append('%s') | |
| 218 vars.append(PathExpr('path', m.group(1) or m.group(2), | |
| 219 engine)) | |
| 220 exp = exp[m.end():] | |
| 221 m = _interp.search(exp) | |
| 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 | 224 '$ must be doubled or followed by a simple path') |
| 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 | 227 self._expr = expr |
|
2349
b43efe461b3e
update PageTemplates to latest Zope codebase
Richard Jones <richard@users.sourceforge.net>
parents:
2005
diff
changeset
|
228 |
| 1049 | 229 def __call__(self, econtext): |
| 230 vvals = [] | |
| 231 for var in self._vars: | |
| 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 | 236 vvals.append(v) |
| 237 return self._expr % tuple(vvals) | |
| 238 | |
| 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 | 241 |
| 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 | 244 |
| 245 class NotExpr: | |
| 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 | 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 | 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 | 255 |
| 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 | 258 |
| 259 class DeferWrapper: | |
| 260 def __init__(self, expr, econtext): | |
| 261 self._expr = expr | |
| 262 self._econtext = econtext | |
| 263 | |
| 264 def __str__(self): | |
| 265 return str(self()) | |
| 266 | |
| 267 def __call__(self): | |
| 268 return self._expr(self._econtext) | |
| 269 | |
| 270 class DeferExpr: | |
| 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 | 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 | 275 def __call__(self, econtext): |
| 276 return DeferWrapper(self._c, econtext) | |
| 277 | |
| 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 | 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 | 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 | 289 get=getattr, has=hasattr, N=None, M=[], |
| 290 TupleType=type(()) ): | |
| 291 | |
| 292 REQUEST = {'path': path} | |
| 293 REQUEST['TraversalRequestNameStack'] = path = path[:] # Copy! | |
| 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 | 298 while path: |
| 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 | 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 | 314 |
| 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 | 317 if o is M: |
| 318 # Try an item. | |
| 319 try: | |
| 320 # XXX maybe in Python 2.2 we can just check whether | |
| 321 # the object has the attribute "__getitem__" | |
| 322 # instead of blindly catching exceptions. | |
| 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 | 325 if str(exc).find('__getitem__') >= 0: |
| 326 # The object does not support the item interface. | |
| 327 # Try to re-raise the original attribute error. | |
| 328 # XXX I think this only happens with | |
| 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 | 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 | 333 if str(exc).find('unsubscriptable') >= 0: |
| 334 # The object does not support the item interface. | |
| 335 # Try to re-raise the original attribute error. | |
| 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 | 338 raise |
|
2351
97fae0466d97
more ZPT porting tweaks
Richard Jones <richard@users.sourceforge.net>
parents:
2349
diff
changeset
|
339 done.append((name, o)) |
| 1049 | 340 object = o |
| 341 | |
| 342 return object |
