Skip to content

decorators.pyi interface file? #3044

@dwreeves

Description

@dwreeves

Background

In rich-click 1.9.0.dev1, I added a decorators.pyi (link) that enables typed args and-- critically for the developer experience-- tab completion for IDEs.

So in rich-click, @click.option() (and other decorators) still take in arbitrary **kwargs, but as far as type-checking and the overall developer experience in a modern IDE is concerned, the experience is vastly improved:

image

context_settings=... is an especially opaque and benefits tremendously from a TypedDict:

image

The ask

I've found this to be an incredibly useful change that vastly improves the developer experience, but I also feel like it should be something in base Click? It feels odd to add this additional functionality that's not in base click and is orthogonal to the purpose of rich-click, and yet it still feels like a necessity to have for modern development.

I'm posting this here because I am wondering if you are interested in a contribution to this effect. I don't see any open issues relating to this. I would be willing to contribute this, especially since I've done a lot of this work already.

Additional considerations

  • I think it is both a rare use case, and a violation of the Liskov substitution principle, to create a subclass of Command, Option, etc. that does not accept all the parent class's args/kwargs. Additionally, if a user does this, then worst case scenario is they can just ignore their IDE's auto-completion, and the static type-checker also shouldn't get upset by it either.
  • context_settings takes in an arbitrary dict, but in rich-click's decorators.pyi, we use a TypedDict. I don't think it's common for developers to subclass Context, but it's certainly possible, and Context will often take in additional kwargs. Thus, if not handled properly, a TypedDict could cause a static type checker to fail when it shouldn't. Additionally, PEP 728 is a long way's away.
    • That said, there is a simple solution: @overload the command and group decorators' context_settings to take in both a TypedDict and a dict[str, Any]; by placing the TypedDict as the first overload, PyCharm autocompletes correctly (this is untested with VSCode). as long as cls=Command or cls=None then the TypedDict is appropriate; otherwise for any arbitrary subclass of Command then an arbitrary dict[str, Any] is the appropriate type.
  • core.py would also strongly benefit from its own core.pyi because of the Group.command and Group.group decorators.

Metadata

Metadata

Assignees

No one assigned

    Labels

    TBDNot enough information to proceed

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions