summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Levkivskyi <levkivskyi@gmail.com>2018-03-31 12:41:17 (GMT)
committerGitHub <noreply@github.com>2018-03-31 12:41:17 (GMT)
commit5a7092de1226a95a50f0f384eea8ddb288959249 (patch)
tree807e9531024aea7af14e1efd02d2c8d11979d35c
parent233de021d915364bd3daee921d1d96d50d46d7fe (diff)
downloadcpython-5a7092de1226a95a50f0f384eea8ddb288959249.zip
cpython-5a7092de1226a95a50f0f384eea8ddb288959249.tar.gz
cpython-5a7092de1226a95a50f0f384eea8ddb288959249.tar.bz2
Allow dynamic creation of generic dataclasses (GH-6319)
-rw-r--r--Lib/dataclasses.py4
-rwxr-xr-xLib/test/test_dataclasses.py19
2 files changed, 21 insertions, 2 deletions
diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py
index bd7252c..04e07f8 100644
--- a/Lib/dataclasses.py
+++ b/Lib/dataclasses.py
@@ -1004,7 +1004,9 @@ def make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True,
anns[name] = tp
namespace['__annotations__'] = anns
- cls = type(cls_name, bases, namespace)
+ # We use `types.new_class()` instead of simply `type()` to allow dynamic creation
+ # of generic dataclassses.
+ cls = types.new_class(cls_name, bases, {}, lambda ns: ns.update(namespace))
return dataclass(cls, init=init, repr=repr, eq=eq, order=order,
unsafe_hash=unsafe_hash, frozen=frozen)
diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py
index 5cd424c..26bfc4e 100755
--- a/Lib/test/test_dataclasses.py
+++ b/Lib/test/test_dataclasses.py
@@ -8,7 +8,7 @@ import pickle
import inspect
import unittest
from unittest.mock import Mock
-from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar
+from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional
from collections import deque, OrderedDict, namedtuple
from functools import total_ordering
@@ -1690,6 +1690,23 @@ class TestCase(unittest.TestCase):
c = Alias(10, 1.0)
self.assertEqual(c.new_method(), 1.0)
+ def test_generic_dynamic(self):
+ T = TypeVar('T')
+
+ @dataclass
+ class Parent(Generic[T]):
+ x: T
+ Child = make_dataclass('Child', [('y', T), ('z', Optional[T], None)],
+ bases=(Parent[int], Generic[T]), namespace={'other': 42})
+ self.assertIs(Child[int](1, 2).z, None)
+ self.assertEqual(Child[int](1, 2, 3).z, 3)
+ self.assertEqual(Child[int](1, 2, 3).other, 42)
+ # Check that type aliases work correctly.
+ Alias = Child[T]
+ self.assertEqual(Alias[int](1, 2).x, 1)
+ # Check MRO resolution.
+ self.assertEqual(Child.__mro__, (Child, Parent, Generic, object))
+
def test_helper_replace(self):
@dataclass(frozen=True)
class C: