PEP 681: Descriptor fields (#2369)
Co-authored-by: CAM Gerlach <CAM.Gerlach@Gerlach.CAM>
This commit is contained in:
parent
15edc5ee28
commit
fb1498c5a8
62
pep-0681.rst
62
pep-0681.rst
|
@ -19,7 +19,7 @@ Abstract
|
|||
libraries have behaviors that are similar to dataclasses, but these
|
||||
behaviors cannot be described using standard type annotations. Such
|
||||
projects include attrs, pydantic, and object relational mapper (ORM)
|
||||
packages such as Django and EdgeDB.
|
||||
packages such as SQLAlchemy and Django.
|
||||
|
||||
Most type checkers, linters and language servers have full support for
|
||||
dataclasses. This proposal aims to generalize this functionality and
|
||||
|
@ -214,6 +214,7 @@ customization of default behaviors:
|
|||
eq_default: bool = True,
|
||||
order_default: bool = False,
|
||||
kw_only_default: bool = False,
|
||||
transform_descriptor_types: bool = False,
|
||||
field_descriptors: tuple[type | Callable[..., Any], ...] = (),
|
||||
) -> Callable[[_T], _T]: ...
|
||||
|
||||
|
@ -229,6 +230,14 @@ customization of default behaviors:
|
|||
assumed to be True or False if it is omitted by the caller. If not
|
||||
specified, ``kw_only_default`` will default to False (the default
|
||||
assumption for dataclass).
|
||||
* ``transform_descriptor_types`` affects fields annotated with
|
||||
descriptor types that define a ``__set__`` method. If True, the type
|
||||
of each parameter on the synthesized ``__init__`` method
|
||||
corresponding to such a field will be the type of the value
|
||||
parameter to the descriptor's ``__set__`` method. If False, the
|
||||
descriptor type will be used. If not specified,
|
||||
``transform_descriptor_types`` will default to False (the default
|
||||
behavior of dataclass).
|
||||
* ``field_descriptors`` specifies a static list of supported classes
|
||||
that describe fields. Some libraries also supply functions to
|
||||
allocate instances of field descriptors, and those functions may
|
||||
|
@ -334,6 +343,37 @@ Metaclass example
|
|||
id: int
|
||||
name: str
|
||||
|
||||
``transform_descriptor_types`` example
|
||||
``````````````````````````````````````
|
||||
|
||||
Because ``transform_descriptor_types`` is set to ``True``, the
|
||||
``target`` parameter on the synthesized ``__init__`` method will be of
|
||||
type ``float`` (the type of ``__set__``\ 's ``value`` parameter)
|
||||
instead of ``Descriptor``.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@typing.dataclass_transform(transform_descriptor_types=True)
|
||||
def create_model() -> Callable[[Type[_T]], Type[_T]]: ...
|
||||
|
||||
# We anticipate that most descriptor classes used with
|
||||
# transform_descriptor_types will be generic with __set__ functions
|
||||
# whose value parameters are based on the generic's type vars.
|
||||
# However, this is not required.
|
||||
class Descriptor:
|
||||
def __get__(self, instance: object, owner: Any) -> int:
|
||||
...
|
||||
|
||||
# The setter and getter can have different types (asymmetric).
|
||||
# The setter's value type is used for the __init__ parameter.
|
||||
# The getter's return type is ignored.
|
||||
def __set__(self, instance: object, value: float):
|
||||
...
|
||||
|
||||
@create_model
|
||||
class CustomerModel:
|
||||
target: Descriptor
|
||||
|
||||
|
||||
Field descriptors
|
||||
-----------------
|
||||
|
@ -467,7 +507,8 @@ For example:
|
|||
"eq_default": True,
|
||||
"order_default": False,
|
||||
"kw_only_default": False,
|
||||
"field_descriptors": ()
|
||||
"transform_descriptor_types": False,
|
||||
"field_descriptors": (),
|
||||
}
|
||||
|
||||
|
||||
|
@ -557,6 +598,11 @@ If multiple ``dataclass_transform`` decorators are found, either on a
|
|||
single function/class or within a class hierarchy, the resulting
|
||||
behavior is undefined. Library authors should avoid these scenarios.
|
||||
|
||||
The ``__set__`` method on descriptors is not expected to be
|
||||
overloaded. If such overloads are found when
|
||||
``transform_descriptor_types`` is ``True``, the resulting behavior is
|
||||
undefined.
|
||||
|
||||
|
||||
Reference Implementation
|
||||
========================
|
||||
|
@ -657,6 +703,18 @@ users of Django would need to explicitly declare the ``id`` field.
|
|||
This limitation may make it impractical to use the
|
||||
``dataclass_transform`` mechanism with Django.
|
||||
|
||||
Class-wide default values
|
||||
-------------------------
|
||||
|
||||
SQLAlchemy requested that we expose a way to specify that the default
|
||||
value of all fields in the transformed class is None. It is typical
|
||||
that all of their fields are optional, and None indicates that the
|
||||
field is not set.
|
||||
|
||||
We chose not to support this feature, since it is specific to
|
||||
SQLAlchemy. Users can manually set ``default=None`` on these fields
|
||||
instead.
|
||||
|
||||
Open Issues
|
||||
===========
|
||||
|
||||
|
|
Loading…
Reference in New Issue