microsoft / pyright

Static Type Checker for Python
Other
13.04k stars 1.39k forks source link

Fall back to source when stubs are incomplete #8339

Closed all-iver closed 1 month ago

all-iver commented 1 month ago

In a large legacy codebase, I have a lot of methods that are added to classes at runtime (on startup, so they always exist). I have created type stub .pyi files to add definitions for these methods, using a script to generate them from a template. But there are also a lot of other methods that could be typed in the original source files. I think I'm observing that if a .pyi file is present for a file/class, ONLY the methods in the .pyi file are discovered by pyright and all the other methods in the original source are ignored. This means that in order to fully type a class, I'd have to duplicate all of its methods into the .pyi stub, which would be an unreasonable amount of ongoing work for us.

I see that there's an option "useLibraryCodeForTypes", but it seems to be on a per-file basis only. Is there a way to have type stub files only add information for our invisible methods, while falling back to the original classes for any methods not found in the stubs?

erictraut commented 1 month ago

This isn't how stub files are defined to work. When a stub file is present, it is assumed to be complete. It is a stand-in for the original code. The absence of a symbol in a stub file is significant and means that the symbol is not present. It would be incorrect for a type checker to interpret the absence of a symbol in a stub file to mean "look elsewhere".

For more details about stub files and how they are interpreted by type checkers, refer to this section of the Python typing specification. PEP 561 (which hasn't yet been incorporated into the typing spec) also provides information and context.

If you would like a type checker to assume that a stub is incomplete and that all undefined symbols should be treated as type Any, you can add the following to the stub:

def __getattr__(name: str) -> Any: ...

Alternatively, there are ways to convert a code file into its type stub equivalent, stripping out all of the implementation details. Pyright has such a capability, which you can read about here. There are also other tools that do this, such as the stubgen tool included with mypy.