vscode complains about python's classmethod typing

433 views Asked by At

My vscode editor always complains about the classmethod typing irrespective of the class.

from __future__ import annotations

class A:
    @classmethod
    def foo(cls: type[A]) -> str:
        return "bar"

Error/warning about the classmethod (raised by Pylance),

Argument of type "(cls: type[A]) -> str" cannot be assigned to parameter "__f" of type "() -> _R_co@classmethod" in function "__init__"
Type "(cls: type[A]) -> str" cannot be assigned to type "() -> _R_co@classmethod"PylancereportGeneralTypeIssues

VSCode Version : 1.83.0 Pylance Version: v2023.10.20

settings.json

{
  "editor.formatOnSave": true,
  "editor.rulers": [140],
  "flake8.args": ["--config=setup.cfg"],
  "flake8.path": ["${workspaceFolder}/venv/bin/python", "-m", "flake8"],
  "[python]": {
    "editor.defaultFormatter": "ms-python.black-formatter",
    "editor.formatOnSave": true
  },
  "black-formatter.args": ["--line-length", "120"],
  "mypy-type-checker.args": ["--config-file=setup.cfg"],
  "mypy-type-checker.path": [
    "${workspaceFolder}/venv/bin/python",
    "-m",
    "mypy"
  ],
  "python.languageServer": "Pylance",
  "python.analysis.typeCheckingMode": "basic",
  "files.exclude": {
    "**/.git": true,
    "**/.svn": true,
    "**/.hg": true,
    "**/CVS": true,
    "**/.DS_Store": true,
    "**/Thumbs.db": true,
    "**/__pycache__": true,
    "**/.pytest_cache": true,
    "**/.mypy_cache": true,
    "**/venv": true
  },
  "python.defaultInterpreterPath": "${workspaceFolder}/venv/bin/python",
  "autoDocstring.docstringFormat": "google-notypes"
}

setup.cfg

[flake8]
max-line-length = 120
extend-ignore =
    # no whitespace before colon on list slice
    E203,
    # line break occurred before a binary operator
    W503,
    # comparison to True should be is not == (not true for pandas)
    E712,
    # line too long (handled by formatter automatically whenever possible)
    E501,
    # missing type annotation for self in method
    ANN101,
    # missing type annotation for *args, **kwargs
    ANN002,
    ANN003
per-file-ignores =
    # imported but unused
    __init__.py: F401
exclude = .vscode, .git, __pycache__, venv, tests
require-plugins = flake8-annotations, flake8-pep585
# infer no return as a None return type
suppress-none-returning = true
# for mypy
mypy-init-return = true
# allow importing from typing for convenience
pep585-whitelisted-symbols =
    Iterator
    Iterable
    Callable

[mypy]
exclude = .vscode, .git, __pycache__, venv, tests
strict_optional = False
2

There are 2 answers

1
Kyle Davis On

When you're working with Python's type hinting system, using type[A] directly for annotating a variable or parameter is not supported.

To annotate a variable or function parameter with a specific type, you should utilize the Type class from the typing module.

It's worth noting that you might not be seeing any immediate errors due to Python's handling of annotations. By using from __future__ import annotations, you enable postponed evaluation of type annotations. In this mode, annotations are stored as strings and are not evaluated until necessary. This can be particularly helpful in avoiding issues related to forward references or circular dependencies.

from __future__ import annotations
from typing import Type

class A:
    @classmethod
    def foo(cls: Type[A]) -> str:
        return "bar"

References:

What are the differences between type() and isinstance()?

Class vs. Type in Python

https://docs.python.org/3/library/typing.html

1
Vineesh Vijayan On

The error/warning you're seeing is related to the type hinting and how it's interpreted by the Pylance language server. Here's what you can do to resolve it:

Change the type hint for the cls parameter to just type instead of type[A]. This will make it a generic type and should resolve the error.

class A:
    @classmethod
    def foo(cls: type) -> str:
        return "bar"

If changing the type hint to type is not feasible or doesn't match your intentions, you can disable the Pylance type checking for this specific line using a comment.

class A:
    @classmethod
    def foo(cls: type[A]) -> str:  # type: ignore
        return "bar"

By adding # type: ignore at the end of the line, you're telling Pylance to ignore the type error/warning for that specific line.

Please note that either of these solutions may affect the overall type safety of your code, so use them carefully and ensure that the intended behavior is still maintained.