rnag / rnag/dataclass-wizard

[wiz-cli] the `wiz` tool shouldn't use any duplicate dataclass names

Open
#58 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug good first issue help wanted self-created
Dominant language
Python
Stars
250
Forks
36
PR merge metrics
No merged PRs in 30d

Description

  • Dataclass Wizard version: 0.22.1
  • Python version: 3.10
  • Operating System: Mac OS
Description

I found an interesting case where the wrong dataclass schema is generated with the wiz command-line tool. The schema is wrong insofar as that the same dataclass name - Ability in this case - is reused between generated dataclasses in a nested dataclass structure. This obviously won't allow us to actually load JSON data to the main dataclass Data, because the nested schema has a bug (duplicate name for dataclass) as indicated.

See output below for more details.

What I Did

I ran wiz gs from my terminal, with the following JSON data as input:

echo '{"id": 1,
"height": 7,
"name": "bulbasur",
"abilities": [
    {
      "ability": {
        "name": "overgrow",
        "url": "https://pokeapi.co/api/v2/ability/65/"
      },
      "is_hidden": false,
      "slot": 1
    },
    {
      "ability": {
        "name": "chlorophyll",
        "url": "https://pokeapi.co/api/v2/ability/34/"
      },
      "is_hidden": true,
      "slot": 3
    }
  ]
}' | wiz gs -x

The result generated the following nested dataclass schema:

from __future__ import annotations

from dataclasses import dataclass

from dataclass_wizard import JSONWizard


@dataclass
class Data(JSONWizard):
    """
    Data dataclass

    """
    id: int
    height: int
    name: str
    abilities: list[Ability]


@dataclass
class Ability:
    """
    Ability dataclass

    """
    ability: Ability
    is_hidden: bool
    slot: int


@dataclass
class Ability:
    """
    Ability dataclass

    """
    name: str
    url: str

As you can already see, the Ability dataclass name is duplicated. This results in the second class definition overwriting the previous one, which is what we would like to avoid in this case.

I've then tried the following Python code with the generated class schema above:

j = '{"id":1,"height":7,"name":"bulbasur","abilities":[{"ability":{"name":"overgrow","url":"https://pokeapi.co/api/v2/ability/65/"},"is_hidden":false,"slot":1},{"ability":{"name":"chlorophyll","url":"https://pokeapi.co/api/v2/ability/34/"},"is_hidden":true,"slot":3}]}'
instance = Data.from_json(j)

Which resulted in an error, as expected, since the second dataclass definition overwrites the first one:

  error: Ability.__init__() missing 2 required positional arguments: 'name' and 'url'

Renaming the second class to something else, for example Ability2, and then updating any references to it, then works as expected to load the JSON input data to a dataclass instance.

Resolution

One possible approach that comes to mind, is to keep a hashset of all generated class names - or better yet a dict mapping of class name to a count of its occurrences, or how many times we've seen it - maybe at the module or global scope, or perhaps recursively pass it in through each function in the generation process.

Then check if the class name we want to add is already in the mapping, and if so we add some random suffix (for example increment by the count of how many times we've already seen the class name) to the generated class name; if not, we use the generated class name as-is. In any case, we then increment the count of the class name in the mapping, to indicate that we've seen it previously.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the wiz gs command that generates nested dataclasses, using the Pokémon JSON example to reproduce the duplicate Ability definitions. Follow the generated schema through Data.from_json; done means nested dataclasses receive distinct names and the example loads without the overwrite error.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.