Skip to content

Commit

Permalink
bpo-37868: Improve is_dataclass for instances. (pythonGH-15325)
Browse files Browse the repository at this point in the history
  • Loading branch information
ericvsmith authored Aug 20, 2019
1 parent d3c8d73 commit b0f4dab
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 2 deletions.
5 changes: 3 additions & 2 deletions Lib/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -1015,13 +1015,14 @@ def fields(class_or_instance):

def _is_dataclass_instance(obj):
"""Returns True if obj is an instance of a dataclass."""
return not isinstance(obj, type) and hasattr(obj, _FIELDS)
return hasattr(type(obj), _FIELDS)


def is_dataclass(obj):
"""Returns True if obj is a dataclass or an instance of a
dataclass."""
return hasattr(obj, _FIELDS)
cls = obj if isinstance(obj, type) else type(obj)
return hasattr(cls, _FIELDS)


def asdict(obj, *, dict_factory=dict):
Expand Down
26 changes: 26 additions & 0 deletions Lib/test/test_dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -1300,6 +1300,32 @@ class D:
self.assertTrue(is_dataclass(d.d))
self.assertFalse(is_dataclass(d.e))

def test_is_dataclass_when_getattr_always_returns(self):
# See bpo-37868.
class A:
def __getattr__(self, key):
return 0
self.assertFalse(is_dataclass(A))
a = A()

# Also test for an instance attribute.
class B:
pass
b = B()
b.__dataclass_fields__ = []

for obj in a, b:
with self.subTest(obj=obj):
self.assertFalse(is_dataclass(obj))

# Indirect tests for _is_dataclass_instance().
with self.assertRaisesRegex(TypeError, 'should be called on dataclass instances'):
asdict(obj)
with self.assertRaisesRegex(TypeError, 'should be called on dataclass instances'):
astuple(obj)
with self.assertRaisesRegex(TypeError, 'should be called on dataclass instances'):
replace(obj, x=0)

def test_helper_fields_with_class_instance(self):
# Check that we can call fields() on either a class or instance,
# and get back the same thing.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix dataclasses.is_dataclass when given an instance that never raises
AttributeError in __getattr__. That is, an object that returns something
for __dataclass_fields__ even if it's not a dataclass.

0 comments on commit b0f4dab

Please sign in to comment.