Skip to content

Commit 3a10da8

Browse files
committed
merge fix
2 parents 1d3e11b + 3d8c01f commit 3a10da8

7 files changed

Lines changed: 67 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,17 @@ All notable changes to this project will be documented in this file.
33

44
The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
55

6+
## [Unreleased]
7+
8+
### Added
9+
10+
- Support for sending and receiving Int64 datatype (`h`).
11+
612
## [1.7.7]
713

8-
- Flaky test ntp bug fix.
14+
### Fixed
15+
16+
Flaky NTP test
917

1018
## [1.7.6]
1119

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Features
2020

2121
* UDP blocking/threading/forking/asyncio server implementations
2222
* UDP client
23-
* int, float, string, double, MIDI, timestamps, blob OSC arguments
23+
* int, int64, float, string, double, MIDI, timestamps, blob OSC arguments
2424
* simple OSC address<->callback matching system
2525
* extensive unit test coverage
2626
* basic client and server examples

pythonosc/osc_message.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ def _parse_datagram(self) -> None:
4040
for param in type_tag:
4141
if param == "i": # Integer.
4242
val, index = osc_types.get_int(self._dgram, index)
43+
elif param == "h": # Int64.
44+
val, index = osc_types.get_int64(self._dgram, index)
4345
elif param == "f": # Float.
4446
val, index = osc_types.get_float(self._dgram, index)
4547
elif param == "d": # Double.

pythonosc/osc_message_builder.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class OscMessageBuilder(object):
1515
ARG_TYPE_FLOAT = "f"
1616
ARG_TYPE_DOUBLE = "d"
1717
ARG_TYPE_INT = "i"
18+
ARG_TYPE_INT64 = "h"
1819
ARG_TYPE_STRING = "s"
1920
ARG_TYPE_BLOB = "b"
2021
ARG_TYPE_RGBA = "r"
@@ -27,7 +28,7 @@ class OscMessageBuilder(object):
2728
ARG_TYPE_ARRAY_STOP = "]"
2829

2930
_SUPPORTED_ARG_TYPES = (
30-
ARG_TYPE_FLOAT, ARG_TYPE_DOUBLE, ARG_TYPE_INT, ARG_TYPE_BLOB, ARG_TYPE_STRING,
31+
ARG_TYPE_FLOAT, ARG_TYPE_DOUBLE, ARG_TYPE_INT, ARG_TYPE_INT64, ARG_TYPE_BLOB, ARG_TYPE_STRING,
3132
ARG_TYPE_RGBA, ARG_TYPE_MIDI, ARG_TYPE_TRUE, ARG_TYPE_FALSE, ARG_TYPE_NIL)
3233

