Skip to content

Commit 3cdfa08

Browse files
authored
support conditional fields on TypedDict/NamedTuple/Enum/dataclasses (#2263)
1 parent c0cc0ab commit 3cdfa08

33 files changed

Lines changed: 377 additions & 203 deletions

conformance/results/mypy/dataclasses_usage.toml

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,19 @@ notes = """
33
Does not detect unannotated usage of `dataclasses.field()`.
44
"""
55
output = """
6-
dataclasses_usage.py:35: error: Accessing "__init__" on an instance is unsound, since instance.__init__ could be from an incompatible subclass [misc]
7-
dataclasses_usage.py:50: error: Missing positional argument "unit_price" in call to "InventoryItem" [call-arg]
8-
dataclasses_usage.py:51: error: Argument 2 to "InventoryItem" has incompatible type "str"; expected "float" [arg-type]
9-
dataclasses_usage.py:52: error: Too many arguments for "InventoryItem" [call-arg]
10-
dataclasses_usage.py:61: error: Attributes without a default cannot follow attributes with one [misc]
11-
dataclasses_usage.py:67: error: Attributes without a default cannot follow attributes with one [misc]
12-
dataclasses_usage.py:73: error: Attributes without a default cannot follow attributes with one [misc]
13-
dataclasses_usage.py:83: error: Too many arguments for "DC4" [call-arg]
14-
dataclasses_usage.py:88: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
15-
dataclasses_usage.py:127: error: Too many arguments for "DC7" [call-arg]
16-
dataclasses_usage.py:130: error: Missing positional argument "y" in call to "DC8" [call-arg]
17-
dataclasses_usage.py:179: error: Too many arguments for "DC13" [call-arg]
6+
dataclasses_usage.py:36: error: Accessing "__init__" on an instance is unsound, since instance.__init__ could be from an incompatible subclass [misc]
7+
dataclasses_usage.py:51: error: Missing positional argument "unit_price" in call to "InventoryItem" [call-arg]
8+
dataclasses_usage.py:52: error: Argument 2 to "InventoryItem" has incompatible type "str"; expected "float" [arg-type]
9+
dataclasses_usage.py:53: error: Too many arguments for "InventoryItem" [call-arg]
10+
dataclasses_usage.py:62: error: Attributes without a default cannot follow attributes with one [misc]
11+
dataclasses_usage.py:68: error: Attributes without a default cannot follow attributes with one [misc]
12+
dataclasses_usage.py:74: error: Attributes without a default cannot follow attributes with one [misc]
13+
dataclasses_usage.py:84: error: Too many arguments for "DC4" [call-arg]
14+
dataclasses_usage.py:89: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
15+
dataclasses_usage.py:128: error: Too many arguments for "DC7" [call-arg]
16+
dataclasses_usage.py:131: error: Missing positional argument "y" in call to "DC8" [call-arg]
17+
dataclasses_usage.py:180: error: Too many arguments for "DC13" [call-arg]
18+
dataclasses_usage.py:246: error: Too many arguments for "DC19" [call-arg]
1819
"""
1920
conformance_automated = "Pass"
2021
errors_diff = """

conformance/results/mypy/enums_definition.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ conformant = "Pass"
22
errors_diff = """
33
"""
44
output = """
5+
enums_definition.py:92: error: "type[Color12]" has no attribute "BLUE" [attr-defined]
56
"""
67
conformance_automated = "Pass"
Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,37 @@
11
conformant = "Partial"
22
notes = """
33
Does not reject override of named tuple attribute in child class.
4+
Does not support version-conditional fields.
45
"""
56
output = """
6-
namedtuples_define_class.py:32: error: Tuple index out of range [misc]
77
namedtuples_define_class.py:33: error: Tuple index out of range [misc]
8-
namedtuples_define_class.py:44: error: Missing positional argument "y" in call to "Point" [call-arg]
8+
namedtuples_define_class.py:34: error: Tuple index out of range [misc]
99
namedtuples_define_class.py:45: error: Missing positional argument "y" in call to "Point" [call-arg]
10-
namedtuples_define_class.py:46: error: Argument 2 to "Point" has incompatible type "str"; expected "int" [arg-type]
11-
namedtuples_define_class.py:47: error: Argument "units" to "Point" has incompatible type "int"; expected "str" [arg-type]
12-
namedtuples_define_class.py:48: error: Too many arguments for "Point" [call-arg]
13-
namedtuples_define_class.py:49: error: Unexpected keyword argument "other" for "Point" [call-arg]
14-
namedtuples_define_class.py:59: error: Invalid statement in NamedTuple definition; expected "field_name: field_type [= default]" [misc]
15-
namedtuples_define_class.py:65: error: Missing positional argument "units" in call to "Point2" [call-arg]
16-
namedtuples_define_class.py:67: error: Too many values to unpack (2 expected, 3 provided) [misc]
17-
namedtuples_define_class.py:76: error: NamedTuple field name cannot start with an underscore: _y [misc]
18-
namedtuples_define_class.py:86: error: Non-default NamedTuple fields cannot follow default fields [misc]
19-
namedtuples_define_class.py:125: error: Argument 2 to "Property" has incompatible type "float"; expected "str" [arg-type]
20-
namedtuples_define_class.py:132: error: NamedTuple should be a single base [misc]
10+
namedtuples_define_class.py:46: error: Missing positional argument "y" in call to "Point" [call-arg]
11+
namedtuples_define_class.py:47: error: Argument 2 to "Point" has incompatible type "str"; expected "int" [arg-type]
12+
namedtuples_define_class.py:48: error: Argument "units" to "Point" has incompatible type "int"; expected "str" [arg-type]
13+
namedtuples_define_class.py:49: error: Too many arguments for "Point" [call-arg]
14+
namedtuples_define_class.py:50: error: Unexpected keyword argument "other" for "Point" [call-arg]
15+
namedtuples_define_class.py:60: error: Invalid statement in NamedTuple definition; expected "field_name: field_type [= default]" [misc]
16+
namedtuples_define_class.py:66: error: Missing positional argument "units" in call to "Point2" [call-arg]
17+
namedtuples_define_class.py:68: error: Too many values to unpack (2 expected, 3 provided) [misc]
18+
namedtuples_define_class.py:77: error: NamedTuple field name cannot start with an underscore: _y [misc]
19+
namedtuples_define_class.py:87: error: Non-default NamedTuple fields cannot follow default fields [misc]
20+
namedtuples_define_class.py:114: error: Invalid statement in NamedTuple definition; expected "field_name: field_type [= default]" [misc]
21+
namedtuples_define_class.py:116: error: Invalid statement in NamedTuple definition; expected "field_name: field_type [= default]" [misc]
22+
namedtuples_define_class.py:120: error: Too many arguments for "ConditionalField" [call-arg]
23+
namedtuples_define_class.py:121: error: Too many arguments for "ConditionalField" [call-arg]
24+
namedtuples_define_class.py:140: error: Argument 2 to "Property" has incompatible type "float"; expected "str" [arg-type]
25+
namedtuples_define_class.py:147: error: NamedTuple should be a single base [misc]
2126
"""
2227
conformance_automated = "Fail"
2328
errors_diff = """
24-
Line 69: Expected 1 errors
25-
Line 106: Expected 1 errors
26-
Line 59: Unexpected errors ['namedtuples_define_class.py:59: error: Invalid statement in NamedTuple definition; expected "field_name: field_type [= default]" [misc]']
27-
Line 65: Unexpected errors ['namedtuples_define_class.py:65: error: Missing positional argument "units" in call to "Point2" [call-arg]']
28-
Line 67: Unexpected errors ['namedtuples_define_class.py:67: error: Too many values to unpack (2 expected, 3 provided) [misc]']
29+
Line 70: Expected 1 errors
30+
Line 107: Expected 1 errors
31+
Line 60: Unexpected errors ['namedtuples_define_class.py:60: error: Invalid statement in NamedTuple definition; expected "field_name: field_type [= default]" [misc]']
32+
Line 66: Unexpected errors ['namedtuples_define_class.py:66: error: Missing positional argument "units" in call to "Point2" [call-arg]']
33+
Line 68: Unexpected errors ['namedtuples_define_class.py:68: error: Too many values to unpack (2 expected, 3 provided) [misc]']
34+
Line 114: Unexpected errors ['namedtuples_define_class.py:114: error: Invalid statement in NamedTuple definition; expected "field_name: field_type [= default]" [misc]']
35+
Line 116: Unexpected errors ['namedtuples_define_class.py:116: error: Invalid statement in NamedTuple definition; expected "field_name: field_type [= default]" [misc]']
36+
Line 120: Unexpected errors ['namedtuples_define_class.py:120: error: Too many arguments for "ConditionalField" [call-arg]']
2937
"""
Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
1-
conformant = "Pass"
1+
conformant = "Partial"
2+
notes = """
3+
Does not support version-conditional items in TypedDict definitions.
4+
"""
25
output = """
3-
typeddicts_class_syntax.py:29: error: Invalid statement in TypedDict definition; expected "field_name: field_type" [misc]
4-
typeddicts_class_syntax.py:33: error: Invalid statement in TypedDict definition; expected "field_name: field_type" [misc]
5-
typeddicts_class_syntax.py:38: error: Invalid statement in TypedDict definition; expected "field_name: field_type" [misc]
6-
typeddicts_class_syntax.py:44: error: Unexpected keyword argument "metaclass" for "__init_subclass__" of "TypedDict" [call-arg]
7-
typeddicts_class_syntax.py:49: error: Unexpected keyword argument "other" for "__init_subclass__" of "TypedDict" [call-arg]
6+
typeddicts_class_syntax.py:30: error: Invalid statement in TypedDict definition; expected "field_name: field_type" [misc]
7+
typeddicts_class_syntax.py:34: error: Invalid statement in TypedDict definition; expected "field_name: field_type" [misc]
8+
typeddicts_class_syntax.py:39: error: Invalid statement in TypedDict definition; expected "field_name: field_type" [misc]
9+
typeddicts_class_syntax.py:45: error: Unexpected keyword argument "metaclass" for "__init_subclass__" of "TypedDict" [call-arg]
10+
typeddicts_class_syntax.py:50: error: Unexpected keyword argument "other" for "__init_subclass__" of "TypedDict" [call-arg]
11+
typeddicts_class_syntax.py:58: error: Invalid statement in TypedDict definition; expected "field_name: field_type" [misc]
12+
typeddicts_class_syntax.py:60: error: Invalid statement in TypedDict definition; expected "field_name: field_type" [misc]
13+
typeddicts_class_syntax.py:64: error: Extra key "y" for TypedDict "ConditionalField" [typeddict-unknown-key]
14+
typeddicts_class_syntax.py:65: error: Extra keys ("y", "z") for TypedDict "ConditionalField" [typeddict-unknown-key]
815
"""
9-
conformance_automated = "Pass"
16+
conformance_automated = "Fail"
1017
errors_diff = """
18+
Line 58: Unexpected errors ['typeddicts_class_syntax.py:58: error: Invalid statement in TypedDict definition; expected "field_name: field_type" [misc]']
19+
Line 60: Unexpected errors ['typeddicts_class_syntax.py:60: error: Invalid statement in TypedDict definition; expected "field_name: field_type" [misc]']
20+
Line 64: Unexpected errors ['typeddicts_class_syntax.py:64: error: Extra key "y" for TypedDict "ConditionalField" [typeddict-unknown-key]']
1121
"""

conformance/results/pycroscope/dataclasses_usage.toml

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ conformance_automated = "Pass"
22
errors_diff = """
33
"""
44
output = """
5-
./dataclasses_usage.py:50:5: Missing required argument 'unit_price' [incompatible_call]
6-
./dataclasses_usage.py:51:27: Incompatible argument type for unit_price: expected float | int but got Literal['price'] [incompatible_argument]
7-
./dataclasses_usage.py:52:5: Takes 3 positional arguments but 4 were given [incompatible_call]
8-
./dataclasses_usage.py:58:1: Dataclass fields without defaults cannot follow fields with defaults [invalid_dataclass]
9-
./dataclasses_usage.py:64:1: Dataclass fields without defaults cannot follow fields with defaults [invalid_dataclass]
10-
./dataclasses_usage.py:70:1: Dataclass fields without defaults cannot follow fields with defaults [invalid_dataclass]
11-
./dataclasses_usage.py:83:5: Takes 1 positional arguments but 2 were given [incompatible_call]
12-
./dataclasses_usage.py:88:4: Dataclass default_factory return type is incompatible with field type int [incompatible_assignment]
13-
./dataclasses_usage.py:127:0: Takes 1 positional arguments but 2 were given [incompatible_call]
14-
./dataclasses_usage.py:130:0: Missing required argument 'y' [incompatible_call]
15-
./dataclasses_usage.py:179:0: Takes 0 positional arguments but 1 were given [incompatible_call]
5+
./dataclasses_usage.py:51:5: Missing required argument 'unit_price' [incompatible_call]
6+
./dataclasses_usage.py:52:27: Incompatible argument type for unit_price: expected float | int but got Literal['price'] [incompatible_argument]
7+
./dataclasses_usage.py:53:5: Takes 3 positional arguments but 4 were given [incompatible_call]
8+
./dataclasses_usage.py:59:1: Dataclass fields without defaults cannot follow fields with defaults [invalid_dataclass]
9+
./dataclasses_usage.py:65:1: Dataclass fields without defaults cannot follow fields with defaults [invalid_dataclass]
10+
./dataclasses_usage.py:71:1: Dataclass fields without defaults cannot follow fields with defaults [invalid_dataclass]
11+
./dataclasses_usage.py:84:5: Takes 1 positional arguments but 2 were given [incompatible_call]
12+
./dataclasses_usage.py:89:4: Dataclass default_factory return type is incompatible with field type int [incompatible_assignment]
13+
./dataclasses_usage.py:128:0: Takes 1 positional arguments but 2 were given [incompatible_call]
14+
./dataclasses_usage.py:131:0: Missing required argument 'y' [incompatible_call]
15+
./dataclasses_usage.py:180:0: Takes 0 positional arguments but 1 were given [incompatible_call]
16+
./dataclasses_usage.py:246:0: Takes 2 positional arguments but 3 were given [incompatible_call]
1617
"""
Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
1-
conformance_automated = "Pass"
1+
conformant = "Partial"
2+
notes = """
3+
Does not allow enum members to be conditional on version/platform checks.
4+
"""
5+
conformance_automated = "Fail"
26
errors_diff = """
7+
Line 91: Unexpected errors ['./enums_definition.py:91:12: ./enums_definition.py.Color12 is not equivalent to Any[unannotated]']
38
"""
49
output = """
10+
./enums_definition.py:34:12: enum.Enum has no attribute 'RED' [undefined_attribute]
11+
./enums_definition.py:34:32: enum.Enum has no attribute 'RED' [undefined_attribute]
12+
./enums_definition.py:35:12: type[enum.Enum] has no attribute 'RED' [undefined_attribute]
13+
./enums_definition.py:35:32: type[enum.Enum] has no attribute 'RED' [undefined_attribute]
14+
./enums_definition.py:36:12: type[enum.Enum] has no attribute 'RED' [undefined_attribute]
15+
./enums_definition.py:36:32: type[enum.Enum] has no attribute 'RED' [undefined_attribute]
16+
./enums_definition.py:37:12: type[enum.Enum] has no attribute 'RED' [undefined_attribute]
17+
./enums_definition.py:37:32: type[enum.Enum] has no attribute 'RED' [undefined_attribute]
18+
./enums_definition.py:38:12: type[enum.Enum] has no attribute 'RED' [undefined_attribute]
19+
./enums_definition.py:38:32: type[enum.Enum] has no attribute 'RED' [undefined_attribute]
20+
./enums_definition.py:39:12: type[enum.Enum] has no attribute 'RED' [undefined_attribute]
21+
./enums_definition.py:39:32: type[enum.Enum] has no attribute 'RED' [undefined_attribute]
22+
./enums_definition.py:40:12: type[enum.Enum] has no attribute 'RED' [undefined_attribute]
23+
./enums_definition.py:40:32: type[enum.Enum] has no attribute 'RED' [undefined_attribute]
24+
./enums_definition.py:41:12: type[enum.Enum] has no attribute 'RED' [undefined_attribute]
25+
./enums_definition.py:41:32: type[enum.Enum] has no attribute 'RED' [undefined_attribute]
26+
./enums_definition.py:91:12: ./enums_definition.py.Color12 is not equivalent to Any[unannotated]
27+
./enums_definition.py:92:0: <class 'Color12'> has no attribute 'BLUE' [undefined_attribute]
528
"""

conformance/results/pycroscope/namedtuples_define_class.toml

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,25 @@ Does not support precise type inference for slices over namedtuples.
44
"""
55
conformance_automated = "Fail"
66
errors_diff = """
7-
Line 29: Unexpected errors ['./namedtuples_define_class.py:29:12: tuple is not equivalent to tuple[int, int]']
8-
Line 30: Unexpected errors ['./namedtuples_define_class.py:30:12: tuple is not equivalent to tuple[int, int, str]']
7+
Line 30: Unexpected errors ['./namedtuples_define_class.py:30:12: tuple is not equivalent to tuple[int, int]']
8+
Line 31: Unexpected errors ['./namedtuples_define_class.py:31:12: tuple is not equivalent to tuple[int, int, str]']
99
"""
1010
output = """
11-
./namedtuples_define_class.py:29:12: tuple is not equivalent to tuple[int, int]
12-
./namedtuples_define_class.py:30:12: tuple is not equivalent to tuple[int, int, str]
13-
./namedtuples_define_class.py:32:6: Tuple index out of range: Literal[3] [incompatible_call]
14-
./namedtuples_define_class.py:33:6: Tuple index out of range: Literal[-4] [incompatible_call]
15-
./namedtuples_define_class.py:44:5: Missing required argument 'y' [incompatible_call]
11+
./namedtuples_define_class.py:30:12: tuple is not equivalent to tuple[int, int]
12+
./namedtuples_define_class.py:31:12: tuple is not equivalent to tuple[int, int, str]
13+
./namedtuples_define_class.py:33:6: Tuple index out of range: Literal[3] [incompatible_call]
14+
./namedtuples_define_class.py:34:6: Tuple index out of range: Literal[-4] [incompatible_call]
1615
./namedtuples_define_class.py:45:5: Missing required argument 'y' [incompatible_call]
17-
./namedtuples_define_class.py:46:14: Incompatible argument type for y: expected int but got Literal[''] [incompatible_argument]
18-
./namedtuples_define_class.py:47:23: Incompatible argument type for units: expected str but got Literal[3] [incompatible_argument]
19-
./namedtuples_define_class.py:48:5: Takes 3 positional arguments but 4 were given [incompatible_call]
20-
./namedtuples_define_class.py:49:6: Got an unexpected keyword argument 'other' [incompatible_call]
21-
./namedtuples_define_class.py:69:6: Takes 2 positional arguments but 3 were given [incompatible_call]
22-
./namedtuples_define_class.py:76:4: NamedTuple field names cannot start with an underscore [invalid_namedtuple]
23-
./namedtuples_define_class.py:86:4: NamedTuple fields without defaults cannot follow fields with defaults [invalid_namedtuple]
24-
./namedtuples_define_class.py:106:4: Field 'x' conflicts with base NamedTuple field [incompatible_override]
25-
./namedtuples_define_class.py:125:18: Incompatible argument type for value: expected str but got Literal[3.1] [incompatible_argument]
26-
./namedtuples_define_class.py:132:23: NamedTuple classes may only inherit from NamedTuple and Generic [invalid_base]
16+
./namedtuples_define_class.py:46:5: Missing required argument 'y' [incompatible_call]
17+
./namedtuples_define_class.py:47:14: Incompatible argument type for y: expected int but got Literal[''] [incompatible_argument]
18+
./namedtuples_define_class.py:48:23: Incompatible argument type for units: expected str but got Literal[3] [incompatible_argument]
19+
./namedtuples_define_class.py:49:5: Takes 3 positional arguments but 4 were given [incompatible_call]
20+
./namedtuples_define_class.py:50:6: Got an unexpected keyword argument 'other' [incompatible_call]
21+
./namedtuples_define_class.py:70:6: Takes 2 positional arguments but 3 were given [incompatible_call]
22+
./namedtuples_define_class.py:77:4: NamedTuple field names cannot start with an underscore [invalid_namedtuple]
23+
./namedtuples_define_class.py:87:4: NamedTuple fields without defaults cannot follow fields with defaults [invalid_namedtuple]
24+
./namedtuples_define_class.py:107:4: Field 'x' conflicts with base NamedTuple field [incompatible_override]
25+
./namedtuples_define_class.py:121:0: Takes 2 positional arguments but 3 were given [incompatible_call]
26+
./namedtuples_define_class.py:140:18: Incompatible argument type for value: expected str but got Literal[3.1] [incompatible_argument]
27+
./namedtuples_define_class.py:147:23: NamedTuple classes may only inherit from NamedTuple and Generic [invalid_base]
2728
"""

conformance/results/pycroscope/typeddicts_class_syntax.toml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ conformance_automated = "Pass"
22
errors_diff = """
33
"""
44
output = """
5-
./typeddicts_class_syntax.py:29:4: Methods are not allowed in TypedDict definitions [invalid_typeddict]
6-
./typeddicts_class_syntax.py:34:4: Methods are not allowed in TypedDict definitions [invalid_typeddict]
7-
./typeddicts_class_syntax.py:39:4: Methods are not allowed in TypedDict definitions [invalid_typeddict]
8-
./typeddicts_class_syntax.py:44:31: TypedDict definitions cannot specify a metaclass [invalid_typeddict]
9-
./typeddicts_class_syntax.py:49:31: Unexpected keyword argument 'other' in TypedDict definition [invalid_typeddict]
5+
./typeddicts_class_syntax.py:30:4: Methods are not allowed in TypedDict definitions [invalid_typeddict]
6+
./typeddicts_class_syntax.py:35:4: Methods are not allowed in TypedDict definitions [invalid_typeddict]
7+
./typeddicts_class_syntax.py:40:4: Methods are not allowed in TypedDict definitions [invalid_typeddict]
8+
./typeddicts_class_syntax.py:45:31: TypedDict definitions cannot specify a metaclass [invalid_typeddict]
9+
./typeddicts_class_syntax.py:50:31: Unexpected keyword argument 'other' in TypedDict definition [invalid_typeddict]
10+
./typeddicts_class_syntax.py:65:0: Got an unexpected keyword argument 'z' [incompatible_call]
1011
"""

0 commit comments

Comments
 (0)