Skip to content

Commit 83749c8

Browse files
authored
Merge pull request #10927 from FoamyGuy/zephyr_msgpack_and_fix
enable msgpack in zephyr port and add test for it. fix unpack issue
2 parents 0243b34 + be90f60 commit 83749c8

File tree

5 files changed

+147
-5
lines changed

5 files changed

+147
-5
lines changed

ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ memorymap = false
7171
memorymonitor = false
7272
microcontroller = true
7373
mipidsi = false
74-
msgpack = false
74+
msgpack = true
7575
neopixel_write = false
7676
nvm = true # Zephyr board has nvm
7777
onewireio = false

ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ i2cdisplaybus = true # Zephyr board has busio
5656
i2cioexpander = false
5757
i2ctarget = false
5858
imagecapture = false
59-
ipaddress = false
59+
ipaddress = true # Zephyr networking enabled
6060
is31fl3741 = false
6161
jpegio = false
6262
keypad = false
@@ -71,7 +71,7 @@ memorymap = false
7171
memorymonitor = false
7272
microcontroller = true
7373
mipidsi = false
74-
msgpack = false
74+
msgpack = true
7575
neopixel_write = false
7676
nvm = true # Zephyr board has nvm
7777
onewireio = false

ports/zephyr-cp/cptools/build_circuitpython.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"errno",
6161
"io",
6262
"math",
63+
"msgpack",
6364
]
6465
# Flags that don't match with with a *bindings module. Some used by adafruit_requests
6566
MPCONFIG_FLAGS = ["array", "errno", "io", "json", "math"]
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# SPDX-FileCopyrightText: 2026 Tim Cocks for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
4+
"""Test the msgpack module."""
5+
6+
import pytest
7+
8+
9+
ROUNDTRIP_CODE = """\
10+
import msgpack
11+
from io import BytesIO
12+
13+
obj = {"list": [True, False, None, 1, 3.125], "str": "blah"}
14+
b = BytesIO()
15+
msgpack.pack(obj, b)
16+
encoded = b.getvalue()
17+
print(f"encoded_len: {len(encoded)}")
18+
print(f"encoded_hex: {encoded.hex()}")
19+
20+
b.seek(0)
21+
decoded = msgpack.unpack(b)
22+
print(f"decoded: {decoded}")
23+
print(f"match: {decoded == obj}")
24+
print("done")
25+
"""
26+
27+
28+
@pytest.mark.circuitpy_drive({"code.py": ROUNDTRIP_CODE})
29+
def test_msgpack_roundtrip(circuitpython):
30+
"""Pack and unpack a dict containing the basic msgpack types."""
31+
circuitpython.wait_until_done()
32+
33+
output = circuitpython.serial.all_output
34+
assert "match: True" in output
35+
assert "done" in output
36+
37+
38+
USE_LIST_CODE = """\
39+
import msgpack
40+
from io import BytesIO
41+
42+
b = BytesIO()
43+
msgpack.pack([1, 2, 3], b)
44+
45+
b.seek(0)
46+
as_list = msgpack.unpack(b)
47+
print(f"as_list: {as_list} type={type(as_list).__name__}")
48+
49+
b.seek(0)
50+
as_tuple = msgpack.unpack(b, use_list=False)
51+
print(f"as_tuple: {as_tuple} type={type(as_tuple).__name__}")
52+
print("done")
53+
"""
54+
55+
56+
@pytest.mark.circuitpy_drive({"code.py": USE_LIST_CODE})
57+
def test_msgpack_use_list(circuitpython):
58+
"""use_list=False should return a tuple instead of a list."""
59+
circuitpython.wait_until_done()
60+
61+
output = circuitpython.serial.all_output
62+
assert "as_list: [1, 2, 3] type=list" in output
63+
assert "as_tuple: (1, 2, 3) type=tuple" in output
64+
assert "done" in output
65+
66+
67+
EXTTYPE_CODE = """\
68+
from msgpack import pack, unpack, ExtType
69+
from io import BytesIO
70+
71+
class MyClass:
72+
def __init__(self, val):
73+
self.value = val
74+
75+
data = MyClass(b"my_value")
76+
77+
def encoder(obj):
78+
if isinstance(obj, MyClass):
79+
return ExtType(1, obj.value)
80+
return f"no encoder for {obj}"
81+
82+
def decoder(code, data):
83+
if code == 1:
84+
return MyClass(data)
85+
return f"no decoder for type {code}"
86+
87+
buf = BytesIO()
88+
pack(data, buf, default=encoder)
89+
buf.seek(0)
90+
decoded = unpack(buf, ext_hook=decoder)
91+
print(f"decoded_type: {type(decoded).__name__}")
92+
print(f"decoded_value: {decoded.value}")
93+
print("done")
94+
"""
95+
96+
97+
@pytest.mark.circuitpy_drive({"code.py": EXTTYPE_CODE})
98+
def test_msgpack_exttype(circuitpython):
99+
"""ExtType with a custom encoder/decoder should round-trip."""
100+
circuitpython.wait_until_done()
101+
102+
output = circuitpython.serial.all_output
103+
assert "decoded_type: MyClass" in output
104+
assert "decoded_value: b'my_value'" in output
105+
assert "done" in output
106+
107+
108+
EXTTYPE_PROPS_CODE = """\
109+
from msgpack import ExtType
110+
111+
e = ExtType(5, b"hello")
112+
print(f"code: {e.code}")
113+
print(f"data: {e.data}")
114+
115+
e.code = 10
116+
print(f"new_code: {e.code}")
117+
118+
try:
119+
ExtType(128, b"x")
120+
except (ValueError, OverflowError) as ex:
121+
print(f"range_error: {type(ex).__name__}")
122+
123+
print("done")
124+
"""
125+
126+
127+
@pytest.mark.circuitpy_drive({"code.py": EXTTYPE_PROPS_CODE})
128+
def test_msgpack_exttype_properties(circuitpython):
129+
"""ExtType exposes code/data as read/write properties and rejects out-of-range codes."""
130+
circuitpython.wait_until_done()
131+
132+
output = circuitpython.serial.all_output
133+
assert "code: 5" in output
134+
assert "data: b'hello'" in output
135+
assert "new_code: 10" in output
136+
assert "range_error:" in output
137+
assert "done" in output

shared-module/msgpack/__init__.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,9 @@ static mp_obj_t unpack(msgpack_stream_t *s, mp_obj_t ext_hook, bool use_list) {
394394
size_t len = code & 0b1111;
395395
mp_obj_dict_t *d = MP_OBJ_TO_PTR(mp_obj_new_dict(len));
396396
for (size_t i = 0; i < len; i++) {
397-
mp_obj_dict_store(d, unpack(s, ext_hook, use_list), unpack(s, ext_hook, use_list));
397+
mp_obj_t key = unpack(s, ext_hook, use_list);
398+
mp_obj_t value = unpack(s, ext_hook, use_list);
399+
mp_obj_dict_store(d, key, value);
398400
}
399401
return MP_OBJ_FROM_PTR(d);
400402
}
@@ -462,7 +464,9 @@ static mp_obj_t unpack(msgpack_stream_t *s, mp_obj_t ext_hook, bool use_list) {
462464
size_t len = read_size(s, code - 0xde + 1);
463465
mp_obj_dict_t *d = MP_OBJ_TO_PTR(mp_obj_new_dict(len));
464466
for (size_t i = 0; i < len; i++) {
465-
mp_obj_dict_store(d, unpack(s, ext_hook, use_list), unpack(s, ext_hook, use_list));
467+
mp_obj_t key = unpack(s, ext_hook, use_list);
468+
mp_obj_t value = unpack(s, ext_hook, use_list);
469+
mp_obj_dict_store(d, key, value);
466470
}
467471
return MP_OBJ_FROM_PTR(d);
468472
}

0 commit comments

Comments
 (0)