3334
def __init__(self, address: str=None) -> None:
@@ -105,7 +106,10 @@ def _get_arg_type(self, arg_value: Union[str, bytes, bool, int, float, tuple, li
105106
elif arg_value is False:
106107
arg_type = self.ARG_TYPE_FALSE
107108
elif isinstance(arg_value, int):
108-
arg_type = self.ARG_TYPE_INT
109+
if arg_value.bit_length() > 32:
110+
arg_type = self.ARG_TYPE_INT64
111+
else:
112+
arg_type = self.ARG_TYPE_INT
109113
elif isinstance(arg_value, float):
110114
arg_type = self.ARG_TYPE_FLOAT
111115
elif isinstance(arg_value, tuple) and len(arg_value) == 4:
@@ -146,6 +150,8 @@ def build(self) -> osc_message.OscMessage:
146150
dgram += osc_types.write_string(value)
147151
elif arg_type == self.ARG_TYPE_INT:
148152
dgram += osc_types.write_int(value)
153+
elif arg_type == self.ARG_TYPE_INT64:
154+
dgram += osc_types.write_int64(value)
149155
elif arg_type == self.ARG_TYPE_FLOAT:
150156
dgram += osc_types.write_float(value)
151157
elif arg_type == self.ARG_TYPE_DOUBLE:

pythonosc/parsing/osc_types.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class BuildError(Exception):
2121

2222
# Datagram length in bytes for types that have a fixed size.
2323
_INT_DGRAM_LEN = 4
24+
_INT64_DGRAM_LEN = 8
2425
_UINT64_DGRAM_LEN = 8
2526
_FLOAT_DGRAM_LEN = 4
2627
_DOUBLE_DGRAM_LEN = 8
@@ -126,6 +127,42 @@ def get_int(dgram: bytes, start_index: int) -> Tuple[int, int]:
126127
raise ParseError('Could not parse datagram %s' % e)
127128

128129

130+
def write_int64(val: int) -> bytes:
131+
"""Returns the datagram for the given 64-bit big-endian signed parameter value
132+
133+
Raises:
134+
- BuildError if the int64 could not be converted.
135+
"""
136+
try:
137+
return struct.pack('>q', val)
138+
except struct.error as e:
139+
raise BuildError('Wrong argument value passed: {}'.format(e))
140+
141+
142+
def get_int64(dgram: bytes, start_index: int) -> Tuple[int, int]:
143+
"""Get a 64-bit big-endian signed integer from the datagram.
144+
145+
Args:
146+
dgram: A datagram packet.
147+
start_index: An index where the 64-bit integer starts in the datagram.
148+
149+
Returns:
150+
A tuple containing the 64-bit integer and the new end index.
151+
152+
Raises:
153+
ParseError if the datagram could not be parsed.
154+
"""
155+
try:
156+
if len(dgram[start_index:]) < _INT64_DGRAM_LEN:
157+
raise ParseError('Datagram is too short')
158+
return (
159+
struct.unpack('>q',
160+
dgram[start_index:start_index + _INT64_DGRAM_LEN])[0],
161+
start_index + _INT64_DGRAM_LEN)
162+
except (struct.error, TypeError) as e:
163+
raise ParseError('Could not parse datagram %s' % e)
164+
165+
129166
def get_uint64(dgram: bytes, start_index: int) -> Tuple[int, int]:
130167
"""Get a 64-bit big-endian unsigned integer from the datagram.
131168

pythonosc/test/test_osc_message.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@
3434
b"/SYNC\x00\x00\x00"
3535
b"T" # True
3636
b"F" # False
37-
b"[]\x00\x00\x00" # Empty array
38-
b"t\x00\x00\x00\x00\x00\x00\x00\x00"
37+
b"[]th\x00\x00" # Empty array
38+
b"\x00\x00\x00\x00\x00\x00\x00\x00"
39+
b"\x00\x00\x00\xe8\xd4\xa5\x10\x00" # 1000000000000
3940
)
4041

4142
_DGRAM_COMPLEX_ARRAY_PARAMS = (
@@ -99,12 +100,13 @@ def test_all_non_standard_params(self):
99100
msg = osc_message.OscMessage(_DGRAM_ALL_NON_STANDARD_TYPES_OF_PARAMS)
100101

101102
self.assertEqual("/SYNC", msg.address)
102-
self.assertEqual(4, len(msg.params))
103+
self.assertEqual(5, len(msg.params))
103104
self.assertEqual(True, msg.params[0])
104105
self.assertEqual(False, msg.params[1])
105106
self.assertEqual([], msg.params[2])
106107
self.assertEqual((datetime(1900, 1, 1, 0, 0, 0), 0), msg.params[3])
107-
self.assertEqual(4, len(list(msg)))
108+
self.assertEqual(1000000000000, msg.params[4])
109+
self.assertEqual(5, len(list(msg)))
108110

109111
def test_complex_array_params(self):
110112
msg = osc_message.OscMessage(_DGRAM_COMPLEX_ARRAY_PARAMS)

pythonosc/test/test_osc_message_builder.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def test_all_param_types(self):
2727
builder = osc_message_builder.OscMessageBuilder(address="/SYNC")
2828
builder.add_arg(4.0)
2929
builder.add_arg(2)
30+
builder.add_arg(1099511627776)
3031
builder.add_arg("value")
3132
builder.add_arg(True)
3233
builder.add_arg(False)
@@ -36,6 +37,7 @@ def test_all_param_types(self):
3637
# The same args but with explicit types.
3738
builder.add_arg(4.0, builder.ARG_TYPE_FLOAT)
3839
builder.add_arg(2, builder.ARG_TYPE_INT)
40+
builder.add_arg(1099511627776, builder.ARG_TYPE_INT64)
3941
builder.add_arg("value", builder.ARG_TYPE_STRING)
4042
builder.add_arg(True)
4143
builder.add_arg(False)
@@ -45,13 +47,13 @@ def test_all_param_types(self):
4547
builder.add_arg(4278255360, builder.ARG_TYPE_RGBA)
4648
builder.add_arg((1, 145, 36, 125), builder.ARG_TYPE_MIDI)
4749
builder.add_arg(1e-9, builder.ARG_TYPE_DOUBLE)
48-
self.assertEqual(len("fisTFb[i[s]]N") * 2 + 3, len(builder.args))
50+
self.assertEqual(len("fihsTFb[i[s]]N") * 2 + 3, len(builder.args))
4951
self.assertEqual("/SYNC", builder.address)
5052
builder.address = '/SEEK'
5153
msg = builder.build()
5254
self.assertEqual("/SEEK", msg.address)
5355
self.assertSequenceEqual(
54-
[4.0, 2, "value", True, False, b"\x01\x02\x03", [1, ["abc"]]] * 2 +
56+
[4.0, 2, 1099511627776, "value", True, False, b"\x01\x02\x03", [1, ["abc"]]] * 2 +
5557
[4278255360, (1, 145, 36, 125), 1e-9],
5658
msg.params)
5759

0 commit comments

Comments
 (0)