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

Dicts with non-json keys (e.g. Enums) could be dumped more nicely. #140

Open
rupert-madden-abbott opened this issue Aug 3, 2021 · 3 comments
Labels
feature_request A request for a new feature that is not decided on yet

Comments

@rupert-madden-abbott
Copy link

Example

class WeekDay(Enum):
    MONDAY = "MONDAY"
    TUESDAY = "TUESDAY"
    WEDNESDAY = "WEDNESDAY"
    THURSDAY = "THURSDAY"
    FRIDAY = "FRIDAY"
    SATURDAY = "SATURDAY"
    SUNDAY = "SUNDAY"

example = {
  WeekDay.MONDAY: 10,
  WeekDay.SUNDAY: 1
}

jsons.dump(example)

Expected Output

{
  "MONDAY": 10,
  "SUNDAY": 1
}

Actual Output
The enum keys are hashed and the hashes are used in place of the actual keys whilst an additional "-keys" map is added with the hashes back to the original values.

@swissguest
Copy link

I have a similar scenario (mixed value types only for experimentation).

class WeekDay(Enum):
    MONDAY = "MON"
    TUESDAY = 2
    WEDNESDAY = 3
    THURSDAY = 4
    FRIDAY = 5
    SATURDAY = 6
    SUNDAY = 7

example: Dict[WeekDay, int]
example = {
    WeekDay.MONDAY: 10,
    WeekDay.SUNDAY: 1
}

print(example)
dumped = jsons.dumps(example, strict=True, use_enum_name=False)
print(dumped)

deserialized = jsons.loads(dumped, Dict[WeekDay, int], use_enum_name=False)
print(deserialized)

De-serialization of the serialized form does work as expected:

{<WeekDay.MONDAY: 'MON'>: 10, <WeekDay.SUNDAY: 7>: 1}
{"-keys": {"6161275848482540713": "MON", "7973924388498358727": 7}, "6161275848482540713": 10, "7973924388498358727": 1}
{<WeekDay.MONDAY: 'MON'>: 10, <WeekDay.SUNDAY: 7>: 1}

Admittedly, the serialized form of a dict with Enum keys does look a little odd. But it seems they need to make sure the keys are valid types for Python's JSON. Search the code for "if not any(issubclass(type(key), json_key) for json_key in JSON_KEYS)".

I think you should rephrase the issue's title into "A dict with Enum keys serialized representation does not look the way I like". This way, you can argue the beauty of the representation (along the lines "readability counts", compatibility with external systems, use of de-serialization libs other than JSON). But for as long as you want to dump into JSON format, you need to make sure that the keys are of acceptable types.

@rupert-madden-abbott
Copy link
Author

@swissguest

Admittedly, the serialized form of a dict with Enum keys does look a little odd. But it seems they need to make sure the keys are valid types for Python's JSON.

Why is that? Enums are serialised to strings when they are not dict keys.

@ramonhagenaars
Copy link
Owner

I think swissguest answered it nicely. 💐

Python allows more types as keys in dicts than json allows keys in objects. As you know, anything that is hashable in Python can be used as a key in a dict, whereas json allows only strings, integers, floats, booleans or null.

jsons uses the object's hash to still be able to dump dicts with keys that would not be valid in json. Enumerations are no exception to this, that's why you get the output you described.

I'm not against making an exception for enumerations though, as I agree that your expected outcome would be nicer to read. However, it would encompass also featuring a new argument to the load function. Because upon loading, you would need to somehow tell jsons to load the keys of the source into your enum. Something like this:

jsons.load(dumped, cls=SomeClass, key_cls=SomeEnum)

@ramonhagenaars ramonhagenaars added the feature_request A request for a new feature that is not decided on yet label Oct 7, 2021
@ramonhagenaars ramonhagenaars changed the title A dict with enum keys is not deserialized as expected Dicts with non-json keys (e.g. Enums) could be dumped more nicely. Oct 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature_request A request for a new feature that is not decided on yet
Projects
None yet
Development

No branches or pull requests

3 participants