Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about JsonSerializable.json method #173

Open
nightan42643 opened this issue Jun 15, 2022 · 2 comments
Open

Question about JsonSerializable.json method #173

nightan42643 opened this issue Jun 15, 2022 · 2 comments

Comments

@nightan42643
Copy link

nightan42643 commented Jun 15, 2022

Hey

When I defined a dataclass as a subclass of JsonSerializable, I can access its json method. But json method returns an object

@dataclass
class Person(JsonSerializable
                .with_dump(key_transformer=KEY_TRANSFORMER_CAMELCASE)
                .with_load(key_transformer=KEY_TRANSFORMER_SNAKECASE)):
    first_name: str
    last_name: str

arno = Person('Arno','Y')
arno_json = arno.json

arno_json is an object that lint thinks. If I want let lint think it is a dict, I need to ...

if isinstance(arno_json, dict):
    print(arno_json.keys())

I am not sure if my understanding was correct: If I use JsonSerializable like above, I mean create a subclass of it. In this case, the object json returned always is a dict? But I must do an isInstance judgment, it looks a little weird.

Is it possible to let the json method return a dict not an object

@nightan42643 nightan42643 changed the title Question about JsonSerializable.json method Question about JsonSerializable.json method #question Jun 15, 2022
@nightan42643 nightan42643 changed the title Question about JsonSerializable.json method #question Question about JsonSerializable.json method Jun 15, 2022
@ramonhagenaars
Copy link
Owner

Hi @nightan42643,

The reason for .json to return an object and not a dict is a bit theoretical. One could be writing a class that is not to be represented as a dict when turned into json, for example a custom collection class:

class MyCollection(list, JsonSerializable):
    ...

c = MyCollection((1, 2, 3))
c.json  # <-- this results in a list, not a dict.

MyCollection could not override .json to hint the right type (list instead of dict) as that would be a violation of the Liskov Substitution Principle. But since JsonSerializable hints .json as returning an object, it is possible to override and hint list (or dict in your case) since that is a subtype of object. Liskov can rest assured.

In your case, you could override as follows:

@dataclass
class Person(JsonSerializable
                .with_dump(key_transformer=KEY_TRANSFORMER_CAMELCASE)
                .with_load(key_transformer=KEY_TRANSFORMER_SNAKECASE)):
    first_name: str
    last_name: str

    @property
    def json(self) -> dict[str, str]:
        return JsonSerializable.json.fget(self)

Or maybe even like this:

@dataclass
class Person(JsonSerializable
                .with_dump(key_transformer=KEY_TRANSFORMER_CAMELCASE)
                .with_load(key_transformer=KEY_TRANSFORMER_SNAKECASE)):
    first_name: str
    last_name: str

    json: dict[str, str] = field(init=False, repr=False, compare=False)

Alternatively, you could use typing.cast:

arno_json = typing.cast(dict[str, str], arno.json)

I hope this helps.

@nightan42643
Copy link
Author

@ramonhagenaars Very clear, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants