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

F402 is triggered by __future__.annotations #15747

Open
mattmess1221 opened this issue Jan 26, 2025 · 2 comments
Open

F402 is triggered by __future__.annotations #15747

mattmess1221 opened this issue Jan 26, 2025 · 2 comments
Labels
question Asking for support or clarification

Comments

@mattmess1221
Copy link

mattmess1221 commented Jan 26, 2025

Description

F402 is being triggered by __future__ imports. These imports can probably be safely ignored.

Searched terms: F402, annotations, future

Reproduction

from __future__ import annotations

for annotations in [["anno1", "anno2"]]:
    print(annotations)

Output:

% ruff --version
ruff 0.9.3
% ruff check --select F
f.py:3:5: F402 Import `annotations` from line 1 shadowed by loop variable
  |
1 | from __future__ import annotations
2 |
3 | for annotations in [["anno1", "anno2"]]:
  |     ^^^^^^^^^^^ F402
4 |     print(annotations)
  |

Found 1 error.
@InSyncWithFoo
Copy link
Contributor

This seems to be by design, considering what Pyflakes does:

# https://github.com/PyCQA/pyflakes/blob/d9e32c4c/pyflakes/checker.py#L971
if isinstance(existing, Importation) and isinstance(parent_stmt, FOR_TYPES):
    self.report(messages.ImportShadowedByLoopVar,
                node, value.name, existing.source)

# https://github.com/PyCQA/pyflakes/blob/d9e32c4c/pyflakes/checker.py#L415
class FutureImportation(ImportationFrom):
    """
    A binding created by a from `__future__` import statement.

    `__future__` imports are implicitly used.
    """
    ...

@AlexWaygood
Copy link
Member

AlexWaygood commented Jan 26, 2025

Yes, putting from __future__ import annotations in a module does actually insert an annotations symbol into the module's namespace:

>>> from __future__ import annotations
>>> annotations
_Feature((3, 7, 0, 'beta', 1), None, 16777216)

This is documented at https://docs.python.org/3/library/__future__.html.

I appreciate that most people don't ever use the symbol that's inserted as a result of these import statements -- the main use case is the "side effect" the import statement has that causes the module to be parsed in a different way. However, your code still might be more readable if you used a different variable name to differentiate your loop variable from the symbol inserted by the import statement.

@AlexWaygood AlexWaygood added the question Asking for support or clarification label Jan 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Asking for support or clarification
Projects
None yet
Development

No branches or pull requests

3 participants