Skip to content

🐛 fix(resolver): accept guarded code the interpreter rejects - #757

Merged
gaborbernat merged 2 commits into
tox-dev:mainfrom
gaborbernat:fix-751-unexecutable-guarded-code
Aug 24, 2026
Merged

🐛 fix(resolver): accept guarded code the interpreter rejects#757
gaborbernat merged 2 commits into
tox-dev:mainfrom
gaborbernat:fix-751-unexecutable-guarded-code

Conversation

@gaborbernat

Copy link
Copy Markdown
Member

A TYPE_CHECKING block only has to satisfy a type checker, so it can hold expressions the interpreter refuses. xarray writes T_XarrayOther = TypeVar("T_XarrayOther", bound="DataArray" | Dataset), which raises TypeError: unsupported operand type(s) for |: 'str' and 'type' the moment it runs. Executing the guard to recover its names hit that error and warned Failed guarded type import. The annotation then reached a name nobody had bound, so a second warning followed: Cannot resolve forward reference ... name 'T_Other' is not defined. The rendered page was right the whole time. The warnings alone fail a build run with -W, which is what #751 reports.

An import that raises keeps its warning, since a dependency missing from the docs environment is worth reporting, as #741 asked for. Other statements now leave their names behind as forward references, read off the assignment targets, or off the class or function name. That matches what a type checker sees, and format_annotation prints such a reference as its own name, so the rendered output holds still while both warnings go away. ✨

The stand-ins go into the module namespace the guarded code writes to, through setdefault, so a name that already resolves keeps whatever it points at.

A TYPE_CHECKING block is read by type checkers, not run by the interpreter,
so it holds constructs that raise when executed. xarray writes
TypeVar("T_XarrayOther", bound="DataArray" | Dataset), which is a TypeError
at runtime. Executing the guard to recover its names hit that error, warned
about a failed type import, and then warned a second time when the
annotation using the name could not resolve. Both warnings pointed at code
that is correct.

An import that fails still warns, since a missing dependency is worth
knowing about. Any other statement now stands its names in as forward
references, which is what a type checker sees and what the renderer already
knows how to print.

Closes tox-dev#751
@gaborbernat
gaborbernat force-pushed the fix-751-unexecutable-guarded-code branch from 339d7c9 to e4cb9f3 Compare August 24, 2026 14:38
@gaborbernat
gaborbernat merged commit 3f6d334 into tox-dev:main Aug 24, 2026
10 checks passed
@djhoese

djhoese commented Aug 24, 2026

Copy link
Copy Markdown

Wow, awesome, thanks for the fixes. One question:

An import that raises keeps its warning, since a dependency missing from the docs environment is worth reporting

Does this mean that if a type checking guard has a try/except ImportError that it will still warn on the missing import since I think this code is still executing one line at a time? Installing these missing dependencies is an easy enough workaround, but I wanted to check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants