tmsgpack 0.3.24__tar.gz → 0.3.26__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tmsgpack-0.3.24/tmsgpack.egg-info → tmsgpack-0.3.26}/PKG-INFO +1 -1
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/pyproject.toml +1 -1
- tmsgpack-0.3.26/tests/test_codec.py +135 -0
- tmsgpack-0.3.26/tests/test_codec_custom.py +212 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack/codec.py +4 -8
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack/core.c +9 -9
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack/core.pyx +1 -1
- {tmsgpack-0.3.24 → tmsgpack-0.3.26/tmsgpack.egg-info}/PKG-INFO +1 -1
- tmsgpack-0.3.24/tests/test_codec.py +0 -197
- tmsgpack-0.3.24/tests/test_codec_custom.py +0 -240
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/MANIFEST.in +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/README.md +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/build_pyx.py +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/setup.cfg +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/setup.py +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tests/test_build_pyx.py +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tests/test_round_trip.py +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack/__init__.py +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack/api.py +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack/codec_custom.py +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack/src-parts/01-imports +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack/src-parts/02-constants +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack/src-parts/03-encode-fn +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack/src-parts/04-decode-fn +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack/src-parts/05-encode-buffer +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack/src-parts/06-decode-buffer +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack/src-parts/07-encode-buffer-slow +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack/src-parts/08-decode-buffer-slow +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack/src-parts/09-exceptions +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack.egg-info/SOURCES.txt +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack.egg-info/dependency_links.txt +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack.egg-info/requires.txt +0 -0
- {tmsgpack-0.3.24 → tmsgpack-0.3.26}/tmsgpack.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""Integration tests for TmsgpackCodec with DI and the dispatch system."""
|
|
2
|
+
|
|
3
|
+
import textwrap
|
|
4
|
+
import pytest
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from tmsgpack.codec import NoDependencyInjector, TmsgpackCodec
|
|
8
|
+
from semifun.dispatch.Inject import Inject, injected_type
|
|
9
|
+
from semifun.dispatch.SemifunApp import SemifunApp
|
|
10
|
+
from semifun.dispatch.load_lookup_tables import LoadedFn
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# --- Inline test types (no file scanning needed) ---
|
|
14
|
+
|
|
15
|
+
import enum
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
|
|
18
|
+
#::testing_tmsgpack_codec:FailureSeverity
|
|
19
|
+
class FailureSeverity(enum.IntEnum):
|
|
20
|
+
OK = 0
|
|
21
|
+
PROBLEM = 1
|
|
22
|
+
NOT_AUTHORIZED = 2
|
|
23
|
+
NOT_AUTHENTICATED = 3
|
|
24
|
+
UNEXPECTED = 4
|
|
25
|
+
|
|
26
|
+
@dataclass(frozen=True)
|
|
27
|
+
class Dbh:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
#::testing_tmsgpack_codec:Foo
|
|
31
|
+
@dataclass(frozen=True)
|
|
32
|
+
class Foo:
|
|
33
|
+
x: str
|
|
34
|
+
y: int
|
|
35
|
+
|
|
36
|
+
#::testing_tmsgpack_codec:Bar
|
|
37
|
+
@dataclass(frozen=True)
|
|
38
|
+
class Bar:
|
|
39
|
+
dbh: Inject[Dbh]
|
|
40
|
+
x: str
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# --- DI adapter for tests ---
|
|
44
|
+
|
|
45
|
+
@dataclass(frozen=True)
|
|
46
|
+
class _TestDiAdapter:
|
|
47
|
+
"""Test DI adapter satisfying DependencyInjectorProtocol."""
|
|
48
|
+
lookup_table: dict # {type_name: class}
|
|
49
|
+
seed_data: dict
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def injected_type(annotation):
|
|
53
|
+
return injected_type(annotation)
|
|
54
|
+
|
|
55
|
+
def lookup_type(self, type_name):
|
|
56
|
+
if type_name in self.lookup_table:
|
|
57
|
+
return self.lookup_table[type_name]
|
|
58
|
+
raise LookupError(f"No codec for {type_name}")
|
|
59
|
+
|
|
60
|
+
def with_seed_data(self, seed_data):
|
|
61
|
+
return _TestDiAdapter(lookup_table=self.lookup_table, seed_data={**self.seed_data, **seed_data})
|
|
62
|
+
|
|
63
|
+
def sync_call_with_args(self, *, fn, args, kwargs):
|
|
64
|
+
app = SemifunApp(entry_points_group={})
|
|
65
|
+
with app.open_sync_di_ctx(parent_ctx=None, seed_data=self.seed_data, ftype='test') as ctx:
|
|
66
|
+
return ctx.fn_call(fn=fn, args=args, kwargs=kwargs)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
LOOKUP_TABLE = {
|
|
70
|
+
'FailureSeverity': FailureSeverity,
|
|
71
|
+
'Foo': Foo,
|
|
72
|
+
'Bar': Bar,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@pytest.fixture
|
|
77
|
+
def codec():
|
|
78
|
+
di = _TestDiAdapter(lookup_table=LOOKUP_TABLE, seed_data={Dbh: Dbh()})
|
|
79
|
+
return TmsgpackCodec(sort_keys=False, di=di)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@pytest.fixture
|
|
83
|
+
def codec_no_di():
|
|
84
|
+
return TmsgpackCodec(sort_keys=False, di=NoDependencyInjector())
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# --- Round-trip: plain dataclass ---
|
|
88
|
+
|
|
89
|
+
def test_round_trip_dataclass(codec):
|
|
90
|
+
foo = Foo(x='hello', y=123)
|
|
91
|
+
assert codec.decode(codec.encode(foo)) == foo
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# --- Round-trip: enum ---
|
|
95
|
+
|
|
96
|
+
def test_round_trip_enum(codec):
|
|
97
|
+
for severity in FailureSeverity:
|
|
98
|
+
assert codec.decode(codec.encode(severity)) == severity
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# --- Round-trip: dataclass with Inject[T] fields ---
|
|
102
|
+
|
|
103
|
+
def test_round_trip_dataclass_with_inject(codec):
|
|
104
|
+
bar = Bar(dbh=Dbh(), x='world')
|
|
105
|
+
data = codec.encode(bar)
|
|
106
|
+
decoded = codec.decode(data)
|
|
107
|
+
assert decoded.x == 'world'
|
|
108
|
+
assert isinstance(decoded.dbh, Dbh)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
# --- NoDependencyInjector: plain types work without DI ---
|
|
112
|
+
|
|
113
|
+
def test_no_di_raises_on_lookup(codec_no_di):
|
|
114
|
+
foo = Foo(x='abc', y=42)
|
|
115
|
+
with pytest.raises(TypeError, match='Type lookup'):
|
|
116
|
+
codec_no_di.encode(foo)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# --- with_seed_data ---
|
|
120
|
+
|
|
121
|
+
def test_with_seed_data_round_trip(codec):
|
|
122
|
+
other_dbh = Dbh()
|
|
123
|
+
codec2 = codec.with_seed_data({Dbh: other_dbh})
|
|
124
|
+
bar = Bar(dbh=Dbh(), x='test')
|
|
125
|
+
decoded = codec2.decode(codec2.encode(bar))
|
|
126
|
+
assert decoded.x == 'test'
|
|
127
|
+
assert decoded.dbh is other_dbh
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# --- with_seed_data produces independent caches ---
|
|
131
|
+
|
|
132
|
+
def test_with_seed_data_has_independent_caches(codec):
|
|
133
|
+
codec2 = codec.with_seed_data({Dbh: Dbh()})
|
|
134
|
+
assert codec2.encoder_cache is not codec.encoder_cache
|
|
135
|
+
assert codec2.decoder_cache is not codec.decoder_cache
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""Tests for TmsgpackCustom: custom encode/decode for non-dataclass types."""
|
|
2
|
+
|
|
3
|
+
import struct
|
|
4
|
+
import pytest
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
from tmsgpack.codec import NoDependencyInjector, TmsgpackCodec
|
|
8
|
+
from tmsgpack.codec_custom import TmsgpackCustom
|
|
9
|
+
from semifun.dispatch.Inject import Inject, injected_type
|
|
10
|
+
from semifun.dispatch.SemifunApp import SemifunApp
|
|
11
|
+
from semifun.dispatch.load_lookup_tables import LoadedFn
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# --- Inline test types ---
|
|
15
|
+
|
|
16
|
+
class Pair:
|
|
17
|
+
def __init__(self, x, y):
|
|
18
|
+
self.x = x
|
|
19
|
+
self.y = y
|
|
20
|
+
def __eq__(self, other):
|
|
21
|
+
return type(other) is Pair and self.x == other.x and self.y == other.y
|
|
22
|
+
|
|
23
|
+
class Point:
|
|
24
|
+
def __init__(self, x, y):
|
|
25
|
+
self.x = x
|
|
26
|
+
self.y = y
|
|
27
|
+
def __eq__(self, other):
|
|
28
|
+
return type(other) is Point and self.x == other.x and self.y == other.y
|
|
29
|
+
|
|
30
|
+
class FloatPair:
|
|
31
|
+
def __init__(self, x, y):
|
|
32
|
+
self.x = x
|
|
33
|
+
self.y = y
|
|
34
|
+
def __eq__(self, other):
|
|
35
|
+
return (type(other) is FloatPair
|
|
36
|
+
and self.x == other.x and self.y == other.y)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# --- Custom codecs ---
|
|
40
|
+
|
|
41
|
+
class CodecPairDict(TmsgpackCustom):
|
|
42
|
+
def encode_dict(obj):
|
|
43
|
+
return {'x': obj.x, 'y': obj.y}
|
|
44
|
+
def decode_dict(*, x, y):
|
|
45
|
+
return Pair(x=x, y=y)
|
|
46
|
+
|
|
47
|
+
class CodecPointList(TmsgpackCustom):
|
|
48
|
+
def encode_list(obj):
|
|
49
|
+
return [obj.x, obj.y]
|
|
50
|
+
def decode_list(x, y):
|
|
51
|
+
return Point(x, y)
|
|
52
|
+
|
|
53
|
+
class CodecFloatPairBytes(TmsgpackCustom):
|
|
54
|
+
def encode_bytes(obj):
|
|
55
|
+
return struct.pack('<ff', obj.x, obj.y)
|
|
56
|
+
def decode_bytes(data):
|
|
57
|
+
x, y = struct.unpack('<ff', data)
|
|
58
|
+
return FloatPair(x, y)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# --- DI adapter for tests ---
|
|
62
|
+
|
|
63
|
+
@dataclass(frozen=True)
|
|
64
|
+
class _TestDiAdapter:
|
|
65
|
+
lookup_table: dict
|
|
66
|
+
seed_data: dict
|
|
67
|
+
|
|
68
|
+
@staticmethod
|
|
69
|
+
def injected_type(annotation):
|
|
70
|
+
return injected_type(annotation)
|
|
71
|
+
|
|
72
|
+
def lookup_type(self, type_name):
|
|
73
|
+
if type_name in self.lookup_table:
|
|
74
|
+
return self.lookup_table[type_name]
|
|
75
|
+
raise LookupError(f"No codec for {type_name}")
|
|
76
|
+
|
|
77
|
+
def with_seed_data(self, seed_data):
|
|
78
|
+
return _TestDiAdapter(lookup_table=self.lookup_table, seed_data={**self.seed_data, **seed_data})
|
|
79
|
+
|
|
80
|
+
def sync_call_with_args(self, *, fn, args, kwargs):
|
|
81
|
+
app = SemifunApp(entry_points_group={})
|
|
82
|
+
with app.open_sync_di_ctx(parent_ctx=None, seed_data=self.seed_data, ftype='test') as ctx:
|
|
83
|
+
return ctx.fn_call(fn=fn, args=args, kwargs=kwargs)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
LOOKUP_TABLE = {
|
|
87
|
+
'Pair': CodecPairDict,
|
|
88
|
+
'Point': CodecPointList,
|
|
89
|
+
'FloatPair': CodecFloatPairBytes,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@pytest.fixture
|
|
94
|
+
def codec():
|
|
95
|
+
di = _TestDiAdapter(lookup_table=LOOKUP_TABLE, seed_data={})
|
|
96
|
+
return TmsgpackCodec(sort_keys=False, di=di)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# --- Dict mode round-trip ---
|
|
100
|
+
|
|
101
|
+
def test_dict_mode_round_trip(codec):
|
|
102
|
+
pair = Pair(x='hello', y=42)
|
|
103
|
+
data = codec.encode(pair)
|
|
104
|
+
restored = codec.decode(data)
|
|
105
|
+
assert restored == pair
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# --- List mode round-trip ---
|
|
109
|
+
|
|
110
|
+
def test_list_mode_round_trip(codec):
|
|
111
|
+
point = Point(x=10, y=20)
|
|
112
|
+
data = codec.encode(point)
|
|
113
|
+
restored = codec.decode(data)
|
|
114
|
+
assert restored == point
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# --- Bytes mode round-trip ---
|
|
118
|
+
|
|
119
|
+
def test_bytes_mode_round_trip(codec):
|
|
120
|
+
fp = FloatPair(x=1.5, y=2.5)
|
|
121
|
+
data = codec.encode(fp)
|
|
122
|
+
restored = codec.decode(data)
|
|
123
|
+
assert restored == fp
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# --- Content hashing works with custom types ---
|
|
127
|
+
|
|
128
|
+
def test_content_hash_dict_mode(codec):
|
|
129
|
+
di = _TestDiAdapter(lookup_table=LOOKUP_TABLE, seed_data={})
|
|
130
|
+
codec_sorted = TmsgpackCodec(sort_keys=True, di=di)
|
|
131
|
+
pair = Pair(x='a', y=1)
|
|
132
|
+
h = codec_sorted.hash_to_str(pair)
|
|
133
|
+
assert isinstance(h, str)
|
|
134
|
+
assert len(h) == 22
|
|
135
|
+
# Same value, same hash
|
|
136
|
+
assert codec_sorted.hash_to_str(Pair(x='a', y=1)) == h
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# --- Nested values in custom types ---
|
|
140
|
+
|
|
141
|
+
def test_dict_mode_nested_values(codec):
|
|
142
|
+
pair = Pair(x=[1, 2, 3], y={'a': True})
|
|
143
|
+
data = codec.encode(pair)
|
|
144
|
+
restored = codec.decode(data)
|
|
145
|
+
assert restored == pair
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# --- Validation: mismatched modes ---
|
|
149
|
+
|
|
150
|
+
def test_mismatched_modes_raises():
|
|
151
|
+
with pytest.raises(TypeError, match="mode mismatch"):
|
|
152
|
+
class Bad(TmsgpackCustom):
|
|
153
|
+
def encode_dict(obj): return {}
|
|
154
|
+
def decode_list(x): return None
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def test_no_encode_raises():
|
|
158
|
+
with pytest.raises(TypeError, match="encode_dict, encode_list, encode_bytes"):
|
|
159
|
+
class Bad(TmsgpackCustom):
|
|
160
|
+
def decode_dict(*, x): return None
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def test_no_decode_raises():
|
|
164
|
+
with pytest.raises(TypeError, match="decode_dict, decode_list, decode_bytes"):
|
|
165
|
+
class Bad(TmsgpackCustom):
|
|
166
|
+
def encode_dict(obj): return {}
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
# --- DI on encode and decode ---
|
|
170
|
+
|
|
171
|
+
class Cache:
|
|
172
|
+
def __init__(self):
|
|
173
|
+
self.store = {}
|
|
174
|
+
def get(self, key):
|
|
175
|
+
return self.store[key]
|
|
176
|
+
def put(self, key, value):
|
|
177
|
+
self.store[key] = value
|
|
178
|
+
|
|
179
|
+
class Widget:
|
|
180
|
+
def __init__(self, name, data):
|
|
181
|
+
self.name = name
|
|
182
|
+
self.data = data
|
|
183
|
+
def __eq__(self, other):
|
|
184
|
+
return (type(other) is Widget
|
|
185
|
+
and self.name == other.name
|
|
186
|
+
and self.data == other.data)
|
|
187
|
+
|
|
188
|
+
class CodecWidget(TmsgpackCustom):
|
|
189
|
+
def encode_dict(obj, cache: Inject[Cache]):
|
|
190
|
+
cache.put(obj.name, obj.data)
|
|
191
|
+
return {'name': obj.name}
|
|
192
|
+
def decode_dict(*, name, cache: Inject[Cache]):
|
|
193
|
+
data = cache.get(name)
|
|
194
|
+
return Widget(name=name, data=data)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def test_di_on_encode_and_decode():
|
|
198
|
+
cache = Cache()
|
|
199
|
+
di = _TestDiAdapter(
|
|
200
|
+
lookup_table={'Widget': CodecWidget},
|
|
201
|
+
seed_data={Cache: cache},
|
|
202
|
+
)
|
|
203
|
+
codec = TmsgpackCodec(sort_keys=False, di=di)
|
|
204
|
+
|
|
205
|
+
widget = Widget(name='gizmo', data=[1, 2, 3])
|
|
206
|
+
data = codec.encode(widget)
|
|
207
|
+
|
|
208
|
+
# The cache was populated during encode
|
|
209
|
+
assert cache.store == {'gizmo': [1, 2, 3]}
|
|
210
|
+
|
|
211
|
+
restored = codec.decode(data)
|
|
212
|
+
assert restored == widget
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from base64 import urlsafe_b64encode
|
|
2
2
|
from dataclasses import dataclass, field, fields, is_dataclass, replace
|
|
3
3
|
from typing import Any, Protocol
|
|
4
|
-
from semifun.caching.cached_property import cached_property
|
|
5
4
|
|
|
6
5
|
import enum
|
|
7
6
|
from .api import EncodeDecode
|
|
@@ -11,6 +10,7 @@ from .codec_custom import TmsgpackCustom, make_codec_handler_custom
|
|
|
11
10
|
class DependencyInjectorProtocol(Protocol):
|
|
12
11
|
@staticmethod
|
|
13
12
|
def injected_type(annotation: Any) -> type | None: ...
|
|
13
|
+
def lookup_type(self, type_name: str) -> Any: ...
|
|
14
14
|
def with_seed_data(self, seed_data: dict) -> "DependencyInjectorProtocol": ...
|
|
15
15
|
def sync_call_with_args(self, *, fn: Any, args: tuple, kwargs: dict[str, Any]) -> Any: ...
|
|
16
16
|
|
|
@@ -20,6 +20,8 @@ class NoDependencyInjector:
|
|
|
20
20
|
@staticmethod
|
|
21
21
|
def injected_type(annotation):
|
|
22
22
|
return None
|
|
23
|
+
def lookup_type(self, type_name):
|
|
24
|
+
raise TypeError("Type lookup is not supported without a DependencyInjector")
|
|
23
25
|
def with_seed_data(self, seed_data):
|
|
24
26
|
raise TypeError("Dependency injection is not supported without a DependencyInjector")
|
|
25
27
|
def sync_call_with_args(self, *, fn, args, kwargs):
|
|
@@ -34,7 +36,6 @@ class TmsgpackCodec(EncodeDecode):
|
|
|
34
36
|
# `replace()` re-runs default_factory, giving each derived codec fresh caches.
|
|
35
37
|
encoder_cache: dict = field(default_factory=dict, init=False, repr=False)
|
|
36
38
|
decoder_cache: dict = field(default_factory=dict, init=False, repr=False)
|
|
37
|
-
plugin_feature_type: str
|
|
38
39
|
|
|
39
40
|
def with_seed_data(self, seed_data):
|
|
40
41
|
return replace(self, di=self.di.with_seed_data(seed_data))
|
|
@@ -73,16 +74,11 @@ class TmsgpackCodec(EncodeDecode):
|
|
|
73
74
|
codec_handler = self.decoder_cache[type_name]
|
|
74
75
|
return codec_handler.decode_dctx(dctx=dctx)
|
|
75
76
|
|
|
76
|
-
@cached_property
|
|
77
|
-
def feature_map(self):
|
|
78
|
-
from semifun.plugins.registry import get_cached_feature_map
|
|
79
|
-
return get_cached_feature_map(feature_type=self.plugin_feature_type)
|
|
80
|
-
|
|
81
77
|
def type_to_type_name(self, _type):
|
|
82
78
|
return _type.__name__
|
|
83
79
|
|
|
84
80
|
def type_name_to_codec_spec(self, type_name):
|
|
85
|
-
return self.
|
|
81
|
+
return self.di.lookup_type(type_name)
|
|
86
82
|
|
|
87
83
|
def codec_spec_to_codec_handler(self, codec_spec, type_name):
|
|
88
84
|
if isinstance(codec_spec, enum.EnumType):
|
|
@@ -3515,7 +3515,7 @@ static __pyx_mstatetype * const __pyx_mstate_global = &__pyx_mstate_global_stati
|
|
|
3515
3515
|
#endif
|
|
3516
3516
|
/* #### Code section: constant_name_defines ### */
|
|
3517
3517
|
#define __pyx_kp_u_tree_fragment __pyx_string_tab[0]
|
|
3518
|
-
#define
|
|
3518
|
+
#define __pyx_kp_u_0_3_26 __pyx_string_tab[1]
|
|
3519
3519
|
#define __pyx_kp_u_B __pyx_string_tab[2]
|
|
3520
3520
|
#define __pyx_kp_u_H __pyx_string_tab[3]
|
|
3521
3521
|
#define __pyx_kp_u_I __pyx_string_tab[4]
|
|
@@ -27280,11 +27280,11 @@ __Pyx_RefNannySetupContext("PyInit_core", 0);
|
|
|
27280
27280
|
/* "tmsgpack/core.pyx":4
|
|
27281
27281
|
* # DON'T EDIT THIS FILE. EDIT THE SOURCES, INSTEAD: tmsgpack/src-parts/[inserted by cython to avoid comment start]*
|
|
27282
27282
|
*
|
|
27283
|
-
* __version__ = "0.3.
|
|
27283
|
+
* __version__ = "0.3.26" # <<<<<<<<<<<<<<
|
|
27284
27284
|
*
|
|
27285
27285
|
* from libc.stdint cimport int8_t, int16_t, int32_t, int64_t
|
|
27286
27286
|
*/
|
|
27287
|
-
if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_version, __pyx_mstate_global->
|
|
27287
|
+
if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_version, __pyx_mstate_global->__pyx_kp_u_0_3_26) < (0)) __PYX_ERR(0, 4, __pyx_L1_error)
|
|
27288
27288
|
|
|
27289
27289
|
/* "tmsgpack/core.pyx":13
|
|
27290
27290
|
* ctypedef double float64_t
|
|
@@ -28889,7 +28889,7 @@ static int __Pyx_InitConstants(__pyx_mstatetype *__pyx_mstate) {
|
|
|
28889
28889
|
#define CYTHON_COMPRESS_STRINGS 90
|
|
28890
28890
|
#endif
|
|
28891
28891
|
#if (CYTHON_COMPRESS_STRINGS) == 3 && __PYX_LIMITED_VERSION_HEX >= 0x030e0000 /* compression: zstd (1723 bytes) */
|
|
28892
|
-
static const char cstring[] = "(\265/\375`.\021\2155\000zH\374\016E\
|
|
28892
|
+
static const char cstring[] = "(\265/\375`.\021\2155\000zH\374\016E\000\221\250\r\374?\337\273\377=\337\253\357=\225\240_\372U\307\327Tr\023\212\260\277\271%\221\310\362\\\335HRl\010\016/\000J;\2504\303\214\376\261\022\372!xpf\234\223\025f\034Ch\036S\001\250\305\321F\315\000\307\000\347\000\237\210\245\352\343\223\252p\2162?5\177[3M\223\221\305F\315+\335\\\2530\221%%\005\345$CtS\225\367\263\215\256\331\331\255\3708\346$\tO\321K\265hb\2524\253\226\276|[\2534\211\3578V\217y,\273h?j\3565f\373\305\315%~\260w\337\307J\237\243\271\0247\033\261c,\271Y\3128\342\237^\303o\324\252\214\241\225\320\t\213\026\026\261^\377I\357\343\370q\376\362z\211r\256ELc\2651\377\211\210/c>\272|\251\305\317]\2451\306\224m\365\370VEd\361\314\311T\254\3229kK\221\223&\3478\027\020\236\210\212bD\232\250$\"\211\\D&D!D*(\037\r\237\014\026\276:\312$\357\026\335\357W\010\377\216e\234\223\331+\311O9w\232\264\253\271\373\376\271\214\375\2422>M\217\231~e\347\267S\271\243duz\277zf/\2275+\337+\225(\374n\252y\2336\313l\2552\3136o\3612\256\"\373IG\310|,\262\354\332{[R\274l\322\205w\337\213W\253\342\276\317\352\331s\374\271\343\272\3742/\342\252\260\254-!\224\034B\001}\245+/-\267i\367\337q\226\315\317\365m\313!|\204c\031B\346\353>~\355\304p\232\2623a\324}\374\223j\217)\027\257\3358N\316\230\371I~d\301\376_)\313\236V:9IS\364\376I\2655k1\313|f\315o\226\305\347\262\214\266j\230NSuw\347J\022S-\037\035\257\221\007v\300\024,|\001S;\264_lh:44Z&\026\2115\302\002\205\270B:^\336\006pe\177\215\247\025h\004{d\267h\030\253\224\047\344\366\200\355\351\216>\320\361\"\351\021\2155\360\360\2606\204%@\020hac\373\303\nD\000\200\216\034\033\034\240\027\314\213\253\316\220\320\340\362\260P:^\236\275A\337\300\321\341\274F!(\\\001%\210\270D8\257\026$\327i\246C\353\203\225!\272\274\ra\024\302\000G \207\355\331 V\037\234\032V*\224\341\207\244/\254<8\257\r\016\3548k]\316\037\374\341\237\371\312\307\370\363Sv-~\307\033\3478\324\331\256\232\270\177\312a\224?}\031\327\334\035e\357\226e[.i\3634e\311\247\274\317\315\353\332\265\370c\351\254\037\226^\351g{\355\3140\245""\370z\n{\230\210\007Z\305E\210\022\"\010OX\250\002\372~\320\002\301q\221Z,\254\017eH\022\201\343\362\010\355\315F\201\225\314\032\227W\215\247\344\205\321\330\330\320|-\331\222\301bq\321\021bh\t\010\n,\000_\266IO\3200\253\002\243-\262m\224\320#3r\246\244\265iy\010_\200\246\216\366j(xZ6\010\006n>(l\017\217d\023@\021Ia\312\300VP\203\201&[\323$M\202\301\031\2400@\370\205Xh\002\302\354\222\321v\000\332\rFa\366l\006;\225\200\304\032\261DX\033\326\007\206`\350\024\266_\364Hg\031\252\344\356\020&\0107/<P\202\252\335b\217B@\241o\325f\306k\205t\302\024\217\202\3064\266\t\321\007@^#P\004T\331O\242[jP\237\004\047\200\030H`\004r@owv\212\226\372\304\n\244\343\265ay\341\tHbs\320\277\n\255\002\201x\250\241!rhDfDR\220\024\2440\034\341\014a\026:u\345\001B\221d\010q\2341D\031C \221#\222\nR\217Bs\264\026,\3104\356\356@\303&\010\030\267m\335\246I\326N\263\213\224\364\312 \243\345\301U:p\372y\023\033\216\241*9\262Q\200\034}\252\367;z8\254\203O\034#\217L\265B\314\034G+$\330\322}\235\327\001U\334L\254\244I\360\316\333\210\321iX\227\375\006\002\202\372h\016\000\204\234\246l@\332\374\014R\276r\304a\020\321r\302\004\366\023\"\207\300)\246\341`2\211|\354\373\335+t\311\010\205\307\352\310c\377p\235\201B\031\312\204\020\030\370\030L\357\025f\375\026\032\343{\264\321\200\367\237\227\333\t\344\324K\335h\347\366\322L\343\256K&\325b+n\367\211\245\211e\245;\335\0060H\203\326\341\215EK\232^\034,\347\013M\020\3664@\017;\310\365\023_`\234\3121TJQ\00759\212)dF\017\303bi\240\001\207\247$.l\240\317\021\304`AY\032\324\225\026j\260\345\336[\374\304\251U}\322\365~\250\n\200\222\245(E\224R\363\224\024\014U\306\005\253\030F\315E\270\325\324\227\032\005\360p-\334\033\212\177|\047\271X\304?\234(\323Jf\276\244\027>\2726\204\275\244\214rJa\250\\4\225\020}\360\313\326<F\207\314$\340f\250\335D\323\326\230$H<\262\341\356)\324\344-\243\324\250\313\227=\313~\0344\252\r4T\317\253\246\260\0000\307n\366\206\314\332\263>p\241\036pH\002\346Ih\237\376o\026e\242%\030\345j\013\252\367L\371B\320\206A\304\267\226\323\330.\267%""\213\273_\323\201\357\270\nG\213\370\235\036,i\304\202\331cD\r\223\271\251\036\017\326j\326\010N,*v\372\367\271\257F\345\366\260&|b\";\323o\214\336bs\322\214\277 *en\222\314\253w\263\263)\372(\224\031\305\016\230\006\2049\2361\367\332\r\245%X\370;\027O%D8p\215>A\2370\223\264\201\016@\352\274\272.2\226\316\257\037\000Su%\260\007#\306\354Q\245\250mY\002\320-RZ\210\235\261\226\352\216\"[\t\010\331\035\220\177\310\317\n\270\304}\\\251\330!Gk\212\017&U\324\322\00645\035\366\261jM\200\257\320\216UF\202\2479\2510\235\275\232\020\264\351\003hR/\276`\217T\013\tK\243\247Qy_^\336[\271\265\276<\342X\250\266\257\013\200\r\270\251YR2\251\356\344\"\237\330\317\204\352jg!W\243\341\275\017\344G\351I\225a?\335N\257\217z\247\261J\013\350\031_\"\203\3173 \047\324\023h\241\314\263\005\345\242\223]\350:\003\355\005]+#\344\247P\221T\001";
|
|
28893
28893
|
PyObject *data = __Pyx_DecompressString(cstring, 1723, 3);
|
|
28894
28894
|
#define __Pyx_DecompressString_LZSS_UNUSED
|
|
28895
28895
|
if (unlikely(!data)) __PYX_ERR(0, 1, __pyx_L1_error)
|
|
@@ -28897,9 +28897,9 @@ static const char cstring[] = "(\265/\375`.\021\2155\000zH\374\016E\360\222\250\
|
|
|
28897
28897
|
#if !CYTHON_ASSUME_SAFE_MACROS
|
|
28898
28898
|
if (likely(bytes)); else { Py_DECREF(data); __PYX_ERR(0, 1, __pyx_L1_error) }
|
|
28899
28899
|
#endif
|
|
28900
|
-
#elif (CYTHON_COMPRESS_STRINGS) == 1 /* compression: zlib (
|
|
28901
|
-
static const char cstring[] = "x\332\245W\315s\323F\024\257\247i\223\222\264\301$\224\351\007t\003e(\323\211K\202\003i\352\2261\020h:-%\020\240\037\007\315ZZ;j\224\225\255\335ub\246\007\216>\352\270G\035u\364\321\307\0349\346\350c\376\204\376\t}\273\262\024\331\226Z:\315\214\254\335\337{zo\367\367\336\276}\371\202{\204\240\272\207\033\373\204\362\3537J7K\253\
|
|
28902
|
-
PyObject *data = __Pyx_DecompressString(cstring,
|
|
28900
|
+
#elif (CYTHON_COMPRESS_STRINGS) == 1 /* compression: zlib (1739 bytes) */
|
|
28901
|
+
static const char cstring[] = "x\332\245W\315s\323F\024\257\247i\223\222\264\301$\224\351\007t\003e(\323\211K\202\003i\352\2261\020h:-%\020\240\037\007\315ZZ;j\224\225\255\335ub\246\007\216>\352\270G\035u\364\321\307\0349\346\350c\376\204\376\t}\273\262\024\331\226Z:\315\214\254\335\337{zo\367\367\336\276}\371\202{\204\240\272\207\033\373\204\362\3537J7K\253\267*w+\337W\266*\333\225Z\305\252\354V\354J\353\316\226\343\220\006vP\315u\035\202)jcG\220\r\364\310\345\210PW4v\221M\233\202#\013s\014 A|\027st\257\303w]\212l\206,\342\3305\342aN\234\016b\334\263MN<\245D\321\343\315\307\313\345\3652\302\324B\036\371\203\230\234!&j\246\203\031#\014\271uT\023\266\303m\212x\247IX\tm\325Q\307\025\210\022b!\356\242&\350\245?\340\273\204\"F\270\032\240k\230R\227cn\273\324\200\317m\332\270\206,\333\003\047v\233\250\257\037`\207\221\322\317M\323\265\010ra\007\340\317\303\264A\320\215\345\325\265\265\r\364\214Z\244nS\360\345j\245\r\204-\313\000\243\3042\371!\022L\255\342\3006II\317\0170C \324x\311\262\031\2569\204\214)\222\tEB\225^\303\264Y4\262\250\013\224\325\261p82\014\217X\302$\206\201,\241\327L]\272\014\024\266m\010\210a\2306\265\271\241V\204j\035N\330\006\342x\217\030z\214L\014\201\263P\335\365\220c3\256%\026\220\237\026hM-Q*\331\022\010\331\204\255}\326hbs\357+\323\365H\251\3319\274\213\031\271O\024GwE\275N\274\361y)\331\211\251\363\302024 p\340\221\377\203\216gE{\313\022\324\035\027\363\365,\211M\371J\016\276\232\203\227s\360L\373@P\026,\362\374\212<\307\"\317\263\210]o\322Q\216\323\363l\216\307429\036\321\301\354\224\343\021\301\201\227/8%\177\\\022\223\220\201\257\346\340\345\034<\323\376\220\374qX\344\371\025y\216E\236gM~:\"\321\370\036?L\006\223\324\247E\023\234\237\nO\217\353\030\246\016\352\030\244\016\336\030\004\233\037C\270h:#;\210\306 O\006\223\213M\213&\026{*\204\"\037\255u\024RK\035E\030i\tBM2\206ro\024\320\027\311#\227\222\035(\356Oq}$\355\307\347\223\253\316\320\230X\374\204NR(\262$*gr\360\325\034\274\234\203g\332\027y\016D\236\007\221\347B\304>\322\261\036\237gs\366o\025aB\0479\337Y\222xKY\347;""\007/\347\340\231\366E\236\003\221\347A\344\271\320\234\355\374\024]]\233\236\347z\206\361\270s\010\317}Ha\343\0219\344OH\3350\206}\003\334\272\206Nn\375vM\365\252\013\252\337\215\2304\370\333\3076\325o\302\261nD\364\304\265\204\023\211=\327\200\376\312\263\211\026P\274\257aJ\016\324\253\351\221&\3664\002\327\250a\356\022s\217\211\375h\346\021\006]@4\036\272SC\325\013E#A\233\266\271\007~\306/\215\014q\232\2151\361x\202e\210\047\277ns\325\255\250\205\267\004v\342m\305\375\312D\346%\0009T\023\310\272\204\n\226\"s\"\033\rC\365!\352\335&\036\2635\244\203b3\003\272\017h\333\240A\323\224\304\027\027f\035j\332n)\2212\005\273\236E<\323Q\312\020.\356a\223\324 \r\324\256L\253&\352\3521t\t\325e\311\322t\030u\317\335\217\254\246\001U\211\t\350\253\307H*\031\321\024\305c\013\262\t~mN\366\231cs\356\300\273AU\3465\335fRI\343\372\231\256\232\303Z\231\330\215\233\236\244t\r+\325\2600\r\353\320\260\354D\355H\\k\342\322\022W\222\270p0\342\324\201\351a\233\311\\O?\306\036\3510`\337\213B\000v\0044\344\035vzI%WSr!\305\327\320\351\345\023\367\206\212\177\"\364\216E\023\3767 \320\355&\341\325\033\323?,n+\222*3,*\303\0322,\031\303\n\021]\370qY\210\253@|\350\3433\376\2520\230:\323\375\322\337V\203R\210\303v\017\206\047S\263\335;rI~\035T\203\027aU\001\237\311\3261\272\321\233\355\177s\264w\274\375d0\265p\274p%X\017W\302\352`j\372\325\237\376m\2714\230Y\355-\035\337|pD\217w\236\r\300\306\312\253\302_3o\2753\327\375N\026\345\365`%x\030\336\356-i\360\314\047J\277\350/\372\333\203\231\263\376\264\337\222\357J\047\\R\306\332\335\027\376\246\\\224 9\347\203\326\005\277u\002?\\\256\007\267#\215\326`f\376x~\245\267\330\333\3565\372\277\277\236~\r\032#Ha\314\313sY\226\355`\047,\276\271\267\265`:h\275\251\267\352`f\266[\356r\377k\371 X\016[\275\302`f\256\373\203\217}\3655\340krZ\266\202\251\240\372&\252\357\005\305\340\363\000\307\252\035X\355\276\246:V<\201]\350\3176\375\3630\347\362V\260\020T\007sg\375y\360RH\r\212~\321\277\032Yn\375\007{\353\301Z8\rk\233\357\267\216\n\311\307\221\366\201$*\020\341""\212\202\346\365F\252\362\211<\010p\320JC\317\301F!\3740L\300o$\326Z\007!\216 \341W\375\035Y\214&m\377\205\376\250\034tz\205\336B\257\n\251\010\202\017\301c[\352\341\307*\232iC\"\324t~\"W2\361Oe5\023\277(\237\005\327\302b\230\262\326\t\337V\204D\322\337\002\246\266\227b\347\274\277\355[\362ZPL\326s\242\311\272 ?\000\263\355P/\017Ax\177\204\245\353\034{O\236\007\263\255\t\374\214\274\252\0023\201\317B\276\025\202\342\004>\0477!\031\226\024~U\345\357\311i\256\250P\266 \231\017d#x\036~\333/\364/\036\341#X\355\242\3770b\344\245\\\000Ja\255\357w\237\371\237\373\r\271\023|\244w\366\376\271\3775\275\342\377\362\346\323\313\376\326p\272\321\373\265\217\373\235\327\205,\370\345\353\342\340\342\322(p\022\263\255B\261\0051\200\2749IE\324TAT\320E0UTJ?\312\202,Fa-\303)?\243\216\321\361\324e\010\367y\250n\274\267\321\337>\236\272\323\007\366.A\026\337R\365\340\222\334\013\317\205\253\341\323\210\362\331\356-\377\222\nQ\212\351\354\360\337S\371;\230\203\254\204\343WL\006\177\0034\311\034;";
|
|
28902
|
+
PyObject *data = __Pyx_DecompressString(cstring, 1739, 1);
|
|
28903
28903
|
#define __Pyx_DecompressString_LZSS_UNUSED
|
|
28904
28904
|
if (unlikely(!data)) __PYX_ERR(0, 1, __pyx_L1_error)
|
|
28905
28905
|
const char* const bytes = __Pyx_PyBytes_AsString(data);
|
|
@@ -28907,7 +28907,7 @@ static const char cstring[] = "x\332\245W\315s\323F\024\257\247i\223\222\264\301
|
|
|
28907
28907
|
if (likely(bytes)); else { Py_DECREF(data); __PYX_ERR(0, 1, __pyx_L1_error) }
|
|
28908
28908
|
#endif
|
|
28909
28909
|
#elif (CYTHON_COMPRESS_STRINGS) > 0 && (CYTHON_COMPRESS_STRINGS) <= 90 /* compression: lzss (2299 bytes) */
|
|
28910
|
-
static const char cstring[] = "\377(tree fr\377agment)0\377.3.
|
|
28910
|
+
static const char cstring[] = "\377(tree fr\377agment)0\377.3.26<B<\377H<I<Q<b<\377d<h<i<q?\377Illegal \377boolean \377value: N\377ot enoug\377h input \357data\022\000e t\377hat Cyth\377on is de\377liberate\377ly stric\367ter!\001n PE\377P-484 an\377d reject\377s subcla\377sses of \377builtin \377types. I\377f you ne\177ed to p%\000\376%\tthen se\375t\200\000e \047ann\377otation_\376<\000ing\047 di\355rb\000iv\242\000o F\377alse.Opc\237ode o\277\000m\000r\377ange 0-2\37755: Unde\327fini\000o \002: \357add_R\000edc\337tx us\202\001wi\367ce.\013\002was \374o\000\023\002.disab\307lee\032\014\013\002\034\nen\336$\001gcis\004\003dn\375o\260 fault \377__reduce\337__ du\257\002no\333n-\300 vi\216@__\277cinit_\216\001 \377bytes: t\357ake_\007\002 ca\376\266@d for l\027ist\025\002d\372 \r\t1\002\340/\002\037\001\004\023\260@;\016msg\377pack/cor\377e.pyxBas\367eDe\305!Buff\253er\000\r.\301\006c\223b_i_\017\020\266@s\255@e_\013\026\343rd\326\003N\016\026\000flo\367at8\006\021int1\312\001\0242\031\02441\024K\022st\245r}\021u`\025\025\0012\032\0254\0143\025\326\002En\326+\004\t\3163\023\014\314\31729\nas\332\047R\nwr\002\000\026_\363\047#\r\365%\005\020\370\"\035\020\210\370\"5\020\361\016.\220\000\366$\232\ru `\025\364&\036\021e\022\304A8\321\204\t\343\204\003\007Ctx\000\006\315\204\017\017\t\307\204\016.\007\300\245\206\007\005\014\245\206\001\030\014\301\206\001+\014st}r=\014tuple\232i\200\254c\252\000\000\006\372\205\017\017\t\364\205\016.\007p\303ut\325\207\003\005\013\320\207\001\027\013se\277quence\007\014t\371r>\013\304\213\002NoneT?ypeSaf\265\207\n\000\r\000\260\207\017\017\020\261\207\0165\016\240\207\006\006\021\245\207\001\001\024U2\031\02441\0248f\021uI\025\004\215\207\002\032\02543\025_\002\206\207\t\300!\364\206\033\340\017\020\2372\351\206\r\327\211\003O\016wr_\250\254%\314\206\021\031\02441\0248L\021upI\025\253&\264\206\0223\0258TM\265\214\003\377Error__P\373yx\001\000Dict_\377NextRef_}_\261\217\004e____\255\215\001v\003\002oc\013\001fun\003\002\347get\245\214\003!\000mai=n\047\001meta\265""\220\002\010\002\357odul=\002mro\377_entries\356M\001namT\002new~\\\001preparf\002\375p\210\000checks\357um__\n\001res\007ult\006\003h\004!\001\210\221\001\033\003?unpicke\000\360\215\r\300\014\020\257\213\t/\014\354\205\r\014\020,\017vt<\334\220\001\240!qual\317\005\250\220\005\354\337\216\016\302\220\006ex\324!set\345_\203%s\302(\363\216\016__t\367est\207Avers\374\310\222\001\216Dis_cor\277outine\334\222\001e\376\261\214\005asyncio\365.\025\006s\230\221\001orde\347rcl)\001\254@tra\277ceback\370\222\001c/dbuf\000\001_\271\221\002\333\224\002}d\310\220\002_from\311\221\003$\005\t\313\221\001e1\000\000\001_\222\211\001\216\225\002\325e\227\216\002_\005\004d\313`en\377ditemsli\267ttl\005\000gn\261\221\001p\003op\301\211\006\317\211\001\220\222\001\327\211\001\256\211\005\007\002ctrO\006\355\220\005\333\220\006rd\361\205\002\352\001\0032\010\0034\017\0038rd\177_strrd_\371\217\002\352\001\0042\t\0044\021\0048se\177lfsetde\342\223\002\357sort\000\001_ke\277ysstar\326\204\003s\377tructsysp\312\223\007\273\223\006\252\223\006\353\223\002str\363\223\002\262\370\213\002t\225\223\004\374!eu\355\002u\377pdateuse\321_\333\222\005\277\227\002\304\227\002s\317\217\005wr\250\277\217\004\316\207\004\326\207\0032\335\207\0034\344\207\0038\246\353\216\003wr\331\003\001\0042\t\0044\376\021\0048\200\001\330\004\n\210\367+\220Q\005\001.\250a\250\373v\260\010\000\340\004\013\210?\377\230!\2309\240A\240W\377\250A\200\001\340\004\037\230\377q\320 0\260\013\270;\377\300k\320QR\330\004\023\377\320\023#\2408\2501\250\377A\330\004\007\200|\2207\377\230!\330\0102\260!\320\3773F\300n\320TU\330\376A\0001\200\001\360\010\000\005\377\014\210>\230\021\230)\240\1771\240G\2507\260!\020\002\373\n\033,\001\021\220\024\220Q\377\330\010\020\220\007\220q\230\337\006\230l\250!I\001v\210\277W\220E\230\024\230\027\000\022\375\220S\000\027\220q\340\010\027\277\220t\2308\2407\034\003q\377\330\010\017\320\0171\260\024\377\260Q\260g\270[\310\007\351\310\037\000\005\n\001W\014V\2304\277\230v\240T\250\021D\0475""\317\240\007\240q\331\001J!A\330\377\010\013\2104\210t\2209\377\230F\240-\250q\260\001\377\330\010\014\210J\220a\220\374\250\001\025\0005\230\007\230q\240\357\004\240A\200\010 \t\240\021\257\240$\240a#\005y\231 m\344\346\"L\005\340\261 ]\002E\220\025\376a\000t\2306\240\023\240A_\330\014\020\220\017c\000\001\000\006\177\330\014\021\220\021\220%\177\003}q%(8\2405\250\007\304\000o\017\270q\300\310\000\017\2108\002n\314\003w\230e\205A\2501\307\001\375\017\357\002A\230R\230w\240\327a\240q\007\tVA\000\001\250\273\026\250\014\006;\230a!\002w\375\250\326\002\017\210u\220A\220\367T\230\021B\003v\220W\230\377A\230V\2404\240y\260\177\001\260\023\260A\260Q\250!-\026\301 v\230\006\002\032\340am\001vA\005u\250\312\"\033\2301\216`\334\372 \t\014\034\230A\003\022\035\230_U\240\047\250\021\353`\010F\005\347y\250\003\310\204\001\231A\035\230Z\277\240s\250!\2501\271F\340\377\010\025\220Q\220d\230\047\351\240\274`\211\004\340\334@E\220\027[\230\016\363\000v\250\245\002 \334@9L\270\000\337b\t\230\025\353\000\356\"\216\013\n\n\230%\236A\202a#\n\013\277\2305\240\001\240\021\007\016\014\253\230E\212`!\262a%\274\204\001\340\374\315g\355aq\220\007\220w\230\377g\240V\250=\270\001\270\377\035\300a\300q\340\010\024\273\220G\214#z\230\023\320 Q\377\340\010\r\210U\220$\220\337g\230T\240\031\325\002\r\0228\000\014\000\033,\r#\220X?\t\000\014\356\017\014\"\220Iq\004:\260Y\177\270a\270y\310\001\330}\000~\007\rz\310\021\330\035!\233\002L\"\003\016\000\340\010\367D\311\205\001I\201@\357a\200A\340\253Fw\240c\324\301A\017\001\035\327\000\021\356\205\001L\230\367\001\230\021\207c4\220q\230\335\n\303\205\001\320\004\"\354@\025\250\377a\250t\260:\270Q\320\377\004?\270q\330\010\036\230\367e\2406\214\207\001\036\230k\250\337\022\2502\250S\265C\013\210G6\220\036\301\205\001\337(\351SC\274\204\001\177\330\014\032\230!\2306\227`\000\001\005";
|
|
28911
28911
|
PyObject *data = __Pyx_DecompressString_LZSS(cstring, 2299, 4654);
|
|
28912
28912
|
#define __Pyx_DecompressString_UNUSED
|
|
28913
28913
|
if (unlikely(!data)) __PYX_ERR(0, 1, __pyx_L1_error)
|
|
@@ -28916,7 +28916,7 @@ static const char cstring[] = "\377(tree fr\377agment)0\377.3.24<B<\377H<I<Q<b<\
|
|
|
28916
28916
|
if (likely(bytes)); else { Py_DECREF(data); __PYX_ERR(0, 1, __pyx_L1_error) }
|
|
28917
28917
|
#endif
|
|
28918
28918
|
#else /* compression: none (4654 bytes) */
|
|
28919
|
-
static const char bytes[] = "(tree fragment)0.3.
|
|
28919
|
+
static const char bytes[] = "(tree fragment)0.3.26<B<H<I<Q<b<d<h<i<q?Illegal boolean value: Not enough input dataNote that Cython is deliberately stricter than PEP-484 and rejects subclasses of builtin types. If you need to pass subclasses then set the \047annotation_typing\047 directive to False.Opcode out of range 0-255: Undefined opcode: add_notedctx used twice.dctx was not used.disableectx used twice.ectx was not used.enablegcisenabledno default __reduce__ due to non-trivial __cinit__not bytes: take_bytes called for listtake_dict called for bytestake_list called for bytestake_str called for listtmsgpack/core.pyxBaseDecodeBufferBaseDecodeBuffer.__reduce_cython__BaseDecodeBuffer.__setstate_cython__BaseDecodeBuffer.rd_bytesBaseDecodeBuffer.rd_float8BaseDecodeBuffer.rd_int1BaseDecodeBuffer.rd_int2BaseDecodeBuffer.rd_int4BaseDecodeBuffer.rd_int8BaseDecodeBuffer.rd_strBaseDecodeBuffer.rd_uint1BaseDecodeBuffer.rd_uint2BaseDecodeBuffer.rd_uint4BaseDecodeBuffer.rd_uint8BaseEncodeBufferBaseEncodeBuffer.__reduce_cython__BaseEncodeBuffer.__setstate_cython__BaseEncodeBuffer.as_bytesBaseEncodeBuffer.wr_bytesBaseEncodeBuffer.wr_float8BaseEncodeBuffer.wr_int1BaseEncodeBuffer.wr_int2BaseEncodeBuffer.wr_int4BaseEncodeBuffer.wr_int8BaseEncodeBuffer.wr_strBaseEncodeBuffer.wr_uint1BaseEncodeBuffer.wr_uint2BaseEncodeBuffer.wr_uint4BaseEncodeBuffer.wr_uint8DecodeBufferDecodeCtxDecodeCtx.__reduce_cython__DecodeCtx.__setstate_cython__DecodeCtx.take_bytesDecodeCtx.take_dictDecodeCtx.take_listDecodeCtx.take_strDecodeCtx.take_tupleEncodeBufferEncodeCtxEncodeCtx.__reduce_cython__EncodeCtx.__setstate_cython__EncodeCtx.put_bytesEncodeCtx.put_dictEncodeCtx.put_sequenceEncodeCtx.put_strEncodeCtx.put_valueNoneTypeSafeDecodeBufferSafeDecodeBuffer.__reduce_cython__SafeDecodeBuffer.__setstate_cython__SafeDecodeBuffer.rd_float8SafeDecodeBuffer.rd_int1SafeDecodeBuffer.rd_int2SafeDecodeBuffer.rd_int4SafeDecodeBuffer.rd_int8SafeDecodeBuffer.rd_uint1SafeDecodeBuffer.rd_uint2SafeDecodeBuffer.rd_uint4SafeDecodeBuffer.rd_uint8SafeEnco""deBufferSafeEncodeBuffer.__reduce_cython__SafeEncodeBuffer.__setstate_cython__SafeEncodeBuffer.wr_float8SafeEncodeBuffer.wr_int1SafeEncodeBuffer.wr_int2SafeEncodeBuffer.wr_int4SafeEncodeBuffer.wr_int8SafeEncodeBuffer.wr_uint1SafeEncodeBuffer.wr_uint2SafeEncodeBuffer.wr_uint4SafeEncodeBuffer.wr_uint8TMsgpackError__Pyx_PyDict_NextRef__annotate____dict____doc____func____getstate____main____metaclass____module____mro_entries____name____new____prepare____pyx_checksum__pyx_result__pyx_state__pyx_type__pyx_unpickle_BaseDecodeBuffer__pyx_unpickle_BaseEncodeBuffer__pyx_unpickle_SafeDecodeBuffer__pyx_unpickle_SafeEncodeBuffer__pyx_vtable____qualname____reduce____reduce_cython____reduce_ex____set_name____setstate____setstate_cython____test____version___dict_is_coroutine_typeas_bytesasyncio.coroutinesbyteordercline_in_tracebackcodecdbufdbuf_take_valuedecode_from_bytesdecode_from_listebufebuf_put_valueencode_valueendextenditemslittlemsgnpackpopput_bytesput_dictput_sequenceput_strput_valuerd_bytesrd_float8rd_int1rd_int2rd_int4rd_int8rd_strrd_uint1rd_uint2rd_uint4rd_uint8selfsetdefaultsortsort_keysstartstatestructsystake_bytestake_dicttake_listtake_strtake_tupletmsgpack.coreunpackupdateuse_setstatevaluevalueswr_byteswr_float8wr_int1wr_int2wr_int4wr_int8wr_strwr_uint1wr_uint2wr_uint4wr_uint8\200\001\330\004\n\210+\220Q\200\001\330\004.\250a\250v\260Q\200\001\340\004\013\210?\230!\2309\240A\240W\250A\200\001\340\004\037\230q\320 0\260\013\270;\300k\320QR\330\004\023\320\023#\2408\2501\250A\330\004\007\200|\2207\230!\330\0102\260!\3203F\300n\320TU\330\004\013\2101\200\001\360\010\000\005\014\210>\230\021\230)\2401\240G\2507\260!\200\001\360\010\000\n\033\230!\330\010\021\220\024\220Q\330\010\020\220\007\220q\230\006\230l\250!\330\004\007\200v\210W\220E\230\024\230Q\330\010\022\220!\330\010\027\220q\340\010\027\220t\2308\2407\250!\330\004\007\200q\330\010\017\320\0171\260\024\260Q\260g\270[\310\007\310q\340\010\017\320\0171\260\024\260Q\260g\270[\310\001\200\001\360\010\000\n\033\230!""\330\010\021\220\024\220V\2304\230v\240T\250\021\330\010\020\220\007\220q\230\006\230l\250!\330\004\007\200v\210W\220E\230\024\230Q\330\010\022\220!\330\010\027\220q\340\010\027\220t\2305\240\007\240q\330\004\007\200q\330\010\017\320\0171\260\024\260Q\260g\270[\310\007\310q\340\010\017\320\0171\260\024\260Q\260g\270[\310\001\200A\330\010\013\2104\210t\2209\230F\240-\250q\260\001\330\010\014\210J\220a\220q\330\010\017\210t\2205\230\007\230q\240\004\240A\200A\330\010\013\2104\210t\2209\230F\240-\250q\260\001\330\010\014\210J\220a\220q\330\010\017\210t\2205\230\t\240\021\240$\240a\200A\330\010\013\2104\210y\230\006\230m\2501\250A\330\010\014\210J\220a\220q\340\010\020\220\001\330\010\014\210E\220\025\220a\220t\2306\240\023\240A\330\014\020\220\017\230q\240\001\330\014\020\220\017\230q\240\001\330\014\021\220\021\220%\220q\330\010\017\210q\200A\330\010\013\2104\210y\230\006\230m\2501\250A\330\010\014\210J\220a\220q\340\010\020\220\001\330\010\014\210E\220\025\220a\220t\2308\2405\250\007\250q\260\017\270q\300\001\330\010\017\210q\200A\330\010\014\210J\220a\220w\230e\2407\250!\2501\200A\330\010\017\210t\2209\230A\230R\230w\240a\240q\200A\330\010\017\210t\2209\230A\230V\2405\250\001\250\026\250q\200A\330\010\017\210t\220;\230a\230w\240a\240w\250a\200A\330\010\017\210u\220A\220T\230\021\200A\330\010\017\210v\220W\230A\230V\2404\240y\260\001\260\023\260A\260Q\200A\330\010\026\220a\220v\230Q\200A\330\010\032\230!\330\010\017\210t\220;\230a\230w\240a\240u\250A\200A\330\010\033\2301\330\010\017\210t\220;\230a\230w\240a\240u\250A\200A\330\010\034\230A\330\010\017\210t\220;\230a\230w\240a\240u\250A\200A\330\010\035\230U\240\047\250\021\250!\330\010\017\210t\220;\230a\230y\250\003\2501\250A\200A\330\010\035\230Z\240s\250!\2501\330\010\014\210J\220a\220q\340\010\025\220Q\220d\230\047\240\021\330\010\026\220a\220v\230Q\340\010\014\210E\220\027\230\016\240a\240v\250Q\200A\330\010 \240\004\240L\260\001\260\021\330\010\020\220\t\230\025\230a\230q\200A\330\010 \240\004\240L\260\001\260""\021\330\010\020\220\n\230%\230q\240\001\200A\330\010 \240\004\240L\260\001\260\021\330\010\020\220\013\2305\240\001\240\021\200A\330\010 \240\004\240L\260\001\260\021\330\010\020\220\014\230E\240\021\240!\200A\330\010%\240T\250\021\340\010\014\210J\220a\220q\330\010\013\2104\210q\220\007\220w\230g\240V\250=\270\001\270\035\300a\300q\340\010\024\220G\2301\330\010\017\210z\230\023\230A\230Q\340\010\r\210U\220$\220g\230T\240\031\250!\2501\330\r\022\220$\220g\230T\240\031\250!\2501\330\r\022\220$\220g\230T\240\031\250!\2501\330\r\022\220$\220g\230T\240\031\250!\2501\330\r\022\220$\220g\230T\240\031\250!\2501\330\r\022\220#\220X\230T\240\031\250!\2501\330\r\022\220#\220X\230T\240\031\250!\2501\330\r\022\220#\220X\230T\240\031\250!\2501\330\r\022\220\"\220I\230T\240\031\250!\250:\260Y\270a\270y\310\001\330\r\022\220\"\220I\230T\240\031\250!\250:\260Y\270a\270z\310\021\330\035!\240\031\250!\250:\260Y\270a\270z\310\021\340\010\026\220a\220v\230Q\330\010\014\210I\220Q\220a\200A\340\010\017\210t\220;\230a\230w\240c\250\021\250!\200A\340\010\035\230T\240\021\330\010\014\210L\230\001\230\021\330\010\017\210t\2204\220q\230\n\240$\240a\320\004\"\240\047\250\025\250a\250t\260:\270Q\320\004?\270q\330\010\036\230e\2406\250\021\330\010\036\230k\250\022\2502\250S\260\001\260\021\330\010\013\2106\220\036\230q\240\001\340\010\014\210J\220a\220q\330\010\025\220Q\220d\230\047\240\021\330\010\026\220a\220v\230Q\340\010\014\210C\210u\220A\330\014\032\230!\2306\240\021\330\014\032\230!\2306\240\021";
|
|
28920
28920
|
PyObject *data = NULL;
|
|
28921
28921
|
#define __Pyx_DecompressString_UNUSED
|
|
28922
28922
|
#define __Pyx_DecompressString_LZSS_UNUSED
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# THIS FILE IS AUTOMATICALLY CREATED BY build_pyx.py
|
|
2
2
|
# DON'T EDIT THIS FILE. EDIT THE SOURCES, INSTEAD: tmsgpack/src-parts/*
|
|
3
3
|
|
|
4
|
-
__version__ = "0.3.
|
|
4
|
+
__version__ = "0.3.26"
|
|
5
5
|
|
|
6
6
|
from libc.stdint cimport int8_t, int16_t, int32_t, int64_t
|
|
7
7
|
from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
"""Integration tests for TmsgpackCodec with DI and the feature registry."""
|
|
2
|
-
|
|
3
|
-
import textwrap
|
|
4
|
-
import pytest
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
|
|
7
|
-
pytest.importorskip("semifun.di")
|
|
8
|
-
pytest.importorskip("semifun.plugins")
|
|
9
|
-
|
|
10
|
-
from tmsgpack.codec import NoDependencyInjector, TmsgpackCodec
|
|
11
|
-
from semifun.di.injector import DependencyInjector
|
|
12
|
-
from semifun.plugins.testing import create_registry_from_paths
|
|
13
|
-
from semifun.plugins.registry import (
|
|
14
|
-
_feature_map_from_registry,
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
# --- Write a test package with annotated types ---
|
|
19
|
-
|
|
20
|
-
def _write_test_types_package(tmp_path: Path) -> Path:
|
|
21
|
-
pkg = tmp_path / "test_codec_types"
|
|
22
|
-
pkg.mkdir()
|
|
23
|
-
(pkg / "__init__.py").write_text("")
|
|
24
|
-
(pkg / "types.py").write_text(textwrap.dedent("""\
|
|
25
|
-
import enum
|
|
26
|
-
from dataclasses import dataclass
|
|
27
|
-
from semifun.di.model import Inject
|
|
28
|
-
|
|
29
|
-
_HTTP_STATUS = (200, 404, 403, 401, 500)
|
|
30
|
-
|
|
31
|
-
#::testing_tmsgpack_codec:FailureSeverity
|
|
32
|
-
class FailureSeverity(enum.IntEnum):
|
|
33
|
-
OK = 0
|
|
34
|
-
PROBLEM = 1
|
|
35
|
-
NOT_AUTHORIZED = 2
|
|
36
|
-
NOT_AUTHENTICATED = 3
|
|
37
|
-
UNEXPECTED = 4
|
|
38
|
-
|
|
39
|
-
@property
|
|
40
|
-
def http_status_code(self) -> int:
|
|
41
|
-
return _HTTP_STATUS[self]
|
|
42
|
-
|
|
43
|
-
def __str__(self):
|
|
44
|
-
return self.name
|
|
45
|
-
|
|
46
|
-
#::testing_tmsgpack_codec:Foo
|
|
47
|
-
@dataclass(frozen=True)
|
|
48
|
-
class Foo:
|
|
49
|
-
x: str
|
|
50
|
-
y: int
|
|
51
|
-
|
|
52
|
-
@dataclass(frozen=True)
|
|
53
|
-
class Dbh:
|
|
54
|
-
pass
|
|
55
|
-
|
|
56
|
-
#::testing_tmsgpack_codec:Bar
|
|
57
|
-
@dataclass(frozen=True)
|
|
58
|
-
class Bar:
|
|
59
|
-
dbh: Inject[Dbh]
|
|
60
|
-
x: str
|
|
61
|
-
"""))
|
|
62
|
-
return pkg
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
@pytest.fixture
|
|
66
|
-
def test_types(tmp_path):
|
|
67
|
-
pkg = _write_test_types_package(tmp_path)
|
|
68
|
-
registry = create_registry_from_paths(
|
|
69
|
-
packages=[("test_codec_types", pkg)],
|
|
70
|
-
)
|
|
71
|
-
feature_map = _feature_map_from_registry(registry, "testing_tmsgpack_codec")
|
|
72
|
-
|
|
73
|
-
import test_codec_types.types as t
|
|
74
|
-
return t, feature_map
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def _make_injectors_map():
|
|
78
|
-
_MISSING = object()
|
|
79
|
-
# documented-default: mirrors FeatureMap.__call__ — omitting `default`
|
|
80
|
-
# means "raise", which `None` cannot express.
|
|
81
|
-
def lookup(name, default=_MISSING): # documented-default
|
|
82
|
-
if default is not _MISSING:
|
|
83
|
-
return default
|
|
84
|
-
raise LookupError(name)
|
|
85
|
-
return lookup
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
@pytest.fixture
|
|
89
|
-
def codec(test_types):
|
|
90
|
-
t, feature_map = test_types
|
|
91
|
-
di = DependencyInjector(injectors_map=_make_injectors_map(), seed_data={t.Dbh: t.Dbh()})
|
|
92
|
-
# testing-seam: pass feature_map callable instead of a string
|
|
93
|
-
return TmsgpackCodec(sort_keys=False, di=di, plugin_feature_type=feature_map), t
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
@pytest.fixture
|
|
97
|
-
def codec_no_di(test_types):
|
|
98
|
-
t, feature_map = test_types
|
|
99
|
-
# testing-seam: pass feature_map callable instead of a string
|
|
100
|
-
return TmsgpackCodec(sort_keys=False, di=NoDependencyInjector(),
|
|
101
|
-
plugin_feature_type=feature_map), t
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
# --- Round-trip: plain dataclass ---
|
|
105
|
-
|
|
106
|
-
def test_round_trip_dataclass(codec):
|
|
107
|
-
codec, t = codec
|
|
108
|
-
foo = t.Foo(x='hello', y=123)
|
|
109
|
-
assert codec.decode(codec.encode(foo)) == foo
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
# --- Round-trip: enum ---
|
|
113
|
-
|
|
114
|
-
def test_round_trip_enum(codec):
|
|
115
|
-
codec, t = codec
|
|
116
|
-
for severity in t.FailureSeverity:
|
|
117
|
-
assert codec.decode(codec.encode(severity)) == severity
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
# --- Round-trip: dataclass with Inject[T] fields ---
|
|
121
|
-
|
|
122
|
-
def test_round_trip_dataclass_with_inject(codec):
|
|
123
|
-
codec, t = codec
|
|
124
|
-
bar = t.Bar(dbh=t.Dbh(), x='world')
|
|
125
|
-
data = codec.encode(bar)
|
|
126
|
-
decoded = codec.decode(data)
|
|
127
|
-
assert decoded.x == 'world'
|
|
128
|
-
assert isinstance(decoded.dbh, t.Dbh)
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
# --- NoDependencyInjector: plain types work without DI ---
|
|
132
|
-
|
|
133
|
-
def test_no_di_dataclass(codec_no_di):
|
|
134
|
-
codec, t = codec_no_di
|
|
135
|
-
foo = t.Foo(x='abc', y=42)
|
|
136
|
-
assert codec.decode(codec.encode(foo)) == foo
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
def test_no_di_enum(codec_no_di):
|
|
140
|
-
codec, t = codec_no_di
|
|
141
|
-
baz = t.FailureSeverity.PROBLEM
|
|
142
|
-
assert codec.decode(codec.encode(baz)) == baz
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
# --- with_seed_data ---
|
|
146
|
-
|
|
147
|
-
def test_with_seed_data_round_trip(codec):
|
|
148
|
-
codec, t = codec
|
|
149
|
-
other_dbh = t.Dbh()
|
|
150
|
-
codec2 = codec.with_seed_data({t.Dbh: other_dbh})
|
|
151
|
-
bar = t.Bar(dbh=t.Dbh(), x='test')
|
|
152
|
-
decoded = codec2.decode(codec2.encode(bar))
|
|
153
|
-
assert decoded.x == 'test'
|
|
154
|
-
assert decoded.dbh is other_dbh
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
# --- with_seed_data produces independent caches ---
|
|
158
|
-
|
|
159
|
-
def test_with_seed_data_has_independent_caches(codec):
|
|
160
|
-
codec, t = codec
|
|
161
|
-
codec2 = codec.with_seed_data({t.Dbh: t.Dbh()})
|
|
162
|
-
assert codec2.encoder_cache is not codec.encoder_cache
|
|
163
|
-
assert codec2.decoder_cache is not codec.decoder_cache
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
# --- Inject[T] without a DependencyInjector ---
|
|
167
|
-
|
|
168
|
-
def test_inject_field_without_an_injector_fails_on_encode():
|
|
169
|
-
"""`NoDependencyInjector` does not recognise Inject[T], so the field is serialized.
|
|
170
|
-
|
|
171
|
-
Documented in [[tmsgpack:di-on-decode]]: exclusion depends on the
|
|
172
|
-
injector, so without one the codec tries to encode the injected value and
|
|
173
|
-
fails there — not on decode.
|
|
174
|
-
"""
|
|
175
|
-
from dataclasses import dataclass
|
|
176
|
-
|
|
177
|
-
from tmsgpack.codec import NoDependencyInjector, TmsgpackCodec
|
|
178
|
-
from semifun.di.model import Inject
|
|
179
|
-
|
|
180
|
-
class DbHandle:
|
|
181
|
-
pass
|
|
182
|
-
|
|
183
|
-
@dataclass(frozen=True)
|
|
184
|
-
class NeedsInjection:
|
|
185
|
-
dbh: Inject[DbHandle]
|
|
186
|
-
x: str
|
|
187
|
-
|
|
188
|
-
def feature_map(feature, default=None):
|
|
189
|
-
return {'NeedsInjection': NeedsInjection}.get(feature, default)
|
|
190
|
-
|
|
191
|
-
codec = TmsgpackCodec(
|
|
192
|
-
sort_keys=True,
|
|
193
|
-
di=NoDependencyInjector(),
|
|
194
|
-
plugin_feature_type=feature_map,
|
|
195
|
-
)
|
|
196
|
-
with pytest.raises(ValueError, match='Cannot encode this type'):
|
|
197
|
-
codec.encode(NeedsInjection(dbh=DbHandle(), x='hi'))
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
"""Tests for TmsgpackCustom: custom encode/decode for non-dataclass types."""
|
|
2
|
-
|
|
3
|
-
import struct
|
|
4
|
-
import textwrap
|
|
5
|
-
import pytest
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
|
|
8
|
-
pytest.importorskip("semifun.di")
|
|
9
|
-
pytest.importorskip("semifun.plugins")
|
|
10
|
-
|
|
11
|
-
from tmsgpack.codec import NoDependencyInjector, TmsgpackCodec
|
|
12
|
-
from semifun.di.injector import DependencyInjector
|
|
13
|
-
from semifun.plugins.testing import create_registry_from_paths
|
|
14
|
-
from semifun.plugins.registry import _feature_map_from_registry
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# --- Write test packages with custom codec types ---
|
|
18
|
-
|
|
19
|
-
def _write_custom_types_package(tmp_path: Path) -> Path:
|
|
20
|
-
pkg = tmp_path / "test_custom_types"
|
|
21
|
-
pkg.mkdir()
|
|
22
|
-
(pkg / "__init__.py").write_text("")
|
|
23
|
-
(pkg / "types.py").write_text(textwrap.dedent("""\
|
|
24
|
-
import struct
|
|
25
|
-
from tmsgpack.codec_custom import TmsgpackCustom
|
|
26
|
-
|
|
27
|
-
# --- Target types (not dataclasses) ---
|
|
28
|
-
|
|
29
|
-
class Pair:
|
|
30
|
-
def __init__(self, x, y):
|
|
31
|
-
self.x = x
|
|
32
|
-
self.y = y
|
|
33
|
-
def __eq__(self, other):
|
|
34
|
-
return type(other) is Pair and self.x == other.x and self.y == other.y
|
|
35
|
-
|
|
36
|
-
class Point:
|
|
37
|
-
def __init__(self, x, y):
|
|
38
|
-
self.x = x
|
|
39
|
-
self.y = y
|
|
40
|
-
def __eq__(self, other):
|
|
41
|
-
return type(other) is Point and self.x == other.x and self.y == other.y
|
|
42
|
-
|
|
43
|
-
# --- Dict mode ---
|
|
44
|
-
|
|
45
|
-
#::testing_custom_codec:Pair=CodecPairDict
|
|
46
|
-
class CodecPairDict(TmsgpackCustom):
|
|
47
|
-
def encode_dict(obj):
|
|
48
|
-
return {'x': obj.x, 'y': obj.y}
|
|
49
|
-
def decode_dict(*, x, y):
|
|
50
|
-
return Pair(x=x, y=y)
|
|
51
|
-
|
|
52
|
-
# --- List mode ---
|
|
53
|
-
|
|
54
|
-
#::testing_custom_codec:Point=CodecPointList
|
|
55
|
-
class CodecPointList(TmsgpackCustom):
|
|
56
|
-
def encode_list(obj):
|
|
57
|
-
return [obj.x, obj.y]
|
|
58
|
-
def decode_list(x, y):
|
|
59
|
-
return Point(x, y)
|
|
60
|
-
"""))
|
|
61
|
-
(pkg / "types_bytes.py").write_text(textwrap.dedent("""\
|
|
62
|
-
import struct
|
|
63
|
-
from tmsgpack.codec_custom import TmsgpackCustom
|
|
64
|
-
|
|
65
|
-
class FloatPair:
|
|
66
|
-
def __init__(self, x, y):
|
|
67
|
-
self.x = x
|
|
68
|
-
self.y = y
|
|
69
|
-
def __eq__(self, other):
|
|
70
|
-
return (type(other) is FloatPair
|
|
71
|
-
and self.x == other.x and self.y == other.y)
|
|
72
|
-
|
|
73
|
-
#::testing_custom_codec:FloatPair=CodecFloatPairBytes
|
|
74
|
-
class CodecFloatPairBytes(TmsgpackCustom):
|
|
75
|
-
def encode_bytes(obj):
|
|
76
|
-
return struct.pack('<ff', obj.x, obj.y)
|
|
77
|
-
def decode_bytes(data):
|
|
78
|
-
x, y = struct.unpack('<ff', data)
|
|
79
|
-
return FloatPair(x, y)
|
|
80
|
-
"""))
|
|
81
|
-
return pkg
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
@pytest.fixture
|
|
85
|
-
def test_types(tmp_path):
|
|
86
|
-
pkg = _write_custom_types_package(tmp_path)
|
|
87
|
-
registry = create_registry_from_paths(
|
|
88
|
-
packages=[("test_custom_types", pkg)],
|
|
89
|
-
)
|
|
90
|
-
feature_map = _feature_map_from_registry(registry, "testing_custom_codec")
|
|
91
|
-
import test_custom_types.types as t
|
|
92
|
-
import test_custom_types.types_bytes as tb
|
|
93
|
-
return t, tb, feature_map
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
@pytest.fixture
|
|
97
|
-
def codec(test_types):
|
|
98
|
-
t, tb, feature_map = test_types
|
|
99
|
-
return TmsgpackCodec(sort_keys=False, di=NoDependencyInjector(),
|
|
100
|
-
plugin_feature_type=feature_map), t, tb
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
# --- Dict mode round-trip ---
|
|
104
|
-
|
|
105
|
-
def test_dict_mode_round_trip(codec):
|
|
106
|
-
codec, t, tb = codec
|
|
107
|
-
pair = t.Pair(x='hello', y=42)
|
|
108
|
-
data = codec.encode(pair)
|
|
109
|
-
restored = codec.decode(data)
|
|
110
|
-
assert restored == pair
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
# --- List mode round-trip ---
|
|
114
|
-
|
|
115
|
-
def test_list_mode_round_trip(codec):
|
|
116
|
-
codec, t, tb = codec
|
|
117
|
-
point = t.Point(x=10, y=20)
|
|
118
|
-
data = codec.encode(point)
|
|
119
|
-
restored = codec.decode(data)
|
|
120
|
-
assert restored == point
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
# --- Bytes mode round-trip ---
|
|
124
|
-
|
|
125
|
-
def test_bytes_mode_round_trip(codec):
|
|
126
|
-
codec, t, tb = codec
|
|
127
|
-
fp = tb.FloatPair(x=1.5, y=2.5)
|
|
128
|
-
data = codec.encode(fp)
|
|
129
|
-
restored = codec.decode(data)
|
|
130
|
-
assert restored == fp
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
# --- Content hashing works with custom types ---
|
|
134
|
-
|
|
135
|
-
def test_content_hash_dict_mode(codec):
|
|
136
|
-
codec, t, tb = codec
|
|
137
|
-
codec_sorted = TmsgpackCodec(sort_keys=True, di=NoDependencyInjector(),
|
|
138
|
-
plugin_feature_type=codec.plugin_feature_type)
|
|
139
|
-
pair = t.Pair(x='a', y=1)
|
|
140
|
-
h = codec_sorted.hash_to_str(pair)
|
|
141
|
-
assert isinstance(h, str)
|
|
142
|
-
assert len(h) == 22
|
|
143
|
-
# Same value, same hash
|
|
144
|
-
assert codec_sorted.hash_to_str(t.Pair(x='a', y=1)) == h
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
# --- Nested values in custom types ---
|
|
148
|
-
|
|
149
|
-
def test_dict_mode_nested_values(codec):
|
|
150
|
-
codec, t, tb = codec
|
|
151
|
-
pair = t.Pair(x=[1, 2, 3], y={'a': True})
|
|
152
|
-
data = codec.encode(pair)
|
|
153
|
-
restored = codec.decode(data)
|
|
154
|
-
assert restored == pair
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
# --- Validation: mismatched modes ---
|
|
158
|
-
|
|
159
|
-
def test_mismatched_modes_raises():
|
|
160
|
-
from tmsgpack.codec_custom import TmsgpackCustom
|
|
161
|
-
with pytest.raises(TypeError, match="mode mismatch"):
|
|
162
|
-
class Bad(TmsgpackCustom):
|
|
163
|
-
def encode_dict(obj): return {}
|
|
164
|
-
def decode_list(x): return None
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
def test_no_encode_raises():
|
|
168
|
-
from tmsgpack.codec_custom import TmsgpackCustom
|
|
169
|
-
with pytest.raises(TypeError, match="encode_dict, encode_list, encode_bytes"):
|
|
170
|
-
class Bad(TmsgpackCustom):
|
|
171
|
-
def decode_dict(*, x): return None
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
def test_no_decode_raises():
|
|
175
|
-
from tmsgpack.codec_custom import TmsgpackCustom
|
|
176
|
-
with pytest.raises(TypeError, match="decode_dict, decode_list, decode_bytes"):
|
|
177
|
-
class Bad(TmsgpackCustom):
|
|
178
|
-
def encode_dict(obj): return {}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
# --- DI on decode ---
|
|
182
|
-
|
|
183
|
-
def _write_di_types_package(tmp_path: Path) -> Path:
|
|
184
|
-
pkg = tmp_path / "test_custom_di_types"
|
|
185
|
-
pkg.mkdir()
|
|
186
|
-
(pkg / "__init__.py").write_text("")
|
|
187
|
-
(pkg / "types.py").write_text(textwrap.dedent("""\
|
|
188
|
-
from tmsgpack.codec_custom import TmsgpackCustom
|
|
189
|
-
from semifun.di.model import Inject
|
|
190
|
-
|
|
191
|
-
class Cache:
|
|
192
|
-
def __init__(self):
|
|
193
|
-
self.store = {}
|
|
194
|
-
def get(self, key):
|
|
195
|
-
return self.store[key]
|
|
196
|
-
def put(self, key, value):
|
|
197
|
-
self.store[key] = value
|
|
198
|
-
|
|
199
|
-
class Widget:
|
|
200
|
-
def __init__(self, name, data):
|
|
201
|
-
self.name = name
|
|
202
|
-
self.data = data
|
|
203
|
-
def __eq__(self, other):
|
|
204
|
-
return (type(other) is Widget
|
|
205
|
-
and self.name == other.name
|
|
206
|
-
and self.data == other.data)
|
|
207
|
-
|
|
208
|
-
#::testing_custom_di_codec:Widget=CodecWidget
|
|
209
|
-
class CodecWidget(TmsgpackCustom):
|
|
210
|
-
def encode_dict(obj, cache: Inject[Cache]):
|
|
211
|
-
cache.put(obj.name, obj.data)
|
|
212
|
-
return {'name': obj.name}
|
|
213
|
-
def decode_dict(*, name, cache: Inject[Cache]):
|
|
214
|
-
data = cache.get(name)
|
|
215
|
-
return Widget(name=name, data=data)
|
|
216
|
-
"""))
|
|
217
|
-
return pkg
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
def test_di_on_encode_and_decode(tmp_path):
|
|
221
|
-
pkg = _write_di_types_package(tmp_path)
|
|
222
|
-
registry = create_registry_from_paths(
|
|
223
|
-
packages=[("test_custom_di_types", pkg)],
|
|
224
|
-
)
|
|
225
|
-
feature_map = _feature_map_from_registry(registry, "testing_custom_di_codec")
|
|
226
|
-
import test_custom_di_types.types as t
|
|
227
|
-
|
|
228
|
-
cache = t.Cache()
|
|
229
|
-
injectors_map = lambda name, default=None: default
|
|
230
|
-
di = DependencyInjector(injectors_map=injectors_map, seed_data={t.Cache: cache})
|
|
231
|
-
codec = TmsgpackCodec(sort_keys=False, di=di, plugin_feature_type=feature_map)
|
|
232
|
-
|
|
233
|
-
widget = t.Widget(name='gizmo', data=[1, 2, 3])
|
|
234
|
-
data = codec.encode(widget)
|
|
235
|
-
|
|
236
|
-
# The cache was populated during encode
|
|
237
|
-
assert cache.store == {'gizmo': [1, 2, 3]}
|
|
238
|
-
|
|
239
|
-
restored = codec.decode(data)
|
|
240
|
-
assert restored == widget
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|