Skip to content

Commit f0a84dd

Browse files
committed
Fix type vars order when Generic is in bases
1 parent e6894ef commit f0a84dd

3 files changed

Lines changed: 55 additions & 4 deletions

File tree

mashumaro/core/meta/helpers.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -551,11 +551,17 @@ def resolve_type_params(
551551
result = {typ: resolved_type_params}
552552
type_params = []
553553

554+
# According to the docs, if Generic[...] is present, then the order
555+
# of variables is always determined by their order in Generic[...]
554556
for base in get_orig_bases(typ):
555-
base_type_params = collect_type_params(base)
556-
for type_param in base_type_params:
557-
if type_param not in type_params:
558-
type_params.append(type_param)
557+
if get_type_origin(base) is typing.Generic:
558+
type_params = list(collect_type_params(base))
559+
if not type_params:
560+
for base in get_orig_bases(typ):
561+
base_type_params = collect_type_params(base)
562+
for type_param in base_type_params:
563+
if type_param not in type_params:
564+
type_params.append(type_param)
559565

560566
_check_generic(typ, type_params, type_args)
561567

tests/test_generics.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
T = TypeVar("T")
1313
S = TypeVar("S")
14+
K = TypeVar("K")
1415
P = TypeVar("P", Mapping[int, int], List[float])
1516

1617

@@ -279,3 +280,25 @@ class Config(BaseConfig):
279280
fieldD=A(field=1.2), fieldC=B(fieldB=A(field=2)), fieldB=A(field=2)
280281
)
281282
assert D.from_dict(obj.to_dict()) == obj
283+
284+
285+
def test_vars_order_when_generic_presented_in_bases() -> None:
286+
@dataclass
287+
class Base(DataClassDictMixin, Generic[T]):
288+
kind: str = "base"
289+
290+
class NotSerializable:
291+
pass
292+
293+
@dataclass
294+
class Extended(Base[K], Generic[S, K]):
295+
payload: S | None = None
296+
297+
@dataclass
298+
class Sub(Extended[Base, NotSerializable]):
299+
pass
300+
301+
assert Sub(payload=Base()).to_dict() == {
302+
"kind": "base",
303+
"payload": {"kind": "base"},
304+
}

tests/test_generics_pep_695.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,3 +259,25 @@ def test_generic_serializable_type_getitem():
259259
class DataClass(DataClassDictMixin):
260260
# Simply specializing the type would lead to an AttributeError.
261261
x: GenericSerializableType[int]
262+
263+
264+
def test_vars_order_when_generic_presented_in_bases_pep_695() -> None:
265+
@dataclass
266+
class Base[T](DataClassDictMixin):
267+
kind: str = "base"
268+
269+
class NotSerializable:
270+
pass
271+
272+
@dataclass
273+
class Extended[S: Base, K](Base[K]):
274+
payload: S | None = None
275+
276+
@dataclass
277+
class Sub(Extended[Base, NotSerializable]):
278+
pass
279+
280+
assert Sub(payload=Base()).to_dict() == {
281+
"kind": "base",
282+
"payload": {"kind": "base"},
283+
}

0 commit comments

Comments
 (0)