dataclass-wizard icon indicating copy to clipboard operation
dataclass-wizard copied to clipboard

dataclass-wizard only use the inner class name in nested classes, and cause problem in nested classes.

Open wanmeihuali opened this issue 1 year ago • 1 comments

  • Dataclass Wizard version: 0.22.3
  • Python version: 3.8
  • Operating System: ubuntu20

Description

I'm trying to have to use data class-wizard for config, and I have some code like:

class A:
    @dataclass
    class Config(JSONWizard):
        name: str = "A"
        x: int = 0
        y: int = 0

    def __init__(self, config: Config):
        self.config = config

class B:
    @dataclass
    class Config(JSONWizard):
        name: str = "A"
        x: int = 0
        z: int = 0

    def __init__(self, config: Config):
        self.config = config


@dataclass
class ConfigC(JSONWizard):
    class Meta(JSONWizard.Meta):
        tag_key = 'type'
        auto_assign_tags = True
    sub_config: A.Config | B.Config = field(default_factory=A.Config)
    sub_name: str = "A"


config = ConfigC(sub_config=A.Config())
new_config = ConfigC.from_json(config.to_json())
assert isinstance(new_config.sub_config, A.Config) # <----------- assert fails
print(config.to_json()) # '{"subConfig": {"name": "A", "x": 0, "y": 0, "type": "Config"}, "subName": "A"}'

And it turns out that dataclass-wizard only use the inner class name in nested classes. Is this issue fixed in later version?

wanmeihuali avatar Jul 23 '24 22:07 wanmeihuali

@wanmeihuali Thanks for opening the issue. I didn't even think about nested classes and that they could be used in Union types. Can you expand on your use case?

Also, does it work if you manually assign tags, instead of auto_assign_tags Meta field? I tested below example and got the correct/intended result:

from dataclasses import dataclass, field

from dataclass_wizard import JSONWizard


class A:
    @dataclass
    class Config(JSONWizard):
        class _(JSONWizard.Meta):
            tag = __qualname__  # or: 'A.Config'

        name: str = "A"
        x: int = 0
        y: int = 0

    def __init__(self, config: Config):
        self.config = config

class B:
    @dataclass
    class Config(JSONWizard):
        class _(JSONWizard.Meta):
            tag = __qualname__  # or: 'B.Config'

        name: str = "A"
        x: int = 0
        z: int = 0

    def __init__(self, config: Config):
        self.config = config


@dataclass
class ConfigC(JSONWizard):
    class Meta(JSONWizard.Meta):
        tag_key = 'type'
    sub_config: A.Config | B.Config = field(default_factory=A.Config)
    sub_name: str = "A"


config = ConfigC(sub_config=A.Config())
new_config = ConfigC.from_json(config.to_json())

print(repr(new_config.sub_config))
assert isinstance(new_config.sub_config, A.Config) # <----------- assert succeeds
print(config.to_json()) # '{"subConfig": {"name": "A", "x": 0, "y": 0, "type": "A.Config"}, "subName": "A"}'

rnag avatar Nov 24 '24 05:11 rnag