Skip to content

Commit

Permalink
PEP 681: Move descriptor-field support to Rejected Ideas (#2477)
Browse files Browse the repository at this point in the history
Co-authored-by: CAM Gerlach <CAM.Gerlach@Gerlach.CAM>
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
  • Loading branch information
3 people authored Mar 31, 2022
1 parent d0a55d7 commit 03d6747
Showing 1 changed file with 21 additions and 46 deletions.
67 changes: 21 additions & 46 deletions pep-0681.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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]: ...
Expand All @@ -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
Expand Down Expand Up @@ -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
-----------------
Expand Down Expand Up @@ -506,7 +466,6 @@ For example:
"eq_default": True,
"order_default": False,
"kw_only_default": False,
"transform_descriptor_types": False,
"field_descriptors": (),
}
Expand Down Expand Up @@ -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
========================
Expand Down Expand Up @@ -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
----------------------------------------

Expand Down Expand Up @@ -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
=========
Expand Down

0 comments on commit 03d6747

Please sign in to comment.