3 Commits

Author SHA1 Message Date
Daniel Johnson
697fa22d23 Detect string literals in | union annotations (crashes Python <3.14)
`"Foo" | None` fails at runtime on Python 3.10–3.13 because str doesn't
implement __or__. This only works on 3.14+ where PEP 749 defers annotation
evaluation. Add a check for this pattern alongside the existing conditional
import check so we catch it before it reaches users.

Ref: https://github.com/lutris/lutris/pull/6595

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 07:16:30 -04:00
Daniel Johnson
444385decc check_annotations: detect all conditional imports, not just TYPE_CHECKING
Broaden the checker to flag unquoted annotations referencing any import
under an `if` or `try` block, not only `TYPE_CHECKING` guards. This
catches cases like try/except optional imports (e.g. GnomeDesktop) that
can be None at runtime and crash on dotted attribute access in eager
annotations.

Also fix dotted access check to cover `from X import Y` names used as
`Y.Attr` in annotations, not just `import X` modules.

Motivated by #6552 (fixed in 7019866).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 18:30:35 -04:00
Daniel Johnson
ea743a236f Detect unquoted TYPE_CHECKING annotations that break on Python 3.10
Python 3.14 evaluates annotations lazily (PEP 649), so unquoted
annotations like `threading.Event` work even when `threading` is only
imported under TYPE_CHECKING. On Python 3.10, these annotations are
evaluated eagerly and raise NameError at import time.

Add utils/check_annotations.py, an AST-based checker that detects
unquoted annotations referencing TYPE_CHECKING-only imports, covering
both bare names (`HTTPResponse`) and dotted access (`threading.Event`)
— the latter being a gap in ruff's FA102 rule. Wire it into `make
annotation-compat`, `make check`, and a new CI job.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 16:12:14 -05:00