[Python-checkins] bpo-32499: Add dataclasses.is_dataclass(obj), which returns True if obj is a dataclass or an instance of one. (#5113)
Eric V. Smith
webhook-mailer at python.org
Sat Jan 6 12:41:55 EST 2018
https://github.com/python/cpython/commit/e7ba013d870012157f695ead7e3645c2828a7fc5
commit: e7ba013d870012157f695ead7e3645c2828a7fc5
branch: master
author: Eric V. Smith <ericvsmith at users.noreply.github.com>
committer: GitHub <noreply at github.com>
date: 2018-01-06T12:41:53-05:00
summary:
bpo-32499: Add dataclasses.is_dataclass(obj), which returns True if obj is a dataclass or an instance of one. (#5113)
files:
A Misc/NEWS.d/next/Library/2018-01-06-10-54-16.bpo-32499.koyY-4.rst
M Lib/dataclasses.py
M Lib/test/test_dataclasses.py
diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py
index eaaed63ef28..b4786bf502e 100644
--- a/Lib/dataclasses.py
+++ b/Lib/dataclasses.py
@@ -16,6 +16,7 @@
'astuple',
'make_dataclass',
'replace',
+ 'is_dataclass',
]
# Raised when an attempt is made to modify a frozen class.
@@ -615,11 +616,17 @@ def fields(class_or_instance):
return tuple(f for f in fields.values() if f._field_type is _FIELD)
-def _isdataclass(obj):
+def _is_dataclass_instance(obj):
"""Returns True if obj is an instance of a dataclass."""
return not isinstance(obj, type) and hasattr(obj, _MARKER)
+def is_dataclass(obj):
+ """Returns True if obj is a dataclass or an instance of a
+ dataclass."""
+ return hasattr(obj, _MARKER)
+
+
def asdict(obj, *, dict_factory=dict):
"""Return the fields of a dataclass instance as a new dictionary mapping
field names to field values.
@@ -639,12 +646,12 @@ class C:
dataclass instances. This will also look into built-in containers:
tuples, lists, and dicts.
"""
- if not _isdataclass(obj):
+ if not _is_dataclass_instance(obj):
raise TypeError("asdict() should be called on dataclass instances")
return _asdict_inner(obj, dict_factory)
def _asdict_inner(obj, dict_factory):
- if _isdataclass(obj):
+ if _is_dataclass_instance(obj):
result = []
for f in fields(obj):
value = _asdict_inner(getattr(obj, f.name), dict_factory)
@@ -678,12 +685,12 @@ class C:
tuples, lists, and dicts.
"""
- if not _isdataclass(obj):
+ if not _is_dataclass_instance(obj):
raise TypeError("astuple() should be called on dataclass instances")
return _astuple_inner(obj, tuple_factory)
def _astuple_inner(obj, tuple_factory):
- if _isdataclass(obj):
+ if _is_dataclass_instance(obj):
result = []
for f in fields(obj):
value = _astuple_inner(getattr(obj, f.name), tuple_factory)
@@ -751,7 +758,7 @@ class C:
# We're going to mutate 'changes', but that's okay because it's a new
# dict, even if called with 'replace(obj, **my_changes)'.
- if not _isdataclass(obj):
+ if not _is_dataclass_instance(obj):
raise TypeError("replace() should be called on dataclass instances")
# It's an error to have init=False fields in 'changes'.
diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py
index ed695639882..fca384d8c3c 100755
--- a/Lib/test/test_dataclasses.py
+++ b/Lib/test/test_dataclasses.py
@@ -1,6 +1,6 @@
from dataclasses import (
dataclass, field, FrozenInstanceError, fields, asdict, astuple,
- make_dataclass, replace, InitVar, Field, MISSING
+ make_dataclass, replace, InitVar, Field, MISSING, is_dataclass,
)
import pickle
@@ -1365,27 +1365,32 @@ class C:
self.assertIs(C().x, int)
- def test_isdataclass(self):
- # There is no isdataclass() helper any more, but the PEP
- # describes how to write it, so make sure that works. Note
- # that this version returns True for both classes and
- # instances.
- def isdataclass(obj):
- try:
- fields(obj)
- return True
- except TypeError:
- return False
+ def test_is_dataclass(self):
+ class NotDataClass:
+ pass
- self.assertFalse(isdataclass(0))
- self.assertFalse(isdataclass(int))
+ self.assertFalse(is_dataclass(0))
+ self.assertFalse(is_dataclass(int))
+ self.assertFalse(is_dataclass(NotDataClass))
+ self.assertFalse(is_dataclass(NotDataClass()))
@dataclass
class C:
x: int
- self.assertTrue(isdataclass(C))
- self.assertTrue(isdataclass(C(0)))
+ @dataclass
+ class D:
+ d: C
+ e: int
+
+ c = C(10)
+ d = D(c, 4)
+
+ self.assertTrue(is_dataclass(C))
+ self.assertTrue(is_dataclass(c))
+ self.assertFalse(is_dataclass(c.x))
+ self.assertTrue(is_dataclass(d.d))
+ self.assertFalse(is_dataclass(d.e))
def test_helper_fields_with_class_instance(self):
# Check that we can call fields() on either a class or instance,
diff --git a/Misc/NEWS.d/next/Library/2018-01-06-10-54-16.bpo-32499.koyY-4.rst b/Misc/NEWS.d/next/Library/2018-01-06-10-54-16.bpo-32499.koyY-4.rst
new file mode 100644
index 00000000000..bf3e99c8d86
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-01-06-10-54-16.bpo-32499.koyY-4.rst
@@ -0,0 +1,2 @@
+Add dataclasses.is_dataclass(obj), which returns True if obj is a dataclass
+or an instance of one.
More information about the Python-checkins
mailing list