Skip to content

Raise FeatureNotAvailable for unsupported comprehension targets#190

Open
gaoflow wants to merge 1 commit into
danthedeckie:mainfrom
gaoflow:fix-comprehension-target-exception
Open

Raise FeatureNotAvailable for unsupported comprehension targets#190
gaoflow wants to merge 1 commit into
danthedeckie:mainfrom
gaoflow:fix-comprehension-target-exception

Conversation

@gaoflow

@gaoflow gaoflow commented Jun 23, 2026

Copy link
Copy Markdown

Summary

Fixes #76. A list/dict comprehension whose for clause uses a non-name assignment target — a subscript like x[0] or an attribute like x.attr — crashes with a raw, non-SimpleEval exception:

>>> EvalWithCompoundTypes().eval("[x for x in ([None],) for x[0] in (15,)]")
AttributeError: 'Subscript' object has no attribute 'elts'

recurse_targets only special-cased ast.Name and assumed every other target was a tuple/list with an .elts attribute.

Fix

Handle ast.Name and ast.Tuple/ast.List explicitly, and raise the library's own FeatureNotAvailable for any other target type. This resolves the actual complaint in the issue (a raw AttributeError leaking instead of a SimpleEval exception).

I deliberately did not implement subscript assignment (container[key] = value). The same target path is what enables the self-referential-list construction the reporter flagged in the thread:

>>> [x for x in ([None],) for x[0] in (x,)]   # CPython: [[[...]]]

i.e. a list that contains itself — a potential DoS vector (e.g. RecursionError on comparison). For a sandboxing evaluator, rejecting these targets is the safer behaviour, and it keeps attribute/subscript writes out of the sandbox (attribute writes were never supported). After the fix both the subscript and attribute target forms raise FeatureNotAvailable.

Verification

  • Reproduced on main (afd1ffc): subscript target raises a raw AttributeError; after the fix it raises FeatureNotAvailable, as does the self-referential construction and an attribute target.
  • All existing name / tuple / list / nested-unpack / dict-comprehension paths are unchanged.
  • Added 3 regression tests (test_subscript_target_fails_cleanly, test_attribute_target_fails_cleanly, test_self_referential_target_blocked); each fails before the change (raw AttributeError) and passes after.
  • Full test suite: 162 passed (159 + 3). ruff==0.6.9 and mypy==1.11.2 clean.

This pull request was prepared with the assistance of AI, under my direction and review.

A comprehension assignment target that is not a name or a tuple/list
(e.g. a subscript x[0] or attribute x.attr) made recurse_targets access
target.elts, raising a raw AttributeError instead of a SimpleEval
exception (issue danthedeckie#76).

Handle Name and Tuple/List explicitly and raise FeatureNotAvailable for
anything else. This keeps subscript and attribute writes out of the
sandbox, so the self-referential-list construction noted in the issue is
rejected cleanly instead of being built.
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.

Evaluator crash on complex assignment target in list comprehension

1 participant