Closed
Description
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 thedataclasses
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.