You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
exclude_type_checking_imports also excludes imports in the else branch of if TYPE_CHECKING: #323
With exclude_type_checking_imports=True, the imports in the else (and elif) branches of an if TYPE_CHECKING: statement are excluded too, even though those branches are the ones that run at runtime. So contracts broken by those imports are kept.
For example, with pkg/domain.py:
fromtypingimportTYPE_CHECKINGifTYPE_CHECKING:
frompkg.infraimportSessionelse:
# Runs whenever pkg.domain is imported.frompkg.infraimportSession
I'd expect {'pkg.infra'}, from line 7. Through Import Linter, with exclude_type_checking_imports = True, a forbidden contract from pkg.domain to pkg.infra is kept.
This pattern is common in libraries. For example filelock/__init__.py imports ._async_read_write and ._read_write under if TYPE_CHECKING: for type checkers, and again in a try in the else branch for runtime. grimp.build_graph("filelock", exclude_type_checking_imports=True) has no import from filelock to either module. Other packages with runtime imports in such else branches include aiohttp, numpy, docutils, propcache, packaging and anyio.
Two related cases are also wrong:
elif TYPE_CHECKING: isn't detected, so its imports are kept. (The Python import scanner did detect it, before the move to Rust.)
A nested if TYPE_CHECKING: sets the state back to "not type checking" when it ends, so the imports after it in the enclosing if TYPE_CHECKING: block are kept.
The cause is in Visitor::visit_stmt in rust/src/import_parsing.rs: for an if TYPE_CHECKING: statement, it sets typechecking_only to true while walking the whole statement, including its elif/else clauses, and then sets it to false rather than back to its previous value.
Activity