Skip to content

Commit

Permalink
PEP 749: Move dataclass field types out of open issues
Browse files Browse the repository at this point in the history
  • Loading branch information
JelleZijlstra committed Sep 24, 2024
1 parent 680c8b1 commit 0d213b1
Showing 1 changed file with 35 additions and 57 deletions.
92 changes: 35 additions & 57 deletions peps/pep-0749.rst
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,41 @@ Usually, users would use these attributes in combinations with
in SOURCE format, one could write
``annotationlib.call_evaluate_function(T.evaluate_bound, annotationlib.Format.SOURCE)``.

Behavior of dataclass field types
=================================

One consequence of the deferred evaluation of annotations is that
dataclasses can use forward references in their annotations:

.. code:: pycon
>>> from dataclasses import dataclass
>>> @dataclass
... class D:
... x: undefined
...
However, the ``FORWARDREF`` format leaks into the field types of the dataclass:

.. code:: pycon
>>> fields(D)[0].type
ForwardRef('undefined')
We considered a change where the ``.type`` attribute of a field object would
trigger evaluation of annotations, so that the field type could contain actual
values in the case of forward references that were defined after the dataclass
itself was created, but before the field type is accessed.
However, this would also mean that accessing ``.type`` could now run arbitrary
code in the annotation, and potentially throws errors such as :py:exc:`NameError`.

Therefore, we consider it more user-friendly to keep the ``ForwardRef`` object
in the type, and document that users who want to resolve forward references
can use the ``ForwardRef.evaluate`` method.

If use cases come up in the future, we could add additional functionality,
such as a new method that re-evaluates the annotation from scratch.

Miscellaneous implementation details
====================================

Expand Down Expand Up @@ -793,63 +828,6 @@ as we make progress on implementing it. Readers are encouraged to follow the
implementation of the PEP and try out the draft implementation. Any feedback may
be incorporated into future versions of this PEP.

Should dataclass field types use deferred evaluation?
-----------------------------------------------------

The current draft implementation already supports deferred evaluation in dataclasses,
so this works:

.. code:: pycon
>>> from dataclasses import dataclass
>>> @dataclass
... class D:
... x: undefined
...
However, the ``FORWARDREF`` format leaks into the field types of the dataclass:

.. code:: pycon
>>> fields(D)[0].type
ForwardRef('undefined')
We could instead add deferred evaluation for the field type, similar to that outlined
above for type alias values.

Accessing ``.type`` might throw an error:

.. code:: pycon
>>> @dataclass
... class D:
... x: undefined
...
>>> field = fields(D)[0]
>>> field.type
Traceback (most recent call last):
File "<python-input-4>", line 1, in <module>
field.type
File ".../dataclasses.py", line 308, in type
annos = self._annotate(annotationlib.Format.VALUE)
File "<python-input-2>", line 3, in __annotate__
x: undefined
^^^^^^^^^
NameError: name 'undefined' is not defined
But users could use ``annotationlib.call_evaluate_function`` to get the type in other formats:

.. code:: pycon
>>> annotationlib.call_evaluate_function(field.evaluate_type, annotationlib.Format.SOURCE)
'undefined'
>>> annotationlib.call_evaluate_function(field.evaluate_type, annotationlib.Format.FORWARDREF)
ForwardRef('undefined')
Other variations are possible. For example, we could leave the ``type`` attribute unchanged,
and only add the ``evaluate_type`` method. This avoids unpleasant surprises where accessing
``.type`` may throw an exception.

Acknowledgments
===============

Expand Down

0 comments on commit 0d213b1

Please sign in to comment.