Code Monkey home page Code Monkey logo

Comments (5)

jcrist avatar jcrist commented on June 5, 2024

However, this has the downside that when I am programmatically constructing an instance of this struct, it will no longer fail fast if I've forgotten one of the arguments. I want to be sure that as new fields are added to this struct, I'm not forgetting to add them in my code in other places.

That's an interesting use case. What about using a custom classmethod as a constructor in the places where you always want to explicitly set each field? Something like:

from __future__ import annotations

import msgspec


class Demo(msgspec.Struct):
    field_one: int | None = None
    field_two: int | None = None
    field_three: int | None = None

    @classmethod
    def new(cls, *, field_one: int, field_two: int, field_three: int) -> Demo:
        return cls(field_one, field_two, field_three)


# elsewhere in your code...
demo = Demo.new(field_one=1, field_two=2, field_three=3)
print(demo)
#> Demo(field_one=1, field_two=2, field_three=3)

# any locations where you forgot to add `field_three` would then error
Demo.new(field_one=1, field_two=2)

When adding a new field to the struct you'd need to remember to also add it to the classmethod, but the close proximity of the two should help you remember. Heck you could even enforce these align with a check at import time via a __init_subclass__ hook if you wanted to (I'm happy to provide an example if this interests you). IMO this is a nice low-tech solution to a code hygiene problem.


Add an omit_none option

This also might make sense, but would obviously take more work on my end.

As a meta conversation, I'm now wondering if options like this or omit_defaults should be set per-call to encode (or on the Encoder once) rather than on the type. The logic being that sometimes you might want to encode the full model and sometimes you might want a more compact representation - but these attributes are more specific to the call site than to the type being represented?

from msgspec.

HansBrende avatar HansBrende commented on June 5, 2024

@jcrist actually, I already have the class method you speak of, and by "other places in my code" I was referring to this one class method 😆

The __init_subclass__ hook you mention would be interesting indeed, would love to see that example! Provided it adds minimal overhead (I'm instantiating millions of these quite often) I think that could work. All I need is a basic fail-fast sanity check to make sure I'm populating all fields (previously accomplished very smoothly simply by not having defaults set).

I agree with your meta comment... it seems like that would provide more flexibility. Although, for my own use-cases (currently) I personally do not need multiple flavors of serialization. I could see how it would be annoying though if I at some point in the future needed to serialize two different ways.

One possible downside I could see is that to generate the "schema" correctly you'd need to also supply the encoder you use to serialize... as the schema might also depend on encoder arguments. But on the other hand, maybe that is not a downside at all. I think something similar happened in pydantic recently (as far as needing additional arguments to generate schema properly), because FastAPI now generates potentially two different schemas... one "deserialization" schema, and one "serialization" schema... as what is required vs. not changes depending on whether reading or writing.

from msgspec.

mishamsk avatar mishamsk commented on June 5, 2024

@jcrist

As a meta conversation, I'm now wondering if options like this or omit_defaults should be set per-call to encode (or on the Encoder once) rather than on the type

as in #549 (my reply here) - I'd say ideal is for the class-based parameter to define a default, but also provide a way to override it in the encoder. But if this is too much work, encoder seems like the best option as it has no downsides but gives finer control.

from msgspec.

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.