lovasoa / marshmallow_dataclass

Automatic generation of marshmallow schemas from dataclasses.

Home Page:https://lovasoa.github.io/marshmallow_dataclass/html/marshmallow_dataclass.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

cyclic references break when using class_schema

noirbee opened this issue · comments

v8.5.4 sadly broke recursive / cyclic schema support:

import dataclasses
from typing import List

from marshmallow_dataclass import class_schema


@dataclasses.dataclass
class Tree:
    name: str
    children: List["Tree"]


class_schema(Tree)
[…]
  File "/home/nnoirbent/src/marshmallow_dataclass/marshmallow_dataclass/__init__.py", line 393, in _internal_class_schema
    attributes.update(
  File "/home/nnoirbent/src/marshmallow_dataclass/marshmallow_dataclass/__init__.py", line 396, in <genexpr>
    field_for_schema(
  File "/home/nnoirbent/src/marshmallow_dataclass/marshmallow_dataclass/__init__.py", line 686, in field_for_schema
    generic_field = _field_for_generic_type(typ, base_schema, typ_frame, **metadata)
  File "/home/nnoirbent/src/marshmallow_dataclass/marshmallow_dataclass/__init__.py", line 494, in _field_for_generic_type
    child_type = field_for_schema(
  File "/home/nnoirbent/src/marshmallow_dataclass/marshmallow_dataclass/__init__.py", line 718, in field_for_schema
    or _internal_class_schema(typ, base_schema, typ_frame)
  File "/home/nnoirbent/src/marshmallow_dataclass/marshmallow_dataclass/__init__.py", line 385, in _internal_class_schema
    for k, v in inspect.getmembers(clazz)
  File "/usr/lib/python3.10/inspect.py", line 447, in getmembers
    if isclass(object):
  File "/usr/lib/python3.10/inspect.py", line 197, in isclass
    return isinstance(object, type)
RecursionError: maximum recursion depth exceeded while calling a Python object

This is due to how marshmallow_dataclass now uses typing.get_type_hints() for better handling of forward references, since fac0b6d

Unfortunately the recursion guard from lazy_class_attribute only works when modifying the target class, i.e. with @marshmallow_dataclass.dataclass or @add_schema (which is triggered by this line:

nested_schema = getattr(typ, "Schema", None)
)

I'm not sure what's the best way to tackle this: adding a dict[class, forward_value] of "seen" classes to the various functions/helpers to avoid recursion ?

Yes, that should work

Just ran into this as well. Interestingly though using from dataclasses import dataclass:

from dataclasses import dataclass
from typing import List

from marshmallow_dataclass import class_schema


@dataclass
class Tree:
    name: str
    children: List["Tree"]


print(class_schema(Tree))

breaks with maximum recursion depth

however from marshmallow_dataclass import dataclass doesn't:

from marshmallow_dataclass import dataclass
from typing import List

from marshmallow_dataclass import class_schema


@dataclass
class Tree:
    name: str
    children: List["Tree"]


print(class_schema(Tree))

works fine with output of:

<class 'marshmallow.schema.Tree'>

Process finished with exit code 0

Another option is just to update everything to use from marshmallow_dataclass import dataclass instead of from dataclasses import dataclass?

@AleksanderPawlak , you may want to have a look