Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-37757: Disallow PEP 572 cases that expose implementation details #15131

Conversation

ncoghlan
Copy link
Contributor

@ncoghlan ncoghlan commented Aug 5, 2019

  • drop TargetScopeError in favour of raising SyntaxError directly
    as per the updated PEP 572
  • comprehension iteration variables are explicitly local, but
    named expression targets in comprehensions are nonlocal or
    global. Raise SyntaxError as specified in PEP 572
  • named expression targets in the outermost iterable of a
    comprehension have an ambiguous target scope. Avoid resolving
    that question now by raising SyntaxError. PEP 572
    originally required this only for cases where the bound name
    conflicts with the iteration variable in the comprehension,
    but CPython can't easily restrict the exception to that case
    (as it doesn't know the target variable names when visiting
    the outermost iterator expression)

https://bugs.python.org/issue37757

- comprehension iteration variables are explicitly local, but
  named expression targets in comprehensions are nonlocal or
  global. Raise TargetScopeError as specified in PEP 572
- named expression targets in the outermost iterable of a
  comprehension have an ambiguous target scope. Avoid resolving
  that question now by raising TargetScopeError. PEP 572
  explicitly requires this for cases where the bound name
  conflicts with the iteration variable in the comprehension,
  but CPython can't easily restrict the exception to that case
  (as it doesn't know the target variable names when visiting
  the outermost iterator expression)
@ncoghlan ncoghlan added the needs backport to 3.8 only security fixes label Aug 5, 2019
@ncoghlan ncoghlan changed the title Bug #37757: Raise TargetScopeError as specified in PEP 572 bpo-37757: Raise TargetScopeError as specified in PEP 572 Aug 5, 2019
@ncoghlan
Copy link
Contributor Author

ncoghlan commented Aug 5, 2019

There's a test design issue that comes up with this PR: in CPython, all the different comprehension types share several common code paths, so these tests only test list comprehensions, and rely on the common code paths to extend that to the rules also being applied correctly for set, dict, and generator comprehensions.

From a language testing perspective though, perhaps we should be testing all 4 cases, as other implementations may not have the same level of code sharing, and hence have bugs specific to one of the other variants that don't exist for list comprehensions?

@ncoghlan ncoghlan requested a review from a team as a code owner August 9, 2019 14:15
@ncoghlan ncoghlan changed the title bpo-37757: Raise TargetScopeError as specified in PEP 572 bpo-37757: Disallow PEP 572 cases that expose implementation details Aug 9, 2019
- use the public "assignment expression" name rather than the
  internal "named expression" one
- mention the variable name when the conflict is related to
  the exact name rather than the code structure
- don't pass the variable name when the exception message
  doesn't need it
@ncoghlan
Copy link
Contributor Author

ncoghlan commented Aug 14, 2019

@emilyemorehouse The PEP update to remove TargetScopeError and clarify the rationale for treating these cases as syntax errors has been accepted and merged, so this is ready for review now.

Edit: I've updated the PR to add more test cases now, so the test suite is covering situations where we reference a global or nonlocal in a comprehension before we rebind it, like:

j = -1;  increasing = [j := i for i in random.choices(range(10)) if j < i]

I was right that the flags the PR is checking only get set for target names, not references, but it's good to have the extra test cases that ensure that remains true.

I've also tweaked the tests for the scoping syntax error checks to make sure they trigger in all 3 scopes (module, function, class). We normally wouldn't bother to do that, but this is a case where we know the compiler contains scope dependent code paths, so it makes sense to explicitly cover them all.

@ncoghlan
Copy link
Contributor Author

I don't believe edit notifications get sent via email, so adding an explicit note to say that I've added the extra test cases I mentioned in my last comment, and edited that comment accordingly.

So unless I've missed something, I believe this should be good to go now.

@ncoghlan
Copy link
Contributor Author

Note that I'm deliberately not bumping the bytecode magic number here - this means that you could technically compile affected code under 3.8b3 or earlier, and 3.8b4 and later will still run it. I think that's fine, and don't see a reason to compel a rebuild of all bytecode just to enforce new syntax errors.

@ncoghlan
Copy link
Contributor Author

My current plan is to merge this on Sunday August 25th, to make the 3.8b4 cut-off. If folks have comments before then, I can take them into account for the beta, otherwise, I'm still interested in post-merge reviews, but I'll handle addressing them as follow-up changes before rc1.

