← Back to index

dataclasses_usage.py

True Positive
False Positive
False Negative
Optional (detected)
Warning or Info
TP: 11
FP: 0
FN: 0
Optional: 0 / 1
1"""
2Tests basic handling of the dataclass factory.
3"""
4
5# Specification: https://typing.readthedocs.io/en/latest/spec/dataclasses.html
6# Also, see https://peps.python.org/pep-0557/
7
8from dataclasses import InitVar, dataclass, field
9from typing import Any, Callable, ClassVar, Generic, Protocol, TypeVar, assert_type
11T = TypeVar("T")
14@dataclass(order=True)
15class InventoryItem:
16 x = 0
17 name: str
18 unit_price: float
19 quantity_on_hand: int = 0
21 def total_cost(self) -> float:
22 return self.unit_price * self.quantity_on_hand
25v1 = InventoryItem("soap", 2.3)
28class InventoryItemInitProto(Protocol):
29 def __call__(
30 self, name: str, unit_price: float, quantity_on_hand: int = ...
31 ) -> None: ...
34# Validate the type of the synthesized __init__ method.
35x1: InventoryItemInitProto = v1.__init__
37# Make sure the following additional methods were synthesized.
38print(v1.__repr__)
39print(v1.__eq__)
40print(v1.__ne__)
41print(v1.__lt__)
42print(v1.__le__)
43print(v1.__gt__)
44print(v1.__ge__)
46assert_type(v1.name, str)
47assert_type(v1.unit_price, float)
48assert_type(v1.quantity_on_hand, int)
50v2 = InventoryItem("name") # E: missing unit_price
[missing-argument] No argument provided for required parameter `unit_price`
51v3 = InventoryItem("name", "price") # E: incorrect type for unit_price
[invalid-argument-type] Argument is incorrect: Expected `int | float`, found `Literal["price"]`
52v4 = InventoryItem("name", 3.1, 3, 4) # E: too many arguments
[too-many-positional-arguments] Too many positional arguments: expected 3, got 4
55# > TypeError will be raised if a field without a default value follows a
56# > field with a default value. This is true either when this occurs in a
57# > single class, or as a result of class inheritance.
58@dataclass # E[DC1]
59class DC1:
60 a: int = 0 # E[DC1]: field with default should follow a field with no default.
61 b: int # E[DC1]: field with no default cannot follow field with default.
Tag 'DC1' [dataclass-field-order] Required field `b` cannot be defined after fields with default values
64@dataclass # E[DC2]
65class DC2:
66 a: int = field(default=1) # E[DC2]: field with default should follow a field with no default.
67 b: int # E[DC2]: field with no default cannot follow field with default.
Tag 'DC2' [dataclass-field-order] Required field `b` cannot be defined after fields with default values
70@dataclass # E[DC3]
71class DC3:
72 a: InitVar[int] = 0 # E[DC3]: field with default should follow a field with no default.
73 b: int # E[DC3]: field with no default cannot follow field with default.
Tag 'DC3' [dataclass-field-order] Required field `b` cannot be defined after fields with default values
76@dataclass
77class DC4:
78 a: int = field(init=False)
79 b: int
82v5 = DC4(0)
83v6 = DC4(0, 1) # E: too many parameters
[too-many-positional-arguments] Too many positional arguments: expected 1, got 2
86@dataclass
87class DC5:
88 a: int = field(default_factory=str) # E: type mismatch
[invalid-assignment] Object of type `dataclasses.Field[str]` is not assignable to `int`
91def f(s: str) -> int:
92 return int(s)
95@dataclass
96class DC6:
97 a: ClassVar[int] = 0
98 b: str
99 c: Callable[[str], int] = f
102dc6 = DC6("")
103assert_type(dc6.a, int)
104assert_type(DC6.a, int)
105assert_type(dc6.b, str)
106assert_type(dc6.c, Callable[[str], int])
109@dataclass
110class DC7:
111 x: int
114@dataclass(init=False)
115class DC8(DC7):
116 y: int
118 def __init__(self, a: DC7, y: int):
119 self.__dict__ = a.__dict__
120 self.y = y
123a = DC7(3)
124b = DC8(a, 5)
126# This should generate an error because there is an extra parameter
127DC7(3, 4) # E
[too-many-positional-arguments] Too many positional arguments: expected 1, got 2
129# This should generate an error because there is one too few parameters
130DC8(a) # E
[missing-argument] No argument provided for required parameter `y` of bound method `__init__`
133@dataclass
134class DC9:
135 a: str = field(init=False, default="s")
136 b: bool = field()
139@dataclass
140class DC10(DC9):
141 a: str = field()
142 b: bool = field()
145@dataclass(init=False)
146class DC11:
147 x: int
148 x_squared: int
150 def __init__(self, x: int):
151 self.x = x
152 self.x_squared = x * x
155DC11(3)
158@dataclass(init=True)
159class DC12:
160 x: int
161 x_squared: int
163 def __init__(self, x: int):
164 self.x = x
165 self.x_squared = x * x
168DC12(3)
171@dataclass(init=False)
172class DC13:
173 x: int
174 x_squared: int
177# This should generate an error because there is no matching
178# override __init__ method and no synthesized __init__.
179DC13(3) # E
[too-many-positional-arguments] Too many positional arguments to bound method `__init__`: expected 1, got 2
182@dataclass
183class DC14:
184 prop_1: str = field(init=False)
185 prop_2: str = field(default="hello")
186 prop_3: str = field(default_factory=lambda: "hello")
189@dataclass
190class DC15(DC14):
191 prop_2: str = ""
194dc15 = DC15(prop_2="test")
196assert_type(dc15.prop_1, str)
197assert_type(dc15.prop_2, str)
198assert_type(dc15.prop_3, str)
201class DataclassProto(Protocol):
202 __dataclass_fields__: ClassVar[dict[str, Any]]
205v7: DataclassProto = dc15
208@dataclass
209class DC16(Generic[T]):
210 value: T
213assert_type(DC16(1), DC16[int])
216class DC17(DC16[str]):
217 pass
220assert_type(DC17(""), DC17)
223@dataclass
224class DC18:
225 x: int = field()
226 # This may generate a type checker error because an unannotated field
227 # will result in a runtime exception.
228 y = field() # E?