PEP 681: Move descriptor-field support to Rejected Ideas (#2477)
Co-authored-by: CAM Gerlach <CAM.Gerlach@Gerlach.CAM> Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
This commit is contained in:
parent
d0a55d763b
commit
03d6747f8f
67
pep-0681.rst
67
pep-0681.rst
|
@ -213,7 +213,6 @@ 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,14 +228,6 @@ 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
|
||||
|
@ -342,37 +333,6 @@ 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
|
||||
-----------------
|
||||
|
@ -506,7 +466,6 @@ For example:
|
|||
"eq_default": True,
|
||||
"order_default": False,
|
||||
"kw_only_default": False,
|
||||
"transform_descriptor_types": False,
|
||||
"field_descriptors": (),
|
||||
}
|
||||
|
||||
|
@ -597,11 +556,6 @@ 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
|
||||
========================
|
||||
|
@ -711,6 +665,26 @@ We chose not to support this feature, since it is specific to
|
|||
SQLAlchemy. Users can manually set ``default=None`` on these fields
|
||||
instead.
|
||||
|
||||
Descriptor-typed field support
|
||||
------------------------------
|
||||
|
||||
We considered adding a boolean parameter on ``dataclass_transform``
|
||||
to enable better support for fields with descriptor types, which is
|
||||
common in SQLAlchemy. When enabled, the type of each parameter on the
|
||||
synthesized ``__init__`` method corresponding to a descriptor-typed
|
||||
field would be the type of the value parameter to the descriptor's
|
||||
``__set__`` method rather than the descriptor type itself. Similarly,
|
||||
when setting the field, the ``__set__`` value type would be expected.
|
||||
And when getting the value of the field, its type would be expected to
|
||||
match the return type of ``__get__``.
|
||||
|
||||
This idea was based on the belief that ``dataclass`` did not properly
|
||||
support descriptor-typed fields. In fact it does, but type checkers
|
||||
(at least mypy and pyright) did not reflect the runtime behavior which
|
||||
led to our misunderstanding. For more details, see the
|
||||
`Pyright bug <#pyright-descriptor-bug_>`__.
|
||||
|
||||
|
||||
``converter`` field descriptor parameter
|
||||
----------------------------------------
|
||||
|
||||
|
@ -748,6 +722,7 @@ References
|
|||
.. _#kw-only-docs: https://docs.python.org/3/library/dataclasses.html#dataclasses.KW_ONLY
|
||||
.. _#kw-only-issue: https://bugs.python.org/issue43532
|
||||
.. _#class-var: https://docs.python.org/3/library/dataclasses.html#class-variables
|
||||
.. _#pyright-descriptor-bug: https://github.com/microsoft/pyright/issues/3245
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
|
Loading…
Reference in New Issue