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
pyright tests: doesn't support __getattr__ for resolving submodules #5598
Example: stubs/paramiko/paramiko/kex_ecdh_nist.pyi contains imports from cryptography, but pyright can't find cryptograpy, probably because it's "hidden" in stubs/cryptography. Cc @erictraut and @jakebailey: Do you have any ideas how we could fix this?
On initial investigation, it looks like paramiko is accessing some modules in cryptography that are missing stubs. For example stubs/paramiko/paramiko/kex_curve25519.pyi imports from cryptography.hazmat.primitives.asymmetric.x25519 which has a stub, and the import succeeds. But stubs/paramiko/paramiko/kex_ecdh_nist.pyi imports from cryptography.hazmat.primitives.asymmetric.ec2, and there is no stub for that module, so the import fails.
I blame my morning tiredness for missing the 2 at the end of that filename. That said, cryptography/cryptography/hazmat/primitives/asymmetric/__init__.pyi contains a __getattr__() definition, meaning that all non-existing sub-modules should exist (as Any).
Pyright doesn't currently apply the module-level __getattr__ for submodule resolutions. Doing so would be quite expensive at analysis time because it would need to parse and bind every module along the import path to determine whether any of the parent modules contain this directive, so I'd prefer not to implement this unless it's really needed. This is the first time I've heard of a stub that depends on that behavior.
Suppose a stub does from foo.bar import baz. First we find a folder named foo/, and this is the only step where the entire import path is needed. Then, to make this work, we would look for def __getattr__ in foo/__init__.py. Most of the time it shouldn't make things slower, because it's only needed in the less likely case that foo/bar.py doesn't exist. What am I missing?
The good news is that the ec2 module does not seem to exist at runtime, either, so I'm just going to fix the import. There is no immediate need to fix this and we'll see what the future brings. We should leave this issue open, though.
This likely negatively affects the new PIL stubs (#5594); in the ones I wrote that ship with Pylance (https://github.com/microsoft/python-type-stubs/tree/main/PIL), I made the stub py.typed with partial to avoid warnings about unresolved imports (for modules I didn't explicitly mark as incomplete).
In general, we assume that stub packages that aren't partial to be complete, including that a given module doesn't exist. The import resolver doesn't really have access to the analysis info like "this file is marked as incomplete via a __getattr__" (it doesn't read the contents at all, it's purely based on the filesystem layout).
changed the title [-]pyright tests: Can't import from other third-party stubs[/-][+]pyright tests: doesn't support `__getattr__` for resolving submodules[/+]on Jun 20, 2022
Activity
erictraut commentedon Jun 9, 2021
Can you point to a specific example?
On initial investigation, it looks like
paramikois accessing some modules incryptographythat are missing stubs. For examplestubs/paramiko/paramiko/kex_curve25519.pyiimports fromcryptography.hazmat.primitives.asymmetric.x25519which has a stub, and the import succeeds. Butstubs/paramiko/paramiko/kex_ecdh_nist.pyiimports fromcryptography.hazmat.primitives.asymmetric.ec2, and there is no stub for that module, so the import fails.srittau commentedon Jun 9, 2021
I blame my morning tiredness for missing the
2at the end of that filename. That said,cryptography/cryptography/hazmat/primitives/asymmetric/__init__.pyicontains a__getattr__()definition, meaning that all non-existing sub-modules should exist (asAny).erictraut commentedon Jun 9, 2021
Pyright doesn't currently apply the module-level
__getattr__for submodule resolutions. Doing so would be quite expensive at analysis time because it would need to parse and bind every module along the import path to determine whether any of the parent modules contain this directive, so I'd prefer not to implement this unless it's really needed. This is the first time I've heard of a stub that depends on that behavior.Akuli commentedon Jun 9, 2021
Suppose a stub does
from foo.bar import baz. First we find a folder namedfoo/, and this is the only step where the entire import path is needed. Then, to make this work, we would look fordef __getattr__infoo/__init__.py. Most of the time it shouldn't make things slower, because it's only needed in the less likely case thatfoo/bar.pydoesn't exist. What am I missing?srittau commentedon Jun 9, 2021
The good news is that the
ec2module does not seem to exist at runtime, either, so I'm just going to fix the import. There is no immediate need to fix this and we'll see what the future brings. We should leave this issue open, though.jakebailey commentedon Jun 9, 2021
This likely negatively affects the new PIL stubs (#5594); in the ones I wrote that ship with Pylance (https://github.com/microsoft/python-type-stubs/tree/main/PIL), I made the stub
py.typedwithpartialto avoid warnings about unresolved imports (for modules I didn't explicitly mark as incomplete).In general, we assume that stub packages that aren't partial to be complete, including that a given module doesn't exist. The import resolver doesn't really have access to the analysis info like "this file is marked as incomplete via a
__getattr__" (it doesn't read the contents at all, it's purely based on the filesystem layout).[-]pyright tests: Can't import from other third-party stubs[/-][+]pyright tests: doesn't support `__getattr__` for resolving submodules[/+]hauntsaninja commentedon Jun 20, 2022
(retitled the issue to be more specific, feel free to change if I misunderstood what's going on here)
srittau commentedon May 13, 2025
I'm not sure this is still a problem. If it is, we can always open a new issue.