GithubHelp home page GithubHelp logo

Comments (3)

Tinche avatar Tinche commented on June 17, 2024

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.

bvitaz-ck avatar bvitaz-ck commented on June 17, 2024

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.

Tinche avatar Tinche commented on June 17, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.