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` in a class decorator

thejcannon opened this issue · comments

Not unlike #188, however the calling code is in a class decorator trying to do interesting things on top of the schema

Version: 8.5.10

import dataclasses
from typing import List

from marshmallow_dataclass import class_schema


def class_dec(cls):
    class_schema(cls)

    return cls

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

The above leads to NameError: name 'Tree' is not defined


Workaround is to manually stamp out the decorator:

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

Tree = class_dec(Tree)

The issue is that, when class_dec calls class_schema, Tree is not yet accessible via the global (module) namespace. That doesn't happen until just after the class decorators are applied.

I suppose we could special-case the self-referential case: have class_schema look a the name of the class, so that self-type-references would work.
That seems pretty hacky though, and it still wouldn't fix the case where forward type references are involved, e.g.:

@class_dec
@dataclasses.dataclass
class Tree:
    name: str
    children: "Children"

@dataclass
class Children:
    trees: List[Tree]

I'm thinking the is probably not fixable (or not worth fixing). The solution, in your case, might be to have the class decorator defer its call to class_schema as long as possible. (Hopefully, until after the module is fully loaded.)

(The marshmallow_dataclass.dataclass decorator does essentially this, by using a LazyClassAttribute descriptor to defer the computation of the dataclass' .Schema attribute.)

Closing. (Feel free to reopen, if you can come up with a clean way to fix this.)