Skip to content

Commit ed7d429

Browse files
authored
bpo-32278: Allow dataclasses.make_dataclass() to omit type information. (gh-5115)
1 parent e7ba013 commit ed7d429

3 files changed

Lines changed: 30 additions & 6 deletions

File tree

Lib/dataclasses.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -708,9 +708,10 @@ def _astuple_inner(obj, tuple_factory):
708708
def make_dataclass(cls_name, fields, *, bases=(), namespace=None):
709709
"""Return a new dynamically created dataclass.
710710
711-
The dataclass name will be 'cls_name'. 'fields' is an interable
712-
of either (name, type) or (name, type, Field) objects. Field
713-
objects are created by calling 'field(name, type [, Field])'.
711+
The dataclass name will be 'cls_name'. 'fields' is an iterable
712+
of either (name), (name, type) or (name, type, Field) objects. If type is
713+
omitted, use the string 'typing.Any'. Field objects are created by
714+
calling 'field(name, type [, Field])'.
714715
715716
C = make_class('C', [('a', int', ('b', int, Field(init=False))], bases=Base)
716717
@@ -730,12 +731,19 @@ class C(Base):
730731
# Copy namespace since we're going to mutate it.
731732
namespace = namespace.copy()
732733

733-
anns = collections.OrderedDict((name, tp) for name, tp, *_ in fields)
734-
namespace['__annotations__'] = anns
734+
anns = collections.OrderedDict()
735735
for item in fields:
736-
if len(item) == 3:
736+
if isinstance(item, str):
737+
name = item
738+
tp = 'typing.Any'
739+
elif len(item) == 2:
740+
name, tp, = item
741+
elif len(item) == 3:
737742
name, tp, spec = item
738743
namespace[name] = spec
744+
anns[name] = tp
745+
746+
namespace['__annotations__'] = anns
739747
cls = type(cls_name, bases, namespace)
740748
return dataclass(cls)
741749

Lib/test/test_dataclasses.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2033,6 +2033,20 @@ def test_helper_make_dataclass_class_var(self):
20332033
self.assertEqual(C.y, 10)
20342034
self.assertEqual(C.z, 20)
20352035

2036+
def test_helper_make_dataclass_no_types(self):
2037+
C = make_dataclass('Point', ['x', 'y', 'z'])
2038+
c = C(1, 2, 3)
2039+
self.assertEqual(vars(c), {'x': 1, 'y': 2, 'z': 3})
2040+
self.assertEqual(C.__annotations__, {'x': 'typing.Any',
2041+
'y': 'typing.Any',
2042+
'z': 'typing.Any'})
2043+
2044+
C = make_dataclass('Point', ['x', ('y', int), 'z'])
2045+
c = C(1, 2, 3)
2046+
self.assertEqual(vars(c), {'x': 1, 'y': 2, 'z': 3})
2047+
self.assertEqual(C.__annotations__, {'x': 'typing.Any',
2048+
'y': int,
2049+
'z': 'typing.Any'})
20362050

20372051
class TestDocString(unittest.TestCase):
20382052
def assertDocStrEqual(self, a, b):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Make type information optional on dataclasses.make_dataclass(). If omitted,
2+
the string 'typing.Any' is used.

0 commit comments

Comments
 (0)