You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
mypy 1.0 shipped with extremely rudimentary support for dataclass_transform decorator with no parameters passed. mypy master has increasingly better support for PEP 681.
Reacted by Neil Girdhar, Fabian Keller, Jacopo Farina and Peter
Re-reading the PEP, it looks like the use of overloads for field specifiers isn't quite fully implemented. We currently have this behaviour on mypy master:
importtypingfromtypingimportoverload, Optional, Any, Callable, Literal, Type, TypeVar# Library code (within type stub or inline)# In this library, passing a resolver means that init must be False,# and the overload with Literal[False] enforces that.@overloaddefmodel_field(
*,
default: Optional[Any] = ...,
resolver: Callable[[], Any],
init: Literal[False] =False,
) ->Any: ...
@overloaddefmodel_field(
*,
default: Optional[Any] = ...,
resolver: None=None,
init: bool=True,
) ->Any: ...
defmodel_field(
*,
default: Optional[Any] = ...,
resolver: Optional[Callable[[], Any]] = ...,
init: bool= ...,
) ->Any: ...
_T=TypeVar("_T")
@typing.dataclass_transform(kw_only_default=True,field_specifiers=(model_field, ))defcreate_model(
*,
init: bool=True,
) ->Callable[[Type[_T]], Type[_T]]: ...
# Code that imports this library:@create_model(init=True)classCustomerModel:
id: int=model_field(resolver=lambda : 0)
name: strcm=CustomerModel(name="John")
Mypy output:
test.py:32: error: Missing return statement [empty-body]
test.py:43: error: Missing named argument "id" for "CustomerModel" [call-arg]
Found 2 errors in 1 file (checked 1 source file)
The second error is a false positive: mypy should be able to infer that there's no "id" argument in the __init__ method for CustomerModel, due to the fact that the resolver argument was specified for model_field for the id attribute.
Opened #14870 to support the implicit defaults for the init parameter, though I'm not sure how to plumb the correct overload in, so it only works for non-overloads for now. Hopefully that should be easy to fix and the feature will be properly supported.
I suspect that full overload resolution in the dataclass plugin would require some changes to the plugin system, since during the main dataclass transform pass types aren't fully set up yet, and subtype checks can't be reliably used. I wonder if it would be sufficient to do "lightweight" overload resolution using only the argument counts and names and some simple type rules (e.g. matching None value to None type). This might unblock the currently known use cases while we figure out how to do this in a more general way.
A possible more general approach would to postpone the determination of the __init__ signature until just before type checking, when all types are fully set up. Even then it may be tricky to use the existing machinery to match overloads.
Yet another idea would be to generate the __init__ signature lazily during type checking. I think this could also hit some difficulties, but I'm not sure.
Activity
NeilGirdhar commentedon Dec 14, 2022
It would be really nice to support
frozen_default, which is not part of the PEP, but was added to CPython (python/cpython#99957) andtyping_extensions(python/typing_extensions#101).tmke8 commentedon Dec 14, 2022
Hm? Python 3.11 has already been released.
NeilGirdhar commentedon Dec 14, 2022
@thomkeh Thanks for catching my mistake, edited 😄
hauntsaninja commentedon Feb 8, 2023
Just to keep this issue up to date:
mypy 1.0 shipped with extremely rudimentary support for dataclass_transform decorator with no parameters passed. mypy master has increasingly better support for PEP 681.
NeilGirdhar commentedon Feb 25, 2023
@wesleywright Looks like this complete on master? If so, I'll close this issue. Please feel free to tick this off the Python 3.11 issue.
wesleywright commentedon Mar 5, 2023
@NeilGirdhar Yes, as far as I'm aware we're feature complete on master now.
tmke8 commentedon Mar 5, 2023
Does the implementation support taking into account overloads to determine whether a field will be present in the
__init__? The master version in mypy play doesn't seem to support it: https://mypy-play.net/?mypy=master&python=3.11&gist=eec5f42639277ba0988d496cee03d3d4The example is from this section of the PEP: https://peps.python.org/pep-0681/#field-specifier-parameters
AlexWaygood commentedon Mar 5, 2023
AlexWaygood commentedon Mar 5, 2023
AlexWaygood commentedon Mar 5, 2023
Re-reading the PEP, it looks like the use of overloads for field specifiers isn't quite fully implemented. We currently have this behaviour on mypy master:
Mypy output:
The second error is a false positive: mypy should be able to infer that there's no "id" argument in the
__init__method forCustomerModel, due to the fact that theresolverargument was specified formodel_fieldfor theidattribute.wesleywright commentedon Mar 10, 2023
Opened #14870 to support the implicit defaults for the
initparameter, though I'm not sure how to plumb the correct overload in, so it only works for non-overloads for now. Hopefully that should be easy to fix and the feature will be properly supported.wesleywright commentedon Mar 15, 2023
@tmke8 are you aware of any specific use cases for such overloads in the wild?
tmke8 commentedon Mar 15, 2023
@wesleywright no, I just read about them in the PEP
AlexWaygood commentedon Mar 15, 2023
You could check with the pydantic and SQLAlchemy folks; they seem to be heavy users of
dataclass_transformhauntsaninja commentedon Mar 15, 2023
You can see more context about the field specifier overloads in microsoft/pyright#1782 cc @patrick91
tmke8 commentedon Mar 15, 2023
More specific link: microsoft/pyright#1782 (comment)
JukkaL commentedon Mar 16, 2023
I suspect that full overload resolution in the dataclass plugin would require some changes to the plugin system, since during the main dataclass transform pass types aren't fully set up yet, and subtype checks can't be reliably used. I wonder if it would be sufficient to do "lightweight" overload resolution using only the argument counts and names and some simple type rules (e.g. matching
Nonevalue toNonetype). This might unblock the currently known use cases while we figure out how to do this in a more general way.A possible more general approach would to postpone the determination of the
__init__signature until just before type checking, when all types are fully set up. Even then it may be tricky to use the existing machinery to match overloads.Yet another idea would be to generate the
__init__signature lazily during type checking. I think this could also hit some difficulties, but I'm not sure.Update to Python 3.12.
Update to Python 3.12.
Update to Python 3.12. (#53)
NeilGirdhar commentedon Oct 15, 2024
I believe this is complete now.