[ty] add legacy namespace package support#20897
Conversation
Diagnostic diff on typing conformance testsNo changes detected when running ty on typing conformance tests ✅ |
|
|
I'm now reasonably happy with the shape of the implementation, main place to quibble is how much elbow grease to put into the visitor that tries to find the idiom. |
|
For added context: This makes airflow work out-of-the box (whereas it wasn't even possible to set up the import paths correctly before) and fixes about 5k unresolved import errors |
MichaReiser
left a comment
There was a problem hiding this comment.
Thanks for finishing this up. Looks good to me but I'll leave this open for a little longer in case someone else wants to take a look
AlexWaygood
left a comment
There was a problem hiding this comment.
This looks great, thank you!! I only have a couple of minor nits about comments
| in_namespace_package = false; | ||
| // This is the only place where we need to consider the existence of legacy namespace | ||
| // packages, as we are explicitly searching for the *parent* package of the module | ||
| // we actually want. Here, such a package should be treated as a namespace package. |
There was a problem hiding this comment.
to better distinguish the two kinds of namespace packages?
| // we actually want. Here, such a package should be treated as a namespace package. | |
| // we actually want. Here, such a package should be treated as a PEP-420 ("modern") namespace package. |
|
|
||
| /// Determines whether a package is a legacy namespace package. | ||
| /// | ||
| /// Before PEP 420 introduce proper namespace packages, the ecosystem developed |
There was a problem hiding this comment.
| /// Before PEP 420 introduce proper namespace packages, the ecosystem developed | |
| /// Before PEP 420 introduced implicit namespace packages, the ecosystem developed |
| /// | ||
| /// Before PEP 420 introduce proper namespace packages, the ecosystem developed | ||
| /// its own form of namespace packages. These legacy namespace packages continue to persist | ||
| /// in modern codebases because they work with ancient pythons and if it ain't broke don't fix it. |
There was a problem hiding this comment.
| /// in modern codebases because they work with ancient pythons and if it ain't broke don't fix it. | |
| /// in modern codebases because they work with ancient Pythons and if it ain't broke don't, fix it. |
| /// The resulting package simultaneously has properties of both regular packages and namespace ones: | ||
| /// | ||
| /// * Like regular packages, `__init__.py` is defined and can contain items other than submodules | ||
| /// * Like namespace packages, multiple copies of the package may exist with different submodules |
There was a problem hiding this comment.
| /// * Like namespace packages, multiple copies of the package may exist with different submodules | |
| /// * Like implicit namespace packages, multiple copies of the package may exist with different submodules, | |
| /// and these submodules will be merged into one namespace at runtime by the interpreter |
| }) | ||
| } | ||
|
|
||
| /// Determines whether a package is a legacy namespace package. |
There was a problem hiding this comment.
this comment is fantastic, thanks for writing it up!!
Detect legacy namespace packages and treat them like namespace packages when looking them up as the parent of the module we're interested in. In all other cases treat them like a regular package.
(This PR is coauthored by @MichaReiser in a shared coding session)
Fixes astral-sh/ty#838