-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
[dataclass_transform] support field_specifiers #14667
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
JukkaL
merged 9 commits into
python:master
from
wesleywright:dataclass-transform-field-specifiers
Feb 15, 2023
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
0e19686
[dataclass_transform] support field_specifiers
wesleywright 1aaa317
Merge branch 'master' of https://github.com/python/mypy into dataclas…
wesleywright cfb861a
add a docstring
wesleywright e190e18
update error message formatting
wesleywright e4c6929
allow non-standard positional args for dataclass_transform field spec…
wesleywright 1dc5fd9
Merge branch 'master' of https://github.com/python/mypy into dataclas…
wesleywright 23e9300
explicit error when field_specifiers arg is not a tuple literal
wesleywright 3340b3c
more coverage on field attribute tests
wesleywright d911373
add test with multiple field specifiers
wesleywright File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -210,6 +210,125 @@ 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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Try passing |
||
# 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 | ||
|
||
# this metadata should only exist for dataclasses.dataclass classes | ||
Foo.__dataclass_fields__ # E: "Type[Foo]" has no attribute "__dataclass_fields__" | ||
|
||
[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,)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also test more than one field specifiers. |
||
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 testDataclassTransformOverloadsDecoratorOnOverload] | ||
# flags: --python-version 3.11 | ||
from typing import dataclass_transform, overload, Any, Callable, Type, Literal | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we generate an error here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch; i was going to let typeshed handle it, but i overlooked that we need to enforce that a literal is passed