FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Allow generic class variables by ilevkivskyi · Pull Request #7906 · python/mypy · GitHub

Repository navigation

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .py  (3) .test  (2) All 2 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
6 changes: 5 additions & 1 deletion mypy/checkmember.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,11 @@ def analyze_class_attribute_access(itype: Instance,
if isinstance(t, TypeVarType) or get_type_vars(t):
# Exception: access on Type[...], including first argument of class methods is OK.
if not isinstance(get_proper_type(mx.original_type), TypeType):
mx.msg.fail(message_registry.GENERIC_INSTANCE_VAR_CLASS_ACCESS, mx.context)
if node.node.is_classvar:
message = message_registry.GENERIC_CLASS_VAR_ACCESS
else:
message = message_registry.GENERIC_INSTANCE_VAR_CLASS_ACCESS
mx.msg.fail(message, mx.context)

# Erase non-mapped variables, but keep mapped ones, even if there is an error.
# In the above example this means that we infer following types:
Expand Down
2 changes: 2 additions & 0 deletions mypy/message_registry.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@
# Generic
GENERIC_INSTANCE_VAR_CLASS_ACCESS = \
'Access to generic instance variables via class is ambiguous' # type: Final
GENERIC_CLASS_VAR_ACCESS = \
'Access to generic class variables is ambiguous' # type: Final
BARE_GENERIC = 'Missing type parameters for generic type {}' # type: Final
IMPLICIT_GENERIC_ANY_BUILTIN = \
'Implicit generic "Any". Use "{}" and specify generic parameters' # type: Final
Expand Down
7 changes: 2 additions & 5 deletions mypy/typeanal.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
Type, UnboundType, TypeVarType, TupleType, TypedDictType, UnionType, Instance, AnyType,
CallableType, NoneType, ErasedType, DeletedType, TypeList, TypeVarDef, SyntheticTypeVisitor,
StarType, PartialType, EllipsisType, UninhabitedType, TypeType, replace_alias_tvars,
CallableArgument, get_type_vars, TypeQuery, union_items, TypeOfAny,
LiteralType, RawExpressionType, PlaceholderType, Overloaded, get_proper_type, ProperType
CallableArgument, TypeQuery, union_items, TypeOfAny, LiteralType, RawExpressionType,
PlaceholderType, Overloaded, get_proper_type, ProperType
)

from mypy.nodes import (
Expand Down Expand Up @@ -311,9 +311,6 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Opt
self.fail('ClassVar[...] must have at most one type argument', t)
return AnyType(TypeOfAny.from_error)
item = self.anal_type(t.args[0])
if isinstance(item, TypeVarType) or get_type_vars(item):
self.fail('Invalid type: ClassVar cannot be generic', t)
return AnyType(TypeOfAny.from_error)
return item
elif fullname in ('mypy_extensions.NoReturn', 'typing.NoReturn'):
return UninhabitedType(is_noreturn=True)
Expand Down
45 changes: 45 additions & 0 deletions test-data/unit/check-classvar.test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,48 @@ class A:
[out]
main:2: note: Revealed type is 'builtins.int'
main:3: error: Cannot assign to class variable "x" via instance

[case testClassVarWithGeneric]
from typing import ClassVar, Generic, TypeVar
T = TypeVar('T')
class A(Generic[T]):
x: ClassVar[T]
@classmethod
def foo(cls) -> T:
return cls.x # OK

A.x # E: Access to generic class variables is ambiguous
A.x = 1 # E: Access to generic class variables is ambiguous
A[int].x # E: Access to generic class variables is ambiguous

class Bad(A[int]):
pass
Bad.x # E: Access to generic class variables is ambiguous

class Good(A[int]):
x = 42
reveal_type(Good.x) # N: Revealed type is 'builtins.int'
[builtins fixtures/classmethod.pyi]

[case testClassVarWithNestedGeneric]
from typing import ClassVar, Generic, Tuple, TypeVar, Union, Type
T = TypeVar('T')
U = TypeVar('U')
class A(Generic[T, U]):
x: ClassVar[Union[T, Tuple[U, Type[U]]]]
@classmethod
def foo(cls) -> Union[T, Tuple[U, Type[U]]]:
return cls.x # OK

A.x # E: Access to generic class variables is ambiguous
A.x = 1 # E: Access to generic class variables is ambiguous
A[int, str].x # E: Access to generic class variables is ambiguous

class Bad(A[int, str]):
pass
Bad.x # E: Access to generic class variables is ambiguous

class Good(A[int, str]):
x = 42
reveal_type(Good.x) # N: Revealed type is 'builtins.int'
[builtins fixtures/classmethod.pyi]
18 changes: 0 additions & 18 deletions test-data/unit/semanal-classvar.test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -206,21 +206,3 @@ class B:
pass
[out]
main:4: error: ClassVar can only be used for assignments in class body

[case testClassVarWithGeneric]
from typing import ClassVar, Generic, TypeVar
T = TypeVar('T')
class A(Generic[T]):
x = None # type: ClassVar[T]
[out]
main:4: error: Invalid type: ClassVar cannot be generic

[case testClassVarWithNestedGeneric]
from typing import ClassVar, Generic, List, TypeVar, Union
T = TypeVar('T')
U = TypeVar('U')
class A(Generic[T, U]):
x = None # type: ClassVar[Union[T, List[U]]]
[builtins fixtures/list.pyi]
[out]
main:5: error: Invalid type: ClassVar cannot be generic

Back | FazBrowse Home | New Git URL