python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.26k stars 2.79k forks source link

:bug: Methods converted to `staticmethod`s using a decorator not treated as `staticmethod`s #13434

Open tombulled opened 2 years ago

tombulled commented 2 years ago

Bug Report The @staticmethod decorator only appears to work with MyPy when used as a decorator.

For example, the following code works:

class MyClass:
    @staticmethod
    def my_method():
        ...

However, the following code does not work:

from typing import Callable

def make_staticmethod(func: Callable, /) -> staticmethod:
    return staticmethod(func)

class MyClass:
    @make_staticmethod
    def my_method():
        ...

The above code produces the following error:

error: Method must have at least one argument

To Reproduce

  1. Run MyPy against the non-working example shown above

Expected Behavior MyPy sees that the decorator returns a staticmethod and proceeds to treat MyClass.my_method as a staticmethod

Actual Behavior MyPy produces the following error:

error: Method must have at least one argument

The above error implies that MyPy is not treating the method as a staticmethod.

Your Environment

RivenSkaye commented 1 year ago

I've noticed this too, for both staticmethod and classmethod. Which is a shame, because application order of decorators can cause some funky stuff to happen, including but not limited to straight up errors at runtime, or typehints breaking down to *args: Any, **kwargs: Any. If you do add arguments to the functions, the error changes to a warning that there is no self or cls argument. Tangentially related, both of those decorators return object instances of their specific classes that are seen as e.g. staticmethod[int], but trying to hint a function or method as returning such a function causes a runtime error due to the classes not being subscriptable. I think a possible solution would be typing entries for StaticMethod[] (and perhaps for typing_extensions too?) and ClassMethod[].

As a positive side effect, this might also stop IDE autocomplete from adding cls as a positional argument in its autocomplete, since the handling of these annotations would be different