Skip to content

Commit 2f8f153

Browse files
d-maurericemac
andauthored
new function safer_getattr_raise (#288)
* new function `safer_getattr_raise` similar to `safer_getattr` but with `default` handling like `getattr` * [force ci] * force ci * Apply review suggestion from @icemac Co-authored-by: Michael Howitz <[email protected]> --------- Co-authored-by: Michael Howitz <[email protected]>
1 parent 95f323c commit 2f8f153

File tree

3 files changed

+29
-1
lines changed

3 files changed

+29
-1
lines changed

Diff for: CHANGES.rst

+7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ Changes
77
- Allow to use the package with Python 3.13 -- Caution: No security
88
audit has been done so far.
99

10+
- Provide new function ``RestrictedPython.Guards.safer_getattr_raise``.
11+
It is similar to ``safer_getattr`` but handles its parameter
12+
``default`` like ``getattr``, i.e. it raises ``AttributeError``
13+
if the attribute lookup fails and this parameter is not provided,
14+
fixes `#287 <https://github.com/zopefoundation/RestrictedPython/issues/287>`_.
15+
16+
1017

1118
7.3 (2024-09-30)
1219
----------------

Diff for: src/RestrictedPython/Guards.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,9 @@ def guarded_delattr(object, name):
240240
safe_builtins['delattr'] = guarded_delattr
241241

242242

243+
raise_ = object()
244+
245+
243246
def safer_getattr(object, name, default=None, getattr=getattr):
244247
"""Getattr implementation which prevents using format on string objects.
245248
@@ -263,12 +266,18 @@ def safer_getattr(object, name, default=None, getattr=getattr):
263266
'"{name}" is an invalid attribute name because it '
264267
'starts with "_"'.format(name=name)
265268
)
266-
return getattr(object, name, default)
269+
args = (object, name) + (() if default is raise_ else (default,))
270+
return getattr(*args)
267271

268272

269273
safe_builtins['_getattr_'] = safer_getattr
270274

271275

276+
def safer_getattr_raise(object, name, default=raise_):
277+
"""like ``safer_getattr`` but raising ``AttributeError`` if failing."""
278+
return safer_getattr(object, name, default)
279+
280+
272281
def guarded_iter_unpack_sequence(it, spec, _getiter_):
273282
"""Protect sequence unpacking of targets in a 'for loop'.
274283

Diff for: tests/test_Guards.py

+12
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,18 @@ def test_Guards__safer_getattr__5():
329329
) == str(err.value)
330330

331331

332+
def test_Guards__safer_getattr_raise():
333+
from types import SimpleNamespace
334+
335+
from RestrictedPython.Guards import safer_getattr_raise
336+
337+
o = SimpleNamespace(a="a")
338+
assert safer_getattr_raise(o, "a") == "a"
339+
assert safer_getattr_raise(o, "b", None) is None
340+
with pytest.raises(AttributeError):
341+
safer_getattr_raise(o, "b")
342+
343+
332344
def test_call_py3_builtins():
333345
"""It should not be allowed to access global builtins in Python3."""
334346
result = compile_restricted_exec('builtins["getattr"]')

0 commit comments

Comments
 (0)