ruff icon indicating copy to clipboard operation
ruff copied to clipboard

False positive for `F821` on circular reference in `TYPE_CHECKING` block

Open ngnpope opened this issue 1 year ago • 4 comments

Keywords searched for before creating issue: F821, TYPE_CHECKING.

Example code that produces the false positive:

from __future__ import annotations

from typing import TYPE_CHECKING, TypeAlias

if TYPE_CHECKING:
    Nested: TypeAlias = dict[str, bool | Nested]

Command line and output:

$ ruff --version
ruff 0.4.2
$ ruff check --isolated --select=F821 bug.py 
bug.py:6:42: F821 Undefined name `Nested`
Found 1 error.
$ mypy --strict bug.py 
Success: no issues found in 1 source file

Expected that F821 would not be raised in a TYPE_CHECKING block for a circular reference when using postponed evaluation of annotations (PEP 563).

ngnpope avatar May 02 '24 10:05 ngnpope

nit: indeed, PEP 563 applies to annotations, but dict[str, bool | Nested] isn't one (in fact the __future__ import doesn't make a difference).

I think the issue is still valid though :+1:

trag1c avatar May 02 '24 11:05 trag1c

Not sure... @AlexWaygood would know.

charliermarsh avatar May 02 '24 14:05 charliermarsh

Yeah I think from __future__ import annotations is irrelevant here, but if it's in an if TYPE_CHECKING block we should treat it as though it has "stub file" semantics (whether or not __future__ annotations are enabled). The rhs of an assignment is evaluated at runtime regardless of whether __future__ annotations are enabled, but nothing in an if TYPE_CHECKING block is ever evaluated at runtime, so it doesn't matter

TL;DR: I agree that this is a false positive

AlexWaygood avatar May 02 '24 14:05 AlexWaygood

If you tried to use Nested in a type annotation anywhere without either quoting it or having __future__ annotations enabled, it would fail, because the alias doesn't exist at runtime. But that's a separate issue

AlexWaygood avatar May 02 '24 14:05 AlexWaygood