| [case testDataclassTransformReusesDataclassLogic] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Type | |
| @dataclass_transform() | |
| def my_dataclass(cls: Type) -> Type: | |
| return cls | |
| @my_dataclass | |
| class Person: | |
| name: str | |
| age: int | |
| def summary(self): | |
| return "%s is %d years old." % (self.name, self.age) | |
| reveal_type(Person) # N: Revealed type is "def (name: builtins.str, age: builtins.int) -> __main__.Person" | |
| Person('John', 32) | |
| Person('Jonh', 21, None) # E: Too many arguments for "Person" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformIsFoundInTypingExtensions] | |
| from typing import Type | |
| from typing_extensions import dataclass_transform | |
| @dataclass_transform() | |
| def my_dataclass(cls: Type) -> Type: | |
| return cls | |
| @my_dataclass | |
| class Person: | |
| name: str | |
| age: int | |
| def summary(self): | |
| return "%s is %d years old." % (self.name, self.age) | |
| reveal_type(Person) # N: Revealed type is "def (name: builtins.str, age: builtins.int) -> __main__.Person" | |
| Person('John', 32) | |
| Person('Jonh', 21, None) # E: Too many arguments for "Person" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformParametersAreApplied] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Callable, Type | |
| @dataclass_transform() | |
| def my_dataclass(*, eq: bool, order: bool) -> Callable[[Type], Type]: | |
| def transform(cls: Type) -> Type: | |
| return cls | |
| return transform | |
| @my_dataclass(eq=False, order=True) # E: "eq" must be True if "order" is True | |
| class Person: | |
| name: str | |
| age: int | |
| reveal_type(Person) # N: Revealed type is "def (name: builtins.str, age: builtins.int) -> __main__.Person" | |
| Person('John', 32) | |
| Person('John', 21, None) # E: Too many arguments for "Person" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformParametersMustBeBoolLiterals] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Callable, Type | |
| @dataclass_transform() | |
| def my_dataclass(*, eq: bool = True, order: bool = False) -> Callable[[Type], Type]: | |
| def transform(cls: Type) -> Type: | |
| return cls | |
| return transform | |
| @dataclass_transform() | |
| class BaseClass: | |
| def __init_subclass__(cls, *, eq: bool): ... | |
| @dataclass_transform() | |
| class Metaclass(type): ... | |
| BOOL_CONSTANT = True | |
| @my_dataclass(eq=BOOL_CONSTANT) # E: "eq" argument must be a True or False literal | |
| class A: ... | |
| @my_dataclass(order=not False) # E: "order" argument must be a True or False literal | |
| class B: ... | |
| class C(BaseClass, eq=BOOL_CONSTANT): ... # E: "eq" argument must be a True or False literal | |
| class D(metaclass=Metaclass, order=not False): ... # E: "order" argument must be a True or False literal | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformDefaultParamsMustBeLiterals] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Type, Final | |
| BOOLEAN_CONSTANT = True | |
| FINAL_BOOLEAN: Final = True | |
| @dataclass_transform(eq_default=BOOLEAN_CONSTANT) # E: "eq_default" argument must be a True or False literal | |
| def foo(cls: Type) -> Type: | |
| return cls | |
| @dataclass_transform(eq_default=(not True)) # E: "eq_default" argument must be a True or False literal | |
| def bar(cls: Type) -> Type: | |
| return cls | |
| @dataclass_transform(eq_default=FINAL_BOOLEAN) # E: "eq_default" argument must be a True or False literal | |
| def baz(cls: Type) -> Type: | |
| return cls | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformUnrecognizedParamsAreErrors] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Type | |
| BOOLEAN_CONSTANT = True | |
| @dataclass_transform(nonexistent=True) # E: Unrecognized dataclass_transform parameter "nonexistent" | |
| def foo(cls: Type) -> Type: | |
| return cls | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformDefaultParams] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Type, Callable | |
| @dataclass_transform(eq_default=False) | |
| def no_eq(*, order: bool = False) -> Callable[[Type], Type]: | |
| return lambda cls: cls | |
| @no_eq() | |
| class Foo: ... | |
| @no_eq(order=True) # E: "eq" must be True if "order" is True | |
| class Bar: ... | |
| @dataclass_transform(kw_only_default=True) | |
| def always_use_kw(cls: Type) -> Type: | |
| return cls | |
| @always_use_kw | |
| class Baz: | |
| x: int | |
| Baz(x=5) | |
| Baz(5) # E: Too many positional arguments for "Baz" | |
| @dataclass_transform(order_default=True) | |
| def ordered(*, eq: bool = True) -> Callable[[Type], Type]: | |
| return lambda cls: cls | |
| @ordered() | |
| class A: | |
| x: int | |
| A(1) > A(2) | |
| @dataclass_transform(frozen_default=True) | |
| def frozen(cls: Type) -> Type: | |
| return cls | |
| @frozen | |
| class B: | |
| x: int | |
| b = B(x=1) | |
| b.x = 2 # E: Property "x" defined in "B" is read-only | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformDefaultsCanBeOverridden] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Callable, Type | |
| @dataclass_transform(kw_only_default=True) | |
| def my_dataclass(*, kw_only: bool = True) -> Callable[[Type], Type]: | |
| return lambda cls: cls | |
| @my_dataclass() | |
| class KwOnly: | |
| x: int | |
| @my_dataclass(kw_only=False) | |
| class KwOptional: | |
| x: int | |
| KwOnly(5) # E: Too many positional arguments for "KwOnly" | |
| KwOptional(5) | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformFieldSpecifiersDefaultsToEmpty] | |
| # flags: --python-version 3.11 | |
| from dataclasses import field, dataclass | |
| from typing import dataclass_transform, Type | |
| @dataclass_transform() | |
| def my_dataclass(cls: Type) -> Type: | |
| return cls | |
| @my_dataclass | |
| class Foo: | |
| foo: int = field(kw_only=True) | |
| # Does not cause a type error because `dataclasses.field` is not a recognized field specifier by | |
| # default | |
| Foo(5) | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformFieldSpecifierRejectMalformed] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Any, Callable, Final, Type | |
| def some_type() -> Type: ... | |
| def some_function() -> Callable[[], None]: ... | |
| def field(*args, **kwargs): ... | |
| def fields_tuple() -> tuple[type | Callable[..., Any], ...]: return (field,) | |
| CONSTANT: Final = (field,) | |
| @dataclass_transform(field_specifiers=(some_type(),)) # E: "field_specifiers" must only contain identifiers | |
| def bad_dataclass1() -> None: ... | |
| @dataclass_transform(field_specifiers=(some_function(),)) # E: "field_specifiers" must only contain identifiers | |
| def bad_dataclass2() -> None: ... | |
| @dataclass_transform(field_specifiers=CONSTANT) # E: "field_specifiers" argument must be a tuple literal | |
| def bad_dataclass3() -> None: ... | |
| @dataclass_transform(field_specifiers=fields_tuple()) # E: "field_specifiers" argument must be a tuple literal | |
| def bad_dataclass4() -> None: ... | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformFieldSpecifierParams] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Any, Callable, Type, Final | |
| def field( | |
| *, | |
| init: bool = True, | |
| kw_only: bool = False, | |
| alias: str | None = None, | |
| default: Any | None = None, | |
| default_factory: Callable[[], Any] | None = None, | |
| factory: Callable[[], Any] | None = None, | |
| ): ... | |
| @dataclass_transform(field_specifiers=(field,)) | |
| def my_dataclass(cls: Type) -> Type: | |
| return cls | |
| B: Final = 'b_' | |
| @my_dataclass | |
| class Foo: | |
| a: int = field(alias='a_') | |
| b: int = field(alias=B) | |
| # cannot be passed as a positional | |
| kwonly: int = field(kw_only=True, default=0) | |
| # Safe to omit from constructor, error to pass | |
| noinit: int = field(init=False, default=1) | |
| # It should be safe to call the constructor without passing any of these | |
| unused1: int = field(default=0) | |
| unused2: int = field(factory=lambda: 0) | |
| unused3: int = field(default_factory=lambda: 0) | |
| Foo(a=5, b_=1) # E: Unexpected keyword argument "a" for "Foo" | |
| Foo(a_=1, b_=1, noinit=1) # E: Unexpected keyword argument "noinit" for "Foo" | |
| Foo(1, 2, 3) # (a, b, unused1) | |
| foo = Foo(1, 2, kwonly=3) | |
| reveal_type(foo.noinit) # N: Revealed type is "builtins.int" | |
| reveal_type(foo.unused1) # N: Revealed type is "builtins.int" | |
| Foo(a_=5, b_=1, unused1=2, unused2=3, unused3=4) | |
| def some_str() -> str: ... | |
| def some_bool() -> bool: ... | |
| @my_dataclass | |
| class Bad: | |
| bad1: int = field(alias=some_str()) # E: "alias" argument to dataclass field must be a string literal | |
| bad2: int = field(kw_only=some_bool()) # E: "kw_only" argument must be a boolean literal | |
| reveal_type(Foo.__dataclass_fields__) # N: Revealed type is "builtins.dict[builtins.str, Any]" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformFieldSpecifierExtraArgs] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform | |
| def field(extra1, *, kw_only=False, extra2=0): ... | |
| @dataclass_transform(field_specifiers=(field,)) | |
| def my_dataclass(cls): | |
| return cls | |
| @my_dataclass | |
| class Good: | |
| a: int = field(5) | |
| b: int = field(5, extra2=1) | |
| c: int = field(5, kw_only=True) | |
| @my_dataclass | |
| class Bad: | |
| a: int = field(kw_only=True) # E: Missing positional argument "extra1" in call to "field" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformMultipleFieldSpecifiers] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform | |
| def field1(*, default: int) -> int: ... | |
| def field2(*, default: str) -> str: ... | |
| @dataclass_transform(field_specifiers=(field1, field2)) | |
| def my_dataclass(cls): return cls | |
| @my_dataclass | |
| class Foo: | |
| a: int = field1(default=0) | |
| b: str = field2(default='hello') | |
| reveal_type(Foo) # N: Revealed type is "def (a: builtins.int =, b: builtins.str =) -> __main__.Foo" | |
| Foo() | |
| Foo(a=1, b='bye') | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformFieldSpecifierImplicitInit] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Literal, overload | |
| def init(*, init: Literal[True] = True): ... | |
| def no_init(*, init: Literal[False] = False): ... | |
| @overload | |
| def field_overload(*, custom: None, init: Literal[True] = True): ... | |
| @overload | |
| def field_overload(*, custom: str, init: Literal[False] = False): ... | |
| def field_overload(*, custom, init): ... | |
| @dataclass_transform(field_specifiers=(init, no_init, field_overload)) | |
| def my_dataclass(cls): return cls | |
| @my_dataclass | |
| class Foo: | |
| a: int = init() | |
| b: int = field_overload(custom=None) | |
| bad1: int = no_init() | |
| bad2: int = field_overload(custom="bad2") | |
| reveal_type(Foo) # N: Revealed type is "def (a: builtins.int, b: builtins.int) -> __main__.Foo" | |
| Foo(a=1, b=2) | |
| Foo(a=1, b=2, bad1=0) # E: Unexpected keyword argument "bad1" for "Foo" | |
| Foo(a=1, b=2, bad2=0) # E: Unexpected keyword argument "bad2" for "Foo" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformOverloadsDecoratorOnOverload] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, overload, Any, Callable, Type, Literal | |
| @overload | |
| def my_dataclass(*, foo: str) -> Callable[[Type], Type]: ... | |
| @overload | |
| @dataclass_transform(frozen_default=True) | |
| def my_dataclass(*, foo: int) -> Callable[[Type], Type]: ... | |
| def my_dataclass(*, foo: Any) -> Callable[[Type], Type]: | |
| return lambda cls: cls | |
| @my_dataclass(foo="hello") | |
| class A: | |
| a: int | |
| @my_dataclass(foo=5) | |
| class B: | |
| b: int | |
| reveal_type(A) # N: Revealed type is "def (a: builtins.int) -> __main__.A" | |
| reveal_type(B) # N: Revealed type is "def (b: builtins.int) -> __main__.B" | |
| A(1, "hello") # E: Too many arguments for "A" | |
| a = A(1) | |
| a.a = 2 # E: Property "a" defined in "A" is read-only | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformOverloadsDecoratorOnImpl] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, overload, Any, Callable, Type, Literal | |
| @overload | |
| def my_dataclass(*, foo: str) -> Callable[[Type], Type]: ... | |
| @overload | |
| def my_dataclass(*, foo: int) -> Callable[[Type], Type]: ... | |
| @dataclass_transform(frozen_default=True) | |
| def my_dataclass(*, foo: Any) -> Callable[[Type], Type]: | |
| return lambda cls: cls | |
| @my_dataclass(foo="hello") | |
| class A: | |
| a: int | |
| @my_dataclass(foo=5) | |
| class B: | |
| b: int | |
| reveal_type(A) # N: Revealed type is "def (a: builtins.int) -> __main__.A" | |
| reveal_type(B) # N: Revealed type is "def (b: builtins.int) -> __main__.B" | |
| A(1, "hello") # E: Too many arguments for "A" | |
| a = A(1) | |
| a.a = 2 # E: Property "a" defined in "A" is read-only | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformViaBaseClass] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform | |
| @dataclass_transform(frozen_default=True) | |
| class Dataclass: | |
| def __init_subclass__(cls, *, kw_only: bool = False): ... | |
| class Person(Dataclass, kw_only=True): | |
| name: str | |
| age: int | |
| reveal_type(Person) # N: Revealed type is "def (*, name: builtins.str, age: builtins.int) -> __main__.Person" | |
| Person('Jonh', 21) # E: Too many positional arguments for "Person" | |
| person = Person(name='John', age=32) | |
| person.name = "John Smith" # E: Property "name" defined in "Person" is read-only | |
| class Contact(Person): | |
| email: str | |
| reveal_type(Contact) # N: Revealed type is "def (email: builtins.str, *, name: builtins.str, age: builtins.int) -> __main__.Contact" | |
| Contact('john@john.com', name='John', age=32) | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformViaMetaclass] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform | |
| @dataclass_transform(frozen_default=True) | |
| class Dataclass(type): ... | |
| # Note that PEP 681 states that a class that directly specifies a dataclass_transform-decorated | |
| # metaclass should be treated as neither frozen nor unfrozen. For Person to have frozen semantics, | |
| # it may not directly specify the metaclass. | |
| class BaseDataclass(metaclass=Dataclass): ... | |
| class Person(BaseDataclass, kw_only=True): | |
| name: str | |
| age: int | |
| reveal_type(Person) # N: Revealed type is "def (*, name: builtins.str, age: builtins.int) -> __main__.Person" | |
| Person('Jonh', 21) # E: Too many positional arguments for "Person" | |
| person = Person(name='John', age=32) | |
| person.name = "John Smith" # E: Property "name" defined in "Person" is read-only | |
| class Contact(Person): | |
| email: str | |
| reveal_type(Contact) # N: Revealed type is "def (email: builtins.str, *, name: builtins.str, age: builtins.int) -> __main__.Contact" | |
| Contact('john@john.com', name='John', age=32) | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformViaSubclassOfMetaclass] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform | |
| @dataclass_transform(frozen_default=True) | |
| class BaseMeta(type): ... | |
| class SubMeta(BaseMeta): ... | |
| # MyPy does *not* recognize this as a dataclass because the metaclass is not directly decorated with | |
| # dataclass_transform | |
| class Foo(metaclass=SubMeta): | |
| foo: int | |
| reveal_type(Foo) # N: Revealed type is "def () -> __main__.Foo" | |
| Foo(1) # E: Too many arguments for "Foo" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformTypeCheckingInFunction] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Type, TYPE_CHECKING | |
| @dataclass_transform() | |
| def model(cls: Type) -> Type: | |
| return cls | |
| @model | |
| class FunctionModel: | |
| if TYPE_CHECKING: | |
| string_: str | |
| integer_: int | |
| else: | |
| string_: tuple | |
| integer_: tuple | |
| FunctionModel(string_="abc", integer_=1) | |
| FunctionModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "FunctionModel" has incompatible type "tuple[Never, ...]"; expected "int" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformNegatedTypeCheckingInFunction] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Type, TYPE_CHECKING | |
| @dataclass_transform() | |
| def model(cls: Type) -> Type: | |
| return cls | |
| @model | |
| class FunctionModel: | |
| if not TYPE_CHECKING: | |
| string_: tuple | |
| integer_: tuple | |
| else: | |
| string_: str | |
| integer_: int | |
| FunctionModel(string_="abc", integer_=1) | |
| FunctionModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "FunctionModel" has incompatible type "tuple[Never, ...]"; expected "int" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformTypeCheckingInBaseClass] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, TYPE_CHECKING | |
| @dataclass_transform() | |
| class ModelBase: | |
| ... | |
| class BaseClassModel(ModelBase): | |
| if TYPE_CHECKING: | |
| string_: str | |
| integer_: int | |
| else: | |
| string_: tuple | |
| integer_: tuple | |
| BaseClassModel(string_="abc", integer_=1) | |
| BaseClassModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "BaseClassModel" has incompatible type "tuple[Never, ...]"; expected "int" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformNegatedTypeCheckingInBaseClass] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, TYPE_CHECKING | |
| @dataclass_transform() | |
| class ModelBase: | |
| ... | |
| class BaseClassModel(ModelBase): | |
| if not TYPE_CHECKING: | |
| string_: tuple | |
| integer_: tuple | |
| else: | |
| string_: str | |
| integer_: int | |
| BaseClassModel(string_="abc", integer_=1) | |
| BaseClassModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "BaseClassModel" has incompatible type "tuple[Never, ...]"; expected "int" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformTypeCheckingInMetaClass] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Type, TYPE_CHECKING | |
| @dataclass_transform() | |
| class ModelMeta(type): | |
| ... | |
| class ModelBaseWithMeta(metaclass=ModelMeta): | |
| ... | |
| class MetaClassModel(ModelBaseWithMeta): | |
| if TYPE_CHECKING: | |
| string_: str | |
| integer_: int | |
| else: | |
| string_: tuple | |
| integer_: tuple | |
| MetaClassModel(string_="abc", integer_=1) | |
| MetaClassModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "MetaClassModel" has incompatible type "tuple[Never, ...]"; expected "int" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformNegatedTypeCheckingInMetaClass] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Type, TYPE_CHECKING | |
| @dataclass_transform() | |
| class ModelMeta(type): | |
| ... | |
| class ModelBaseWithMeta(metaclass=ModelMeta): | |
| ... | |
| class MetaClassModel(ModelBaseWithMeta): | |
| if not TYPE_CHECKING: | |
| string_: tuple | |
| integer_: tuple | |
| else: | |
| string_: str | |
| integer_: int | |
| MetaClassModel(string_="abc", integer_=1) | |
| MetaClassModel(string_="abc", integer_=tuple()) # E: Argument "integer_" to "MetaClassModel" has incompatible type "tuple[Never, ...]"; expected "int" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformStaticConditionalAttributes] | |
| # flags: --python-version 3.11 --always-true TRUTH | |
| from typing import dataclass_transform, Type, TYPE_CHECKING | |
| TRUTH = False # Is set to --always-true | |
| @dataclass_transform() | |
| def model(cls: Type) -> Type: | |
| return cls | |
| @model | |
| class FunctionModel: | |
| if TYPE_CHECKING: | |
| present_1: int | |
| else: | |
| skipped_1: int | |
| if True: # Mypy does not know if it is True or False, so the block is used | |
| present_2: int | |
| if False: # Mypy does not know if it is True or False, so the block is used | |
| present_3: int | |
| if not TRUTH: | |
| skipped_2: int | |
| else: | |
| present_4: int | |
| FunctionModel( | |
| present_1=1, | |
| present_2=2, | |
| present_3=3, | |
| present_4=4, | |
| ) | |
| FunctionModel() # E: Missing positional arguments "present_1", "present_2", "present_3", "present_4" in call to "FunctionModel" | |
| FunctionModel( # E: Unexpected keyword argument "skipped_1" for "FunctionModel" | |
| present_1=1, | |
| present_2=2, | |
| present_3=3, | |
| present_4=4, | |
| skipped_1=5, | |
| ) | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformStaticDeterministicConditionalElifAttributes] | |
| # flags: --python-version 3.11 --always-true TRUTH --always-false LIE | |
| from typing import dataclass_transform, Type, TYPE_CHECKING | |
| TRUTH = False # Is set to --always-true | |
| LIE = True # Is set to --always-false | |
| @dataclass_transform() | |
| def model(cls: Type) -> Type: | |
| return cls | |
| @model | |
| class FunctionModel: | |
| if TYPE_CHECKING: | |
| present_1: int | |
| elif TRUTH: | |
| skipped_1: int | |
| else: | |
| skipped_2: int | |
| if LIE: | |
| skipped_3: int | |
| elif TRUTH: | |
| present_2: int | |
| else: | |
| skipped_4: int | |
| if LIE: | |
| skipped_5: int | |
| elif LIE: | |
| skipped_6: int | |
| else: | |
| present_3: int | |
| FunctionModel( | |
| present_1=1, | |
| present_2=2, | |
| present_3=3, | |
| ) | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformStaticNotDeterministicConditionalElifAttributes] | |
| # flags: --python-version 3.11 --always-true TRUTH --always-false LIE | |
| from typing import dataclass_transform, Type, TYPE_CHECKING | |
| TRUTH = False # Is set to --always-true | |
| LIE = True # Is set to --always-false | |
| @dataclass_transform() | |
| def model(cls: Type) -> Type: | |
| return cls | |
| @model | |
| class FunctionModel: | |
| if 123: # Mypy does not know if it is True or False, so this block is used | |
| present_1: int | |
| elif TRUTH: # Mypy does not know if previous condition is True or False, so it uses also this block | |
| present_2: int | |
| else: # Previous block is for sure True, so this block is skipped | |
| skipped_1: int | |
| if 123: | |
| present_3: int | |
| elif 123: | |
| present_4: int | |
| else: | |
| present_5: int | |
| if 123: # Mypy does not know if it is True or False, so this block is used | |
| present_6: int | |
| elif LIE: # This is for sure False, so the block is skipped used | |
| skipped_2: int | |
| else: # None of the conditions above for sure True, so this block is used | |
| present_7: int | |
| FunctionModel( | |
| present_1=1, | |
| present_2=2, | |
| present_3=3, | |
| present_4=4, | |
| present_5=5, | |
| present_6=6, | |
| present_7=7, | |
| ) | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformFunctionConditionalAttributes] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Type | |
| @dataclass_transform() | |
| def model(cls: Type) -> Type: | |
| return cls | |
| def condition() -> bool: | |
| return True | |
| @model | |
| class FunctionModel: | |
| if condition(): | |
| x: int | |
| y: int | |
| z1: int | |
| else: | |
| x: str # E: Name "x" already defined on line 14 | |
| y: int # E: Name "y" already defined on line 15 | |
| z2: int | |
| FunctionModel(x=1, y=2, z1=3, z2=4) | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformNegatedFunctionConditionalAttributes] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Type | |
| @dataclass_transform() | |
| def model(cls: Type) -> Type: | |
| return cls | |
| def condition() -> bool: | |
| return True | |
| @model | |
| class FunctionModel: | |
| if not condition(): | |
| x: int | |
| y: int | |
| z1: int | |
| else: | |
| x: str # E: Name "x" already defined on line 14 | |
| y: int # E: Name "y" already defined on line 15 | |
| z2: int | |
| FunctionModel(x=1, y=2, z1=3, z2=4) | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformDirectMetaclassNeitherFrozenNorNotFrozen] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, Type | |
| @dataclass_transform() | |
| class Meta(type): ... | |
| class Base(metaclass=Meta): | |
| base: int | |
| class Foo(Base, frozen=True): | |
| foo: int | |
| class Bar(Base, frozen=False): | |
| bar: int | |
| foo = Foo(0, 1) | |
| foo.foo = 5 # E: Property "foo" defined in "Foo" is read-only | |
| foo.base = 6 | |
| reveal_type(foo.base) # N: Revealed type is "builtins.int" | |
| bar = Bar(0, 1) | |
| bar.bar = 5 | |
| bar.base = 6 | |
| reveal_type(bar.base) # N: Revealed type is "builtins.int" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformReplace] | |
| from dataclasses import replace | |
| from typing import dataclass_transform, Type | |
| @dataclass_transform() | |
| def my_dataclass(cls: Type) -> Type: | |
| return cls | |
| @my_dataclass | |
| class Person: | |
| name: str | |
| p = Person('John') | |
| y = replace(p, name='Bob') | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformSimpleDescriptor] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, overload, Any | |
| @dataclass_transform() | |
| def my_dataclass(cls): ... | |
| class Desc: | |
| @overload | |
| def __get__(self, instance: None, owner: Any) -> Desc: ... | |
| @overload | |
| def __get__(self, instance: object, owner: Any) -> str: ... | |
| def __get__(self, instance: object | None, owner: Any) -> Desc | str: ... | |
| def __set__(self, instance: Any, value: str) -> None: ... | |
| @my_dataclass | |
| class C: | |
| x: Desc | |
| y: int | |
| C(x='x', y=1) | |
| C(x=1, y=1) # E: Argument "x" to "C" has incompatible type "int"; expected "str" | |
| reveal_type(C(x='x', y=1).x) # N: Revealed type is "builtins.str" | |
| reveal_type(C(x='x', y=1).y) # N: Revealed type is "builtins.int" | |
| reveal_type(C.x) # N: Revealed type is "__main__.Desc" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformUnannotatedDescriptor] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, overload, Any | |
| @dataclass_transform() | |
| def my_dataclass(cls): ... | |
| class Desc: | |
| @overload | |
| def __get__(self, instance: None, owner: Any) -> Desc: ... | |
| @overload | |
| def __get__(self, instance: object, owner: Any) -> str: ... | |
| def __get__(self, instance: object | None, owner: Any) -> Desc | str: ... | |
| def __set__(*args, **kwargs): ... | |
| @my_dataclass | |
| class C: | |
| x: Desc | |
| y: int | |
| C(x='x', y=1) | |
| C(x=1, y=1) | |
| reveal_type(C(x='x', y=1).x) # N: Revealed type is "builtins.str" | |
| reveal_type(C(x='x', y=1).y) # N: Revealed type is "builtins.int" | |
| reveal_type(C.x) # N: Revealed type is "__main__.Desc" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformGenericDescriptor] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, overload, Any, TypeVar, Generic | |
| @dataclass_transform() | |
| def my_dataclass(frozen: bool = False): ... | |
| T = TypeVar("T") | |
| class Desc(Generic[T]): | |
| @overload | |
| def __get__(self, instance: None, owner: Any) -> Desc[T]: ... | |
| @overload | |
| def __get__(self, instance: object, owner: Any) -> T: ... | |
| def __get__(self, instance: object | None, owner: Any) -> Desc | T: ... | |
| def __set__(self, instance: Any, value: T) -> None: ... | |
| @my_dataclass() | |
| class C: | |
| x: Desc[str] | |
| C(x='x') | |
| C(x=1) # E: Argument "x" to "C" has incompatible type "int"; expected "str" | |
| reveal_type(C(x='x').x) # N: Revealed type is "builtins.str" | |
| reveal_type(C.x) # N: Revealed type is "__main__.Desc[builtins.str]" | |
| @my_dataclass() | |
| class D(C): | |
| y: Desc[int] | |
| d = D(x='x', y=1) | |
| reveal_type(d.x) # N: Revealed type is "builtins.str" | |
| reveal_type(d.y) # N: Revealed type is "builtins.int" | |
| reveal_type(D.x) # N: Revealed type is "__main__.Desc[builtins.str]" | |
| reveal_type(D.y) # N: Revealed type is "__main__.Desc[builtins.int]" | |
| @my_dataclass(frozen=True) | |
| class F: | |
| x: Desc[str] = Desc() | |
| F(x='x') | |
| F(x=1) # E: Argument "x" to "F" has incompatible type "int"; expected "str" | |
| reveal_type(F(x='x').x) # N: Revealed type is "builtins.str" | |
| reveal_type(F.x) # N: Revealed type is "__main__.Desc[builtins.str]" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformGenericDescriptorWithInheritance] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, overload, Any, TypeVar, Generic | |
| @dataclass_transform() | |
| def my_dataclass(cls): ... | |
| T = TypeVar("T") | |
| class Desc(Generic[T]): | |
| @overload | |
| def __get__(self, instance: None, owner: Any) -> Desc[T]: ... | |
| @overload | |
| def __get__(self, instance: object, owner: Any) -> T: ... | |
| def __get__(self, instance: object | None, owner: Any) -> Desc | T: ... | |
| def __set__(self, instance: Any, value: T) -> None: ... | |
| class Desc2(Desc[str]): | |
| pass | |
| @my_dataclass | |
| class C: | |
| x: Desc2 | |
| C(x='x') | |
| C(x=1) # E: Argument "x" to "C" has incompatible type "int"; expected "str" | |
| reveal_type(C(x='x').x) # N: Revealed type is "builtins.str" | |
| reveal_type(C.x) # N: Revealed type is "__main__.Desc[builtins.str]" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformDescriptorWithDifferentGetSetTypes] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, overload, Any | |
| @dataclass_transform() | |
| def my_dataclass(cls): ... | |
| class Desc: | |
| @overload | |
| def __get__(self, instance: None, owner: Any) -> int: ... | |
| @overload | |
| def __get__(self, instance: object, owner: Any) -> str: ... | |
| def __get__(self, instance, owner): ... | |
| def __set__(self, instance: Any, value: bytes | None) -> None: ... | |
| @my_dataclass | |
| class C: | |
| x: Desc | |
| c = C(x=b'x') | |
| c = C(x=None) | |
| C(x=1) # E: Argument "x" to "C" has incompatible type "int"; expected "bytes | None" | |
| reveal_type(c.x) # N: Revealed type is "builtins.str" | |
| reveal_type(C.x) # N: Revealed type is "builtins.int" | |
| c.x = b'x' | |
| c.x = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "bytes | None") | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testDataclassTransformUnsupportedDescriptors] | |
| # flags: --python-version 3.11 | |
| from typing import dataclass_transform, overload, Any | |
| @dataclass_transform() | |
| def my_dataclass(cls): ... | |
| class Desc: | |
| @overload | |
| def __get__(self, instance: None, owner: Any) -> int: ... | |
| @overload | |
| def __get__(self, instance: object, owner: Any) -> str: ... | |
| def __get__(self, instance, owner): ... | |
| def __set__(*args, **kwargs) -> None: ... | |
| class Desc2: | |
| @overload | |
| def __get__(self, instance: None, owner: Any) -> int: ... | |
| @overload | |
| def __get__(self, instance: object, owner: Any) -> str: ... | |
| def __get__(self, instance, owner): ... | |
| @overload | |
| def __set__(self, instance: Any, value: bytes) -> None: ... | |
| @overload | |
| def __set__(self) -> None: ... | |
| def __set__(self, *args, **kawrga) -> None: ... | |
| @my_dataclass | |
| class C: | |
| x: Desc # E: Unsupported signature for "__set__" in "Desc" | |
| y: Desc2 # E: Unsupported "__set__" in "Desc2" | |
| [typing fixtures/typing-full.pyi] | |
| [builtins fixtures/dataclasses.pyi] |