Skip to content

Commit

Permalink
dataclass_transform: use regular dataclasses.field for field_specifiers
Browse files Browse the repository at this point in the history
cf https://docs.python.org/3/library/typing.html#typing.dataclass_transform:
this is needed so that type checkers properly handle attributes using
field(). Without this, any attribute using `= field(...)` is treated as
if it were a default value by mypy, which makes it impossible to use
its other arguments. This is even more problematic for
marshmallow-dataclass since it makes it impossible to pass arguments
to marshmallow using `metadata=...`
  • Loading branch information
noirbee authored and dairiki committed Apr 20, 2023
1 parent 792dc66 commit 5f7ffd0
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 2 deletions.
8 changes: 6 additions & 2 deletions marshmallow_dataclass/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,12 @@ class User:

if sys.version_info >= (3, 11):
from typing import dataclass_transform
else:
elif sys.version_info >= (3, 7):
from typing_extensions import dataclass_transform
else:
# @dataclass_transform() only helps us with mypy>=1.1 which is only available for python>=3.7
def dataclass_transform(**kwargs):
return lambda cls: cls


__all__ = ["dataclass", "add_schema", "class_schema", "field_for_schema", "NewType"]
Expand Down Expand Up @@ -122,7 +126,7 @@ def dataclass(
# _cls should never be specified by keyword, so start it with an
# underscore. The presence of _cls is used to detect if this
# decorator is being called with parameters or not.
@dataclass_transform()
@dataclass_transform(field_specifiers=(dataclasses.Field, dataclasses.field))
def dataclass(
_cls: Optional[Type[_U]] = None,
*,
Expand Down
15 changes: 15 additions & 0 deletions tests/test_mypy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,18 @@
reveal_type(website.email) # N: Revealed type is "builtins.str"
Website(url=42, email="user@email.com") # E: Argument "url" to "Website" has incompatible type "int"; expected "str" [arg-type]
- case: dataclasses_field_not_a_default
mypy_config: |
follow_imports = silent
plugins = marshmallow_dataclass.mypy
show_error_codes = true
env:
- PYTHONPATH=.
main: |
from dataclasses import field
from marshmallow_dataclass import dataclass
@dataclass
class User:
id: int = field(metadata={"required": True})
name: str

0 comments on commit 5f7ffd0

Please sign in to comment.