Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/RestrictedPython/Guards.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import builtins

from RestrictedPython._compat import IS_PY311_OR_GREATER


safe_builtins = {}

Expand Down Expand Up @@ -103,6 +105,9 @@
'ZeroDivisionError',
]

if IS_PY311_OR_GREATER:
_safe_exceptions.append("ExceptionGroup")

for name in _safe_names:
safe_builtins[name] = getattr(builtins, name)

Expand Down
1 change: 1 addition & 0 deletions src/RestrictedPython/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
IS_PY37_OR_GREATER = _version.major == 3 and _version.minor >= 7
IS_PY38_OR_GREATER = _version.major == 3 and _version.minor >= 8
IS_PY310_OR_GREATER = _version.major == 3 and _version.minor >= 10
IS_PY311_OR_GREATER = _version.major == 3 and _version.minor >= 11

IS_CPYTHON = platform.python_implementation() == 'CPython'
4 changes: 4 additions & 0 deletions src/RestrictedPython/transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,10 @@ def visit_Try(self, node):
"""Allow `try` without restrictions."""
return self.node_contents_visit(node)

def visit_TryStar(self, node):
"""Allow `ExceptionGroup` without restrictions."""
return self.node_contents_visit(node)

def visit_ExceptHandler(self, node):
"""Protect exception handlers."""
node = self.node_contents_visit(node)
Expand Down
36 changes: 36 additions & 0 deletions tests/transformer/test_try.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import pytest

from RestrictedPython import compile_restricted_exec
from RestrictedPython._compat import IS_PY311_OR_GREATER
from tests.helper import restricted_exec


Expand Down Expand Up @@ -47,6 +50,39 @@ def test_RestrictingNodeTransformer__visit_Try__2(
])


TRY_EXCEPT_STAR = """
def try_except_star(m):
try:
m('try')
raise ExceptionGroup("group", [IndentationError('f1'), ValueError(65)])
except* IndentationError:
m('IndentationError')
except* ValueError:
m('ValueError')
except* RuntimeError:
m('RuntimeError')
"""


@pytest.mark.skipif(
not IS_PY311_OR_GREATER,
reason="ExceptionGroup class was added in Python 3.11.",
)
def test_RestrictingNodeTransformer__visit_Try__3(mocker):
Comment thread
loechel marked this conversation as resolved.
Outdated
Comment thread
eikichi18 marked this conversation as resolved.
Outdated
"""It allows try-except* PEP 654 statements."""
trace = mocker.stub()
restricted_exec(TRY_EXCEPT_STAR)['try_except_star'](trace)

trace.assert_has_calls([
mocker.call('try'),
mocker.call('IndentationError'),
mocker.call('ValueError')
])

with pytest.raises(AssertionError):
trace.assert_has_calls([mocker.call('RuntimeError')])


TRY_FINALLY = """
def try_finally(m):
try:
Expand Down