Skip to content

Commit dde6584

Browse files
committed
Pass options to unpackb static method.
1 parent 7bd4170 commit dde6584

15 files changed

+347
-319
lines changed

README.md

Lines changed: 139 additions & 112 deletions
Large diffs are not rendered by default.

asyntest.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from sys import platform
1212
import asyncio
13-
import umsgpack
13+
import umsgpack, umsgpack.mpk_complex
1414
from machine import UART, Pin
1515
import gc
1616

@@ -32,7 +32,8 @@ async def sender():
3232
True,
3333
False,
3434
0xFFFFFFFF,
35-
{"foo": b"\x80\x01\x02", "bar": [1, 2, 3, {"a": [1, 2, 3, {}]}]},
35+
1 + 1j,
36+
{"foox": b"\x80\x01\x02", "bar": [1, 2, 3, {"a": [1, 2, 3, {}]}], (1, (2, 3)): 42},
3637
-1,
3738
2.12345,
3839
]
@@ -56,7 +57,7 @@ def __call__(self, data: bytes) -> None:
5657

5758

5859
async def receiver():
59-
uart_aloader = umsgpack.aloader(asyncio.StreamReader(uart), observer=StreamObserver())
60+
uart_aloader = umsgpack.ALoader(asyncio.StreamReader(uart), observer=StreamObserver())
6061
async for res in uart_aloader:
6162
print("Received (aloader):", res)
6263

asyntest_py3_serial.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,23 @@
22

33
# Configured for pyserial. Link RX and TX pins.
44

5-
# Copyright (c) 2024 Peter Hinch Released under the MIT License see LICENSE
5+
# Copyright (c) 2024-2025 Peter Hinch Released under the MIT License see LICENSE
66

77
import asyncio
88
import umsgpack
99
import serial_asyncio
1010

11+
1112
async def sender(swriter):
12-
obj = [1, True, False, 0xffffffff, {u"foo": b"\x80\x01\x02", \
13-
u"bar": [1,2,3, {u"a": [1,2,3,{}]}]}, -1, 2.12345]
13+
obj = [
14+
1,
15+
True,
16+
False,
17+
0xFFFFFFFF,
18+
{"foo": b"\x80\x01\x02", "bar": [1, 2, 3, {"a": [1, 2, 3, {}]}]},
19+
-1,
20+
2.12345,
21+
]
1422

1523
while True:
1624
s = umsgpack.dumps(obj)
@@ -19,35 +27,41 @@ async def sender(swriter):
1927
await asyncio.sleep(5)
2028
obj[0] += 1
2129

30+
2231
class stream_observer:
2332
def update(self, data: bytes) -> None:
24-
print(f'{data}')
33+
print(f"{data}")
34+
2535

2636
async def receiver(sreader):
2737
recv_observer = stream_observer()
2838
while True:
2939
res = await umsgpack.aload(sreader, observer=recv_observer)
30-
print('Received:', res)
40+
print("Received:", res)
41+
3142

3243
async def receiver_using_aloader(sreader):
3344
uart_aloader = umsgpack.aloader(sreader, observer=stream_observer())
3445
while True:
3546
res = await uart_aloader.load()
36-
print('Received (aloader):', res)
47+
print("Received (aloader):", res)
48+
3749

3850
async def main():
39-
reader, writer = await serial_asyncio.open_serial_connection(url='/dev/ttyUSB0', baudrate=9600)
51+
reader, writer = await serial_asyncio.open_serial_connection(url="/dev/ttyUSB0", baudrate=9600)
4052
asyncio.create_task(sender(writer))
4153
# asyncio.create_task(receiver(reader))
4254
asyncio.create_task(receiver_using_aloader(reader))
4355
while True:
44-
print('running...')
56+
print("running...")
4557
await asyncio.sleep(20)
4658

59+
4760
def test():
4861
try:
4962
asyncio.run(main())
5063
except KeyboardInterrupt:
51-
print('Interrupted')
64+
print("Interrupted")
65+
5266

5367
test()

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
{
22
"urls": [
33
["umsgpack/__init__.py", "github:peterhinch/micropython-msgpack/umsgpack/__init__.py"],
4-
["umsgpack/as_load.py", "github:peterhinch/micropython-msgpack/umsgpack/as_load.py"],
54
["umsgpack/as_loader.py", "github:peterhinch/micropython-msgpack/umsgpack/as_loader.py"],
65
["umsgpack/mp_dump.py", "github:peterhinch/micropython-msgpack/umsgpack/mp_dump.py"],
76
["umsgpack/mp_load.py", "github:peterhinch/micropython-msgpack/umsgpack/mp_load.py"],
8-
["umsgpack/umsgpack_ext.py", "github:peterhinch/micropython-msgpack/umsgpack/umsgpack_ext.py"],
7+
["umsgpack/mpk_bytearray.py", "github:peterhinch/micropython-msgpack/umsgpack/mpk_bytearray.py"],
8+
["umsgpack/mpk_complex.py", "github:peterhinch/micropython-msgpack/umsgpack/mpk_complex.py"],
9+
["umsgpack/mpk_set.py", "github:peterhinch/micropython-msgpack/umsgpack/mpk_set.py"],
10+
["umsgpack/mpk_tuple.py", "github:peterhinch/micropython-msgpack/umsgpack/mpk_tuple.py"],
911
["asyntest.py", "github:peterhinch/micropython-msgpack/asyntest.py"],
1012
["user_class.py", "github:peterhinch/micropython-msgpack/user_class.py"]
1113
],

run_test_suite

Lines changed: 0 additions & 5 deletions
This file was deleted.

test_umsgpack.py

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -290,30 +290,31 @@
290290
],
291291
]
292292

