-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
global declaration in except has incorrect prior use #111123
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
Comments
I feel like this issue might be interesting to @iritkatriel and @pablogsal. |
I think this is because
|
The converse of this bug is that this code currently works (and prints 1): a = 0
def f():
try:
1 / 0
except:
a = 1
else:
global a
f()
print(a) With Irit's fix, this would instead be a SyntaxError. I don't know if any code in existence would rely on this weird behavior, but we should probably fix this only on main (not the bugfix branches) and call out the change in behavior in What's New. |
I agree @JelleZijlstra I think I understood how the logic behind a=0
def f(cnd,value):
if cnd:
global a
a=value
f(True,1)
print(a)
f(False,2)
print(a) output (Python 3.12.0): 1
2 global is not affected by the actual order of execution. It is more "the line" in which it was declared. The syntax error for prior use exists mainly to safe the user from thinking that he could put the global behind the use of some variable and to expect a different behavior. A @iritkatriel I saw your fix and I think |
Right, thanks. |
…odes before 3.13 (#17285) Summary -- This PR extends the documentation of the `LoadBeforeGlobalDeclaration` check to specify the behavior on versions of Python before 3.13. Namely, on Python 3.12, the `else` clause of a `try` statement is visited before the `except` handlers: ```pycon Python 3.12.9 (main, Feb 12 2025, 14:50:50) [Clang 19.1.6 ] on linux Type "help", "copyright", "credits" or "license" for more information. >>> a = 10 >>> def g(): ... try: ... 1 / 0 ... except: ... a = 1 ... else: ... global a ... >>> def f(): ... try: ... pass ... except: ... global a ... else: ... print(a) ... File "<stdin>", line 5 SyntaxError: name 'a' is used prior to global declaration ``` The order is swapped on 3.13 (see [CPython#111123](python/cpython#111123)): ```pycon Python 3.13.2 (main, Feb 5 2025, 08:05:21) [GCC 14.2.1 20250128] on linux Type "help", "copyright", "credits" or "license" for more information. >>> a = 10 ... def g(): ... try: ... 1 / 0 ... except: ... a = 1 ... else: ... global a ... File "<python-input-0>", line 8 global a ^^^^^^^^ SyntaxError: name 'a' is assigned to before global declaration >>> def f(): ... try: ... pass ... except: ... global a ... else: ... print(a) ... >>> ``` The current implementation of PLE0118 is correct for 3.13 but not 3.12: [playground](https://play.ruff.rs/d7467ea6-f546-4a76-828f-8e6b800694c9) (it flags the first case regardless of Python version). We decided to maintain this incorrect diagnostic for Python versions before 3.13 because the pre-3.13 behavior is very unintuitive and confirmed to be a bug, although the bug fix was not backported to earlier versions. This can lead to false positives and false negatives for pre-3.13 code, but we also expect that to be very rare, as demonstrated by the ecosystem check (before the version-dependent check was reverted here). Test Plan -- N/a
…odes before 3.13 (astral-sh#17285) Summary -- This PR extends the documentation of the `LoadBeforeGlobalDeclaration` check to specify the behavior on versions of Python before 3.13. Namely, on Python 3.12, the `else` clause of a `try` statement is visited before the `except` handlers: ```pycon Python 3.12.9 (main, Feb 12 2025, 14:50:50) [Clang 19.1.6 ] on linux Type "help", "copyright", "credits" or "license" for more information. >>> a = 10 >>> def g(): ... try: ... 1 / 0 ... except: ... a = 1 ... else: ... global a ... >>> def f(): ... try: ... pass ... except: ... global a ... else: ... print(a) ... File "<stdin>", line 5 SyntaxError: name 'a' is used prior to global declaration ``` The order is swapped on 3.13 (see [CPython#111123](python/cpython#111123)): ```pycon Python 3.13.2 (main, Feb 5 2025, 08:05:21) [GCC 14.2.1 20250128] on linux Type "help", "copyright", "credits" or "license" for more information. >>> a = 10 ... def g(): ... try: ... 1 / 0 ... except: ... a = 1 ... else: ... global a ... File "<python-input-0>", line 8 global a ^^^^^^^^ SyntaxError: name 'a' is assigned to before global declaration >>> def f(): ... try: ... pass ... except: ... global a ... else: ... print(a) ... >>> ``` The current implementation of PLE0118 is correct for 3.13 but not 3.12: [playground](https://play.ruff.rs/d7467ea6-f546-4a76-828f-8e6b800694c9) (it flags the first case regardless of Python version). We decided to maintain this incorrect diagnostic for Python versions before 3.13 because the pre-3.13 behavior is very unintuitive and confirmed to be a bug, although the bug fix was not backported to earlier versions. This can lead to false positives and false negatives for pre-3.13 code, but we also expect that to be very rare, as demonstrated by the ecosystem check (before the version-dependent check was reverted here). Test Plan -- N/a
Bug report
Bug description:
I think the
global a
has no prior use in this code (and pyright tells me the same). But I don't understand why cpython thinks it has a prior use.output (Python 3.12.0):
the following code has no syntax error:
I can also reproduce this issue in 3.7.
I also don't know what the exact semantic of global/nonlocal inside statements like if/while/try/... is. I would like to know more about it because I'm currently writing pysource-codegen where I generate such cases.
CPython versions tested on:
3.12
Operating systems tested on:
Linux
Linked PRs
The text was updated successfully, but these errors were encountered: