python / python/mypy

Mypy plugins: Changing class signature impossible here?

Open
#19,195 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Hello,

I'm trying to write a plugin for my paramclasses library. I already posted about it on gitter to ask a few questions (without answer at the moment).

I'm still trying to get to work on my library's typing issues whilst being a complete noob on the subject.

So I started by writing a logger-like dummy plugin which shows the called hooked with their args/kwargs (so that I understand the mechanisms a bit better), and trying to solve the signature problem.

1. Nonparamclass MWE: looks OK

Here's a MWE:

class A:
    def __init__(self, *args: object, **kwargs: object) -> None:
    """Takes anything at runtime but raises unless only 'foo' kwarg."""
        if args or list(kwargs) != ["foo"]:
            msg = "Only 'foo' kwarg is acceptable"
            raise ValueError(msg)

        self.foo = kwargs.get("foo")


A(bar="should fail")

I would like mypy to pick up the fact that the signature is in fact A(*, foo). The logger picks up this (filtered to keep only signature related hooks):
(removing the report hook):

[get_function_signature_hook] → ('builtins.list',), {}
[get_method_signature_hook] → ('builtins.list.__ne__',), {}
[get_function_signature_hook] → ('builtins.ValueError',), {}
[get_method_signature_hook] → ('builtins.dict.get',), {}
[get_method_signature_hook] → ('builtins.dict.get',), {}
[get_method_signature_hook] → ('builtins.object.__init_subclass__',), {}
[get_function_signature_hook] → ('mwe.A',), {}

Q1. Am I right to assume that I logically should use get_function_signature_hook with mwe.A for this example?If so, I think this works fine since I have a way to write a plugin to do what I want.

Now on to my use case

2. Paramclass MWE: not OK

My usecase MWE would be:

from paramclasses import ParamClass


class A(ParamClass):
    foo: int


A(bar="should fail")

When I filter out the logger plugin output, to keep only the "signature" hook, I only get this which refers to internals that seem unrelated:

[get_function_signature_hook] → ('paramclasses.paramclasses._MissingType',), {}
[get_function_signature_hook] → ('paramclasses.paramclasses._run_once',), {}
[get_function_signature_hook] → ('paramclasses.paramclasses._run_once',), {}
[get_function_signature_hook] → ('paramclasses.paramclasses._run_once',), {}

So in the end, I'm completely lost on what I should/could do.

Q2. Is there a way to think about understanding the problem? Note that if useful, the __signature__ attribute returns the desired result at runtim.


Thanks in advance!
Élie

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the two Python MWEs and compare the plugin callbacks shown for the plain class and the ParamClass subclass. Investigate how get_function_signature_hook relates to ParamClass and its runtime signature; done should establish whether the desired constructor signature is supported and identify the appropriate plugin entry point or limitation.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.