omlish 0.0.0.dev161__py3-none-any.whl → 0.0.0.dev163__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. omlish/.manifests.json +228 -0
  2. omlish/__about__.py +2 -2
  3. omlish/asyncs/bluelet/LICENSE +6 -0
  4. omlish/asyncs/bluelet/__init__.py +0 -0
  5. omlish/asyncs/bluelet/all.py +67 -0
  6. omlish/asyncs/bluelet/api.py +23 -0
  7. omlish/asyncs/bluelet/core.py +178 -0
  8. omlish/asyncs/bluelet/events.py +78 -0
  9. omlish/asyncs/bluelet/files.py +80 -0
  10. omlish/asyncs/bluelet/runner.py +416 -0
  11. omlish/asyncs/bluelet/sockets.py +214 -0
  12. omlish/codecs/__init__.py +69 -0
  13. omlish/codecs/base.py +102 -0
  14. omlish/codecs/bytes.py +119 -0
  15. omlish/codecs/chain.py +23 -0
  16. omlish/codecs/funcs.py +28 -0
  17. omlish/codecs/registry.py +139 -0
  18. omlish/codecs/standard.py +4 -0
  19. omlish/codecs/text.py +217 -0
  20. omlish/formats/cbor.py +31 -0
  21. omlish/formats/codecs.py +93 -0
  22. omlish/formats/json/codecs.py +33 -0
  23. omlish/formats/json5.py +31 -0
  24. omlish/formats/pickle.py +31 -0
  25. omlish/formats/toml.py +17 -0
  26. omlish/formats/yaml.py +18 -0
  27. omlish/io/compress/brotli.py +15 -1
  28. omlish/io/compress/bz2.py +14 -0
  29. omlish/io/compress/codecs.py +58 -0
  30. omlish/io/compress/gzip.py +11 -0
  31. omlish/io/compress/lz4.py +14 -0
  32. omlish/io/compress/lzma.py +14 -0
  33. omlish/io/compress/snappy.py +14 -0
  34. omlish/io/compress/zlib.py +14 -0
  35. omlish/io/compress/zstd.py +14 -0
  36. omlish/lang/__init__.py +1 -0
  37. omlish/lang/functions.py +11 -0
  38. omlish/lite/inject.py +16 -29
  39. omlish/manifests/load.py +44 -6
  40. {omlish-0.0.0.dev161.dist-info → omlish-0.0.0.dev163.dist-info}/METADATA +1 -1
  41. {omlish-0.0.0.dev161.dist-info → omlish-0.0.0.dev163.dist-info}/RECORD +45 -21
  42. {omlish-0.0.0.dev161.dist-info → omlish-0.0.0.dev163.dist-info}/LICENSE +0 -0
  43. {omlish-0.0.0.dev161.dist-info → omlish-0.0.0.dev163.dist-info}/WHEEL +0 -0
  44. {omlish-0.0.0.dev161.dist-info → omlish-0.0.0.dev163.dist-info}/entry_points.txt +0 -0
  45. {omlish-0.0.0.dev161.dist-info → omlish-0.0.0.dev163.dist-info}/top_level.txt +0 -0
omlish/codecs/base.py ADDED
@@ -0,0 +1,102 @@
1
+ """
2
+ TODO:
3
+ - bytes-like - bytearray, memoryview
4
+ """
5
+ import abc
6
+ import typing as ta
7
+
8
+ from omlish import check
9
+ from omlish import dataclasses as dc
10
+ from omlish import lang
11
+ from omlish import reflect as rfl
12
+
13
+
14
+ I = ta.TypeVar('I')
15
+ O = ta.TypeVar('O')
16
+
17
+
18
+ ##
19
+
20
+
21
+ class EagerCodec(lang.Abstract, ta.Generic[I, O]):
22
+ @abc.abstractmethod
23
+ def encode(self, i: I) -> O:
24
+ raise NotImplementedError
25
+
26
+ @abc.abstractmethod
27
+ def decode(self, o: O) -> I:
28
+ raise NotImplementedError
29
+
30
+
31
+ class IncrementalCodec(lang.Abstract, ta.Generic[I, O]):
32
+ @abc.abstractmethod
33
+ def encode_incremental(self) -> ta.Generator[O | None, I, None]:
34
+ raise NotImplementedError
35
+
36
+ @abc.abstractmethod
37
+ def decode_incremental(self) -> ta.Generator[I | None, O, None]:
38
+ raise NotImplementedError
39
+
40
+
41
+ class ComboCodec( # noqa
42
+ EagerCodec[I, O],
43
+ IncrementalCodec[I, O],
44
+ lang.Abstract,
45
+ ta.Generic[I, O],
46
+ ):
47
+ pass
48
+
49
+
50
+ ##
51
+
52
+
53
+ def check_codec_name(s: str) -> str:
54
+ check.non_empty_str(s)
55
+ check.not_in('_', s)
56
+ check.equal(s.strip(), s)
57
+ return s
58
+
59
+
60
+ ##
61
+
62
+
63
+ @dc.dataclass(frozen=True, kw_only=True)
64
+ class Codec:
65
+ name: str = dc.xfield(coerce=check_codec_name)
66
+ aliases: ta.Collection[str] | None = dc.xfield(
67
+ default=None,
68
+ coerce=lang.opt_fn(lambda s: [check_codec_name(a) for a in s]), # type: ignore
69
+ )
70
+
71
+ input: rfl.Type = dc.xfield(coerce=rfl.type_)
72
+ output: rfl.Type = dc.xfield(coerce=rfl.type_)
73
+
74
+ options: type | None = None
75
+
76
+ new: ta.Callable[..., EagerCodec]
77
+ new_incremental: ta.Callable[..., IncrementalCodec] | None = None
78
+
79
+
80
+ ##
81
+
82
+
83
+ @dc.dataclass(frozen=True, kw_only=True)
84
+ class LazyLoadedCodec:
85
+ mod_name: str
86
+ attr_name: str
87
+ name: str
88
+ aliases: ta.Collection[str] | None = None
89
+
90
+ @classmethod
91
+ def new(
92
+ cls,
93
+ mod_name: str,
94
+ attr_name: str,
95
+ codec: Codec,
96
+ ) -> 'LazyLoadedCodec':
97
+ return cls(
98
+ mod_name=mod_name,
99
+ attr_name=attr_name,
100
+ name=codec.name,
101
+ aliases=codec.aliases,
102
+ )
omlish/codecs/bytes.py ADDED
@@ -0,0 +1,119 @@
1
+ """
2
+ TODO:
3
+ - options / kwargs
4
+ """
5
+ import base64
6
+ import binascii
7
+ import typing as ta
8
+
9
+ from .. import check
10
+ from .base import Codec
11
+ from .funcs import FnPairEagerCodec
12
+ from .standard import STANDARD_CODECS
13
+
14
+
15
+ ##
16
+
17
+
18
+ class BytesCodec(Codec):
19
+ pass
20
+
21
+
22
+ def make_bytes_encoding_codec(
23
+ name: str,
24
+ aliases: ta.Collection[str] | None,
25
+ encode: ta.Callable[[bytes], bytes],
26
+ decode: ta.Callable[[bytes], bytes],
27
+ *,
28
+ append_to: ta.MutableSequence[Codec] | None = None,
29
+ ) -> BytesCodec:
30
+ codec = BytesCodec(
31
+ name=name,
32
+ aliases=check.not_isinstance(aliases, str),
33
+
34
+ input=bytes,
35
+ output=bytes,
36
+
37
+ new=lambda: FnPairEagerCodec.of(encode, decode),
38
+ )
39
+
40
+ if append_to is not None:
41
+ append_to.append(codec)
42
+
43
+ return codec
44
+
45
+
46
+ ##
47
+
48
+
49
+ ASCII85 = make_bytes_encoding_codec(
50
+ 'ascii85',
51
+ ['a85'],
52
+ base64.a85encode,
53
+ base64.a85decode,
54
+ append_to=STANDARD_CODECS,
55
+ )
56
+
57
+ BASE16 = make_bytes_encoding_codec(
58
+ 'base16',
59
+ ['b16'],
60
+ base64.b16encode,
61
+ base64.b16decode,
62
+ append_to=STANDARD_CODECS,
63
+ )
64
+
65
+ BASE32 = make_bytes_encoding_codec(
66
+ 'base32',
67
+ ['b32'],
68
+ base64.b32encode,
69
+ base64.b32decode,
70
+ append_to=STANDARD_CODECS,
71
+ )
72
+
73
+ BASE64 = make_bytes_encoding_codec(
74
+ 'base64',
75
+ ['b64'],
76
+ base64.b64encode,
77
+ base64.b64decode,
78
+ append_to=STANDARD_CODECS,
79
+ )
80
+
81
+ BASE85 = make_bytes_encoding_codec(
82
+ 'base85',
83
+ ['b85'],
84
+ base64.b85encode,
85
+ base64.b85decode,
86
+ append_to=STANDARD_CODECS,
87
+ )
88
+
89
+ BASE32_HEX = make_bytes_encoding_codec(
90
+ 'base32-hex',
91
+ ['b32-hex'],
92
+ base64.b32hexencode,
93
+ base64.b32hexdecode,
94
+ append_to=STANDARD_CODECS,
95
+ )
96
+
97
+ BASE64_HEX = make_bytes_encoding_codec(
98
+ 'base64-hex',
99
+ ['b64-hex'],
100
+ base64.standard_b64encode,
101
+ base64.standard_b64decode,
102
+ append_to=STANDARD_CODECS,
103
+ )
104
+
105
+ BASE64_URLSAFE = make_bytes_encoding_codec(
106
+ 'base64-urlsafe',
107
+ ['b64-urlsafe'],
108
+ base64.urlsafe_b64encode,
109
+ base64.urlsafe_b64decode,
110
+ append_to=STANDARD_CODECS,
111
+ )
112
+
113
+ HEX = make_bytes_encoding_codec(
114
+ 'hex',
115
+ [],
116
+ binascii.b2a_hex,
117
+ binascii.a2b_hex,
118
+ append_to=STANDARD_CODECS,
119
+ )
omlish/codecs/chain.py ADDED
@@ -0,0 +1,23 @@
1
+ import dataclasses as dc
2
+ import typing as ta
3
+
4
+ from .base import EagerCodec
5
+
6
+
7
+ @dc.dataclass(frozen=True)
8
+ class ChainEagerCodec(EagerCodec[ta.Any, ta.Any]):
9
+ codecs: ta.Sequence[EagerCodec]
10
+
11
+ def encode(self, v: ta.Any) -> ta.Any:
12
+ for c in self.codecs:
13
+ v = c.encode(v)
14
+ return v
15
+
16
+ def decode(self, v: ta.Any) -> ta.Any:
17
+ for c in reversed(self.codecs):
18
+ v = c.decode(v)
19
+ return v
20
+
21
+
22
+ def chain(*codecs: EagerCodec) -> ChainEagerCodec:
23
+ return ChainEagerCodec(codecs)
omlish/codecs/funcs.py ADDED
@@ -0,0 +1,28 @@
1
+ import dataclasses as dc
2
+ import typing as ta
3
+
4
+ from ..funcs import pairs as fps
5
+ from .base import EagerCodec
6
+
7
+
8
+ I = ta.TypeVar('I')
9
+ O = ta.TypeVar('O')
10
+
11
+
12
+ @dc.dataclass(frozen=True)
13
+ class FnPairEagerCodec(EagerCodec[I, O]):
14
+ fp: fps.FnPair[I, O]
15
+
16
+ def encode(self, i: I) -> O:
17
+ return self.fp.forward(i)
18
+
19
+ def decode(self, o: O) -> I:
20
+ return self.fp.backward(o)
21
+
22
+ @classmethod
23
+ def of(
24
+ cls,
25
+ encode: ta.Callable[[I], O],
26
+ decode: ta.Callable[[O], I],
27
+ ) -> 'FnPairEagerCodec[I, O]':
28
+ return cls(fps.of(encode, decode))
@@ -0,0 +1,139 @@
1
+ import contextlib
2
+ import importlib
3
+ import threading
4
+ import typing as ta
5
+
6
+ from .. import cached
7
+ from .. import check
8
+ from .. import lang
9
+ from .base import Codec
10
+ from .base import LazyLoadedCodec
11
+ from .standard import STANDARD_CODECS
12
+
13
+
14
+ if ta.TYPE_CHECKING:
15
+ from ..manifests import load as manifest_load
16
+ else:
17
+ manifest_load = lang.proxy_import('..manifests.load', __package__)
18
+
19
+
20
+ ##
21
+
22
+
23
+ class CodecRegistry:
24
+ def __init__(
25
+ self,
26
+ *,
27
+ late_load_callbacks: ta.Iterable[ta.Callable[['CodecRegistry'], None]] | None = None,
28
+ ) -> None:
29
+ super().__init__()
30
+
31
+ self._late_load_callbacks = late_load_callbacks
32
+
33
+ self._lock = threading.RLock()
34
+ self._by_name: dict[str, Codec | LazyLoadedCodec] = {}
35
+ self._names_by_alias: dict[str, str] = {}
36
+ self._names_by_cls: dict[type, list[str]] = {}
37
+
38
+ def _late_load(self) -> None:
39
+ if self._late_load_callbacks:
40
+ for cb in self._late_load_callbacks:
41
+ cb(self)
42
+ self._late_load_callbacks = None
43
+
44
+ @contextlib.contextmanager
45
+ def _lock_and_load(self) -> ta.Iterator[None]:
46
+ with self._lock:
47
+ self._late_load()
48
+ yield
49
+
50
+ def _post_load(self, codec: Codec) -> None:
51
+ for t in type(codec).__mro__:
52
+ if t is not object:
53
+ self._names_by_cls.setdefault(t, []).append(codec.name)
54
+
55
+ def register(self, *codecs: Codec | LazyLoadedCodec) -> ta.Self:
56
+ with self._lock:
57
+ for codec in codecs:
58
+ for n in {codec.name, *(codec.aliases or [])}:
59
+ if n in self._names_by_alias:
60
+ raise KeyError(n)
61
+
62
+ for codec in codecs:
63
+ self._by_name[codec.name] = codec
64
+ for n in {codec.name, *(codec.aliases or [])}:
65
+ self._names_by_alias[n] = codec.name
66
+ if isinstance(codec, Codec):
67
+ self._post_load(codec)
68
+
69
+ return self
70
+
71
+ def lookup(self, name_or_alias: str) -> Codec:
72
+ with self._lock_and_load():
73
+ name = self._names_by_alias[name_or_alias.replace('_', '-')]
74
+ codec_or_lazy = self._by_name[name]
75
+
76
+ if isinstance(codec_or_lazy, LazyLoadedCodec):
77
+ mod = importlib.import_module(codec_or_lazy.mod_name)
78
+ codec = check.isinstance(getattr(mod, codec_or_lazy.attr_name), Codec)
79
+ self._by_name[name] = codec
80
+ self._post_load(codec)
81
+ else:
82
+ codec = check.isinstance(codec_or_lazy, Codec)
83
+
84
+ return codec
85
+
86
+ def lookup_type(self, cls: type) -> list[Codec]:
87
+ with self._lock_and_load():
88
+ return [self.lookup(n) for n in self._names_by_cls.get(cls, [])]
89
+
90
+ def all(self) -> frozenset[str]:
91
+ with self._lock_and_load():
92
+ return frozenset(self._by_name)
93
+
94
+
95
+ ##
96
+
97
+
98
+ def _install_standard_codecs(registry: CodecRegistry) -> None:
99
+ registry.register(*STANDARD_CODECS)
100
+
101
+
102
+ ##
103
+
104
+
105
+ @cached.function
106
+ def _build_manifest_lazy_loaded_codecs() -> ta.Sequence[LazyLoadedCodec]:
107
+ ldr = manifest_load.MANIFEST_LOADER
108
+ pkgs = {__package__.split('.')[0], *ldr.discover()}
109
+ mns = ldr.load(*pkgs, only=[LazyLoadedCodec])
110
+ return [m.value for m in mns]
111
+
112
+
113
+ def _install_manifest_lazy_loaded_codecs(registry: CodecRegistry) -> None:
114
+ registry.register(*_build_manifest_lazy_loaded_codecs())
115
+
116
+
117
+ ##
118
+
119
+
120
+ REGISTRY = CodecRegistry(
121
+ late_load_callbacks=[
122
+ _install_standard_codecs,
123
+ _install_manifest_lazy_loaded_codecs,
124
+ ],
125
+ )
126
+
127
+ register = REGISTRY.register
128
+ lookup = REGISTRY.lookup
129
+
130
+
131
+ ##
132
+
133
+
134
+ def encode(i: ta.Any, name: str, **kwargs: ta.Any) -> ta.Any:
135
+ return lookup(name).new(**kwargs).encode(i)
136
+
137
+
138
+ def decode(o: ta.Any, name: str, **kwargs: ta.Any) -> ta.Any:
139
+ return lookup(name).new(**kwargs).decode(o)
@@ -0,0 +1,4 @@
1
+ from .base import Codec
2
+
3
+
4
+ STANDARD_CODECS: list[Codec] = []
omlish/codecs/text.py ADDED
@@ -0,0 +1,217 @@
1
+ import codecs
2
+ import dataclasses as dc
3
+ import functools
4
+ import typing as ta
5
+
6
+ from omlish import check
7
+
8
+ from .base import Codec
9
+ from .base import ComboCodec
10
+ from .standard import STANDARD_CODECS
11
+
12
+
13
+ ##
14
+
15
+
16
+ TextEncodingErrors: ta.TypeAlias = ta.Literal[
17
+ # Raise UnicodeError (or a subclass), this is the default. Implemented in strict_errors().
18
+ 'strict',
19
+
20
+ # Ignore the malformed data and continue without further notice. Implemented in ignore_errors().
21
+ 'ignore',
22
+
23
+ # Replace with a replacement marker. On encoding, use ? (ASCII character). On decoding, use � (U+FFFD, the official
24
+ # REPLACEMENT CHARACTER). Implemented in replace_errors().
25
+ 'replace',
26
+
27
+ # Replace with backslashed escape sequences. On encoding, use hexadecimal form of Unicode code point with formats
28
+ # \xhh \uxxxx \Uxxxxxxxx. On decoding, use hexadecimal form of byte value with format \xhh. Implemented in
29
+ # backslashreplace_errors().
30
+ 'backslashreplace',
31
+
32
+ # On decoding, replace byte with individual surrogate code ranging from U+DC80 to U+DCFF. This code will then be
33
+ # turned back into the same byte when the 'surrogateescape' error handler is used when encoding the data. (See PEP
34
+ # 383 for more.)
35
+ 'surrogateescape',
36
+
37
+ ##
38
+ # The following error handlers are only applicable to encoding (within text encodings):
39
+
40
+ # Replace with XML/HTML numeric character reference, which is a decimal form of Unicode code point with format
41
+ # &#num;. Implemented in xmlcharrefreplace_errors().
42
+ 'xmlcharrefreplace',
43
+
44
+ # Replace with \N{...} escape sequences, what appears in the braces is the Name property from Unicode Character
45
+ # Database. Implemented in namereplace_errors().
46
+ 'namereplace',
47
+
48
+ ##
49
+ # In addition, the following error handler is specific to the given codecs:
50
+ # utf-8, utf-16, utf-32, utf-16-be, utf-16-le, utf-32-be, utf-32-le
51
+
52
+ # Allow encoding and decoding surrogate code point (U+D800 - U+DFFF) as normal code point. Otherwise these codecs
53
+ # treat the presence of surrogate code point in str as an error.
54
+ 'surrogatepass',
55
+ ]
56
+
57
+
58
+ @dc.dataclass(frozen=True, kw_only=True)
59
+ class TextEncodingOptions:
60
+ errors: TextEncodingErrors = 'strict'
61
+
62
+
63
+ ##
64
+
65
+
66
+ class TextEncodingComboCodec(ComboCodec[str, bytes]):
67
+ def __init__(
68
+ self,
69
+ info: codecs.CodecInfo,
70
+ options: TextEncodingOptions = TextEncodingOptions(),
71
+ ) -> None:
72
+ super().__init__()
73
+ self._info = check.isinstance(info, codecs.CodecInfo)
74
+ self._opts = check.isinstance(options, TextEncodingOptions)
75
+
76
+ @classmethod
77
+ def lookup(
78
+ cls,
79
+ name: str,
80
+ options: TextEncodingOptions = TextEncodingOptions(),
81
+ ) -> 'TextEncodingComboCodec':
82
+ return cls(codecs.lookup(name), options)
83
+
84
+ def encode(self, i: str) -> bytes:
85
+ o, _ = self._info.encode(i, self._opts.errors)
86
+ return o
87
+
88
+ def decode(self, o: bytes) -> str:
89
+ i, _ = self._info.decode(o, self._opts.errors)
90
+ return i
91
+
92
+ def encode_incremental(self) -> ta.Generator[bytes | None, str, None]:
93
+ x = self._info.incrementalencoder(self._opts.errors)
94
+ i = yield None
95
+ while True:
96
+ if not i:
97
+ break
98
+ o = x.encode(i)
99
+ i = yield o or None
100
+ o = x.encode(i, final=True)
101
+ yield o
102
+
103
+ def decode_incremental(self) -> ta.Generator[str | None, bytes, None]:
104
+ x = self._info.incrementaldecoder(self._opts.errors)
105
+ i = yield None
106
+ while True:
107
+ if not i:
108
+ break
109
+ o = x.decode(i)
110
+ i = yield o or None
111
+ o = x.decode(i, final=True)
112
+ yield o
113
+
114
+
115
+ ##
116
+
117
+
118
+ class TextEncodingCodec(Codec):
119
+ pass
120
+
121
+
122
+ def normalize_text_encoding_name(s: str) -> str:
123
+ if ' ' in s:
124
+ raise NameError(s)
125
+ return s.lower().replace('_', '-')
126
+
127
+
128
+ def make_text_encoding_codec(
129
+ name: str,
130
+ aliases: ta.Collection[str] | None = None,
131
+ *,
132
+ append_to: ta.MutableSequence[Codec] | None = None,
133
+ ) -> TextEncodingCodec:
134
+ codec = TextEncodingCodec(
135
+ name=check.equal(name, normalize_text_encoding_name(name)),
136
+ aliases=check.not_isinstance(aliases, str),
137
+
138
+ input=str,
139
+ output=bytes,
140
+
141
+ new=functools.partial(TextEncodingComboCodec.lookup, name),
142
+ new_incremental=functools.partial(TextEncodingComboCodec.lookup, name),
143
+ )
144
+
145
+ if append_to is not None:
146
+ append_to.append(codec)
147
+
148
+ return codec
149
+
150
+
151
+ ##
152
+
153
+
154
+ ASCII = make_text_encoding_codec(
155
+ 'ascii',
156
+ ['646', 'us-ascii'],
157
+ append_to=STANDARD_CODECS,
158
+ )
159
+
160
+ LATIN1 = make_text_encoding_codec(
161
+ 'latin-1',
162
+ ['iso-8859-1', 'iso8859-1', '8859', 'cp819', 'latin', 'latin1', 'l1'],
163
+ append_to=STANDARD_CODECS,
164
+ )
165
+
166
+ UTF32 = make_text_encoding_codec(
167
+ 'utf-32',
168
+ ['u32', 'utf32'],
169
+ append_to=STANDARD_CODECS,
170
+ )
171
+
172
+ UTF32BE = make_text_encoding_codec(
173
+ 'utf-32-be',
174
+ ['utf-32be'],
175
+ append_to=STANDARD_CODECS,
176
+ )
177
+
178
+ UTF32LE = make_text_encoding_codec(
179
+ 'utf-32-le',
180
+ ['utf-32le'],
181
+ append_to=STANDARD_CODECS,
182
+ )
183
+
184
+ UTF16 = make_text_encoding_codec(
185
+ 'utf-16',
186
+ ['u16', 'utf16'],
187
+ append_to=STANDARD_CODECS,
188
+ )
189
+
190
+ UTF16BE = make_text_encoding_codec(
191
+ 'utf-16-be',
192
+ ['utf-16be'],
193
+ append_to=STANDARD_CODECS,
194
+ )
195
+
196
+ UTF16LE = make_text_encoding_codec(
197
+ 'utf-16-le',
198
+ ['utf-16le'],
199
+ append_to=STANDARD_CODECS,
200
+ )
201
+
202
+ UTF7 = make_text_encoding_codec(
203
+ 'utf-7',
204
+ ['u7', 'unicode-1-1-utf-7'],
205
+ append_to=STANDARD_CODECS,
206
+ )
207
+
208
+ UTF8 = make_text_encoding_codec(
209
+ 'utf-8',
210
+ ['u8', 'utf', 'utf8', 'cp65001'],
211
+ append_to=STANDARD_CODECS,
212
+ )
213
+
214
+ UTF8SIG = make_text_encoding_codec(
215
+ 'utf-8-sig',
216
+ append_to=STANDARD_CODECS,
217
+ )
omlish/formats/cbor.py ADDED
@@ -0,0 +1,31 @@
1
+ import typing as ta
2
+
3
+ from .. import lang
4
+ from .codecs import make_bytes_object_codec
5
+ from .codecs import make_object_lazy_loaded_codec
6
+
7
+
8
+ if ta.TYPE_CHECKING:
9
+ import cbor2
10
+ else:
11
+ cbor2 = lang.proxy_import('cbor2')
12
+
13
+
14
+ ##
15
+
16
+
17
+ def dump(obj: ta.Any) -> bytes:
18
+ return cbor2.dumps(obj)
19
+
20
+
21
+ def load(s: bytes) -> ta.Any:
22
+ return cbor2.loads(s)
23
+
24
+
25
+ ##
26
+
27
+
28
+ CBOR_CODEC = make_bytes_object_codec('cbor', dump, load)
29
+
30
+ # @omlish-manifest
31
+ _CBOR_LAZY_CODEC = make_object_lazy_loaded_codec(__name__, 'CBOR_CODEC', CBOR_CODEC)