Currently, if you call dataclasses.fields on a non-dataclass, quite a poor traceback is produced:
>>> import dataclasses
>>> dataclasses.fields(object)
Traceback (most recent call last):
File "C:\Users\alexw\AppData\Local\Programs\Python\Python311\Lib\dataclasses.py", line 1232, in fields
fields = getattr(class_or_instance, _FIELDS)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: type object 'object' has no attribute '__dataclass_fields__'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\alexw\AppData\Local\Programs\Python\Python311\Lib\dataclasses.py", line 1234, in fields
raise TypeError('must be called with a dataclass type or instance')
TypeError: must be called with a dataclass type or instance
There are two issues here:
- The traceback mentions the
__dataclass_fields__ attribute, which is an internal implementation detail of the dataclasses module and should be hidden from the user.
- The "during handling of the above exception, another exception occurred" message implies to the user that there's a bug in the
dataclasses module itself, rather than this being intentional behaviour.
This one-line change to dataclasses.py produces a much better traceback:
diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py
index 82b08fc017..e3fd0b3e38 100644
--- a/Lib/dataclasses.py
+++ b/Lib/dataclasses.py
@@ -1248,7 +1248,7 @@ def fields(class_or_instance):
try:
fields = getattr(class_or_instance, _FIELDS)
except AttributeError:
- raise TypeError('must be called with a dataclass type or instance')
+ raise TypeError('must be called with a dataclass type or instance') from None
With this change applied, we get this traceback instead:
>>> import dataclasses
>>> dataclasses.fields(object)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\alexw\coding\cpython\Lib\dataclasses.py", line 1251, in fields
raise TypeError('must be called with a dataclass type or instance') from None
TypeError: must be called with a dataclass type or instance
Cc. @ericvsmith and @carljm, as dataclasses experts.
Linked PRs
Currently, if you call
dataclasses.fieldson a non-dataclass, quite a poor traceback is produced:There are two issues here:
__dataclass_fields__attribute, which is an internal implementation detail of thedataclassesmodule and should be hidden from the user.dataclassesmodule itself, rather than this being intentional behaviour.This one-line change to
dataclasses.pyproduces a much better traceback:With this change applied, we get this traceback instead:
Cc. @ericvsmith and @carljm, as
dataclassesexperts.Linked PRs
fields()on a non-dataclass #102948fields()on a non-dataclass (GH-102948) #102951fields()on a non-dataclass (#102948) #102954