Skip to content

Allow __enter__ and __exit__ as restricted method names - #333

Closed
afonsojanu wants to merge 1 commit into
zopefoundation:masterfrom
afonsojanu:allow-context-manager-dunders-230
Closed

afonsojanu wants to merge 1 commit into
zopefoundation:masterfrom
afonsojanu:allow-context-manager-dunders-230

Conversation

@afonsojanu

Copy link
Copy Markdown
Member

Fixes #230.

ALLOWED_FUNC_NAMES in src/RestrictedPython/transformer.py only allowlists __init__ and the rich comparison dunders (__lt__, __le__, __eq__, __ne__, __gt__, __ge__, __contains__), so any class defined in restricted code that implements __enter__/__exit__ to support the context manager protocol fails to compile, with the usual "is an invalid variable name because it starts with _" error for both names.

I reproduced this first: compiling the exact snippet from the issue gives that SyntaxError against the unpatched code. The with statement itself is already handled fine by visit_With in the transformer, so the only actual gap is these two method names never being allowlisted. After adding __enter__ and __exit__ to ALLOWED_FUNC_NAMES, the class compiles, and running it through an actual with block calls __enter__ and __exit__ in the right order around the body (verified with a small script and with the added test).

Changes:

  • src/RestrictedPython/transformer.py: add __enter__ and __exit__ to ALLOWED_FUNC_NAMES.
  • tests/test_Guards.py: new test that defines a context manager class in restricted code and exercises it in a real with statement, checking __enter__/__exit__ both ran in the expected order.
  • CHANGES.rst: entry under the unreleased heading.

Ran the full suite locally (pytest tests/): 300 passed, 10 skipped, no failures.

The transformer's ALLOWED_FUNC_NAMES allowlist only covered __init__ and
the rich comparison dunders, so any class defined in restricted code that
implemented the context manager protocol failed to compile with
"__enter__ is an invalid variable name because it starts with _" (and
likewise for __exit__), even though the with statement itself is already
supported by the transformer.

Reproduced first against the unpatched code: compiling a class with an
__enter__/__exit__ pair raised exactly that SyntaxError. Adding both names
to ALLOWED_FUNC_NAMES lets such a class compile, and actually running it
through a with statement invokes __enter__ and __exit__ in the right order
around the block body.

Fixes zopefoundation#230.
@icemac

icemac commented Sep 30, 2026

Copy link
Copy Markdown
Member

Thank you for the PR and the clear write-up. I'm sorry to change direction here, since I invited this change in #230 myself.

While reviewing it, I realized that allowing __exit__ would give restricted code the traceback object (exc_traceback). Right now restricted code has no way to get one: e.__traceback__ is blocked by the underscore rule, and sys is not available. A traceback leads directly to the frames of the trusted code that raised the exception, and from there to their globals. The only thing stopping that is INSPECT_ATTRIBUTES, and applications that bring their own _getattr_ may not use it. For me, that risk is too big.

On the other hand, not allowing context managers to be defined does not block anything. They are syntactic sugar for try/finally, which restricted code can already use. Context managers provided by trusted code already work in with statements.

So I'm closing this PR. Thanks again for your work and sorry for the noise.

@icemac icemac closed this Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

context manager methods (__enter__ and __exit__) raise a SyntaxError

2 participants