-
Notifications
You must be signed in to change notification settings - Fork 74
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
Support omitting Struct attributes from encoding/decoding #199
Comments
Yes please! I would like to cache some (expensive) computed values in my objects, but not serialize them. |
Thanks for the motivating use case (and apologies for the delayed response)! I hope to tackle this issue in the next few weeks before issuing a new release. Since you commented here - as a user, would you want omitted attributes to also be excluded from class Point(Struct):
x: int
y: int
_private_1: Omit[int]
_private_2: Omit[int] = 0 Should |
Honestly I haven't been using the constructors much (decoding from a web request, encoding to a disk cache, decoding from the disk cache) so I don't have a strong opinion. I guess given that the object is valid without those values, the constructor shouldn't require them, but it would be nice if you could include them. Also I would lean towards excluding attributes with leading underscores by default (without the Omit type), but I could see it being more annoying to have to include them if some API you're using has names like that. |
Ok, we finally have the internals setup to make this fairly straightforward to implement. First, I plan to call these "private" attributes, since that's effectively what they are. A private attribute won't be encoded or decoded, but will have space allocated on its respective struct. There are some open questions though. How should this be spelled?There are two places that field configuration like this can go: In the type annotation class Example(Struct):
x: int
y: Private[int]
z: Private[float] = 0.0 An option in class Example(Struct):
x: int
y: int = msgspec.field(private=True)
z: int = msgspec.field(default=0.0, private=True) The former I find a bit easier to read, but it adds some complications:
Right now I'm leaning towards the Should fields with leading underscores be private by default?Since we're providing a way to set whether a field is public/private explicitly, users can always override any default behavior chosen here. Since fields with leading underscores are usually treated as private in python by convention, I'm tempted to do so here as well. So the following would be equivalent: class Example1(Struct):
_field: int = 0 # private, since the leading underscore
class Example2(Struct):
_field: int = field(default=0, private=True) # explicitly private On the other hand, I'd expect most users to never need to define private fields, so maybe inferring private/public status from the field name itself is overreaching. Are private attributes excluded from
|
This would be of great use to my current project --- like IcyMidnight, we've got a cache that would be really pointless to encode. The current plan is to clear the cache before encoding, which will work as long as we remember to do it.
What happens if you do Additionally, automatically treating fields with a leading underscore as private would break backwards compatibility. I found a few examples of Structs with Really looking forward to this feature, I hope you have time to work on it soon. |
Adding a We can also use it to compute and store the path in that data structure because Structs aren't aware of their parent nodes. |
Hi. Any update on this? I'm confused whether the library has this attribute. |
If this is still up for debate, I concur that this is the right approach.
class Primitive(Struct):
iid: int = field(private=True) # internal ID, think auto-incrementing sequence meant to be private
eid: str = field(private=False) # external ID, some sort of public-exposed string identifier In this use case, the object when fetched from the DB would have both IDs so the application layer has them available. But, when serialized as an HTTP response, we strip out the private
Agreed.
This is a nice API 😎
See my comment above. I am not sold on this one. The two paramater approach makes more sense to me as they are different use cases. I am fine if
I guess I am okay with this, as long as I can still require it as an |
Would private fields also be excluded from |
I came here looking for this functionality so I can store some extra metadata on a Struct that I don't want to be serialized or part of the I'm envisaging an api where I can have an alternative constructer which can take optional (metadata) kwargs and store them on the struct without having them be included in the serialized representation - e.g. class MyStruct(msgspec.Struct, tag=True):
metadata: dict = field(default={}, private=True)
@classmethod
def create(cls, **kwargs) -> MyStruct:
instance = MyStruct()
instance.metadata.update(**kwargs)
return instance >>> obj = MyStruct.create(key='value')
>>> obj
MyStruct(metadata={'key': 'value'})
>>> msgspec.json.encode(obj)
b'{"type":"MyStruct"}'
>>> msgspec.json.decode(msgspec.json.encode(obj), type=MyStruct)
MyStruct(metadata={}) My actual use-case is a bit more complex but it boils down to wanting metadata associated with my objects but only for their lifetime in the current interpreter. |
Another example, of something I'd like to do is to attach an class MyStruct(msgspec.Struct, tag=True):
metadata: dict = field(default={})
fs: fsspec.AbstractFileSystem = field(private=True)
@classmethod
def create(cls, fs: fsspec.AbstractFileSystem, **kwargs) -> MyStruct:
instance = MyStruct()
instance.metadata.update(**kwargs)
instance.fs = fs
return instance
def save(self, filepath: str) -> None:
self.fs.write_bytes(
path=filepath,
value=msgspec.msgpack.encode(self),
)
|
Any updates on this? |
Since
Struct
types force users to declare allStruct
attributes, there's currently no way to hold extra state on aStruct
without having it also be encoded/decoded.Two ways to handle this:
omit=True
toMeta
annotations. This could also be packaged up as a parametrized type, so users could writejson
doesn't encode/decode private struct attributes by default.The text was updated successfully, but these errors were encountered: