-
Notifications
You must be signed in to change notification settings - Fork 40
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
Should dump be able to also pass class type to dictionary #14
Comments
Thanks Casparjespersen, for this issue. You make a clear point, I can see why you might want this. {
'foo': 42,
'bar': 24,
'__meta__': {
'type': 'B'
}
} Perhaps the |
I agree, something like that. Then we would only need to work out a way to get the class from the string in a safe manner. This is difficult to make portable and secure. From this post it appears one solution could be something using
However this is not portable at all, and only supports classes defined in the context in question. UpdateInspired by this answer on a different post, one approach could be to let the user input a dictionary mapping a string representation with instantiators:
Something like that perhaps :-) |
The challenge here will indeed be obtaining the jsons.announce_class(A) When writing this, I just realized that the upcoming @dataclass
class A:
foo: int
@dataclass
class B(A):
bar: int
jsons.load({'foo': 123, 'bar': 456}, Union[A, B], strict=True) This would result in: B(foo=123, bar=456) |
@ramonhagenaars Do you have some documentation on, or can you briefly explain, how the Union operator is going to work? How will it decide which one to use? What would it output in case |
For Unions, So in the case of: jsons.load({'foo': 123, 'bar': 456}, Union[A, B]) It will attempt By default, However, you can run So if you instead wrote: jsons.load({'foo': 123, 'bar': 456}, Union[A, B], strict=True) It would result in an instance of Remember that both the |
Right. So that also means one would be able to achieve what I am asking for by under the following condition:
I think this is definitely something, but I also like the aforementioned idea of having a specific map, using some type of global announcing as you mentioned with
|
Yes, as I understand it, this is achievable under that condition. But:
That's not entirely true, because "deeper" classes do not necessarily need additional required parameters; less required parameters would work as well. I would rephrase your sentence to something like:
I agree with you on that, it would be a nice feature. I think I will put it on my TODO list. :-) |
It should also work in a nested structure:
The above should output:
|
Or should it? In your example, the There are some pros and cons for using the nested/not-nested approach. These are what I could think of:
Can you think of more pros/cons? And what do you think is preffered? |
Consider this example:
Here you can only deserialized Bar fully if you have the nested class structure. |
I see. We'll need the nested approach to make it work with inheritance. |
Just a few loose comments to this discussion:
|
Excellent additions, cypreess! To summarize what we've come up so far and what I'm considering, assume having the following classes: @dataclass
class Foo():
my_field: str
@dataclass
class Bar():
foo: Foo You can then announce those classes to ensure that jsons knows those classes: jsons.announce_class(Foo)
jsons.announce_class(Bar) Jsons dumps the class name using its fully qualified name, so you can choose to omit announcing the class and "hope" that jsons can import the correct class using that meta information in the dump. It raises an error upon failure with a hint to use You can specify that you want to have meta information in the dumps. I'm thinking of naming that parameter "verbose". So: jsons.dump(Bar, verbose=True) There are now three options I am considering for the output. The first looks somthing like this: {
"-meta": {
"cls": "my_package.my_module.Bar"
},
"foo": {
"-meta": {
"cls": "my_package.my_module.Foo"
},
"my_field": "hello"
}
} The second option also has nested meta info, but only the "root" object holds the common meta information: {
"-meta": {
"cls": "my_package.my_module.Bar",
"protocol": "1.0",
"serialization_time": "2019-03-07T08:49:00Z"
},
"foo": {
"-cls": "my_package.my_module.Foo",
"my_field": "hello"
}
} The third option I could think of looks something like this: {
"-meta": {
"classes": {
"/": "my_package.my_module.Bar",
"/foo": "my_package.my_module.Foo"
},
"protocol": "1.0",
"serialization_time": "2019-03-07T08:49:00Z"
},
"foo": {
"my_field": "hello"
}
} The third option stores its meta information in the root object only. |
I prefer options 2 and 3 - with option 3 a slight favorite. It is much cleaner in a deep nested structure, and the only downside is that you will not be able to extract a child-part of the object and deserialize it, since you would throw away the metadata. I think this is a fair tradeoff. |
Say I have a class inheritance structure, and I want to generically be able to dump/load with the correct class types in the inheritance structure.
Assume that when loading, I do now know which class type it was dumped from. I would have to analyse the content to determine which class to load as, and then pass this to the
cls
property ofjsons.load
method.Would it make sense to implement an optional flag when dumping to a dictionary that contains information of what class type it was dumped as, that can then be used for loading?
The text was updated successfully, but these errors were encountered: