Comments (3)
There's a way but it's somewhat complex so let me ask you a few questions first.
The type
field is a constant, right? You'd expect all instances of SpecialDevice
to have type
set to the value special
, right?
If that is true, maybe this is redundant information and instead of checking for device.type
you could check isinstance(device, SpecialDevice)
instead. Conceptually, at the Python level, the "tag" would be instance.__class__
(which the isinstance check would use).
A second easy approach you can take is turn your class into:
from typing import Literal
@attrs.define
class SpecialDevice:
hostname: str
port: int
type: Literal["special"] = "special"
Then cattrs will still remove the field from the payload, but there is a default on the class level so the value will still be set.
You can take this one step further an make it a class variable instead of an instance variable:
from typing import ClassVar, Literal
@attrs.define
class SpecialDevice:
hostname: str
port: int
type: ClassVar[Literal["special"]] = "special"
These change the data modeling strategy somewhat so let me know if they work for you, if not we can consider different solutions.
from cattrs.
Thank you for your response. You're correct that the type
field is a constant that the application uses to determine which type of device to instantiate, but the constant is a descriptive name like "trio", "bosch", or "vimba". All of the devices up to this point only require the configuration provided by a StandardDevice, and a new device requires additional fields. If I understand your recommendation, I would set up a data class for each device type to compare the data class instance or add a literal value to specify the type name. I will consider that and I can see that there are benefits to specific data classes for each type of device.
If this is not possible to keep the value of the "type" field when using the key for configure_tagged_union
, I can look into using JSON schema validation for the configuration file to validate that the necessary settings exist and cattrs will use the correct data class type. Ideally for my case, the tagged key's field would remain in the payload so it can be used, but I can see why the removal can be a good idea in certain circumstances.
from cattrs.
Ok, so the problem is that the tagged_union
strategy deletes the type
key out. If you want to keep the key in the payload, we can apply some good old function composition (i.e. wrapping functions). This is what cattrs is all about ;)
First, we change the tag name to _type
instead of type
:
configure_tagged_union(
Device, c, tag_name="_type", tag_generator=tag_generator, default=StandardDevice
)
That way, the strategy will pop out _type
and leave us with type
.
Now, we need to actually copy type
into _type
.
First, we'll fetch the function the strategy generated for us. Then, we just wrap this function in our own function, and register that on the converter.
base_hook = c._union_struct_registry[Device]
def our_hook(value, _):
value["_type"] = value["type"]
return base_hook(value, _)
c.register_structure_hook(Device, our_hook)
And now structuring should work.
I think I'll rework how some of this works internally so this process will be cleaner in the next version of cattrs (you won't have to use an internal registry).
from cattrs.
Related Issues (20)
- Structure failed with `typing_extensions.Any` HOT 3
- Constructor selection for structuring HOT 7
- Tagged Union: How to do structure/unstructure hook(s) for particular member type? HOT 4
- A dictionary gets structured into a list without errors/warnings HOT 2
- Question: Correct use of converters HOT 3
- Documentation does not explain unstruct_collection_overrides' input HOT 4
- Detailed validation exception groups with hook errors HOT 2
- cattrs effectively disables attrs validation HOT 3
- Covert to defaultdict instead of plain dict HOT 4
- How to recursively unstructure with hooks? HOT 5
- Dataclass structuring fails with misleading error message.
- Default field conversion conflicts with user-defined field converter function HOT 3
- [macOS] Error when trying to run tests: `ImportError: cannot import name 'CodecOptions' from 'bson'` HOT 2
- How to hook into structuring of a simple dict? HOT 6
- Incorrect dispatch in Python 3.12 HOT 4
- Why does structuring of datetime in attrs class need a structure hook? HOT 1
- `prefer_attrib_converters` doesn't work when the field is aliased HOT 2
- Register structure hook only for optional types HOT 2
- TYPE_CHECKING and init=False HOT 5
- Problem with tagged union example HOT 3
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 cattrs.