Commit 5a7092de authored by Ivan Levkivskyi's avatar Ivan Levkivskyi Committed by GitHub

Allow dynamic creation of generic dataclasses (GH-6319)

parent 233de021
...@@ -1004,7 +1004,9 @@ def make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True, ...@@ -1004,7 +1004,9 @@ def make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True,
anns[name] = tp anns[name] = tp
namespace['__annotations__'] = anns 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, return dataclass(cls, init=init, repr=repr, eq=eq, order=order,
unsafe_hash=unsafe_hash, frozen=frozen) unsafe_hash=unsafe_hash, frozen=frozen)
......
...@@ -8,7 +8,7 @@ import pickle ...@@ -8,7 +8,7 @@ import pickle
import inspect import inspect
import unittest import unittest
from unittest.mock import Mock 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 collections import deque, OrderedDict, namedtuple
from functools import total_ordering from functools import total_ordering
...@@ -1690,6 +1690,23 @@ class TestCase(unittest.TestCase): ...@@ -1690,6 +1690,23 @@ class TestCase(unittest.TestCase):
c = Alias(10, 1.0) c = Alias(10, 1.0)
self.assertEqual(c.new_method(), 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): def test_helper_replace(self):
@dataclass(frozen=True) @dataclass(frozen=True)
class C: class C:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment