Skip to content

Commit a12b008

Browse files
authored
Merge pull request #525 from pikers/msgspec_struct_updates
`msgspec` struct derivative updates
2 parents a65910c + ae8358a commit a12b008

1 file changed

Lines changed: 52 additions & 37 deletions

File tree

piker/data/types.py

Lines changed: 52 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# piker: trading gear for hackers
2-
# Copyright (C) Guillermo Rodriguez (in stewardship for piker0)
2+
# Copyright (C) (in stewardship for pikers)
3+
# - Tyler Goodlet
4+
# - Guillermo Rodriguez
35

46
# This program is free software: you can redistribute it and/or modify
57
# it under the terms of the GNU Affero General Public License as published by
@@ -14,18 +16,22 @@
1416
# You should have received a copy of the GNU Affero General Public License
1517
# along with this program. If not, see <https://www.gnu.org/licenses/>.
1618

17-
"""
18-
Built-in (extension) types.
19+
'''
20+
Extensions to built-in or (heavily used but 3rd party) friend-lib
21+
types.
1922
20-
"""
21-
import sys
23+
'''
2224
from pprint import pformat
2325

24-
import msgspec
26+
from msgspec import (
27+
msgpack,
28+
Struct,
29+
structs,
30+
)
2531

2632

2733
class Struct(
28-
msgspec.Struct,
34+
Struct,
2935

3036
# https://jcristharif.com/msgspec/structs.html#tagged-unions
3137
# tag='pikerstruct',
@@ -36,22 +42,14 @@ class Struct(
3642
3743
'''
3844
def to_dict(self) -> dict:
39-
return {
40-
f: getattr(self, f)
41-
for f in self.__struct_fields__
42-
}
43-
44-
# Lul, doesn't seem to work that well..
45-
# def __repr__(self):
46-
# # only turn on pprint when we detect a python REPL
47-
# # at runtime B)
48-
# if (
49-
# hasattr(sys, 'ps1')
50-
# # TODO: check if we're in pdb
51-
# ):
52-
# return self.pformat()
53-
54-
# return super().__repr__()
45+
'''
46+
Like it sounds.. direct delegation to:
47+
https://jcristharif.com/msgspec/api.html#msgspec.structs.asdict
48+
49+
TODO: probably just drop this method since it's now a built-int method?
50+
51+
'''
52+
return structs.asdict(self)
5553

5654
def pformat(self) -> str:
5755
return f'Struct({pformat(self.to_dict())})'
@@ -60,30 +58,47 @@ def copy(
6058
self,
6159
update: dict | None = None,
6260

63-
) -> msgspec.Struct:
61+
) -> Struct:
6462
'''
65-
Validate-typecast all self defined fields, return a copy of us
66-
with all such fields.
63+
Validate-typecast all self defined fields, return a copy of
64+
us with all such fields.
6765
68-
This is kinda like the default behaviour in `pydantic.BaseModel`.
66+
NOTE: This is kinda like the default behaviour in
67+
`pydantic.BaseModel` except a copy of the object is
68+
returned making it compat with `frozen=True`.
6969
7070
'''
7171
if update:
7272
for k, v in update.items():
7373
setattr(self, k, v)
7474

75-
# roundtrip serialize to validate
76-
return msgspec.msgpack.Decoder(
77-
type=type(self)
78-
).decode(
79-
msgspec.msgpack.Encoder().encode(self)
75+
# NOTE: roundtrip serialize to validate
76+
# - enode to msgpack binary format,
77+
# - decode that back to a struct.
78+
return msgpack.Decoder(type=type(self)).decode(
79+
msgpack.Encoder().encode(self)
8080
)
8181

82-
# NOTE XXX: this won't work on frozen types!
83-
# use ``.copy()`` above in such cases.
8482
def typecast(
8583
self,
86-
# fields: list[str] | None = None,
84+
85+
# TODO: allow only casting a named subset?
86+
# fields: set[str] | None = None,
87+
8788
) -> None:
88-
for fname, ftype in self.__annotations__.items():
89-
setattr(self, fname, ftype(getattr(self, fname)))
89+
'''
90+
Cast all fields using their declared type annotations
91+
(kinda like what `pydantic` does by default).
92+
93+
NOTE: this of course won't work on frozen types, use
94+
``.copy()`` above in such cases.
95+
96+
'''
97+
# https://jcristharif.com/msgspec/api.html#msgspec.structs.fields
98+
fi: structs.FieldInfo
99+
for fi in structs.fields(self):
100+
setattr(
101+
self,
102+
fi.name,
103+
fi.type(getattr(self, fi.name)),
104+
)

0 commit comments

Comments
 (0)