Skip to content

What names should be included in stubs? #1287

Closed

Description

@JelleZijlstra

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 which inspect.getmodule() either returns None at runtime or returns a different module than a, 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.getmodule is 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.
  • All names in the stub must also be defined at runtime, except for names that start with _ or that are imported without as.

And here are some complications we should be aware of:

  • Some names only exist on some platforms. sys.platform checks 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.scandir is actually defined in the posix module).
  • 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

  1. gvanrossum commented on May 22, 2017

    @gvanrossum
    Member

    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__.

  2. gvanrossum commented on May 22, 2017

    @gvanrossum
    Member

    Also, what about the methods in classes?

  3. JukkaL commented on May 22, 2017

    @JukkaL
    Contributor

    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?).

  4. gvanrossum commented on May 22, 2017

    @gvanrossum
    Member

    Yeah, if you want to learn about data science that's probably the way to go about it.

  5. JelleZijlstra commented on May 25, 2017

    @JelleZijlstra
    MemberAuthor

    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).

  6. gvanrossum commented on May 25, 2017

    @gvanrossum
    Member

    Oh, that's a long list. Are you really planning to work through that entire list?

  7. JelleZijlstra commented on May 25, 2017

    @JelleZijlstra
    MemberAuthor

    It will take a while, but I think it's tractable.

  8. JelleZijlstra commented on Jun 28, 2020

    @JelleZijlstra
    MemberAuthor

    We have more detailed guidelines on this in CONTRIBUTING.md now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    project: policyOrganization of the typeshed project

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions