Comments (3)
Hi @Sanavesa
Deserialization of a dictionary to an object should be successful through any class in the hierarchy (including abstract classes) as long as the dictionary represents a concrete subclass that implements all abstract methods. This is expected to work because of the specified discriminator field that indicates the concrete subclass type.
Since you mentioned abstract classes in the context of inclusion, I assume you expect a concrete subclass to be used to deserialize any of its subclasses? What would you be expecting in the following case? An error or a Bar
instance? And if it's a second option, then how should we be able to validate that the incoming dictionary contains exactly the "foo" type?
from dataclasses import dataclass
from typing import Literal
from mashumaro import DataClassDictMixin
from mashumaro.config import BaseConfig
from mashumaro.types import Discriminator
@dataclass
class Base(DataClassDictMixin):
class Config(BaseConfig):
discriminator = Discriminator(field="type", include_subtypes=True)
@dataclass
class Foo(Base):
type: Literal["foo"] = "foo"
@dataclass
class Bar(Foo):
type: Literal["bar"] = "bar"
obj = Foo.from_dict({"type": "bar"}) # what to expect here?
from mashumaro.
In the code example provided, I noticed that type
is a Literal
. This raises a question: should validation or discrimination take precedence? I lean towards validation (and so does the current implementation), which means an error like mashumaro.exceptions.InvalidFieldValue: Field "type" of type Literal['foo'] in Foo has invalid value 'bar'
should occur. However, if type
were a str
(specifically, ClassVar[str]
), I'd then expect the output to be a Bar
instance instead.
Regarding class hierarchy and their subtype variants, each class seems to have its own lookup map (__mashumaro_subtype_variants__
) including itself (unless it's abstract) and its descendants. Given the hierarchy:
Base
/ \
Foo AbstractFoo
| |
Bar ConcreteBar
The expected lookup maps would be:
Base.__mashumaro_subtype_variants__ = {"foo": Foo, "bar": Bar, "concrete_bar": ConcreteBar}
Foo.__mashumaro_subtype_variants__ = {"foo": Foo, "bar": Bar}
Bar.__mashumaro_subtype_variants__ = {"bar": Bar}
AbstractFoo.__mashumaro_subtype_variants__ = {"concrete_bar": ConcreteBar}
ConcreteBar.__mashumaro_subtype_variants__ = {"concrete_bar": ConcreteBar}
In the from_dict()
method, it should first identify the discriminator field, check its value in the data dictionary, and then look it up in the __mashumaro_subtype_variants__
. If a matching class is found (and all fields are present), it should return data as that class. If not, it should raise a mashumaro.exceptions.SuitableVariantNotFoundError
.
What are your thoughts on this approach? Thank you for considering my feedback.
from mashumaro.
Sorry for being silent for a long time and thank you for the detailed answer. I like your proposal, however, its implementation may require heavy improvements.
Regarding class hierarchy and their subtype variants, each class seems to have its own lookup map (
__mashumaro_subtype_variants__
) including itself (unless it's abstract) and its descendants.
Unfortunately, this is not true in the current implementation. When a dataclass has a discriminator in its config, a map __mashumaro_subtype_variants__
is being created only for that dataclass. I dropped a note in README about this limitation:
The only difference is that you can't use
include_supertypes=True
because it would lead to a recursion error.
I see the following way to resolve this issue:
- Allow using
include_supertypes=True
along withinclude_subtypes=True
in class level discriminators. This can be done by generating two methods for the same class — the first one will search for a suitable class in__mashumaro_subtype_variants__
and the second one will be used for deserialization of the current class itself. - Add an optional flag to
Discriminator
that will enable propagation of discriminator settings to the subclasses.
With an existing workaround, I think this issue will have a low priority. However, if you or someone else can handle it, PR welcome.
from mashumaro.
Related Issues (20)
- The types defined inside the function result in syntactically invalid generated code
- Allow for more complex logic for subclass Discrimnator field matching HOT 3
- TypedDicts not working with `from __future__ import annotations` HOT 2
- omit_default breaks IntFlag serialization HOT 1
- Using Union with int/float casts to whichever appears first HOT 3
- Not parsing Generics correctly HOT 2
- Unserializable field in 3.12 if defined as a Generic TypeVar with mixin bounds HOT 6
- Reject extra keys on deserialization HOT 7
- Investigate support for recursive Union types HOT 2
- Supports `numpy.ndarray` type for `orjson` HOT 2
- Add support for PEP 695
- Union type of [int | float] not serialized correctly HOT 2
- Add an alternative way to assign a field alias with annotations
- Add support for PEP 696
- Annotated SerializationStrategy used as a field serialization strategy leads to RecursionError
- Suppress warning about Union type HOT 4
- Take description from docstring HOT 3
- Incorrect type annotation for the result of `to_json` in `DataClassORJSONMixin`
- Different results between standard library json and orjson
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from mashumaro.