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.