Copy link
Member

@emilyemorehouse emilyemorehouse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very small nit, otherwise LGTM. Thanks, Nick!

Lib/test/test_named_expressions.py Outdated Show resolved Hide resolved
@ncoghlan ncoghlan merged commit 5dbe0f5 into python:master Aug 25, 2019
@ncoghlan ncoghlan deleted the bpo-37757-targetscopeerror-for-iteration-variable-conflicts branch August 25, 2019 13:45
@miss-islington
Copy link
Contributor

Thanks @ncoghlan for the PR 🌮🎉.. I'm working now to backport this PR to: 3.8.
🐍🍒⛏🤖

@miss-islington
Copy link
Contributor

Sorry, @ncoghlan, I could not cleanly backport this to 3.8 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker 5dbe0f59b7a4f39c7c606b48056bc29e406ebf78 3.8

@ncoghlan
Copy link
Contributor Author

@emilyemorehouse Thanks for the review!

ncoghlan added a commit to ncoghlan/cpython that referenced this pull request Aug 25, 2019
…ythonGH-15131)

- drop TargetScopeError in favour of raising SyntaxError directly
  as per the updated PEP 572
- comprehension iteration variables are explicitly local, but
  named expression targets in comprehensions are nonlocal or
  global. Raise SyntaxError as specified in PEP 572
- named expression targets in the outermost iterable of a
  comprehension have an ambiguous target scope. Avoid resolving
  that question now by raising SyntaxError. PEP 572
  originally required this only for cases where the bound name
  conflicts with the iteration variable in the comprehension,
  but CPython can't easily restrict the exception to that case
  (as it doesn't know the target variable names when visiting
  the outermost iterator expression)

(cherry picked from commit 5dbe0f5)
@ncoghlan
Copy link
Contributor Author

#15491 is the deconflicted backport - removing the Windows DLL export symbol for TargetScopeError failed in the implicit backport, as the two branches have different version numbers in the symbols.

@pablogsal
Copy link
Member

This commit introduced a reference leak that is being tracked in https://bugs.python.org/issue37954

lisroach pushed a commit to lisroach/cpython that referenced this pull request Sep 10, 2019
…ythonGH-15131)

- drop TargetScopeError in favour of raising SyntaxError directly
  as per the updated PEP 572
- comprehension iteration variables are explicitly local, but
  named expression targets in comprehensions are nonlocal or
  global. Raise SyntaxError as specified in PEP 572
- named expression targets in the outermost iterable of a
  comprehension have an ambiguous target scope. Avoid resolving
  that question now by raising SyntaxError. PEP 572
  originally required this only for cases where the bound name
  conflicts with the iteration variable in the comprehension,
  but CPython can't easily restrict the exception to that case
  (as it doesn't know the target variable names when visiting
  the outermost iterator expression)
DinoV pushed a commit to DinoV/cpython that referenced this pull request Jan 14, 2020
…ythonGH-15131)

- drop TargetScopeError in favour of raising SyntaxError directly
  as per the updated PEP 572
- comprehension iteration variables are explicitly local, but
  named expression targets in comprehensions are nonlocal or
  global. Raise SyntaxError as specified in PEP 572
- named expression targets in the outermost iterable of a
  comprehension have an ambiguous target scope. Avoid resolving
  that question now by raising SyntaxError. PEP 572
  originally required this only for cases where the bound name
  conflicts with the iteration variable in the comprehension,
  but CPython can't easily restrict the exception to that case
  (as it doesn't know the target variable names when visiting
  the outermost iterator expression)
websurfer5 pushed a commit to websurfer5/cpython that referenced this pull request Jul 20, 2020
…ythonGH-15131)

- drop TargetScopeError in favour of raising SyntaxError directly
  as per the updated PEP 572
- comprehension iteration variables are explicitly local, but
  named expression targets in comprehensions are nonlocal or
  global. Raise SyntaxError as specified in PEP 572
- named expression targets in the outermost iterable of a
  comprehension have an ambiguous target scope. Avoid resolving
  that question now by raising SyntaxError. PEP 572
  originally required this only for cases where the bound name
  conflicts with the iteration variable in the comprehension,
  but CPython can't easily restrict the exception to that case
  (as it doesn't know the target variable names when visiting
  the outermost iterator expression)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs backport to 3.8 only security fixes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants