python / python/mypy

spurious used-before-def on admittedly odd wildcard import

Open
#14,668 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug topic-possibly-undefined
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Bug Report

When using wildcard imports and modifying the import module-level variables, mypy will detect a undef-before-use of imported module-level variables. This is an admittedly weird bit of code, but crops up, for example, in some kinds of Django settings.py refactorings people do.

To Reproduce

This bug unfortunately requires two files to reproduce, so I have to inline them here.
Executing last.py will get you correct output, but mypy will claim there's a undef-before-use.

# first.py
A_VALUE: str = "in first"
# last.py
from first import *
# from first import A_VALUE

A_VALUE += " in last"  # comment either this, or the next line, or uncomment the import above for the mypy check to pass
A_VALUE = "in last again " + A_VALUE

if __name__ == "__main__":
    print(A_VALUE)

Expected Behavior
The expected behavior would be a successful pass, I believe.

Actual Behavior

Running PYTHONPATH=. mypy last.py will get you:

last.py:3: error: Name "A_VALUE" is used before definition  [used-before-def]
Found 1 error in 1 file (checked 1 source file)

For context, running PYTHONPATH=. python3 last.py will show the expected output of in last again in first in last.

Interestingly, both A_VALUE updates in last.py are necessary for mypy to call out a used-before-def. And if you explicitly import the module-level variable, mypy passes successfully, too. We've seen this behavior with a .index and a += method call on a List before a =, so we don't believe it's something specific to str or +=.

Your Environment

  • Mypy version used: 1.0.0
  • Mypy command-line flags: N/A
  • Mypy configuration options from mypy.ini (and other config files): N/A
  • Python version used: 3.10.9 and 3.8.14

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the report with first.py and last.py using PYTHONPATH=. mypy last.py, then compare the wildcard import with the explicit import and with either update removed. Trace how wildcard-import names reach the used-before-def check; done means the two-file example passes without suppressing the diagnostic while preserving the existing behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
compilers, devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.