You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As discussed in #2266, this apparently doesn't work yet:
# See http://stackoverflow.com/questions/3203286/how-to-create-a-read-only-class-property-in-python
from typing import *
T = TypeVar('T')
V = TypeVar('V')
class classproperty(Generic[T, V]):
def __init__(self, getter: Callable[[Type[T]], V]) -> None:
self.getter = getter
def __get__(self, instance: Any, owner: Type[T]) -> V:
# instance is really None, but we don't care
return self.getter(owner)
class C:
@classproperty # <-- error here
def foo(cls) -> int:
return 42
reveal_type(C.foo)
@gvanrossum reported the following output from mypy:
classprop.py: note: In class "C":
classprop.py:20: error: Argument 1 to "classproperty" has incompatible type Callable[[C], int]; expected Callable[[Type[None]], int]
classprop.py: note: At top level:
classprop.py:25: error: Revealed type is 'classprop.classproperty[builtins.None, builtins.int*]'
main.py:24: error: Argument 2 to "__get__" of "classproperty" has incompatible type "Type[Bar]"; expected "Type[F]"
main.py:24: note: Revealed type is 'F`-1'
Found 1 error in 1 file (checked 1 source file)
seems to work if you remove T, although it feels like a wrong thing to do?
Under 3.9, the docs are now recommending the use of classmethod(property(...)) to handle class properties. This is reinforced by sphinx having special-cased support for this case -- if you want autodoc to produce class property docs, it must be done by wrapping a property in the classmethod descriptor.
If you try to do this and run mypy, however, the class property type is deduced as () -> T instead of T.
Would it be possible to special-case classmethod(property(...)) to make that case behave correctly? That would satisfy at least some cases and harmonize with 3.9+ docs and sphinx behavior.
Right now, trying to declare a read-only class property which satisfies the trifecta of
I've been using a TypeVar and wrapping func to hack this together:
fromcollections.abcimportCallablefromtypingimportTypeVarPropReturn=TypeVar("PropReturn")
defclassproperty(meth: Callable[..., PropReturn]) ->PropReturn:
"""Access a @classmethod like a @property."""# mypy doesn't understand class properties yet: https://github.com/python/mypy/issues/2563returnclassmethod(property(meth)) # type: ignoreclassA:
@classpropertydefx(cls) ->int:
return5print(A.x) # 5reveal_type(A.x) # note: Revealed type is "builtins.int"print(A().x) # 5reveal_type(A().x) # note: Revealed type is "builtins.int"
Rather than muck with casts (since they'd be lying anyway 😁), the # type: ignore inside classproperty works around Argument 1 to "classmethod" has incompatible type "property"; expected "Callable[..., Any]" and Incompatible return value type.
Activity
tyrion commentedon Aug 22, 2019
It seems to work in this way:
I don't think it is ideal to have to use both
classpropertyandclassmethodbut I couldn't find an other way to make it work.oakkitten commentedon May 20, 2020
the last example doesn't work with
TypeVars:yields
seems to work if you remove
T, although it feels like a wrong thing to do?sirosen commentedon Nov 5, 2021
Under 3.9, the docs are now recommending the use of
classmethod(property(...))to handle class properties. This is reinforced by sphinx having special-cased support for this case -- if you want autodoc to produce class property docs, it must be done by wrapping a property in the classmethod descriptor.If you try to do this and run mypy, however, the class property type is deduced as
() -> Tinstead ofT.e.g.
shows
Revealed type is "def () -> builtins.int"Would it be possible to special-case
classmethod(property(...))to make that case behave correctly? That would satisfy at least some cases and harmonize with 3.9+ docs and sphinx behavior.Right now, trying to declare a read-only class property which satisfies the trifecta of
is quite tricky.
JacobHayes commentedon May 9, 2022
I've been using a
TypeVarand wrapping func to hack this together:Rather than muck with
casts (since they'd be lying anyway 😁), the# type: ignoreinsideclasspropertyworks aroundArgument 1 to "classmethod" has incompatible type "property"; expected "Callable[..., Any]"andIncompatible return value type.feat(utils): add classproperty decorator