microsoft / pyright

Static Type Checker for Python
Other
13.18k stars 1.41k forks source link

`classmethod` with `partial` does not work properly #9066

Closed benglewis closed 2 days ago

benglewis commented 3 days ago

Note: if you are reporting a wrong signature of a function or a class in the standard library, then the typeshed tracker is better suited for this report: https://github.com/python/typeshed/issues.

If you have a question about typing or a behavior that you’re seeing in Pyright (as opposed to a bug report or enhancement request), consider posting to the Pyright discussion forum.

Describe the bug

Using classmethod as a function on a partial does not seem to work properly, and returns two type errors:

Type "classmethod[Any, (), Any]" is not assignable to declared type "(cls: type[Self@Parent], a: Unknown, b: Unknown) -> str"
  Type "classmethod[Any, (), Any]" is not assignable to type "(cls: type[Self@Parent], a: Unknown, b: Unknown) -> str"Pylance[reportAssignmentType](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportAssignmentType)
Argument missing for parameter "a"Pylance[reportCallIssue](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportCallIssue)

Code or Screenshots

from functools import partial

class Parent:
    @classmethod
    def my_classmethod(cls, a, b):
        return f"Class: {cls.__name__}, a: {a}, b: {b}"

class Child(Parent):
    # Override the class method using partial to fix 'a'
    my_classmethod = classmethod(partial(Parent.my_classmethod.__func__, a=42))

# Now we can call the method on the Child class and it will use the partial method
result = Child.my_classmethod(b=20)
print(result)  # Outputs: Class: Child, a: 42, b: 20

VS Code extension or command-line Are you running pyright as a VS Code extension, a language server in another editor, integrated into Pylance, or the command-line tool? Which version?

VSCode with Pylance: VSCode version 1.93.1 Pylance version v2024.9.2

erictraut commented 2 days ago

This code is clever, but it's unfortunately too dynamic and complex for a static type checker to handle. I don't see a good way to make this work in pyright. Other type checkers like mypy generate the same errors in this case.

If you want to use this technique along with static type checking, you'll need to find workarounds or suppress the type errors you're seeing.