I wonder if anyone has considered the impact of PEP 563 on dataclasses ?
I did find this SO post:
which is related, but not quite the same -- THAT issue was fixed.
My issue does show up in this BPO:
Somewhere in the middle of that thread, Eric wrote: "At this point, this seems more like fodder for python-ideas."
Then there's a bit more to the thread, which peters out without resolution.
On to the issue:
dataclasses may be the only part of the stdlib that uses annotations.
dataclasses store the annotations in Field objects type attribute, in the __dataclass_fields__ attribute.
We can see that with this code:
@dataclass
class Simple:
x : int
y : float
name : str
s = Simple(3, 4.0, "fred")
print("The field types:")
for f in s.__dataclass_fields__.values():
print(f"name: {f.name}, type: {f.type}, type of type: {type(f.type)}")
Which results in:
The field types:
name: x, type: <class 'int'>, type of type: <class 'type'>
name: y, type: <class 'float'>, type of type: <class 'type'>
name: name, type: <class 'str'>, type of type: <class 'type'>
with:
from __future__ import annotations
The result is:
The field types:
name: x, type: int, type of type: <class 'str'>
name: y, type: float, type of type: <class 'str'>
name: name, type: str, type of type: <class 'str'>
This of course is completely as expected.
I have no idea how dataclasses uses the Field type attribute -- as far as I can tell, for nothing at all. However, it is there, and it is called "type", rather than say, "annotation".
And I have a whole pile of code that fully expects the Fields' type attribute to be an actual type object that I can call to crate an instance of that type (or call a method on it, which is what I am actually doing)
So my code will very much break with this change.
I fully understand that the __dataclass_fields__ attribute was probably never intended to be part of the public API, so I get what I deserve.
However, the Field object is documented, as such:
"""
class dataclasses.Field
Field objects describe each defined field. These objects are created internally, and are returned by the fields() module-level method (see below). Users should never instantiate a Field object directly. Its documented attributes are:
name: The name of the field.
type: The type of the field.
default, default_factory, init, repr, hash, compare, and metadata have the identical meaning and values as they do in the field() declaration.
Other attributes may exist, but they are private and must not be inspected or relied on.
"""
That last sentence implies that the type attribute CAN be inspected and relied upon, which is what I am doing.
And I haven't tried to solve this problem in my use case, but I'm not sure it can be done -- when I get around to inspecting the type of the Field objects, I have no idea what namespace they are in -- so I can't reconstruct them from the string. I really need the type object itself.
So I'll probably need to re-write much of the dataclasses decorator, to call eval() early -- though even then I'm not sure I'll have access to the proper namespace.
Anyway -- one more data point: PEP 563 changes the (semi-public?) API of dataclasses.
Though *maybe* that could be addressed with a dataclasses update -- again, I've only started to think about it -- there was some discussion of that in the BPO, though Eric didn't seem particularly interested.
-CHB
--