Skip to content

Commit b297a5f

Browse files
committed
Clarify ClassVar protocol conformance expectations
1 parent 6f7fa73 commit b297a5f

9 files changed

Lines changed: 62 additions & 6 deletions

conformance/results/mypy/protocols_definition.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ protocols_definition.py:340: error: Incompatible types in assignment (expression
5151
protocols_definition.py:340: note: Protocol member Template6.val1 expected settable variable, got read-only attribute
5252
protocols_definition.py:341: error: Incompatible types in assignment (expression has type "Concrete6_Bad3", variable has type "Template6") [assignment]
5353
protocols_definition.py:341: note: Protocol member Template6.val1 expected settable variable, got read-only attribute
54+
protocols_definition.py:369: error: Incompatible types in assignment (expression has type "Concrete7_Bad1", variable has type "Template7") [assignment]
55+
protocols_definition.py:369: note: Protocol member Template7.val1 expected class variable, got instance variable
56+
protocols_definition.py:370: error: Incompatible types in assignment (expression has type "Concrete7_Bad2", variable has type "Template7") [assignment]
5457
"""
5558
conformance_automated = "Fail"
5659
errors_diff = """

conformance/results/pycroscope/protocols_definition.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
conformance_automated = "Pass"
1+
conformance_automated = "Fail"
2+
conformant = "Partial"
3+
notes = """
4+
Incorrectly accepts an instance-only attribute as satisfying a `ClassVar` protocol member.
5+
"""
26
errors_diff = """
7+
Line 369: Expected 1 errors
38
"""
49
output = """
510
./protocols_definition.py:30:10: Incompatible argument type for things: expected collections.abc.Iterable[./protocols_definition.py.SupportsClose] but got Literal[[1]] [incompatible_argument]
@@ -23,4 +28,5 @@ output = """
2328
./protocols_definition.py:339:0: Incompatible assignment: expected ./protocols_definition.py.Template6, got ./protocols_definition.py.Concrete6_Bad1 [incompatible_assignment]
2429
./protocols_definition.py:340:0: Incompatible assignment: expected ./protocols_definition.py.Template6, got ./protocols_definition.py.Concrete6_Bad2 [incompatible_assignment]
2530
./protocols_definition.py:341:0: Incompatible assignment: expected ./protocols_definition.py.Template6, got ./protocols_definition.py.Concrete6_Bad3 [incompatible_assignment]
31+
./protocols_definition.py:370:0: Incompatible assignment: expected ./protocols_definition.py.Template7, got ./protocols_definition.py.Concrete7_Bad2 [incompatible_assignment]
2632
"""

conformance/results/pyrefly/protocols_definition.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ ERROR protocols_definition.py:289:22-38: `Concrete5_Bad5` is not assignable to `
2424
ERROR protocols_definition.py:339:22-38: `Concrete6_Bad1` is not assignable to `Template6` [bad-assignment]
2525
ERROR protocols_definition.py:340:22-38: `Concrete6_Bad2` is not assignable to `Template6` [bad-assignment]
2626
ERROR protocols_definition.py:341:22-38: `Concrete6_Bad3` is not assignable to `Template6` [bad-assignment]
27+
ERROR protocols_definition.py:369:22-38: `Concrete7_Bad1` is not assignable to `Template7` [bad-assignment]
28+
ERROR protocols_definition.py:370:22-38: `Concrete7_Bad2` is not assignable to `Template7` [bad-assignment]
2729
"""

conformance/results/pyright/protocols_definition.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ protocols_definition.py:341:22 - error: Type "Concrete6_Bad3" is not assignable
9797
  "Concrete6_Bad3" is incompatible with protocol "Template6"
9898
    "val1" is writable in protocol
9999
    "val1" is not read-only in protocol (reportAssignmentType)
100+
protocols_definition.py:369:22 - error: Type "Concrete7_Bad1" is not assignable to declared type "Template7"
101+
  "Concrete7_Bad1" is incompatible with protocol "Template7"
102+
    "val1" is defined as a ClassVar in protocol (reportAssignmentType)
103+
protocols_definition.py:370:22 - error: Type "Concrete7_Bad2" is not assignable to declared type "Template7"
104+
  "Concrete7_Bad2" is incompatible with protocol "Template7"
105+
    "val1" is defined as a ClassVar in protocol (reportAssignmentType)
100106
"""
101107
conformance_automated = "Pass"
102108
errors_diff = """

conformance/results/results.html

Lines changed: 8 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

conformance/results/ty/protocols_definition.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,6 @@ protocols_definition.py:289:22: error[invalid-assignment] Object of type `Concre
2323
protocols_definition.py:339:22: error[invalid-assignment] Object of type `Concrete6_Bad1` is not assignable to `Template6`
2424
protocols_definition.py:340:22: error[invalid-assignment] Object of type `Concrete6_Bad2` is not assignable to `Template6`
2525
protocols_definition.py:341:22: error[invalid-assignment] Object of type `Concrete6_Bad3` is not assignable to `Template6`
26+
protocols_definition.py:369:22: error[invalid-assignment] Object of type `Concrete7_Bad1` is not assignable to `Template7`
27+
protocols_definition.py:370:22: error[invalid-assignment] Object of type `Concrete7_Bad2` is not assignable to `Template7`
2628
"""

conformance/results/zuban/protocols_definition.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,7 @@ protocols_definition.py:340: error: Incompatible types in assignment (expression
6767
protocols_definition.py:340: note: Protocol member Template6.val1 expected settable variable, got read-only attribute
6868
protocols_definition.py:341: error: Incompatible types in assignment (expression has type "Concrete6_Bad3", variable has type "Template6") [assignment]
6969
protocols_definition.py:341: note: Protocol member Template6.val1 expected settable variable, got read-only attribute
70+
protocols_definition.py:369: error: Incompatible types in assignment (expression has type "Concrete7_Bad1", variable has type "Template7") [assignment]
71+
protocols_definition.py:369: note: Protocol member Template7.val1 expected class variable, got instance variable
72+
protocols_definition.py:370: error: Incompatible types in assignment (expression has type "Concrete7_Bad2", variable has type "Template7") [assignment]
7073
"""

conformance/tests/protocols_class_objects.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,5 +105,5 @@ class ConcreteC3(metaclass=CMeta):
105105
pc2: ProtoC2 = ConcreteC1 # OK
106106
pc3: ProtoC1 = ConcreteC2 # E
107107
pc4: ProtoC2 = ConcreteC2 # E
108-
pc5: ProtoC1 = ConcreteC3 # E
108+
pc5: ProtoC1 = ConcreteC3 # E?: Explicit ClassVar matching is unspecified
109109
pc6: ProtoC2 = ConcreteC3 # OK

conformance/tests/protocols_definition.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class Concrete2_Bad4:
114114
v2_bad1: Template2 = Concrete2_Bad1() # E
115115
v2_bad2: Template2 = Concrete2_Bad2() # E
116116
v2_bad3: Template2 = Concrete2_Bad3() # E
117-
v2_bad4: Template2 = Concrete2_Bad4() # E
117+
v2_bad4: Template2 = Concrete2_Bad4() # E?: Explicit ClassVar matching is unspecified
118118

119119

120120
class Template3(Protocol):
@@ -339,3 +339,32 @@ class Concrete6_Bad3:
339339
v6_bad1: Template6 = Concrete6_Bad1() # E
340340
v6_bad2: Template6 = Concrete6_Bad2() # E: named tuple is immutable
341341
v6_bad3: Template6 = Concrete6_Bad3() # E: dataclass is frozen
342+
343+
344+
# The specification leaves two possible interpretations of a ClassVar protocol
345+
# member. One interpretation requires the implementing attribute to be explicitly
346+
# declared with ClassVar. The other interpretation imposes only structural
347+
# requirements: the attribute must be readable and writable on the class object
348+
# and readable on instances of the class. Both interpretations therefore require
349+
# the following assignments to be rejected.
350+
351+
352+
class Template7(Protocol):
353+
val1: ClassVar[int]
354+
355+
356+
class Concrete7_Bad1:
357+
def __init__(self) -> None:
358+
self.val1: int = 42
359+
360+
361+
class Concrete7Meta(type):
362+
val1: int = 42
363+
364+
365+
class Concrete7_Bad2(metaclass=Concrete7Meta):
366+
pass
367+
368+
369+
v7_bad1: Template7 = Concrete7_Bad1() # E: val1 is not readable on the class object
370+
v7_bad2: Template7 = Concrete7_Bad2() # E: val1 is not readable on instances

0 commit comments

Comments
 (0)