Repository navigation
What names should be included in stubs? #1287
Description
I'm hoping to create or improve a tool that can automatically check whether stubs are comprehensive. But for such a tool to work reliably, we need to define what names should actually be in the stubs.
I'm assuming the approach would be something like:
- Find all the names defined in the module's
__dict__at runtime. - Find all the names in the stub.
- Compare the two sets of names. If there is an inconsistency, use some set of heuristics to decide if it indicates a bug in the stub.
This is the approach taken by the stubtest.py tool that currently exists in the mypy repo. I've done some very preliminary work on a similar tool (http://github.com/JelleZijlstra/stubcheck).
For now, I want to focus only on finding names that are missing in the stub or at runtime. There's more we can do, like making sure type signatures are consistent, but that's for another day.
Here's a few rules we could consider:
- If there is an
__all__at runtime, all names in__all__must be in the stub. - All documented names must be in the stub. Implementing this would require parsing Sphinx documentation or something like that.
- If there is no
__all__and we can't use documentation:- Private names (starting with
_) don't need to be in the stub. - When you're creating a stub for module
a, names for whichinspect.getmodule()either returns None at runtime or returns a different module thana, don't need to be in the stub. This rule means the stub doesn't have to include names imported from other modules. It also means that it doesn't have to include types that don't set a__module__(like integer constants). In my experience, those are often intended to be private but not actually marked as private. - Names defined at runtime whose
inspect.getmoduleis the module being inspected should be included. This will include some functions that may have been intended to be private but aren't, but my hope is that there are few enough of those that it's not going to be a big problem.
- Private names (starting with
- All names in the stub must also be defined at runtime, except for names that start with
_or that are imported withoutas.
And here are some complications we should be aware of:
- Some names only exist on some platforms.
sys.platformchecks in stubs aren't always sufficient to cover all such cases. - Some names are imported from other modules but still part of the public API of a module (for example,
os.scandiris actually defined in theposixmodule). - Many modules use some kind of weird dynamism that may cause trouble.
- In the stub, we should make sure to parse all the version_info/platform correctly.
Let me know if there's some other heuristic we can use.
Activity
gvanrossum commentedon May 22, 2017
I'd avoid any approach that requires understanding the docs.
A special problem exists for imported modules -- these shouldn't be exported, unless there's some special situation.
Some modules have public interfaces that are intentionally not listed in
__all__.gvanrossum commentedon May 22, 2017
Also, what about the methods in classes?
JukkaL commentedon May 22, 2017
There are probably a relatively large number of exceptions, and we will need an easy way of whitelisting them (and keeping the whitelist up-to-date).
Another random idea that may well be impractical: What about looking at a corpus of code and collecting all names that are imported from library modules within that corpus? These are things that are either part of the public API of the modules or at least there is code in the wild that assumes so. We could then keep this in a list of of known defined names, and we could verify that stubs have all known defined names at least. This might only make sense if there is an existing corpus that we can use and that is known to be Python 2/3 clean (maybe use internal codebases for this?).
gvanrossum commentedon May 22, 2017
Yeah, if you want to learn about data science that's probably the way to go about it.
JelleZijlstra commentedon May 25, 2017
To update, I implemented a tool implementing some of the ideas from my post above and used it to find a number of issues in typeshed. The tool is at https://github.com/JelleZijlstra/stubcheck and my current listing of issues that need to fixed is in https://github.com/JelleZijlstra/stubcheck/pull/1/files.
Once I'm done working through the list of issues generated, I plan to clean up the tool and add it to typeshed's CI. I'll also be able to add more checks (e.g., checking that methods on classes are right, checking that argument signatures are right).
gvanrossum commentedon May 25, 2017
Oh, that's a long list. Are you really planning to work through that entire list?
JelleZijlstra commentedon May 25, 2017
It will take a while, but I think it's tractable.
JelleZijlstra commentedon Jun 28, 2020
We have more detailed guidelines on this in CONTRIBUTING.md now.