| [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] |
| # flags: --python-version 3.7 |
| 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(nonexistant=True) # E: Unrecognized dataclass_transform parameter "nonexistant" |
| 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) # E: Too many positional arguments for "Foo" |
| 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[<nothing>, ...]"; 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[<nothing>, ...]"; 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[<nothing>, ...]"; 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[<nothing>, ...]"; 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[<nothing>, ...]"; 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[<nothing>, ...]"; 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') # E: Argument 1 to "replace" has incompatible type "Person"; expected a dataclass |
| |
| [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 "Optional[bytes]" |
| 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 "Optional[bytes]") |
| |
| [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] |