293-
293+
# Dynamic loader prevents this test from working
294294
# These are the only global variables that should be exported by umsgpack
295-
exported_vars_test_vector = [
296-
"dump",
297-
"dumps",
298-
"load",
299-
"loads",
300-
"aloader",
301-
"Packer",
302-
"custom",
303-
"ext_type_to_class",
304-
"types",
305-
"ext_serializable",
306-
"PackException",
307-
"UnpackException",
308-
"UnsupportedTypeException",
309-
"InsufficientDataException",
310-
"InvalidStringException",
311-
"ReservedCodeException",
312-
"UnhashableKeyException",
313-
"DuplicateKeyException",
314-
"aload",
315-
"aloader",
316-
]
295+
# exported_vars_test_vector = [
296+
# "dump",
297+
# "dumps",
298+
# "load",
299+
# "loads",
300+
# "Packer",
301+
# "custom",
302+
# "ext_type_to_class",
303+
# "types",
304+
# "ext_serializable",
305+
# "PackException",
306+
# "UnpackException",
307+
# "UnsupportedTypeException",
308+
# "InsufficientDataException",
309+
# "InvalidStringException",
310+
# "ReservedCodeException",
311+
# "UnhashableKeyException",
312+
# "DuplicateKeyException",
313+
# "mp_load",
314+
# "mp_dump",
315+
# "ALoader",
316+
# "as_loader",
317+
# ]
317318

318319
##########################################################################
319320

@@ -456,7 +457,7 @@ def packb(self):
456457
return struct.pack("<II", self.real, self.imag)
457458

458459
@classmethod
459-
def unpackb(cls, data):
460+
def unpackb(cls, data, options):
460461
return cls(*struct.unpack("<II", data))
461462

462463
obj, data = CustomComplex(123, 456), b"\xd7\x20\x7b\x00\x00\x00\xc8\x01\x00\x00"
@@ -516,7 +517,7 @@ def packb(self): # Must change to list otherwise get infinite recursion
516517
return umsgpack.dumps(list(self.s))
517518

518519
@staticmethod
519-
def unpackb(data):
520+
def unpackb(data, options):
520521
return set(umsgpack.loads(data))
521522

522523
packed = umsgpack.dumps({1, 2, 3})
@@ -542,7 +543,7 @@ def packb(self):
542543
return umsgpack.dumps([self.length, self.width])
543544

544545
@classmethod
545-
def unpackb(cls, data):
546+
def unpackb(cls, data, options):
546547
return cls(*umsgpack.loads(data))
547548

548549
class Square(Rectangle):
@@ -575,15 +576,16 @@ def test_streaming_reader(self):
575576
reader = io.BytesIO(data)
576577
self.assertEqual(umsgpack.load(reader), obj)
577578

578-
def test_namespacing(self):
579-
# Get a list of global variables from umsgpack module
580-
exported_vars = list([x for x in dir(umsgpack) if not x.startswith("_")])
581-
582-
self.assertEqual(len(exported_vars), len(exported_vars_test_vector))
583-
print("###")
584-
print("Test namespace")
585-
for var in exported_vars_test_vector:
586-
self.assertTrue(var in exported_vars)
579+
# Dynamic loader prevents this test from working
580+
# def test_namespacing(self):
581+
# # Get a list of global variables from umsgpack module
582+
# exported_vars = list([x for x in dir(umsgpack) if not x.startswith("_")])
583+
#
584+
# self.assertEqual(len(exported_vars), len(exported_vars_test_vector))
585+
# print("###")
586+
# print("Test namespace")
587+
# for var in exported_vars_test_vector:
588+
# self.assertTrue(var in exported_vars)
587589

588590
def test_load_short_read(self):
589591
# When reading from files, the network, etc. there's no guarantee that

umsgpack/__init__.py

Lines changed: 45 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
# Method of detecting platform's float size changed.
2525
# Version reset to (0.1.0).
2626

27-
__version__ = (0, 1, 3)
27+
__version__ = (0, 2, 0)
2828

2929
# ABC for classes which handle extended Python built-in classes.
3030
class Packer:
@@ -41,9 +41,15 @@ def __call__(self, obj):
4141
# Ext Serializable Decorator
4242
##############################################################################
4343

44-
custom = {} # Pack. Key: Custom class. Value: ext_type integer.
45-
ext_type_to_class = {} # Unpack. Key: ext_type integer Value: Packer subclass.
46-
types = {} # Pack. Key: data type to pack Value: ext_type integer.
44+
# Global dicts
45+
# Packer
46+
custom = {} # Pack custom. Key: Custom class. Value: ext_type integer.
47+
builtins = {} # Pack built-in. Key: data type to pack
48+
# Value: (ext_type byte, Packer class).
49+
# The second item is replaced with Packer instance once one exists.
50+
51+
# Unpacker
52+
packers = {} # Key: ext_type integer Value: Packer subclass.
4753

4854
# Decorator. Args:
4955
# ext_type: An integer identifying the packed record.
@@ -55,99 +61,82 @@ def wrapper(cls):
5561
raise TypeError("Ext type is not type integer")
5662
elif not (-128 <= ext_type <= 127):
5763
raise ValueError("Ext type value {:d} is out of range of -128 to 127".format(ext_type))
58-
elif ext_type in ext_type_to_class:
64+
elif ext_type in packers:
5965
raise ValueError(
6066
"Ext type {:d} already registered with class {:s}".format(
61-
ext_type, repr(ext_type_to_class[ext_type])
67+
ext_type, repr(packers[ext_type])
6268
)
6369
)
6470
elif cls in custom:
6571
raise ValueError(
6672
"Class {:s} already registered with Ext type {:d}".format(repr(cls), ext_type)
6773
)
6874

69-
ext_type_to_class[ext_type] = cls # For unpack
75+
packers[ext_type] = cls # For unpack
7076
if example is None: # Custom class
7177
custom[cls] = ext_type
7278
else: # Extension type having a Packer class
73-
types[example] = (cls, ext_type)
79+
builtins[example] = (cls, ext_type)
7480
return cls
7581

7682
return wrapper
7783

7884

79-
##############################################################################
8085
# Exceptions
81-
##############################################################################
8286

8387
# Base Exception classes
8488
class PackException(Exception):
85-
"Base class for exceptions encountered during packing."
89+
pass
8690

8791

8892
class UnpackException(Exception):
89-
"Base class for exceptions encountered during unpacking."
93+
pass
9094

9195

9296
# Packing error
9397
class UnsupportedTypeException(PackException):
94-
"Object type not supported for packing."
98+
pass
9599

96100

97101
# Unpacking error
98102
class InsufficientDataException(UnpackException):
99-
"Insufficient data to unpack the serialized object."
103+
pass
100104

101105

102106
class InvalidStringException(UnpackException):
103-
"Invalid UTF-8 string encountered during unpacking."
107+
pass
104108

105109

106110
class ReservedCodeException(UnpackException):
107-
"Reserved code encountered during unpacking."
111+
pass
108112

109113

110114
class UnhashableKeyException(UnpackException):
111-
"""
112-
Unhashable key encountered during map unpacking.
113-
The serialized map cannot be deserialized into a Python dictionary.
114-
"""
115+
pass
115116

116117

117118
class DuplicateKeyException(UnpackException):
118-
"Duplicate key encountered during map unpacking."
119-
120-
121-
##############################################################################
122-
# Lazy module load to save RAM: takes about 20μs on Pyboard 1.x after initial load
123-
##############################################################################
124-
125-
126-
def load(fp, **options):
127-
from . import mp_load
128-
129-
return mp_load.mpload(fp, options)
130-
131-
132-
def loads(s, **options):
133-
from . import mp_load
134-
135-
return mp_load.mploads(s, options)
136-
137-
138-
def dump(obj, fp, **options):
139-
from . import mp_dump
140-
141-
mp_dump.mpdump(obj, fp, options)
142-
143-
144-
def dumps(obj, **options):
145-
from . import mp_dump
146-
147-
return mp_dump.mpdumps(obj, options)
148-
149-
150-
def aloader(fp, **options):
151-
from . import as_loader
152-
153-
return as_loader.asloader(fp, options)
119+
pass
120+
121+
122+
# Lazy loader
123+
124+
_attrs = {
125+
"load": "mp_load",
126+
"loads": "mp_load",
127+
"dump": "mp_dump",
128+
"dumps": "mp_dump",
129+
"ALoader": "as_loader",
130+
}
131+
132+
# Copied from asyncio.__init__.py
133+
# Lazy loader, effectively does:
134+
# global attr
135+
# from .mod import attr
136+
def __getattr__(attr):
137+
mod = _attrs.get(attr, None)
138+
if mod is None:
139+
raise AttributeError(attr)
140+
value = getattr(__import__(mod, globals(), None, True, 1), attr)
141+
globals()[attr] = value
142+
return value

0 commit comments

Comments
 (0)