Skip to content

UnboundLocalError when module is shadowed by a comprehension and then accessed by another comprehension #118513

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

Closed
jmymay opened this issue May 2, 2024 · 6 comments
Labels
3.12 only security fixes 3.13 bugs and security fixes type-bug An unexpected behavior, bug, or error

Comments

@jmymay
Copy link

jmymay commented May 2, 2024

Bug report

Bug description:

Seems to be a regression in 3.12 when compared to 3.11, likely caused by PEP 709: Comprehension inlining, but I haven't verified this. Example below. (Noticed while running this code.)

import sys
def f():
    _ = [sys for sys in []]  # can be any module other than sys
    [sys.stdout.write('success\n') for _ in [1]]
f()
$ python3.11 main.py  # 3.11.9
success
$ python3.12 main.py  # 3.12.3
Traceback (most recent call last):
  File "/home/jkozera/imp/main.py", line 5, in <module>
    f()
  File "/home/jkozera/imp/main.py", line 4, in f
    [sys.stdout.write('success\n') for _ in [1]]
     ^^^
UnboundLocalError: cannot access local variable 'sys' where it is not associated with a value
$ python3.13 main.py  # 3.13.0a6+ (heads/main:2770d5c, May  2 2024, 18:19:03)
Traceback (most recent call last):
  File "/home/jkozera/imp/main.py", line 5, in <module>
    f()
    ~^^
  File "/home/jkozera/imp/main.py", line 4, in f
    [sys.stdout.write('success\n') for _ in [1]]
     ^^^
UnboundLocalError: cannot access local variable 'sys' where it is not associated with a value

CPython versions tested on:

3.11, 3.12, CPython main branch

Operating systems tested on:

Linux

Linked PRs

@jmymay jmymay added the type-bug An unexpected behavior, bug, or error label May 2, 2024
@Eclips4
Copy link
Member

Eclips4 commented May 2, 2024

cc @carljm

@JelleZijlstra
Copy link
Member

Confirmed without a module too:

x = 1
def f():
    [x for x in [1]]
    return [x for _ in [1]]
print(f())
Traceback (most recent call last):
  File "/Users/jelle/py/cpython/globs.py", line 5, in <module>
    print(f())
          ~^^
  File "/Users/jelle/py/cpython/globs.py", line 4, in f
    return [x for _ in [1]]
            ^
UnboundLocalError: cannot access local variable 'x' where it is not associated with a value

Disassembly shows we're using LOAD_FAST_CHECK for the second comprehension when we should be using LOAD_GLOBAL.

@Eclips4 Eclips4 added 3.12 only security fixes 3.13 bugs and security fixes labels May 2, 2024
@carljm
Copy link
Member

carljm commented May 2, 2024

Thanks, taking a look.

@Eclips4
Copy link
Member

Eclips4 commented May 2, 2024

Confirmed without a module too:

x = 1
def f():
    [x for x in [1]]
    return [x for _ in [1]]
print(f())
Traceback (most recent call last):
  File "/Users/jelle/py/cpython/globs.py", line 5, in <module>
    print(f())
          ~^^
  File "/Users/jelle/py/cpython/globs.py", line 4, in f
    return [x for _ in [1]]
            ^
UnboundLocalError: cannot access local variable 'x' where it is not associated with a value

Disassembly shows we're using LOAD_FAST_CHECK for the second comprehension when we should be using LOAD_GLOBAL.

FYI, the assignment x = 1 here's unnecessary (result will be the same).

@carljm
Copy link
Member

carljm commented May 2, 2024

Yes, either way it should compile to LOAD_GLOBAL; without the global assignment it should result in NameError, not UnboundLocalError.

@carljm
Copy link
Member

carljm commented May 2, 2024

Fix in #118526

carljm added a commit that referenced this issue May 3, 2024
…obal in the other (#118526)

Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Co-authored-by: Kirill Podoprigora <kirill.bast9@mail.ru>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue May 3, 2024
…and global in the other (pythonGH-118526)

(cherry picked from commit c8deb1e)

Co-authored-by: Carl Meyer <carl@oddbird.net>
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Co-authored-by: Kirill Podoprigora <kirill.bast9@mail.ru>
carljm added a commit that referenced this issue May 3, 2024
… and global in the other (GH-118526) (#118548)

gh-118513: Fix sibling comprehensions with a name bound in one and global in the other (GH-118526)
(cherry picked from commit c8deb1e)

Co-authored-by: Carl Meyer <carl@oddbird.net>
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Co-authored-by: Kirill Podoprigora <kirill.bast9@mail.ru>
@carljm carljm closed this as completed May 3, 2024
SonicField pushed a commit to SonicField/cpython that referenced this issue May 8, 2024
…and global in the other (python#118526)

Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Co-authored-by: Kirill Podoprigora <kirill.bast9@mail.ru>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.12 only security fixes 3.13 bugs and security fixes type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

4 participants