From 30ef81c6655c7507eb8d9b5bbf7c4679e870250a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9?= Date: Fri, 26 Jul 2024 12:52:11 +0000 Subject: [PATCH] format with black and add gh action to check black format was applied --- .github/workflows/black.yml | 12 ++ .github/workflows/python-test.yml | 2 +- CONTRIBUTING.md | 7 +- docs/conf.py | 60 +++---- examples/async_server.py | 4 +- examples/dispatcher.py | 4 +- examples/simple_2way.py | 23 ++- examples/simple_client.py | 9 +- examples/simple_server.py | 10 +- pythonosc/dispatcher.py | 96 +++++++---- pythonosc/osc_bundle.py | 9 +- pythonosc/osc_bundle_builder.py | 12 +- pythonosc/osc_message.py | 18 +- pythonosc/osc_message_builder.py | 49 ++++-- pythonosc/osc_packet.py | 31 ++-- pythonosc/osc_server.py | 44 +++-- pythonosc/parsing/ntp.py | 21 ++- pythonosc/parsing/osc_types.py | 154 ++++++++--------- pythonosc/test/parsing/test_ntp.py | 2 +- pythonosc/test/parsing/test_osc_types.py | 182 +++++++++++---------- pythonosc/test/test_dispatcher.py | 120 +++++++++----- pythonosc/test/test_osc_bundle.py | 40 ++--- pythonosc/test/test_osc_bundle_builder.py | 6 +- pythonosc/test/test_osc_message.py | 45 ++--- pythonosc/test/test_osc_message_builder.py | 34 ++-- pythonosc/test/test_osc_packet.py | 12 +- pythonosc/test/test_osc_server.py | 34 ++-- pythonosc/test/test_udp_client.py | 23 +-- pythonosc/udp_client.py | 12 +- scripts/print_datagrams_main.py | 11 +- 30 files changed, 635 insertions(+), 451 deletions(-) create mode 100644 .github/workflows/black.yml diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml new file mode 100644 index 0000000..7afeb0b --- /dev/null +++ b/.github/workflows/black.yml @@ -0,0 +1,12 @@ +name: Lint with Black + +on: [push, pull_request] + +permissions: read-all + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: psf/black@stable \ No newline at end of file diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index 72dd0e1..8e7088e 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -35,7 +35,7 @@ jobs: # stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + flake8 . --count --exit-zero --max-complexity=10 --statistics - name: Check with mypy run: mypy pythonosc examples - name: Test with pytest diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d01b9ce..0146cae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,4 +2,9 @@ Thanks for contributing to this package! Before sending a PR, please make sure you checked the [python test workflow](.github/workflows/python-test.yml) and ran it locally, either using [act](https://nektosact.com) or by executing the workflow actions yourself. -Please only send the PR once all tests pass and mypy is happy, thanks! \ No newline at end of file +TL;DR: +- Format all code with Black +- Provide type annotations with mypy +- Write and run tests with pytest + +Please only send the PR once all of the above is done, thanks! \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index da3c34a..f14a2b2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,18 +17,19 @@ # sys.path.insert(0, os.path.abspath('.')) import os import sys + sys.path.insert(0, os.path.abspath("..")) # -- Project information ----------------------------------------------------- -project = 'python-osc' -copyright = '2019, attwad' -author = 'attwad' +project = "python-osc" +copyright = "2019, attwad" +author = "attwad" # The short X.Y version -version = '' +version = "" # The full version, including alpha/beta/rc tags -release = '1.7.1' +release = "1.7.1" # -- General configuration --------------------------------------------------- @@ -41,24 +42,24 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.coverage', - 'sphinx.ext.viewcode', - 'sphinx.ext.napoleon' + "sphinx.ext.autodoc", + "sphinx.ext.doctest", + "sphinx.ext.coverage", + "sphinx.ext.viewcode", + "sphinx.ext.napoleon", ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -70,7 +71,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The name of the Pygments (syntax highlighting) style to use. pygments_style = None @@ -81,7 +82,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -92,7 +93,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Custom sidebar templates, must be a dictionary that maps document names # to template names. @@ -108,7 +109,7 @@ # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. -htmlhelp_basename = 'python-oscdoc' +htmlhelp_basename = "python-oscdoc" # -- Options for LaTeX output ------------------------------------------------ @@ -117,15 +118,12 @@ # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # 'preamble': '', - # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -135,8 +133,7 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'python-osc.tex', 'python-osc Documentation', - 'attwad', 'manual'), + (master_doc, "python-osc.tex", "python-osc Documentation", "attwad", "manual"), ] @@ -144,10 +141,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'python-osc', 'python-osc Documentation', - [author], 1) -] +man_pages = [(master_doc, "python-osc", "python-osc Documentation", [author], 1)] # -- Options for Texinfo output ---------------------------------------------- @@ -156,9 +150,15 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'python-osc', 'python-osc Documentation', - author, 'python-osc', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "python-osc", + "python-osc Documentation", + author, + "python-osc", + "One line description of project.", + "Miscellaneous", + ), ] @@ -177,7 +177,7 @@ # epub_uid = '' # A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] +epub_exclude_files = ["search.html"] # -- Extension configuration ------------------------------------------------- diff --git a/examples/async_server.py b/examples/async_server.py index 5b724c0..87945eb 100644 --- a/examples/async_server.py +++ b/examples/async_server.py @@ -24,7 +24,9 @@ async def loop(): async def init_main(): server = AsyncIOOSCUDPServer((ip, port), dispatcher, asyncio.get_event_loop()) - transport, protocol = await server.create_serve_endpoint() # Create datagram endpoint and start serving + transport, protocol = ( + await server.create_serve_endpoint() + ) # Create datagram endpoint and start serving await loop() # Enter main loop of program diff --git a/examples/dispatcher.py b/examples/dispatcher.py index 59bb2de..7dc7e3d 100644 --- a/examples/dispatcher.py +++ b/examples/dispatcher.py @@ -29,8 +29,8 @@ def set_filter(address: str, *args: List[Any]) -> None: client = SimpleUDPClient("127.0.0.1", 1337) # Send message and receive exactly one message (blocking) -client.send_message("/filter1", [1., 2.]) +client.send_message("/filter1", [1.0, 2.0]) server.handle_request() -client.send_message("/filter8", [6., -2.]) +client.send_message("/filter8", [6.0, -2.0]) server.handle_request() diff --git a/examples/simple_2way.py b/examples/simple_2way.py index 5356efb..2a7b555 100644 --- a/examples/simple_2way.py +++ b/examples/simple_2way.py @@ -25,9 +25,21 @@ def print_xy_fader_handler(unused_addr, args, value1, value2): if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--serverip", default="127.0.0.1", help="The ip to listen on") - parser.add_argument("--serverport", type=int, default=5005, help="The port the OSC Server is listening on") - parser.add_argument("--clientip", default="127.0.0.1", help="The ip of the OSC server") - parser.add_argument("--clientport", type=int, default=5006, help="The port the OSC Client is listening on") + parser.add_argument( + "--serverport", + type=int, + default=5005, + help="The port the OSC Server is listening on", + ) + parser.add_argument( + "--clientip", default="127.0.0.1", help="The ip of the OSC server" + ) + parser.add_argument( + "--clientport", + type=int, + default=5006, + help="The port the OSC Client is listening on", + ) args = parser.parse_args() # listen to addresses and print changes in values @@ -41,8 +53,7 @@ def print_xy_fader_handler(unused_addr, args, value1, value2): def start_server(ip, port): print("Starting Server") - server = osc_server.ThreadingOSCUDPServer( - (ip, port), dispatcher) + server = osc_server.ThreadingOSCUDPServer((ip, port), dispatcher) print("Serving on {}".format(server.server_address)) thread = threading.Thread(target=server.serve_forever) thread.start() @@ -63,7 +74,7 @@ def random_values(client): client.send_message("/1/fader2", random.random()) client.send_message("/1/fader1", random.random()) client.send_message("/1/xy1", [random.random(), random.random()]) - time.sleep(.5) + time.sleep(0.5) start_server(args.serverip, args.serverport) diff --git a/examples/simple_client.py b/examples/simple_client.py index b5f93e3..26849b6 100644 --- a/examples/simple_client.py +++ b/examples/simple_client.py @@ -3,6 +3,7 @@ This program sends 10 random values between 0.0 and 1.0 to the /filter address, waiting for 1 seconds between each value. """ + import argparse import random import time @@ -11,10 +12,10 @@ if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument("--ip", default="127.0.0.1", - help="The ip of the OSC server") - parser.add_argument("--port", type=int, default=5005, - help="The port the OSC server is listening on") + parser.add_argument("--ip", default="127.0.0.1", help="The ip of the OSC server") + parser.add_argument( + "--port", type=int, default=5005, help="The port the OSC server is listening on" + ) args = parser.parse_args() client = udp_client.SimpleUDPClient(args.ip, args.port) diff --git a/examples/simple_server.py b/examples/simple_server.py index 552fb39..a862457 100644 --- a/examples/simple_server.py +++ b/examples/simple_server.py @@ -3,6 +3,7 @@ This program listens to several addresses, and prints some information about received packets. """ + import argparse import math @@ -23,10 +24,8 @@ def print_compute_handler(unused_addr, args, volume): if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument("--ip", - default="127.0.0.1", help="The ip to listen on") - parser.add_argument("--port", - type=int, default=5005, help="The port to listen on") + parser.add_argument("--ip", default="127.0.0.1", help="The ip to listen on") + parser.add_argument("--port", type=int, default=5005, help="The port to listen on") args = parser.parse_args() dispatcher = Dispatcher() @@ -34,7 +33,6 @@ def print_compute_handler(unused_addr, args, volume): dispatcher.map("/volume", print_volume_handler, "Volume") dispatcher.map("/logvolume", print_compute_handler, "Log volume", math.log) - server = osc_server.ThreadingOSCUDPServer( - (args.ip, args.port), dispatcher) + server = osc_server.ThreadingOSCUDPServer((args.ip, args.port), dispatcher) print("Serving on {}".format(server.server_address)) server.serve_forever() diff --git a/pythonosc/dispatcher.py b/pythonosc/dispatcher.py index 03b767a..462a0c1 100644 --- a/pythonosc/dispatcher.py +++ b/pythonosc/dispatcher.py @@ -6,7 +6,17 @@ import re import time from pythonosc import osc_packet -from typing import overload, List, Union, Any, Generator, Tuple, Callable, Optional, DefaultDict +from typing import ( + overload, + List, + Union, + Any, + Generator, + Tuple, + Callable, + Optional, + DefaultDict, +) from pythonosc.osc_message import OscMessage @@ -18,24 +28,30 @@ class Handler(object): message if any were passed. """ - def __init__(self, _callback: Callable, _args: Union[Any, List[Any]], - _needs_reply_address: bool = False) -> None: + def __init__( + self, + _callback: Callable, + _args: Union[Any, List[Any]], + _needs_reply_address: bool = False, + ) -> None: """ Args: _callback Function that is called when handler is invoked _args: Message causing invocation _needs_reply_address Whether the client's ip address shall be passed as an argument or not - """ + """ self.callback = _callback self.args = _args self.needs_reply_address = _needs_reply_address # needed for test module def __eq__(self, other: Any) -> bool: - return (isinstance(self, type(other)) and - self.callback == other.callback and - self.args == other.args and - self.needs_reply_address == other.needs_reply_address) + return ( + isinstance(self, type(other)) + and self.callback == other.callback + and self.args == other.args + and self.needs_reply_address == other.needs_reply_address + ) def invoke(self, client_address: Tuple[str, int], message: OscMessage) -> None: """Invokes the associated callback function @@ -43,7 +59,7 @@ def invoke(self, client_address: Tuple[str, int], message: OscMessage) -> None: Args: client_address: Address match that causes the invocation message: Message causing invocation - """ + """ if self.needs_reply_address: if self.args: self.callback(client_address, message.address, self.args, *message) @@ -66,8 +82,13 @@ def __init__(self) -> None: self._map: DefaultDict[str, List[Handler]] = collections.defaultdict(list) self._default_handler: Optional[Handler] = None - def map(self, address: str, handler: Callable, *args: Union[Any, List[Any]], - needs_reply_address: bool = False) -> Handler: + def map( + self, + address: str, + handler: Callable, + *args: Union[Any, List[Any]], + needs_reply_address: bool = False, + ) -> Handler: """Map an address to a handler The callback function must have one of the following signatures: @@ -107,8 +128,13 @@ def unmap(self, address: str, handler: Handler) -> None: pass @overload - def unmap(self, address: str, handler: Callable, *args: Union[Any, List[Any]], - needs_reply_address: bool = False) -> None: + def unmap( + self, + address: str, + handler: Callable, + *args: Union[Any, List[Any]], + needs_reply_address: bool = False, + ) -> None: """Remove an already mapped handler from an address Args: @@ -127,12 +153,19 @@ def unmap(self, address, handler, *args, needs_reply_address=False): if isinstance(handler, Handler): self._map[address].remove(handler) else: - self._map[address].remove(Handler(handler, list(args), needs_reply_address)) + self._map[address].remove( + Handler(handler, list(args), needs_reply_address) + ) except ValueError as e: if str(e) == "list.remove(x): x not in list": - raise ValueError("Address '%s' doesn't have handler '%s' mapped to it" % (address, handler)) from e - - def handlers_for_address(self, address_pattern: str) -> Generator[Handler, None, None]: + raise ValueError( + "Address '%s' doesn't have handler '%s' mapped to it" + % (address, handler) + ) from e + + def handlers_for_address( + self, address_pattern: str + ) -> Generator[Handler, None, None]: """Yields handlers matching an address @@ -147,27 +180,31 @@ def handlers_for_address(self, address_pattern: str) -> Generator[Handler, None, # Let's consider numbers and _ "characters" too here, it's not said # explicitly in the specification but it sounds good. escaped_address_pattern = re.escape(address_pattern) - pattern = escaped_address_pattern.replace('\\?', '\\w?') + pattern = escaped_address_pattern.replace("\\?", "\\w?") # '*' in the OSC Address Pattern matches any sequence of zero or more # characters. - pattern = pattern.replace('\\*', '[\\w|\\+]*') + pattern = pattern.replace("\\*", "[\\w|\\+]*") # The rest of the syntax in the specification is like the re module so # we're fine. - pattern = pattern + '$' + pattern = pattern + "$" patterncompiled = re.compile(pattern) matched = False for addr, handlers in self._map.items(): - if (patterncompiled.match(addr) - or (('*' in addr) and re.match(addr.replace('*', '[^/]*?/*'), address_pattern))): + if patterncompiled.match(addr) or ( + ("*" in addr) + and re.match(addr.replace("*", "[^/]*?/*"), address_pattern) + ): yield from handlers matched = True if not matched and self._default_handler: - logging.debug('No handler matched but default handler present, added it.') + logging.debug("No handler matched but default handler present, added it.") yield self._default_handler - def call_handlers_for_packet(self, data: bytes, client_address: Tuple[str, int]) -> None: + def call_handlers_for_packet( + self, data: bytes, client_address: Tuple[str, int] + ) -> None: """Invoke handlers for all messages in OSC packet The incoming OSC Packet is decoded and the handlers for each included message is found and invoked. @@ -182,8 +219,7 @@ def call_handlers_for_packet(self, data: bytes, client_address: Tuple[str, int]) packet = osc_packet.OscPacket(data) for timed_msg in packet.messages: now = time.time() - handlers = self.handlers_for_address( - timed_msg.message.address) + handlers = self.handlers_for_address(timed_msg.message.address) if not handlers: continue # If the message is to be handled later, then so be it. @@ -194,7 +230,9 @@ def call_handlers_for_packet(self, data: bytes, client_address: Tuple[str, int]) except osc_packet.ParseError: pass - def set_default_handler(self, handler: Callable, needs_reply_address: bool = False) -> None: + def set_default_handler( + self, handler: Callable, needs_reply_address: bool = False + ) -> None: """Sets the default handler The default handler is invoked every time no other handler is mapped to an address. @@ -203,4 +241,6 @@ def set_default_handler(self, handler: Callable, needs_reply_address: bool = Fal handler: Callback function to handle unmapped requests needs_reply_address: Whether the callback shall be passed the client address """ - self._default_handler = None if (handler is None) else Handler(handler, [], needs_reply_address) + self._default_handler = ( + None if (handler is None) else Handler(handler, [], needs_reply_address) + ) diff --git a/pythonosc/osc_bundle.py b/pythonosc/osc_bundle.py index 274bef6..9598624 100644 --- a/pythonosc/osc_bundle.py +++ b/pythonosc/osc_bundle.py @@ -37,7 +37,9 @@ def __init__(self, dgram: bytes) -> None: # Get the contents as a list of OscBundle and OscMessage. self._contents = self._parse_contents(index) - def _parse_contents(self, index: int) -> List[Union['OscBundle', osc_message.OscMessage]]: + def _parse_contents( + self, index: int + ) -> List[Union["OscBundle", osc_message.OscMessage]]: contents = [] # type: List[Union[OscBundle, osc_message.OscMessage]] try: @@ -49,7 +51,7 @@ def _parse_contents(self, index: int) -> List[Union['OscBundle', osc_message.Osc # Get the sub content size. content_size, index = osc_types.get_int(self._dgram, index) # Get the datagram for the sub content. - content_dgram = self._dgram[index:index + content_size] + content_dgram = self._dgram[index : index + content_size] # Increment our position index up to the next possible content. index += content_size # Parse the content into an OSC message or bundle. @@ -59,7 +61,8 @@ def _parse_contents(self, index: int) -> List[Union['OscBundle', osc_message.Osc contents.append(osc_message.OscMessage(content_dgram)) else: logging.warning( - "Could not identify content type of dgram %r" % content_dgram) + "Could not identify content type of dgram %r" % content_dgram + ) except (osc_types.ParseError, osc_message.ParseError, IndexError) as e: raise ParseError("Could not parse a content datagram: %s" % e) diff --git a/pythonosc/osc_bundle_builder.py b/pythonosc/osc_bundle_builder.py index a438729..2779269 100644 --- a/pythonosc/osc_bundle_builder.py +++ b/pythonosc/osc_bundle_builder.py @@ -41,19 +41,21 @@ def build(self) -> osc_bundle.OscBundle: Raises: - BuildError: if we could not build the bundle. """ - dgram = b'#bundle\x00' + dgram = b"#bundle\x00" try: dgram += osc_types.write_date(self._timestamp) for content in self._contents: - if (isinstance(content, osc_message.OscMessage) - or isinstance(content, osc_bundle.OscBundle)): + if isinstance(content, osc_message.OscMessage) or isinstance( + content, osc_bundle.OscBundle + ): size = content.size dgram += osc_types.write_int(size) dgram += content.dgram else: raise BuildError( "Content must be either OscBundle or OscMessage" - "found {}".format(type(content))) + "found {}".format(type(content)) + ) return osc_bundle.OscBundle(dgram) except osc_types.BuildError as be: - raise BuildError('Could not build the bundle {}'.format(be)) + raise BuildError("Could not build the bundle {}".format(be)) diff --git a/pythonosc/osc_message.py b/pythonosc/osc_message.py index 55b0a0e..3d46551 100644 --- a/pythonosc/osc_message.py +++ b/pythonosc/osc_message.py @@ -31,7 +31,7 @@ def _parse_datagram(self) -> None: # Get the parameters types. type_tag, index = osc_types.get_string(self._dgram, index) - if type_tag.startswith(','): + if type_tag.startswith(","): type_tag = type_tag[1:] params = [] # type: List[Any] @@ -69,19 +69,25 @@ def _parse_datagram(self) -> None: param_stack.append(array) elif param == "]": # Array stop. if len(param_stack) < 2: - raise ParseError('Unexpected closing bracket in type tag: {0}'.format(type_tag)) + raise ParseError( + "Unexpected closing bracket in type tag: {0}".format( + type_tag + ) + ) param_stack.pop() # TODO: Support more exotic types as described in the specification. else: - logging.warning('Unhandled parameter type: {0}'.format(param)) + logging.warning("Unhandled parameter type: {0}".format(param)) continue if param not in "[]": param_stack[-1].append(val) if len(param_stack) != 1: - raise ParseError('Missing closing bracket in type tag: {0}'.format(type_tag)) + raise ParseError( + "Missing closing bracket in type tag: {0}".format(type_tag) + ) self._parameters = params except osc_types.ParseError as pe: - raise ParseError('Found incorrect datagram, ignoring it', pe) + raise ParseError("Found incorrect datagram, ignoring it", pe) @property def address(self) -> str: @@ -91,7 +97,7 @@ def address(self) -> str: @staticmethod def dgram_is_message(dgram: bytes) -> bool: """Returns whether this datagram starts as an OSC message.""" - return dgram.startswith(b'/') + return dgram.startswith(b"/") @property def size(self) -> int: diff --git a/pythonosc/osc_message_builder.py b/pythonosc/osc_message_builder.py index b3b1fdc..e91b76c 100644 --- a/pythonosc/osc_message_builder.py +++ b/pythonosc/osc_message_builder.py @@ -31,8 +31,18 @@ class OscMessageBuilder(object): ARG_TYPE_ARRAY_STOP = "]" _SUPPORTED_ARG_TYPES = ( - ARG_TYPE_FLOAT, ARG_TYPE_DOUBLE, ARG_TYPE_INT, ARG_TYPE_INT64, ARG_TYPE_BLOB, ARG_TYPE_STRING, - ARG_TYPE_RGBA, ARG_TYPE_MIDI, ARG_TYPE_TRUE, ARG_TYPE_FALSE, ARG_TYPE_NIL) + ARG_TYPE_FLOAT, + ARG_TYPE_DOUBLE, + ARG_TYPE_INT, + ARG_TYPE_INT64, + ARG_TYPE_BLOB, + ARG_TYPE_STRING, + ARG_TYPE_RGBA, + ARG_TYPE_MIDI, + ARG_TYPE_TRUE, + ARG_TYPE_FALSE, + ARG_TYPE_NIL, + ) def __init__(self, address: Optional[str] = None) -> None: """Initialize a new builder for a message. @@ -80,8 +90,10 @@ def add_arg(self, arg_value: ArgValue, arg_type: Optional[str] = None) -> None: """ if arg_type and not self._valid_type(arg_type): raise ValueError( - 'arg_type must be one of {}, or an array of valid types' - .format(self._SUPPORTED_ARG_TYPES)) + "arg_type must be one of {}, or an array of valid types".format( + self._SUPPORTED_ARG_TYPES + ) + ) if not arg_type: arg_type = self._get_arg_type(arg_value) if isinstance(arg_type, list): @@ -124,7 +136,7 @@ def _get_arg_type(self, arg_value: ArgValue) -> Union[str, Any]: elif arg_value is None: arg_type = self.ARG_TYPE_NIL else: - raise ValueError('Infered arg_value type is not supported') + raise ValueError("Infered arg_value type is not supported") return arg_type def build(self) -> osc_message.OscMessage: @@ -138,18 +150,18 @@ def build(self) -> osc_message.OscMessage: - an osc_message.OscMessage instance. """ if not self._address: - raise BuildError('OSC addresses cannot be empty') - dgram = b'' + raise BuildError("OSC addresses cannot be empty") + dgram = b"" try: # Write the address. dgram += osc_types.write_string(self._address) if not self._args: - dgram += osc_types.write_string(',') + dgram += osc_types.write_string(",") return osc_message.OscMessage(dgram) # Write the parameters. arg_types = "".join([arg[0] for arg in self._args]) - dgram += osc_types.write_string(',' + arg_types) + dgram += osc_types.write_string("," + arg_types) for arg_type, value in self._args: if arg_type == self.ARG_TYPE_STRING: dgram += osc_types.write_string(value) # type: ignore[arg-type] @@ -167,16 +179,19 @@ def build(self) -> osc_message.OscMessage: dgram += osc_types.write_rgba(value) # type: ignore[arg-type] elif arg_type == self.ARG_TYPE_MIDI: dgram += osc_types.write_midi(value) # type: ignore[arg-type] - elif arg_type in (self.ARG_TYPE_TRUE, - self.ARG_TYPE_FALSE, - self.ARG_TYPE_ARRAY_START, - self.ARG_TYPE_ARRAY_STOP, - self.ARG_TYPE_NIL): + elif arg_type in ( + self.ARG_TYPE_TRUE, + self.ARG_TYPE_FALSE, + self.ARG_TYPE_ARRAY_START, + self.ARG_TYPE_ARRAY_STOP, + self.ARG_TYPE_NIL, + ): continue else: - raise BuildError('Incorrect parameter type found {}'.format( - arg_type)) + raise BuildError( + "Incorrect parameter type found {}".format(arg_type) + ) return osc_message.OscMessage(dgram) except osc_types.BuildError as be: - raise BuildError('Could not build the message: {}'.format(be)) + raise BuildError("Could not build the message: {}".format(be)) diff --git a/pythonosc/osc_packet.py b/pythonosc/osc_packet.py index 32b88a8..9589c90 100644 --- a/pythonosc/osc_packet.py +++ b/pythonosc/osc_packet.py @@ -15,18 +15,23 @@ # 1) the system time at which the message should be executed # in seconds since the epoch. # 2) the actual message. -TimedMessage = NamedTuple('TimedMessage', [ - ('time', float), - ('message', osc_message.OscMessage), -]) - - -def _timed_msg_of_bundle(bundle: osc_bundle.OscBundle, now: float) -> List[TimedMessage]: +TimedMessage = NamedTuple( + "TimedMessage", + [ + ("time", float), + ("message", osc_message.OscMessage), + ], +) + + +def _timed_msg_of_bundle( + bundle: osc_bundle.OscBundle, now: float +) -> List[TimedMessage]: """Returns messages contained in nested bundles as a list of TimedMessage.""" msgs = [] for content in bundle: if type(content) is osc_message.OscMessage: - if (bundle.timestamp == osc_types.IMMEDIATELY or bundle.timestamp < now): + if bundle.timestamp == osc_types.IMMEDIATELY or bundle.timestamp < now: msgs.append(TimedMessage(now, content)) else: msgs.append(TimedMessage(bundle.timestamp, content)) @@ -60,16 +65,18 @@ def __init__(self, dgram: bytes) -> None: if osc_bundle.OscBundle.dgram_is_bundle(dgram): self._messages = sorted( _timed_msg_of_bundle(osc_bundle.OscBundle(dgram), now), - key=lambda x: x.time) + key=lambda x: x.time, + ) elif osc_message.OscMessage.dgram_is_message(dgram): self._messages = [TimedMessage(now, osc_message.OscMessage(dgram))] else: # Empty packet, should not happen as per the spec but heh, UDP... raise ParseError( - 'OSC Packet should at least contain an OscMessage or an ' - 'OscBundle.') + "OSC Packet should at least contain an OscMessage or an " + "OscBundle." + ) except (osc_bundle.ParseError, osc_message.ParseError) as pe: - raise ParseError('Could not parse packet %s' % pe) + raise ParseError("Could not parse packet %s" % pe) @property def messages(self) -> List[TimedMessage]: diff --git a/pythonosc/osc_server.py b/pythonosc/osc_server.py index 62f7df9..7de729e 100644 --- a/pythonosc/osc_server.py +++ b/pythonosc/osc_server.py @@ -39,17 +39,24 @@ def _is_valid_request(request: _RequestType) -> bool: Returns: True if request is OSC bundle or OSC message """ - assert isinstance(request, tuple) # TODO: handle requests which are passed just as a socket? + assert isinstance( + request, tuple + ) # TODO: handle requests which are passed just as a socket? data = request[0] - return ( - osc_bundle.OscBundle.dgram_is_bundle(data) - or osc_message.OscMessage.dgram_is_message(data)) + return osc_bundle.OscBundle.dgram_is_bundle( + data + ) or osc_message.OscMessage.dgram_is_message(data) class OSCUDPServer(socketserver.UDPServer): """Superclass for different flavors of OSC UDP servers""" - def __init__(self, server_address: Tuple[str, int], dispatcher: Dispatcher, bind_and_activate: bool = True) -> None: + def __init__( + self, + server_address: Tuple[str, int], + dispatcher: Dispatcher, + bind_and_activate: bool = True, + ) -> None: """Initialize Args: @@ -60,7 +67,9 @@ def __init__(self, server_address: Tuple[str, int], dispatcher: Dispatcher, bind super().__init__(server_address, _UDPHandler, bind_and_activate) self._dispatcher = dispatcher - def verify_request(self, request: _RequestType, client_address: _AddressType) -> bool: + def verify_request( + self, request: _RequestType, client_address: _AddressType + ) -> bool: """Returns true if the data looks like a valid OSC UDP datagram Args: @@ -95,6 +104,7 @@ class ThreadingOSCUDPServer(socketserver.ThreadingMixIn, OSCUDPServer): if hasattr(os, "fork"): + class ForkingOSCUDPServer(socketserver.ForkingMixIn, OSCUDPServer): """Forking version of the OSC UDP server. @@ -104,13 +114,18 @@ class ForkingOSCUDPServer(socketserver.ForkingMixIn, OSCUDPServer): """ -class AsyncIOOSCUDPServer(): +class AsyncIOOSCUDPServer: """Asynchronous OSC Server An asynchronous OSC Server using UDP. It creates a datagram endpoint that runs in an event loop. """ - def __init__(self, server_address: Tuple[str, int], dispatcher: Dispatcher, loop: BaseEventLoop) -> None: + def __init__( + self, + server_address: Tuple[str, int], + dispatcher: Dispatcher, + loop: BaseEventLoop, + ) -> None: """Initialize Args: @@ -130,7 +145,9 @@ class _OSCProtocolFactory(asyncio.DatagramProtocol): def __init__(self, dispatcher: Dispatcher) -> None: self.dispatcher = dispatcher - def datagram_received(self, data: bytes, client_address: Tuple[str, int]) -> None: + def datagram_received( + self, data: bytes, client_address: Tuple[str, int] + ) -> None: self.dispatcher.call_handlers_for_packet(data, client_address) def serve(self) -> None: @@ -141,7 +158,11 @@ def serve(self) -> None: """ self._loop.run_until_complete(self.create_serve_endpoint()) - def create_serve_endpoint(self) -> Coroutine[Any, Any, Tuple[asyncio.transports.BaseTransport, asyncio.DatagramProtocol]]: + def create_serve_endpoint( + self, + ) -> Coroutine[ + Any, Any, Tuple[asyncio.transports.BaseTransport, asyncio.DatagramProtocol] + ]: """Creates a datagram endpoint and registers it with event loop as coroutine. Returns: @@ -149,7 +170,8 @@ def create_serve_endpoint(self) -> Coroutine[Any, Any, Tuple[asyncio.transports. """ return self._loop.create_datagram_endpoint( lambda: self._OSCProtocolFactory(self.dispatcher), - local_addr=self._server_address) + local_addr=self._server_address, + ) @property def dispatcher(self) -> Dispatcher: diff --git a/pythonosc/parsing/ntp.py b/pythonosc/parsing/ntp.py index c944fd8..068a82a 100644 --- a/pythonosc/parsing/ntp.py +++ b/pythonosc/parsing/ntp.py @@ -8,11 +8,11 @@ # 63 zero bits followed by a one in the least signifigant bit is a special # case meaning "immediately." -IMMEDIATELY = struct.pack('>Q', 1) +IMMEDIATELY = struct.pack(">Q", 1) # timetag * (1 / 2 ** 32) == l32bits + (r32bits / 1 ** 32) -_NTP_TIMESTAMP_TO_SECONDS = 1. / 2. ** 32. -_SECONDS_TO_NTP_TIMESTAMP = 2. ** 32. +_NTP_TIMESTAMP_TO_SECONDS = 1.0 / 2.0**32.0 +_SECONDS_TO_NTP_TIMESTAMP = 2.0**32.0 # From NTP lib. _SYSTEM_EPOCH = datetime.date(*time.gmtime(0)[0:3]) @@ -21,10 +21,13 @@ _NTP_DELTA = (_SYSTEM_EPOCH - _NTP_EPOCH).days * 24 * 3600 -Timestamp = NamedTuple('Timestamp', [ - ('seconds', int), - ('fraction', int), -]) +Timestamp = NamedTuple( + "Timestamp", + [ + ("seconds", int), + ("fraction", int), + ], +) class NtpError(Exception): @@ -41,7 +44,7 @@ def parse_timestamp(timestamp: int) -> Timestamp: def ntp_to_system_time(timestamp: bytes) -> float: """Convert a NTP timestamp to system time in seconds.""" try: - ts = struct.unpack('>Q', timestamp)[0] + ts = struct.unpack(">Q", timestamp)[0] except Exception as e: raise NtpError(e) return ts * _NTP_TIMESTAMP_TO_SECONDS - _NTP_DELTA @@ -53,7 +56,7 @@ def system_time_to_ntp(seconds: float) -> bytes: seconds = seconds + _NTP_DELTA except TypeError as e: raise NtpError(e) - return struct.pack('>Q', int(seconds * _SECONDS_TO_NTP_TIMESTAMP)) + return struct.pack(">Q", int(seconds * _SECONDS_TO_NTP_TIMESTAMP)) def ntp_time_to_system_epoch(seconds: float) -> float: diff --git a/pythonosc/parsing/osc_types.py b/pythonosc/parsing/osc_types.py index 97361ee..5d0ba48 100644 --- a/pythonosc/parsing/osc_types.py +++ b/pythonosc/parsing/osc_types.py @@ -31,7 +31,7 @@ class BuildError(Exception): # Strings and blob dgram length is always a multiple of 4 bytes. _STRING_DGRAM_PAD = 4 _BLOB_DGRAM_PAD = 4 -_EMPTY_STR_DGRAM = b'\x00\x00\x00\x00' +_EMPTY_STR_DGRAM = b"\x00\x00\x00\x00" def write_string(val: str) -> bytes: @@ -41,11 +41,11 @@ def write_string(val: str) -> bytes: - BuildError if the string could not be encoded. """ try: - dgram = val.encode('utf-8') # Default, but better be explicit. + dgram = val.encode("utf-8") # Default, but better be explicit. except (UnicodeEncodeError, AttributeError) as e: - raise BuildError('Incorrect string, could not encode {}'.format(e)) + raise BuildError("Incorrect string, could not encode {}".format(e)) diff = _STRING_DGRAM_PAD - (len(dgram) % _STRING_DGRAM_PAD) - dgram += (b'\x00' * diff) + dgram += b"\x00" * diff return dgram @@ -68,29 +68,31 @@ def get_string(dgram: bytes, start_index: int) -> Tuple[str, int]: ParseError if the datagram could not be parsed. """ if start_index < 0: - raise ParseError('start_index < 0') + raise ParseError("start_index < 0") offset = 0 try: - if (len(dgram) > start_index + _STRING_DGRAM_PAD - and dgram[start_index + _STRING_DGRAM_PAD] == _EMPTY_STR_DGRAM): - return '', start_index + _STRING_DGRAM_PAD + if ( + len(dgram) > start_index + _STRING_DGRAM_PAD + and dgram[start_index + _STRING_DGRAM_PAD] == _EMPTY_STR_DGRAM + ): + return "", start_index + _STRING_DGRAM_PAD while dgram[start_index + offset] != 0: offset += 1 # Align to a byte word. if (offset) % _STRING_DGRAM_PAD == 0: offset += _STRING_DGRAM_PAD else: - offset += (-offset % _STRING_DGRAM_PAD) + offset += -offset % _STRING_DGRAM_PAD # Python slices do not raise an IndexError past the last index, # do it ourselves. if offset > len(dgram[start_index:]): - raise ParseError('Datagram is too short') - data_str = dgram[start_index:start_index + offset] - return data_str.replace(b'\x00', b'').decode('utf-8'), start_index + offset + raise ParseError("Datagram is too short") + data_str = dgram[start_index : start_index + offset] + return data_str.replace(b"\x00", b"").decode("utf-8"), start_index + offset except IndexError as ie: - raise ParseError('Could not parse datagram %s' % ie) + raise ParseError("Could not parse datagram %s" % ie) except TypeError as te: - raise ParseError('Could not parse datagram %s' % te) + raise ParseError("Could not parse datagram %s" % te) def write_int(val: int) -> bytes: @@ -100,9 +102,9 @@ def write_int(val: int) -> bytes: - BuildError if the int could not be converted. """ try: - return struct.pack('>i', val) + return struct.pack(">i", val) except struct.error as e: - raise BuildError('Wrong argument value passed: {}'.format(e)) + raise BuildError("Wrong argument value passed: {}".format(e)) def get_int(dgram: bytes, start_index: int) -> Tuple[int, int]: @@ -120,13 +122,13 @@ def get_int(dgram: bytes, start_index: int) -> Tuple[int, int]: """ try: if len(dgram[start_index:]) < _INT_DGRAM_LEN: - raise ParseError('Datagram is too short') + raise ParseError("Datagram is too short") return ( - struct.unpack('>i', - dgram[start_index:start_index + _INT_DGRAM_LEN])[0], - start_index + _INT_DGRAM_LEN) + struct.unpack(">i", dgram[start_index : start_index + _INT_DGRAM_LEN])[0], + start_index + _INT_DGRAM_LEN, + ) except (struct.error, TypeError) as e: - raise ParseError('Could not parse datagram %s' % e) + raise ParseError("Could not parse datagram %s" % e) def write_int64(val: int) -> bytes: @@ -136,9 +138,9 @@ def write_int64(val: int) -> bytes: - BuildError if the int64 could not be converted. """ try: - return struct.pack('>q', val) + return struct.pack(">q", val) except struct.error as e: - raise BuildError('Wrong argument value passed: {}'.format(e)) + raise BuildError("Wrong argument value passed: {}".format(e)) def get_int64(dgram: bytes, start_index: int) -> Tuple[int, int]: @@ -156,13 +158,13 @@ def get_int64(dgram: bytes, start_index: int) -> Tuple[int, int]: """ try: if len(dgram[start_index:]) < _INT64_DGRAM_LEN: - raise ParseError('Datagram is too short') + raise ParseError("Datagram is too short") return ( - struct.unpack('>q', - dgram[start_index:start_index + _INT64_DGRAM_LEN])[0], - start_index + _INT64_DGRAM_LEN) + struct.unpack(">q", dgram[start_index : start_index + _INT64_DGRAM_LEN])[0], + start_index + _INT64_DGRAM_LEN, + ) except (struct.error, TypeError) as e: - raise ParseError('Could not parse datagram %s' % e) + raise ParseError("Could not parse datagram %s" % e) def get_uint64(dgram: bytes, start_index: int) -> Tuple[int, int]: @@ -180,13 +182,15 @@ def get_uint64(dgram: bytes, start_index: int) -> Tuple[int, int]: """ try: if len(dgram[start_index:]) < _UINT64_DGRAM_LEN: - raise ParseError('Datagram is too short') + raise ParseError("Datagram is too short") return ( - struct.unpack('>Q', - dgram[start_index:start_index + _UINT64_DGRAM_LEN])[0], - start_index + _UINT64_DGRAM_LEN) + struct.unpack(">Q", dgram[start_index : start_index + _UINT64_DGRAM_LEN])[ + 0 + ], + start_index + _UINT64_DGRAM_LEN, + ) except (struct.error, TypeError) as e: - raise ParseError('Could not parse datagram %s' % e) + raise ParseError("Could not parse datagram %s" % e) def get_timetag(dgram: bytes, start_index: int) -> Tuple[Tuple[datetime, int], int]: @@ -205,7 +209,7 @@ def get_timetag(dgram: bytes, start_index: int) -> Tuple[Tuple[datetime, int], i """ try: if len(dgram[start_index:]) < _TIMETAG_DGRAM_LEN: - raise ParseError('Datagram is too short') + raise ParseError("Datagram is too short") timetag, _ = get_uint64(dgram, start_index) seconds, fraction = ntp.parse_timestamp(timetag) @@ -213,12 +217,13 @@ def get_timetag(dgram: bytes, start_index: int) -> Tuple[Tuple[datetime, int], i hours, seconds = seconds // 3600, seconds % 3600 minutes, seconds = seconds // 60, seconds % 60 - utc = (datetime.combine(ntp._NTP_EPOCH, datetime.min.time()) + - timedelta(hours=hours, minutes=minutes, seconds=seconds)) + utc = datetime.combine(ntp._NTP_EPOCH, datetime.min.time()) + timedelta( + hours=hours, minutes=minutes, seconds=seconds + ) return (utc, fraction), start_index + _TIMETAG_DGRAM_LEN except (struct.error, TypeError) as e: - raise ParseError('Could not parse datagram %s' % e) + raise ParseError("Could not parse datagram %s" % e) def write_float(val: float) -> bytes: @@ -228,9 +233,9 @@ def write_float(val: float) -> bytes: - BuildError if the float could not be converted. """ try: - return struct.pack('>f', val) + return struct.pack(">f", val) except struct.error as e: - raise BuildError('Wrong argument value passed: {}'.format(e)) + raise BuildError("Wrong argument value passed: {}".format(e)) def get_float(dgram: bytes, start_index: int) -> Tuple[float, int]: @@ -251,13 +256,13 @@ def get_float(dgram: bytes, start_index: int) -> Tuple[float, int]: # Noticed that Reaktor doesn't send the last bunch of \x00 needed to make # the float representation complete in some cases, thus we pad here to # account for that. - dgram = dgram + b'\x00' * (_FLOAT_DGRAM_LEN - len(dgram[start_index:])) + dgram = dgram + b"\x00" * (_FLOAT_DGRAM_LEN - len(dgram[start_index:])) return ( - struct.unpack('>f', - dgram[start_index:start_index + _FLOAT_DGRAM_LEN])[0], - start_index + _FLOAT_DGRAM_LEN) + struct.unpack(">f", dgram[start_index : start_index + _FLOAT_DGRAM_LEN])[0], + start_index + _FLOAT_DGRAM_LEN, + ) except (struct.error, TypeError) as e: - raise ParseError('Could not parse datagram %s' % e) + raise ParseError("Could not parse datagram %s" % e) def write_double(val: float) -> bytes: @@ -267,9 +272,9 @@ def write_double(val: float) -> bytes: - BuildError if the double could not be converted. """ try: - return struct.pack('>d', val) + return struct.pack(">d", val) except struct.error as e: - raise BuildError('Wrong argument value passed: {}'.format(e)) + raise BuildError("Wrong argument value passed: {}".format(e)) def get_double(dgram: bytes, start_index: int) -> Tuple[float, int]: @@ -287,17 +292,19 @@ def get_double(dgram: bytes, start_index: int) -> Tuple[float, int]: """ try: if len(dgram[start_index:]) < _DOUBLE_DGRAM_LEN: - raise ParseError('Datagram is too short') + raise ParseError("Datagram is too short") return ( - struct.unpack('>d', - dgram[start_index:start_index + _DOUBLE_DGRAM_LEN])[0], - start_index + _DOUBLE_DGRAM_LEN) + struct.unpack(">d", dgram[start_index : start_index + _DOUBLE_DGRAM_LEN])[ + 0 + ], + start_index + _DOUBLE_DGRAM_LEN, + ) except (struct.error, TypeError) as e: - raise ParseError('Could not parse datagram {}'.format(e)) + raise ParseError("Could not parse datagram {}".format(e)) def get_blob(dgram: bytes, start_index: int) -> Tuple[bytes, int]: - """ Get a blob from the datagram. + """Get a blob from the datagram. According to the specifications, a blob is made of "an int32 size count, followed by that many 8-bit bytes of arbitrary @@ -319,8 +326,8 @@ def get_blob(dgram: bytes, start_index: int) -> Tuple[bytes, int]: total_size = size + (-size % _BLOB_DGRAM_PAD) end_index = int_offset + size if end_index - start_index > len(dgram[start_index:]): - raise ParseError('Datagram is too short.') - return dgram[int_offset:int_offset + size], int_offset + total_size + raise ParseError("Datagram is too short.") + return dgram[int_offset : int_offset + size], int_offset + total_size def write_blob(val: bytes) -> bytes: @@ -330,11 +337,11 @@ def write_blob(val: bytes) -> bytes: - BuildError if the value was empty or if its size didn't fit an OSC int. """ if not val: - raise BuildError('Blob value cannot be empty') + raise BuildError("Blob value cannot be empty") dgram = write_int(len(val)) dgram += val while len(dgram) % _BLOB_DGRAM_PAD != 0: - dgram += b'\x00' + dgram += b"\x00" return dgram @@ -358,10 +365,10 @@ def get_date(dgram: bytes, start_index: int) -> Tuple[float, int]: ParseError if the datagram could not be parsed. """ # Check for the special case first. - if dgram[start_index:start_index + _TIMETAG_DGRAM_LEN] == ntp.IMMEDIATELY: + if dgram[start_index : start_index + _TIMETAG_DGRAM_LEN] == ntp.IMMEDIATELY: return IMMEDIATELY, start_index + _TIMETAG_DGRAM_LEN if len(dgram[start_index:]) < _TIMETAG_DGRAM_LEN: - raise ParseError('Datagram is too short') + raise ParseError("Datagram is too short") timetag, start_index = get_uint64(dgram, start_index) seconds = timetag * ntp._NTP_TIMESTAMP_TO_SECONDS return ntp.ntp_time_to_system_epoch(seconds), start_index @@ -384,9 +391,9 @@ def write_rgba(val: bytes) -> bytes: - BuildError if the int could not be converted. """ try: - return struct.pack('>I', val) + return struct.pack(">I", val) except struct.error as e: - raise BuildError('Wrong argument value passed: {}'.format(e)) + raise BuildError("Wrong argument value passed: {}".format(e)) def get_rgba(dgram: bytes, start_index: int) -> Tuple[bytes, int]: @@ -404,13 +411,13 @@ def get_rgba(dgram: bytes, start_index: int) -> Tuple[bytes, int]: """ try: if len(dgram[start_index:]) < _INT_DGRAM_LEN: - raise ParseError('Datagram is too short') + raise ParseError("Datagram is too short") return ( - struct.unpack('>I', - dgram[start_index:start_index + _INT_DGRAM_LEN])[0], - start_index + _INT_DGRAM_LEN) + struct.unpack(">I", dgram[start_index : start_index + _INT_DGRAM_LEN])[0], + start_index + _INT_DGRAM_LEN, + ) except (struct.error, TypeError) as e: - raise ParseError('Could not parse datagram %s' % e) + raise ParseError("Could not parse datagram %s" % e) def write_midi(val: MidiPacket) -> bytes: @@ -423,12 +430,12 @@ def write_midi(val: MidiPacket) -> bytes: """ if len(val) != 4: - raise BuildError('MIDI message length is invalid') + raise BuildError("MIDI message length is invalid") try: value = sum((value & 0xFF) << 8 * (3 - pos) for pos, value in enumerate(val)) - return struct.pack('>I', value) + return struct.pack(">I", value) except struct.error as e: - raise BuildError('Wrong argument value passed: {}'.format(e)) + raise BuildError("Wrong argument value passed: {}".format(e)) def get_midi(dgram: bytes, start_index: int) -> Tuple[MidiPacket, int]: @@ -446,12 +453,11 @@ def get_midi(dgram: bytes, start_index: int) -> Tuple[MidiPacket, int]: """ try: if len(dgram[start_index:]) < _INT_DGRAM_LEN: - raise ParseError('Datagram is too short') - val = struct.unpack('>I', - dgram[start_index:start_index + _INT_DGRAM_LEN])[0] + raise ParseError("Datagram is too short") + val = struct.unpack(">I", dgram[start_index : start_index + _INT_DGRAM_LEN])[0] midi_msg = cast( - MidiPacket, - tuple((val & 0xFF << 8 * i) >> 8 * i for i in range(3, -1, -1))) + MidiPacket, tuple((val & 0xFF << 8 * i) >> 8 * i for i in range(3, -1, -1)) + ) return (midi_msg, start_index + _INT_DGRAM_LEN) except (struct.error, TypeError) as e: - raise ParseError('Could not parse datagram %s' % e) + raise ParseError("Could not parse datagram %s" % e) diff --git a/pythonosc/test/parsing/test_ntp.py b/pythonosc/test/parsing/test_ntp.py index ce8cae0..4bbfd2b 100644 --- a/pythonosc/test/parsing/test_ntp.py +++ b/pythonosc/test/parsing/test_ntp.py @@ -5,7 +5,7 @@ class TestNTP(unittest.TestCase): - """ TODO: Write real tests for this when I get time...""" + """TODO: Write real tests for this when I get time...""" def test_nto_to_system_time(self): unix_time = time.time() diff --git a/pythonosc/test/parsing/test_osc_types.py b/pythonosc/test/parsing/test_osc_types.py index f3a66cb..052a161 100644 --- a/pythonosc/test/parsing/test_osc_types.py +++ b/pythonosc/test/parsing/test_osc_types.py @@ -1,4 +1,5 @@ """Unit tests for the osc_types module.""" + import unittest from pythonosc.parsing import ntp @@ -14,9 +15,8 @@ def test_get_string(self): b"AB\x00\x00": ("AB", 4), b"ABC\x00": ("ABC", 4), b"ABCD\x00\x00\x00\x00": ("ABCD", 8), - b"ABCD\x00\x00\x00\x00GARBAGE": ("ABCD", 8), - b'\x00\x00\x00\x00': ("", 4), + b"\x00\x00\x00\x00": ("", 4), } for dgram, expected in cases.items(): @@ -24,24 +24,21 @@ def test_get_string(self): def test_get_string_raises_on_wrong_dgram(self): cases = [ - b'blablaba', - b'', - b'\x00', - b'\x00\x00', + b"blablaba", + b"", + b"\x00", + b"\x00\x00", True, ] for case in cases: - self.assertRaises( - osc_types.ParseError, osc_types.get_string, case, 0) + self.assertRaises(osc_types.ParseError, osc_types.get_string, case, 0) def test_get_string_raises_when_datagram_too_short(self): - self.assertRaises( - osc_types.ParseError, osc_types.get_string, b'abc\x00', 1) + self.assertRaises(osc_types.ParseError, osc_types.get_string, b"abc\x00", 1) def test_get_string_raises_on_wrong_start_index_negative(self): - self.assertRaises( - osc_types.ParseError, osc_types.get_string, b'abc\x00', -1) + self.assertRaises(osc_types.ParseError, osc_types.get_string, b"abc\x00", -1) class TestInteger(unittest.TestCase): @@ -51,34 +48,33 @@ def test_get_integer(self): b"\x00\x00\x00\x01": (1, 4), b"\x00\x00\x00\x02": (2, 4), b"\x00\x00\x00\x03": (3, 4), - b"\x00\x00\x01\x00": (256, 4), b"\x00\x01\x00\x00": (65536, 4), b"\x01\x00\x00\x00": (16777216, 4), - b"\x00\x00\x00\x01GARBAGE": (1, 4), } for dgram, expected in cases.items(): - self.assertEqual( - expected, osc_types.get_int(dgram, 0)) + self.assertEqual(expected, osc_types.get_int(dgram, 0)) def test_get_integer_raises_on_type_error(self): - cases = [b'', True] + cases = [b"", True] for case in cases: self.assertRaises(osc_types.ParseError, osc_types.get_int, case, 0) def test_get_integer_raises_on_wrong_start_index(self): self.assertRaises( - osc_types.ParseError, osc_types.get_int, b'\x00\x00\x00\x11', 1) + osc_types.ParseError, osc_types.get_int, b"\x00\x00\x00\x11", 1 + ) def test_get_integer_raises_on_wrong_start_index_negative(self): self.assertRaises( - osc_types.ParseError, osc_types.get_int, b'\x00\x00\x00\x00', -1) + osc_types.ParseError, osc_types.get_int, b"\x00\x00\x00\x00", -1 + ) def test_datagram_too_short(self): - dgram = b'\x00' * 3 + dgram = b"\x00" * 3 self.assertRaises(osc_types.ParseError, osc_types.get_int, dgram, 2) @@ -89,35 +85,34 @@ def test_get_rgba(self): b"\x00\x00\x00\x01": (1, 4), b"\x00\x00\x00\x02": (2, 4), b"\x00\x00\x00\x03": (3, 4), - b"\xFF\x00\x00\x00": (4278190080, 4), b"\x00\xFF\x00\x00": (16711680, 4), b"\x00\x00\xFF\x00": (65280, 4), b"\x00\x00\x00\xFF": (255, 4), - b"\x00\x00\x00\x01GARBAGE": (1, 4), } for dgram, expected in cases.items(): - self.assertEqual( - expected, osc_types.get_rgba(dgram, 0)) + self.assertEqual(expected, osc_types.get_rgba(dgram, 0)) def test_get_rgba_raises_on_type_error(self): - cases = [b'', True] + cases = [b"", True] for case in cases: self.assertRaises(osc_types.ParseError, osc_types.get_rgba, case, 0) def test_get_rgba_raises_on_wrong_start_index(self): self.assertRaises( - osc_types.ParseError, osc_types.get_rgba, b'\x00\x00\x00\x11', 1) + osc_types.ParseError, osc_types.get_rgba, b"\x00\x00\x00\x11", 1 + ) def test_get_rgba_raises_on_wrong_start_index_negative(self): self.assertRaises( - osc_types.ParseError, osc_types.get_rgba, b'\x00\x00\x00\x00', -1) + osc_types.ParseError, osc_types.get_rgba, b"\x00\x00\x00\x00", -1 + ) def test_datagram_too_short(self): - dgram = b'\x00' * 3 + dgram = b"\x00" * 3 self.assertRaises(osc_types.ParseError, osc_types.get_rgba, dgram, 2) @@ -128,43 +123,51 @@ def test_get_midi(self): b"\x00\x00\x00\x01": ((0, 0, 0, 1), 4), b"\x00\x00\x00\x02": ((0, 0, 0, 2), 4), b"\x00\x00\x00\x03": ((0, 0, 0, 3), 4), - b"\x00\x00\x01\x00": ((0, 0, 1, 0), 4), b"\x00\x01\x00\x00": ((0, 1, 0, 0), 4), b"\x01\x00\x00\x00": ((1, 0, 0, 0), 4), - b"\x00\x00\x00\x01GARBAGE": ((0, 0, 0, 1), 4), } for dgram, expected in cases.items(): - self.assertEqual( - expected, osc_types.get_midi(dgram, 0)) + self.assertEqual(expected, osc_types.get_midi(dgram, 0)) def test_get_midi_raises_on_type_error(self): - cases = [b'', True] + cases = [b"", True] for case in cases: self.assertRaises(osc_types.ParseError, osc_types.get_midi, case, 0) def test_get_midi_raises_on_wrong_start_index(self): self.assertRaises( - osc_types.ParseError, osc_types.get_midi, b'\x00\x00\x00\x11', 1) + osc_types.ParseError, osc_types.get_midi, b"\x00\x00\x00\x11", 1 + ) def test_get_midi_raises_on_wrong_start_index_negative(self): self.assertRaises( - osc_types.ParseError, osc_types.get_midi, b'\x00\x00\x00\x00', -1) + osc_types.ParseError, osc_types.get_midi, b"\x00\x00\x00\x00", -1 + ) def test_datagram_too_short(self): - dgram = b'\x00' * 3 + dgram = b"\x00" * 3 self.assertRaises(osc_types.ParseError, osc_types.get_midi, dgram, 2) class TestDate(unittest.TestCase): def test_get_timetag(self): cases = { - b"\xde\x9c\x91\xbf\x00\x01\x00\x00": ((datetime(2018, 5, 8, 21, 14, 39), 65536), 8), # NOTE: fraction is expresed as 32bit OSC. - b"\x00\x00\x00\x00\x00\x00\x00\x00": ((datetime(1900, 1, 1, 0, 0, 0), 0), 8), - b"\x83\xaa\x7E\x80\x0A\x00\xB0\x0C": ((datetime(1970, 1, 1, 0, 0, 0), 167817228), 8) + b"\xde\x9c\x91\xbf\x00\x01\x00\x00": ( + (datetime(2018, 5, 8, 21, 14, 39), 65536), + 8, + ), # NOTE: fraction is expresed as 32bit OSC. + b"\x00\x00\x00\x00\x00\x00\x00\x00": ( + (datetime(1900, 1, 1, 0, 0, 0), 0), + 8, + ), + b"\x83\xaa\x7E\x80\x0A\x00\xB0\x0C": ( + (datetime(1970, 1, 1, 0, 0, 0), 167817228), + 8, + ), } for dgram, expected in cases.items(): @@ -172,29 +175,37 @@ def test_get_timetag(self): def test_get_timetag_raises_on_wrong_start_index_negative(self): self.assertRaises( - osc_types.ParseError, osc_types.get_timetag, b'\x00\x00\x00\x00\x00\x00\x00\x00', -1) + osc_types.ParseError, + osc_types.get_timetag, + b"\x00\x00\x00\x00\x00\x00\x00\x00", + -1, + ) def test_get_timetag_raises_on_type_error(self): - cases = [b'', True] + cases = [b"", True] for case in cases: self.assertRaises(osc_types.ParseError, osc_types.get_timetag, case, 0) def test_get_timetag_raises_on_wrong_start_index(self): self.assertRaises( - osc_types.ParseError, osc_types.get_date, b'\x00\x00\x00\x11\x00\x00\x00\x11', 1) + osc_types.ParseError, + osc_types.get_date, + b"\x00\x00\x00\x11\x00\x00\x00\x11", + 1, + ) def test_ttag_datagram_too_short(self): - dgram = b'\x00' * 7 + dgram = b"\x00" * 7 self.assertRaises(osc_types.ParseError, osc_types.get_timetag, dgram, 6) - dgram = b'\x00' * 2 + dgram = b"\x00" * 2 self.assertRaises(osc_types.ParseError, osc_types.get_timetag, dgram, 1) - dgram = b'\x00' * 5 + dgram = b"\x00" * 5 self.assertRaises(osc_types.ParseError, osc_types.get_timetag, dgram, 4) - dgram = b'\x00' * 1 + dgram = b"\x00" * 1 self.assertRaises(osc_types.ParseError, osc_types.get_timetag, dgram, 0) @@ -203,8 +214,7 @@ def test_get_float(self): cases = { b"\x00\x00\x00\x00": (0.0, 4), b"?\x80\x00\x00'": (1.0, 4), - b'@\x00\x00\x00': (2.0, 4), - + b"@\x00\x00\x00": (2.0, 4), b"\x00\x00\x00\x00GARBAGE": (0.0, 4), } @@ -224,19 +234,18 @@ def test_get_float_raises_on_type_error(self): self.assertRaises(osc_types.ParseError, osc_types.get_float, case, 0) def test_datagram_too_short_pads(self): - dgram = b'\x00' * 2 + dgram = b"\x00" * 2 self.assertEqual((0, 4), osc_types.get_float(dgram, 0)) class TestDouble(unittest.TestCase): def test_get_double(self): cases = { - b'\x00\x00\x00\x00\x00\x00\x00\x00': (0.0, 8), - b'?\xf0\x00\x00\x00\x00\x00\x00': (1.0, 8), - b'@\x00\x00\x00\x00\x00\x00\x00': (2.0, 8), - b'\xbf\xf0\x00\x00\x00\x00\x00\x00': (-1.0, 8), - b'\xc0\x00\x00\x00\x00\x00\x00\x00': (-2.0, 8), - + b"\x00\x00\x00\x00\x00\x00\x00\x00": (0.0, 8), + b"?\xf0\x00\x00\x00\x00\x00\x00": (1.0, 8), + b"@\x00\x00\x00\x00\x00\x00\x00": (2.0, 8), + b"\xbf\xf0\x00\x00\x00\x00\x00\x00": (-1.0, 8), + b"\xc0\x00\x00\x00\x00\x00\x00\x00": (-2.0, 8), b"\x00\x00\x00\x00\x00\x00\x00\x00GARBAGE": (0.0, 8), } @@ -256,7 +265,7 @@ def test_get_double_raises_on_type_error(self): self.assertRaises(osc_types.ParseError, osc_types.get_double, case, 0) def test_datagram_too_short_pads(self): - dgram = b'\x00' * 2 + dgram = b"\x00" * 2 self.assertRaises(osc_types.ParseError, osc_types.get_double, dgram, 0) @@ -267,33 +276,35 @@ def test_get_blob(self): b"\x00\x00\x00\x08stuff\x00\x00\x00": (b"stuff\x00\x00\x00", 12), b"\x00\x00\x00\x04\x00\x00\x00\x00": (b"\x00\x00\x00\x00", 8), b"\x00\x00\x00\x02\x00\x00\x00\x00": (b"\x00\x00", 8), - b"\x00\x00\x00\x08stuff\x00\x00\x00datagramcontinues": ( - b"stuff\x00\x00\x00", 12), + b"stuff\x00\x00\x00", + 12, + ), } for dgram, expected in cases.items(): self.assertEqual(expected, osc_types.get_blob(dgram, 0)) def test_get_blob_raises_on_wrong_dgram(self): - cases = [b'', True, b"\x00\x00\x00\x08"] + cases = [b"", True, b"\x00\x00\x00\x08"] for case in cases: self.assertRaises(osc_types.ParseError, osc_types.get_blob, case, 0) def test_get_blob_raises_on_wrong_start_index(self): self.assertRaises( - osc_types.ParseError, osc_types.get_blob, b'\x00\x00\x00\x11', 1) + osc_types.ParseError, osc_types.get_blob, b"\x00\x00\x00\x11", 1 + ) def test_get_blob_raises_too_short_buffer(self): self.assertRaises( - osc_types.ParseError, - osc_types.get_blob, - b'\x00\x00\x00\x11\x00\x00', 1) + osc_types.ParseError, osc_types.get_blob, b"\x00\x00\x00\x11\x00\x00", 1 + ) def test_get_blog_raises_on_wrong_start_index_negative(self): self.assertRaises( - osc_types.ParseError, osc_types.get_blob, b'\x00\x00\x00\x00', -1) + osc_types.ParseError, osc_types.get_blob, b"\x00\x00\x00\x00", -1 + ) class TestNTPTimestamp(unittest.TestCase): @@ -302,56 +313,57 @@ def test_immediately_dgram(self): self.assertEqual(osc_types.IMMEDIATELY, osc_types.get_date(dgram, 0)[0]) def test_origin_of_time(self): - dgram = b'\x00' * 8 + dgram = b"\x00" * 8 self.assertGreater(0, osc_types.get_date(dgram, 0)[0]) def test_datagram_too_short(self): - dgram = b'\x00' * 8 + dgram = b"\x00" * 8 self.assertRaises(osc_types.ParseError, osc_types.get_date, dgram, 2) def test_write_date(self): time = 1569899476.167749 # known round(time.time(), 6) - timetag = b'\xe1=BT*\xf1\x98\x00' + timetag = b"\xe1=BT*\xf1\x98\x00" self.assertEqual(timetag, osc_types.write_date(time)) class TestBuildMethods(unittest.TestCase): def test_string(self): - self.assertEqual(b'\x00\x00\x00\x00', osc_types.write_string('')) - self.assertEqual(b'A\x00\x00\x00', osc_types.write_string('A')) - self.assertEqual(b'AB\x00\x00', osc_types.write_string('AB')) - self.assertEqual(b'ABC\x00', osc_types.write_string('ABC')) - self.assertEqual(b'ABCD\x00\x00\x00\x00', osc_types.write_string('ABCD')) + self.assertEqual(b"\x00\x00\x00\x00", osc_types.write_string("")) + self.assertEqual(b"A\x00\x00\x00", osc_types.write_string("A")) + self.assertEqual(b"AB\x00\x00", osc_types.write_string("AB")) + self.assertEqual(b"ABC\x00", osc_types.write_string("ABC")) + self.assertEqual(b"ABCD\x00\x00\x00\x00", osc_types.write_string("ABCD")) def test_string_raises(self): self.assertRaises(osc_types.BuildError, osc_types.write_string, 123) def test_int(self): - self.assertEqual(b'\x00\x00\x00\x00', osc_types.write_int(0)) - self.assertEqual(b'\x00\x00\x00\x01', osc_types.write_int(1)) + self.assertEqual(b"\x00\x00\x00\x00", osc_types.write_int(0)) + self.assertEqual(b"\x00\x00\x00\x01", osc_types.write_int(1)) def test_int_raises(self): - self.assertRaises(osc_types.BuildError, osc_types.write_int, 'no int') + self.assertRaises(osc_types.BuildError, osc_types.write_int, "no int") def test_float(self): - self.assertEqual(b'\x00\x00\x00\x00', osc_types.write_float(0.0)) - self.assertEqual(b'?\x00\x00\x00', osc_types.write_float(0.5)) - self.assertEqual(b'?\x80\x00\x00', osc_types.write_float(1.0)) - self.assertEqual(b'?\x80\x00\x00', osc_types.write_float(1)) + self.assertEqual(b"\x00\x00\x00\x00", osc_types.write_float(0.0)) + self.assertEqual(b"?\x00\x00\x00", osc_types.write_float(0.5)) + self.assertEqual(b"?\x80\x00\x00", osc_types.write_float(1.0)) + self.assertEqual(b"?\x80\x00\x00", osc_types.write_float(1)) def test_float_raises(self): - self.assertRaises(osc_types.BuildError, osc_types.write_float, 'no float') + self.assertRaises(osc_types.BuildError, osc_types.write_float, "no float") def test_blob(self): self.assertEqual( - b'\x00\x00\x00\x02\x00\x01\x00\x00', - osc_types.write_blob(b'\x00\x01')) + b"\x00\x00\x00\x02\x00\x01\x00\x00", osc_types.write_blob(b"\x00\x01") + ) self.assertEqual( - b'\x00\x00\x00\x04\x00\x01\x02\x03', - osc_types.write_blob(b'\x00\x01\x02\x03')) + b"\x00\x00\x00\x04\x00\x01\x02\x03", + osc_types.write_blob(b"\x00\x01\x02\x03"), + ) def test_blob_raises(self): - self.assertRaises(osc_types.BuildError, osc_types.write_blob, b'') + self.assertRaises(osc_types.BuildError, osc_types.write_blob, b"") if __name__ == "__main__": diff --git a/pythonosc/test/test_dispatcher.py b/pythonosc/test/test_dispatcher.py index 5d9d2fd..523facd 100644 --- a/pythonosc/test/test_dispatcher.py +++ b/pythonosc/test/test_dispatcher.py @@ -15,22 +15,28 @@ def sort(lst): return self.assertSequenceEqual(sort(expected), sort(result)) def test_empty_by_default(self): - self.sortAndAssertSequenceEqual([], self.dispatcher.handlers_for_address('/test')) + self.sortAndAssertSequenceEqual( + [], self.dispatcher.handlers_for_address("/test") + ) def test_use_default_handler_when_set_and_no_match(self): handler = object() self.dispatcher.set_default_handler(handler) - self.sortAndAssertSequenceEqual([Handler(handler, [])], self.dispatcher.handlers_for_address('/test')) + self.sortAndAssertSequenceEqual( + [Handler(handler, [])], self.dispatcher.handlers_for_address("/test") + ) def test_simple_map_and_match(self): handler = object() - self.dispatcher.map('/test', handler, 1, 2, 3) - self.dispatcher.map('/test2', handler) + self.dispatcher.map("/test", handler, 1, 2, 3) + self.dispatcher.map("/test2", handler) self.sortAndAssertSequenceEqual( - [Handler(handler, [1, 2, 3])], self.dispatcher.handlers_for_address('/test')) + [Handler(handler, [1, 2, 3])], self.dispatcher.handlers_for_address("/test") + ) self.sortAndAssertSequenceEqual( - [Handler(handler, [])], self.dispatcher.handlers_for_address('/test2')) + [Handler(handler, [])], self.dispatcher.handlers_for_address("/test2") + ) def test_example_from_spec(self): addresses = [ @@ -46,80 +52,98 @@ def test_example_from_spec(self): for index, address in enumerate(addresses): self.sortAndAssertSequenceEqual( - [Handler(index, [])], self.dispatcher.handlers_for_address(address)) + [Handler(index, [])], self.dispatcher.handlers_for_address(address) + ) self.sortAndAssertSequenceEqual( - [Handler(1, []), Handler(2, [])], self.dispatcher.handlers_for_address("/second/?")) + [Handler(1, []), Handler(2, [])], + self.dispatcher.handlers_for_address("/second/?"), + ) self.sortAndAssertSequenceEqual( [Handler(3, []), Handler(4, []), Handler(5, [])], - self.dispatcher.handlers_for_address("/third/*")) + self.dispatcher.handlers_for_address("/third/*"), + ) def test_do_not_match_over_slash(self): - self.dispatcher.map('/foo/bar/1', 1) - self.dispatcher.map('/foo/bar/2', 2) + self.dispatcher.map("/foo/bar/1", 1) + self.dispatcher.map("/foo/bar/2", 2) - self.sortAndAssertSequenceEqual( - [], self.dispatcher.handlers_for_address("/*")) + self.sortAndAssertSequenceEqual([], self.dispatcher.handlers_for_address("/*")) def test_match_middle_star(self): - self.dispatcher.map('/foo/bar/1', 1) - self.dispatcher.map('/foo/bar/2', 2) + self.dispatcher.map("/foo/bar/1", 1) + self.dispatcher.map("/foo/bar/2", 2) self.sortAndAssertSequenceEqual( - [Handler(2, [])], self.dispatcher.handlers_for_address("/foo/*/2")) + [Handler(2, [])], self.dispatcher.handlers_for_address("/foo/*/2") + ) def test_match_multiple_stars(self): - self.dispatcher.map('/foo/bar/1', 1) - self.dispatcher.map('/foo/bar/2', 2) + self.dispatcher.map("/foo/bar/1", 1) + self.dispatcher.map("/foo/bar/2", 2) self.sortAndAssertSequenceEqual( - [Handler(1, []), Handler(2, [])], self.dispatcher.handlers_for_address("/*/*/*")) + [Handler(1, []), Handler(2, [])], + self.dispatcher.handlers_for_address("/*/*/*"), + ) def test_match_address_contains_plus_as_character(self): - self.dispatcher.map('/footest/bar+tender/1', 1) + self.dispatcher.map("/footest/bar+tender/1", 1) self.sortAndAssertSequenceEqual( - [Handler(1, [])], self.dispatcher.handlers_for_address("/foo*/bar+*/*")) + [Handler(1, [])], self.dispatcher.handlers_for_address("/foo*/bar+*/*") + ) self.sortAndAssertSequenceEqual( - [Handler(1, [])], self.dispatcher.handlers_for_address("/foo*/bar*/*")) + [Handler(1, [])], self.dispatcher.handlers_for_address("/foo*/bar*/*") + ) def test_call_correct_dispatcher_on_star(self): - self.dispatcher.map('/a+b', 1) - self.dispatcher.map('/aaab', 2) + self.dispatcher.map("/a+b", 1) + self.dispatcher.map("/aaab", 2) self.sortAndAssertSequenceEqual( - [Handler(2, [])], self.dispatcher.handlers_for_address('/aaab')) + [Handler(2, [])], self.dispatcher.handlers_for_address("/aaab") + ) self.sortAndAssertSequenceEqual( - [Handler(1, [])], self.dispatcher.handlers_for_address('/a+b')) + [Handler(1, [])], self.dispatcher.handlers_for_address("/a+b") + ) def test_map_star(self): - self.dispatcher.map('/starbase/*', 1) + self.dispatcher.map("/starbase/*", 1) self.sortAndAssertSequenceEqual( - [Handler(1, [])], self.dispatcher.handlers_for_address("/starbase/bar")) + [Handler(1, [])], self.dispatcher.handlers_for_address("/starbase/bar") + ) def test_map_root_star(self): - self.dispatcher.map('/*', 1) + self.dispatcher.map("/*", 1) self.sortAndAssertSequenceEqual( - [Handler(1, [])], self.dispatcher.handlers_for_address("/anything/matches")) + [Handler(1, [])], self.dispatcher.handlers_for_address("/anything/matches") + ) def test_map_double_stars(self): - self.dispatcher.map('/foo/*/bar/*', 1) + self.dispatcher.map("/foo/*/bar/*", 1) self.sortAndAssertSequenceEqual( - [Handler(1, [])], self.dispatcher.handlers_for_address("/foo/wild/bar/wild")) + [Handler(1, [])], self.dispatcher.handlers_for_address("/foo/wild/bar/wild") + ) self.sortAndAssertSequenceEqual( - [], self.dispatcher.handlers_for_address("/foo/wild/nomatch/wild")) + [], self.dispatcher.handlers_for_address("/foo/wild/nomatch/wild") + ) def test_multiple_handlers(self): - self.dispatcher.map('/foo/bar', 1) - self.dispatcher.map('/foo/bar', 2) + self.dispatcher.map("/foo/bar", 1) + self.dispatcher.map("/foo/bar", 2) self.sortAndAssertSequenceEqual( - [Handler(1, []), Handler(2, [])], self.dispatcher.handlers_for_address("/foo/bar")) + [Handler(1, []), Handler(2, [])], + self.dispatcher.handlers_for_address("/foo/bar"), + ) def test_multiple_handlers_with_wildcard_map(self): - self.dispatcher.map('/foo/bar', 1) - self.dispatcher.map('/*', 2) + self.dispatcher.map("/foo/bar", 1) + self.dispatcher.map("/*", 2) self.sortAndAssertSequenceEqual( - [Handler(1, []), Handler(2, [])], self.dispatcher.handlers_for_address("/foo/bar")) + [Handler(1, []), Handler(2, [])], + self.dispatcher.handlers_for_address("/foo/bar"), + ) def test_unmap(self): def dummyhandler(): @@ -127,16 +151,24 @@ def dummyhandler(): # Test with handler returned by map returnedhandler = self.dispatcher.map("/map/me", dummyhandler) - self.sortAndAssertSequenceEqual([Handler(dummyhandler, [])], self.dispatcher.handlers_for_address("/map/me")) + self.sortAndAssertSequenceEqual( + [Handler(dummyhandler, [])], self.dispatcher.handlers_for_address("/map/me") + ) self.dispatcher.unmap("/map/me", returnedhandler) - self.sortAndAssertSequenceEqual([], self.dispatcher.handlers_for_address("/map/me")) + self.sortAndAssertSequenceEqual( + [], self.dispatcher.handlers_for_address("/map/me") + ) # Test with reconstructing handler self.dispatcher.map("/map/me/too", dummyhandler) - self.sortAndAssertSequenceEqual([Handler(dummyhandler, [])], - self.dispatcher.handlers_for_address("/map/me/too")) + self.sortAndAssertSequenceEqual( + [Handler(dummyhandler, [])], + self.dispatcher.handlers_for_address("/map/me/too"), + ) self.dispatcher.unmap("/map/me/too", dummyhandler) - self.sortAndAssertSequenceEqual([], self.dispatcher.handlers_for_address("/map/me/too")) + self.sortAndAssertSequenceEqual( + [], self.dispatcher.handlers_for_address("/map/me/too") + ) def test_unmap_exception(self): def dummyhandler(): diff --git a/pythonosc/test/test_osc_bundle.py b/pythonosc/test/test_osc_bundle.py index f118cdd..7e7fc54 100644 --- a/pythonosc/test/test_osc_bundle.py +++ b/pythonosc/test/test_osc_bundle.py @@ -10,7 +10,8 @@ b"\x00\x00\x00\x14" b"/LFO_Rate\x00\x00\x00" b",f\x00\x00" - b">\x8c\xcc\xcd") + b">\x8c\xcc\xcd" +) _DGRAM_SWITCH_GOES_OFF = ( b"#bundle\x00" @@ -18,7 +19,8 @@ b"\x00\x00\x00\x10" b"/SYNC\x00\x00\x00" b",f\x00\x00" - b"\x00\x00\x00\x00") + b"\x00\x00\x00\x00" +) _DGRAM_SWITCH_GOES_ON = ( b"#bundle\x00" @@ -26,7 +28,8 @@ b"\x00\x00\x00\x10" b"/SYNC\x00\x00\x00" b",f\x00\x00" - b"?\x00\x00\x00") + b"?\x00\x00\x00" +) _DGRAM_TWO_MESSAGES_IN_BUNDLE = ( b"#bundle\x00" @@ -40,11 +43,10 @@ b"\x00\x00\x00\x10" b"/SYNC\x00\x00\x00" b",f\x00\x00" - b"?\x00\x00\x00") + b"?\x00\x00\x00" +) -_DGRAM_EMPTY_BUNDLE = ( - b"#bundle\x00" - b"\x00\x00\x00\x00\x00\x00\x00\x01") +_DGRAM_EMPTY_BUNDLE = b"#bundle\x00" b"\x00\x00\x00\x00\x00\x00\x00\x01" _DGRAM_BUNDLE_IN_BUNDLE = ( b"#bundle\x00" @@ -55,23 +57,24 @@ b"\x00\x00\x00\x10" b"/SYNC\x00\x00\x00" b",f\x00\x00" - b"?\x00\x00\x00") + b"?\x00\x00\x00" +) -_DGRAM_INVALID = ( - b"#bundle\x00" - b"\x00\x00\x00") +_DGRAM_INVALID = b"#bundle\x00" b"\x00\x00\x00" _DGRAM_INVALID_INDEX = ( b"#bundle\x00" b"\x00\x00\x00\x00\x00\x00\x00\x01" b"\x00\x00\x00\x20" - b"/SYNC\x00\x00\x00\x00") + b"/SYNC\x00\x00\x00\x00" +) _DGRAM_UNKNOWN_TYPE = ( b"#bundle\x00" b"\x00\x00\x00\x00\x00\x00\x00\x01" b"\x00\x00\x00\x10" - b"iamnotaslash") + b"iamnotaslash" +) class TestOscBundle(unittest.TestCase): @@ -112,15 +115,14 @@ def test_bundle_in_bundle_we_must_go_deeper(self): self.assertEqual(osc_bundle.OscBundle, type(bundle.content(0))) def test_dgram_is_bundle(self): - self.assertTrue(osc_bundle.OscBundle.dgram_is_bundle( - _DGRAM_SWITCH_GOES_ON)) - self.assertFalse(osc_bundle.OscBundle.dgram_is_bundle(b'junk')) + self.assertTrue(osc_bundle.OscBundle.dgram_is_bundle(_DGRAM_SWITCH_GOES_ON)) + self.assertFalse(osc_bundle.OscBundle.dgram_is_bundle(b"junk")) def test_raises_on_invalid_datagram(self): + self.assertRaises(osc_bundle.ParseError, osc_bundle.OscBundle, _DGRAM_INVALID) self.assertRaises( - osc_bundle.ParseError, osc_bundle.OscBundle, _DGRAM_INVALID) - self.assertRaises( - osc_bundle.ParseError, osc_bundle.OscBundle, _DGRAM_INVALID_INDEX) + osc_bundle.ParseError, osc_bundle.OscBundle, _DGRAM_INVALID_INDEX + ) def test_unknown_type(self): osc_bundle.OscBundle(_DGRAM_UNKNOWN_TYPE) diff --git a/pythonosc/test/test_osc_bundle_builder.py b/pythonosc/test/test_osc_bundle_builder.py index ee5479b..1d20f43 100644 --- a/pythonosc/test/test_osc_bundle_builder.py +++ b/pythonosc/test/test_osc_bundle_builder.py @@ -7,7 +7,8 @@ class TestOscBundleBuilder(unittest.TestCase): def test_empty_bundle(self): bundle = osc_bundle_builder.OscBundleBuilder( - osc_bundle_builder.IMMEDIATELY).build() + osc_bundle_builder.IMMEDIATELY + ).build() self.assertEqual(0, bundle.num_contents) def test_raises_on_build(self): @@ -20,8 +21,7 @@ def test_raises_on_invalid_timestamp(self): self.assertRaises(osc_bundle_builder.BuildError, bundle.build) def test_build_complex_bundle(self): - bundle = osc_bundle_builder.OscBundleBuilder( - osc_bundle_builder.IMMEDIATELY) + bundle = osc_bundle_builder.OscBundleBuilder(osc_bundle_builder.IMMEDIATELY) msg = osc_message_builder.OscMessageBuilder(address="/SYNC") msg.add_arg(4.0) # Add 4 messages in the bundle, each with more arguments. diff --git a/pythonosc/test/test_osc_message.py b/pythonosc/test/test_osc_message.py index efe0076..269901b 100644 --- a/pythonosc/test/test_osc_message.py +++ b/pythonosc/test/test_osc_message.py @@ -5,20 +5,11 @@ from datetime import datetime # Datagrams sent by Reaktor 5.8 by Native Instruments (c). -_DGRAM_KNOB_ROTATES = ( - b"/FB\x00" - b",f\x00\x00" - b">xca=q") +_DGRAM_KNOB_ROTATES = b"/FB\x00" b",f\x00\x00" b">xca=q" -_DGRAM_SWITCH_GOES_OFF = ( - b"/SYNC\x00\x00\x00" - b",f\x00\x00" - b"\x00\x00\x00\x00") +_DGRAM_SWITCH_GOES_OFF = b"/SYNC\x00\x00\x00" b",f\x00\x00" b"\x00\x00\x00\x00" -_DGRAM_SWITCH_GOES_ON = ( - b"/SYNC\x00\x00\x00" - b",f\x00\x00" - b"?\x00\x00\x00") +_DGRAM_SWITCH_GOES_ON = b"/SYNC\x00\x00\x00" b",f\x00\x00" b"?\x00\x00\x00" _DGRAM_NO_PARAMS = b"/SYNC\x00\x00\x00" @@ -28,7 +19,8 @@ b"\x00\x00\x00\x03" # 3 b"@\x00\x00\x00" # 2.0 b"ABC\x00" # "ABC" - b"\x00\x00\x00\x08stuff\x00\x00\x00") # b"stuff\x00\x00\x00" + b"\x00\x00\x00\x08stuff\x00\x00\x00" +) # b"stuff\x00\x00\x00" _DGRAM_ALL_NON_STANDARD_TYPES_OF_PARAMS = ( b"/SYNC\x00\x00\x00" @@ -48,17 +40,17 @@ b"DEF\x00" # "DEF" b"\x00\x00\x00\x02" # 2 b"\x00\x00\x00\x03" # 3 - b"GHI\x00") # "GHI" + b"GHI\x00" +) # "GHI" _DGRAM_UNKNOWN_PARAM_TYPE = ( b"/SYNC\x00\x00\x00" b",fx\x00" # x is an unknown param type. - b"?\x00\x00\x00") + b"?\x00\x00\x00" +) # range(512) param list. -_DGRAM_LONG_LIST = ( - b'/SYNC\x00\x00\x00,[iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii]\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x08\x00\x00\x00\t\x00\x00\x00\n\x00\x00\x00\x0b\x00\x00\x00\x0c\x00\x00\x00\r\x00\x00\x00\x0e\x00\x00\x00\x0f\x00\x00\x00\x10\x00\x00\x00\x11\x00\x00\x00\x12\x00\x00\x00\x13\x00\x00\x00\x14\x00\x00\x00\x15\x00\x00\x00\x16\x00\x00\x00\x17\x00\x00\x00\x18\x00\x00\x00\x19\x00\x00\x00\x1a\x00\x00\x00\x1b\x00\x00\x00\x1c\x00\x00\x00\x1d\x00\x00\x00\x1e\x00\x00\x00\x1f\x00\x00\x00 \x00\x00\x00!\x00\x00\x00"\x00\x00\x00#\x00\x00\x00$\x00\x00\x00%\x00\x00\x00&\x00\x00\x00\'\x00\x00\x00(\x00\x00\x00)\x00\x00\x00*\x00\x00\x00+\x00\x00\x00,\x00\x00\x00-\x00\x00\x00.\x00\x00\x00/\x00\x00\x000\x00\x00\x001\x00\x00\x002\x00\x00\x003\x00\x00\x004\x00\x00\x005\x00\x00\x006\x00\x00\x007\x00\x00\x008\x00\x00\x009\x00\x00\x00:\x00\x00\x00;\x00\x00\x00<\x00\x00\x00=\x00\x00\x00>\x00\x00\x00?\x00\x00\x00@\x00\x00\x00A\x00\x00\x00B\x00\x00\x00C\x00\x00\x00D\x00\x00\x00E\x00\x00\x00F\x00\x00\x00G\x00\x00\x00H\x00\x00\x00I\x00\x00\x00J\x00\x00\x00K\x00\x00\x00L\x00\x00\x00M\x00\x00\x00N\x00\x00\x00O\x00\x00\x00P\x00\x00\x00Q\x00\x00\x00R\x00\x00\x00S\x00\x00\x00T\x00\x00\x00U\x00\x00\x00V\x00\x00\x00W\x00\x00\x00X\x00\x00\x00Y\x00\x00\x00Z\x00\x00\x00[\x00\x00\x00\\\x00\x00\x00]\x00\x00\x00^\x00\x00\x00_\x00\x00\x00`\x00\x00\x00a\x00\x00\x00b\x00\x00\x00c\x00\x00\x00d\x00\x00\x00e\x00\x00\x00f\x00\x00\x00g\x00\x00\x00h\x00\x00\x00i\x00\x00\x00j\x00\x00\x00k\x00\x00\x00l\x00\x00\x00m\x00\x00\x00n\x00\x00\x00o\x00\x00\x00p\x00\x00\x00q\x00\x00\x00r\x00\x00\x00s\x00\x00\x00t\x00\x00\x00u\x00\x00\x00v\x00\x00\x00w\x00\x00\x00x\x00\x00\x00y\x00\x00\x00z\x00\x00\x00{\x00\x00\x00|\x00\x00\x00}\x00\x00\x00~\x00\x00\x00\x7f\x00\x00\x00\x80\x00\x00\x00\x81\x00\x00\x00\x82\x00\x00\x00\x83\x00\x00\x00\x84\x00\x00\x00\x85\x00\x00\x00\x86\x00\x00\x00\x87\x00\x00\x00\x88\x00\x00\x00\x89\x00\x00\x00\x8a\x00\x00\x00\x8b\x00\x00\x00\x8c\x00\x00\x00\x8d\x00\x00\x00\x8e\x00\x00\x00\x8f\x00\x00\x00\x90\x00\x00\x00\x91\x00\x00\x00\x92\x00\x00\x00\x93\x00\x00\x00\x94\x00\x00\x00\x95\x00\x00\x00\x96\x00\x00\x00\x97\x00\x00\x00\x98\x00\x00\x00\x99\x00\x00\x00\x9a\x00\x00\x00\x9b\x00\x00\x00\x9c\x00\x00\x00\x9d\x00\x00\x00\x9e\x00\x00\x00\x9f\x00\x00\x00\xa0\x00\x00\x00\xa1\x00\x00\x00\xa2\x00\x00\x00\xa3\x00\x00\x00\xa4\x00\x00\x00\xa5\x00\x00\x00\xa6\x00\x00\x00\xa7\x00\x00\x00\xa8\x00\x00\x00\xa9\x00\x00\x00\xaa\x00\x00\x00\xab\x00\x00\x00\xac\x00\x00\x00\xad\x00\x00\x00\xae\x00\x00\x00\xaf\x00\x00\x00\xb0\x00\x00\x00\xb1\x00\x00\x00\xb2\x00\x00\x00\xb3\x00\x00\x00\xb4\x00\x00\x00\xb5\x00\x00\x00\xb6\x00\x00\x00\xb7\x00\x00\x00\xb8\x00\x00\x00\xb9\x00\x00\x00\xba\x00\x00\x00\xbb\x00\x00\x00\xbc\x00\x00\x00\xbd\x00\x00\x00\xbe\x00\x00\x00\xbf\x00\x00\x00\xc0\x00\x00\x00\xc1\x00\x00\x00\xc2\x00\x00\x00\xc3\x00\x00\x00\xc4\x00\x00\x00\xc5\x00\x00\x00\xc6\x00\x00\x00\xc7\x00\x00\x00\xc8\x00\x00\x00\xc9\x00\x00\x00\xca\x00\x00\x00\xcb\x00\x00\x00\xcc\x00\x00\x00\xcd\x00\x00\x00\xce\x00\x00\x00\xcf\x00\x00\x00\xd0\x00\x00\x00\xd1\x00\x00\x00\xd2\x00\x00\x00\xd3\x00\x00\x00\xd4\x00\x00\x00\xd5\x00\x00\x00\xd6\x00\x00\x00\xd7\x00\x00\x00\xd8\x00\x00\x00\xd9\x00\x00\x00\xda\x00\x00\x00\xdb\x00\x00\x00\xdc\x00\x00\x00\xdd\x00\x00\x00\xde\x00\x00\x00\xdf\x00\x00\x00\xe0\x00\x00\x00\xe1\x00\x00\x00\xe2\x00\x00\x00\xe3\x00\x00\x00\xe4\x00\x00\x00\xe5\x00\x00\x00\xe6\x00\x00\x00\xe7\x00\x00\x00\xe8\x00\x00\x00\xe9\x00\x00\x00\xea\x00\x00\x00\xeb\x00\x00\x00\xec\x00\x00\x00\xed\x00\x00\x00\xee\x00\x00\x00\xef\x00\x00\x00\xf0\x00\x00\x00\xf1\x00\x00\x00\xf2\x00\x00\x00\xf3\x00\x00\x00\xf4\x00\x00\x00\xf5\x00\x00\x00\xf6\x00\x00\x00\xf7\x00\x00\x00\xf8\x00\x00\x00\xf9\x00\x00\x00\xfa\x00\x00\x00\xfb\x00\x00\x00\xfc\x00\x00\x00\xfd\x00\x00\x00\xfe\x00\x00\x00\xff\x00\x00\x01\x00\x00\x00\x01\x01\x00\x00\x01\x02\x00\x00\x01\x03\x00\x00\x01\x04\x00\x00\x01\x05\x00\x00\x01\x06\x00\x00\x01\x07\x00\x00\x01\x08\x00\x00\x01\t\x00\x00\x01\n\x00\x00\x01\x0b\x00\x00\x01\x0c\x00\x00\x01\r\x00\x00\x01\x0e\x00\x00\x01\x0f\x00\x00\x01\x10\x00\x00\x01\x11\x00\x00\x01\x12\x00\x00\x01\x13\x00\x00\x01\x14\x00\x00\x01\x15\x00\x00\x01\x16\x00\x00\x01\x17\x00\x00\x01\x18\x00\x00\x01\x19\x00\x00\x01\x1a\x00\x00\x01\x1b\x00\x00\x01\x1c\x00\x00\x01\x1d\x00\x00\x01\x1e\x00\x00\x01\x1f\x00\x00\x01 \x00\x00\x01!\x00\x00\x01"\x00\x00\x01#\x00\x00\x01$\x00\x00\x01%\x00\x00\x01&\x00\x00\x01\'\x00\x00\x01(\x00\x00\x01)\x00\x00\x01*\x00\x00\x01+\x00\x00\x01,\x00\x00\x01-\x00\x00\x01.\x00\x00\x01/\x00\x00\x010\x00\x00\x011\x00\x00\x012\x00\x00\x013\x00\x00\x014\x00\x00\x015\x00\x00\x016\x00\x00\x017\x00\x00\x018\x00\x00\x019\x00\x00\x01:\x00\x00\x01;\x00\x00\x01<\x00\x00\x01=\x00\x00\x01>\x00\x00\x01?\x00\x00\x01@\x00\x00\x01A\x00\x00\x01B\x00\x00\x01C\x00\x00\x01D\x00\x00\x01E\x00\x00\x01F\x00\x00\x01G\x00\x00\x01H\x00\x00\x01I\x00\x00\x01J\x00\x00\x01K\x00\x00\x01L\x00\x00\x01M\x00\x00\x01N\x00\x00\x01O\x00\x00\x01P\x00\x00\x01Q\x00\x00\x01R\x00\x00\x01S\x00\x00\x01T\x00\x00\x01U\x00\x00\x01V\x00\x00\x01W\x00\x00\x01X\x00\x00\x01Y\x00\x00\x01Z\x00\x00\x01[\x00\x00\x01\\\x00\x00\x01]\x00\x00\x01^\x00\x00\x01_\x00\x00\x01`\x00\x00\x01a\x00\x00\x01b\x00\x00\x01c\x00\x00\x01d\x00\x00\x01e\x00\x00\x01f\x00\x00\x01g\x00\x00\x01h\x00\x00\x01i\x00\x00\x01j\x00\x00\x01k\x00\x00\x01l\x00\x00\x01m\x00\x00\x01n\x00\x00\x01o\x00\x00\x01p\x00\x00\x01q\x00\x00\x01r\x00\x00\x01s\x00\x00\x01t\x00\x00\x01u\x00\x00\x01v\x00\x00\x01w\x00\x00\x01x\x00\x00\x01y\x00\x00\x01z\x00\x00\x01{\x00\x00\x01|\x00\x00\x01}\x00\x00\x01~\x00\x00\x01\x7f\x00\x00\x01\x80\x00\x00\x01\x81\x00\x00\x01\x82\x00\x00\x01\x83\x00\x00\x01\x84\x00\x00\x01\x85\x00\x00\x01\x86\x00\x00\x01\x87\x00\x00\x01\x88\x00\x00\x01\x89\x00\x00\x01\x8a\x00\x00\x01\x8b\x00\x00\x01\x8c\x00\x00\x01\x8d\x00\x00\x01\x8e\x00\x00\x01\x8f\x00\x00\x01\x90\x00\x00\x01\x91\x00\x00\x01\x92\x00\x00\x01\x93\x00\x00\x01\x94\x00\x00\x01\x95\x00\x00\x01\x96\x00\x00\x01\x97\x00\x00\x01\x98\x00\x00\x01\x99\x00\x00\x01\x9a\x00\x00\x01\x9b\x00\x00\x01\x9c\x00\x00\x01\x9d\x00\x00\x01\x9e\x00\x00\x01\x9f\x00\x00\x01\xa0\x00\x00\x01\xa1\x00\x00\x01\xa2\x00\x00\x01\xa3\x00\x00\x01\xa4\x00\x00\x01\xa5\x00\x00\x01\xa6\x00\x00\x01\xa7\x00\x00\x01\xa8\x00\x00\x01\xa9\x00\x00\x01\xaa\x00\x00\x01\xab\x00\x00\x01\xac\x00\x00\x01\xad\x00\x00\x01\xae\x00\x00\x01\xaf\x00\x00\x01\xb0\x00\x00\x01\xb1\x00\x00\x01\xb2\x00\x00\x01\xb3\x00\x00\x01\xb4\x00\x00\x01\xb5\x00\x00\x01\xb6\x00\x00\x01\xb7\x00\x00\x01\xb8\x00\x00\x01\xb9\x00\x00\x01\xba\x00\x00\x01\xbb\x00\x00\x01\xbc\x00\x00\x01\xbd\x00\x00\x01\xbe\x00\x00\x01\xbf\x00\x00\x01\xc0\x00\x00\x01\xc1\x00\x00\x01\xc2\x00\x00\x01\xc3\x00\x00\x01\xc4\x00\x00\x01\xc5\x00\x00\x01\xc6\x00\x00\x01\xc7\x00\x00\x01\xc8\x00\x00\x01\xc9\x00\x00\x01\xca\x00\x00\x01\xcb\x00\x00\x01\xcc\x00\x00\x01\xcd\x00\x00\x01\xce\x00\x00\x01\xcf\x00\x00\x01\xd0\x00\x00\x01\xd1\x00\x00\x01\xd2\x00\x00\x01\xd3\x00\x00\x01\xd4\x00\x00\x01\xd5\x00\x00\x01\xd6\x00\x00\x01\xd7\x00\x00\x01\xd8\x00\x00\x01\xd9\x00\x00\x01\xda\x00\x00\x01\xdb\x00\x00\x01\xdc\x00\x00\x01\xdd\x00\x00\x01\xde\x00\x00\x01\xdf\x00\x00\x01\xe0\x00\x00\x01\xe1\x00\x00\x01\xe2\x00\x00\x01\xe3\x00\x00\x01\xe4\x00\x00\x01\xe5\x00\x00\x01\xe6\x00\x00\x01\xe7\x00\x00\x01\xe8\x00\x00\x01\xe9\x00\x00\x01\xea\x00\x00\x01\xeb\x00\x00\x01\xec\x00\x00\x01\xed\x00\x00\x01\xee\x00\x00\x01\xef\x00\x00\x01\xf0\x00\x00\x01\xf1\x00\x00\x01\xf2\x00\x00\x01\xf3\x00\x00\x01\xf4\x00\x00\x01\xf5\x00\x00\x01\xf6\x00\x00\x01\xf7\x00\x00\x01\xf8\x00\x00\x01\xf9\x00\x00\x01\xfa\x00\x00\x01\xfb\x00\x00\x01\xfc\x00\x00\x01\xfd\x00\x00\x01\xfe\x00\x00\x01\xff' -) +_DGRAM_LONG_LIST = b"/SYNC\x00\x00\x00,[iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii]\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x08\x00\x00\x00\t\x00\x00\x00\n\x00\x00\x00\x0b\x00\x00\x00\x0c\x00\x00\x00\r\x00\x00\x00\x0e\x00\x00\x00\x0f\x00\x00\x00\x10\x00\x00\x00\x11\x00\x00\x00\x12\x00\x00\x00\x13\x00\x00\x00\x14\x00\x00\x00\x15\x00\x00\x00\x16\x00\x00\x00\x17\x00\x00\x00\x18\x00\x00\x00\x19\x00\x00\x00\x1a\x00\x00\x00\x1b\x00\x00\x00\x1c\x00\x00\x00\x1d\x00\x00\x00\x1e\x00\x00\x00\x1f\x00\x00\x00 \x00\x00\x00!\x00\x00\x00\"\x00\x00\x00#\x00\x00\x00$\x00\x00\x00%\x00\x00\x00&\x00\x00\x00'\x00\x00\x00(\x00\x00\x00)\x00\x00\x00*\x00\x00\x00+\x00\x00\x00,\x00\x00\x00-\x00\x00\x00.\x00\x00\x00/\x00\x00\x000\x00\x00\x001\x00\x00\x002\x00\x00\x003\x00\x00\x004\x00\x00\x005\x00\x00\x006\x00\x00\x007\x00\x00\x008\x00\x00\x009\x00\x00\x00:\x00\x00\x00;\x00\x00\x00<\x00\x00\x00=\x00\x00\x00>\x00\x00\x00?\x00\x00\x00@\x00\x00\x00A\x00\x00\x00B\x00\x00\x00C\x00\x00\x00D\x00\x00\x00E\x00\x00\x00F\x00\x00\x00G\x00\x00\x00H\x00\x00\x00I\x00\x00\x00J\x00\x00\x00K\x00\x00\x00L\x00\x00\x00M\x00\x00\x00N\x00\x00\x00O\x00\x00\x00P\x00\x00\x00Q\x00\x00\x00R\x00\x00\x00S\x00\x00\x00T\x00\x00\x00U\x00\x00\x00V\x00\x00\x00W\x00\x00\x00X\x00\x00\x00Y\x00\x00\x00Z\x00\x00\x00[\x00\x00\x00\\\x00\x00\x00]\x00\x00\x00^\x00\x00\x00_\x00\x00\x00`\x00\x00\x00a\x00\x00\x00b\x00\x00\x00c\x00\x00\x00d\x00\x00\x00e\x00\x00\x00f\x00\x00\x00g\x00\x00\x00h\x00\x00\x00i\x00\x00\x00j\x00\x00\x00k\x00\x00\x00l\x00\x00\x00m\x00\x00\x00n\x00\x00\x00o\x00\x00\x00p\x00\x00\x00q\x00\x00\x00r\x00\x00\x00s\x00\x00\x00t\x00\x00\x00u\x00\x00\x00v\x00\x00\x00w\x00\x00\x00x\x00\x00\x00y\x00\x00\x00z\x00\x00\x00{\x00\x00\x00|\x00\x00\x00}\x00\x00\x00~\x00\x00\x00\x7f\x00\x00\x00\x80\x00\x00\x00\x81\x00\x00\x00\x82\x00\x00\x00\x83\x00\x00\x00\x84\x00\x00\x00\x85\x00\x00\x00\x86\x00\x00\x00\x87\x00\x00\x00\x88\x00\x00\x00\x89\x00\x00\x00\x8a\x00\x00\x00\x8b\x00\x00\x00\x8c\x00\x00\x00\x8d\x00\x00\x00\x8e\x00\x00\x00\x8f\x00\x00\x00\x90\x00\x00\x00\x91\x00\x00\x00\x92\x00\x00\x00\x93\x00\x00\x00\x94\x00\x00\x00\x95\x00\x00\x00\x96\x00\x00\x00\x97\x00\x00\x00\x98\x00\x00\x00\x99\x00\x00\x00\x9a\x00\x00\x00\x9b\x00\x00\x00\x9c\x00\x00\x00\x9d\x00\x00\x00\x9e\x00\x00\x00\x9f\x00\x00\x00\xa0\x00\x00\x00\xa1\x00\x00\x00\xa2\x00\x00\x00\xa3\x00\x00\x00\xa4\x00\x00\x00\xa5\x00\x00\x00\xa6\x00\x00\x00\xa7\x00\x00\x00\xa8\x00\x00\x00\xa9\x00\x00\x00\xaa\x00\x00\x00\xab\x00\x00\x00\xac\x00\x00\x00\xad\x00\x00\x00\xae\x00\x00\x00\xaf\x00\x00\x00\xb0\x00\x00\x00\xb1\x00\x00\x00\xb2\x00\x00\x00\xb3\x00\x00\x00\xb4\x00\x00\x00\xb5\x00\x00\x00\xb6\x00\x00\x00\xb7\x00\x00\x00\xb8\x00\x00\x00\xb9\x00\x00\x00\xba\x00\x00\x00\xbb\x00\x00\x00\xbc\x00\x00\x00\xbd\x00\x00\x00\xbe\x00\x00\x00\xbf\x00\x00\x00\xc0\x00\x00\x00\xc1\x00\x00\x00\xc2\x00\x00\x00\xc3\x00\x00\x00\xc4\x00\x00\x00\xc5\x00\x00\x00\xc6\x00\x00\x00\xc7\x00\x00\x00\xc8\x00\x00\x00\xc9\x00\x00\x00\xca\x00\x00\x00\xcb\x00\x00\x00\xcc\x00\x00\x00\xcd\x00\x00\x00\xce\x00\x00\x00\xcf\x00\x00\x00\xd0\x00\x00\x00\xd1\x00\x00\x00\xd2\x00\x00\x00\xd3\x00\x00\x00\xd4\x00\x00\x00\xd5\x00\x00\x00\xd6\x00\x00\x00\xd7\x00\x00\x00\xd8\x00\x00\x00\xd9\x00\x00\x00\xda\x00\x00\x00\xdb\x00\x00\x00\xdc\x00\x00\x00\xdd\x00\x00\x00\xde\x00\x00\x00\xdf\x00\x00\x00\xe0\x00\x00\x00\xe1\x00\x00\x00\xe2\x00\x00\x00\xe3\x00\x00\x00\xe4\x00\x00\x00\xe5\x00\x00\x00\xe6\x00\x00\x00\xe7\x00\x00\x00\xe8\x00\x00\x00\xe9\x00\x00\x00\xea\x00\x00\x00\xeb\x00\x00\x00\xec\x00\x00\x00\xed\x00\x00\x00\xee\x00\x00\x00\xef\x00\x00\x00\xf0\x00\x00\x00\xf1\x00\x00\x00\xf2\x00\x00\x00\xf3\x00\x00\x00\xf4\x00\x00\x00\xf5\x00\x00\x00\xf6\x00\x00\x00\xf7\x00\x00\x00\xf8\x00\x00\x00\xf9\x00\x00\x00\xfa\x00\x00\x00\xfb\x00\x00\x00\xfc\x00\x00\x00\xfd\x00\x00\x00\xfe\x00\x00\x00\xff\x00\x00\x01\x00\x00\x00\x01\x01\x00\x00\x01\x02\x00\x00\x01\x03\x00\x00\x01\x04\x00\x00\x01\x05\x00\x00\x01\x06\x00\x00\x01\x07\x00\x00\x01\x08\x00\x00\x01\t\x00\x00\x01\n\x00\x00\x01\x0b\x00\x00\x01\x0c\x00\x00\x01\r\x00\x00\x01\x0e\x00\x00\x01\x0f\x00\x00\x01\x10\x00\x00\x01\x11\x00\x00\x01\x12\x00\x00\x01\x13\x00\x00\x01\x14\x00\x00\x01\x15\x00\x00\x01\x16\x00\x00\x01\x17\x00\x00\x01\x18\x00\x00\x01\x19\x00\x00\x01\x1a\x00\x00\x01\x1b\x00\x00\x01\x1c\x00\x00\x01\x1d\x00\x00\x01\x1e\x00\x00\x01\x1f\x00\x00\x01 \x00\x00\x01!\x00\x00\x01\"\x00\x00\x01#\x00\x00\x01$\x00\x00\x01%\x00\x00\x01&\x00\x00\x01'\x00\x00\x01(\x00\x00\x01)\x00\x00\x01*\x00\x00\x01+\x00\x00\x01,\x00\x00\x01-\x00\x00\x01.\x00\x00\x01/\x00\x00\x010\x00\x00\x011\x00\x00\x012\x00\x00\x013\x00\x00\x014\x00\x00\x015\x00\x00\x016\x00\x00\x017\x00\x00\x018\x00\x00\x019\x00\x00\x01:\x00\x00\x01;\x00\x00\x01<\x00\x00\x01=\x00\x00\x01>\x00\x00\x01?\x00\x00\x01@\x00\x00\x01A\x00\x00\x01B\x00\x00\x01C\x00\x00\x01D\x00\x00\x01E\x00\x00\x01F\x00\x00\x01G\x00\x00\x01H\x00\x00\x01I\x00\x00\x01J\x00\x00\x01K\x00\x00\x01L\x00\x00\x01M\x00\x00\x01N\x00\x00\x01O\x00\x00\x01P\x00\x00\x01Q\x00\x00\x01R\x00\x00\x01S\x00\x00\x01T\x00\x00\x01U\x00\x00\x01V\x00\x00\x01W\x00\x00\x01X\x00\x00\x01Y\x00\x00\x01Z\x00\x00\x01[\x00\x00\x01\\\x00\x00\x01]\x00\x00\x01^\x00\x00\x01_\x00\x00\x01`\x00\x00\x01a\x00\x00\x01b\x00\x00\x01c\x00\x00\x01d\x00\x00\x01e\x00\x00\x01f\x00\x00\x01g\x00\x00\x01h\x00\x00\x01i\x00\x00\x01j\x00\x00\x01k\x00\x00\x01l\x00\x00\x01m\x00\x00\x01n\x00\x00\x01o\x00\x00\x01p\x00\x00\x01q\x00\x00\x01r\x00\x00\x01s\x00\x00\x01t\x00\x00\x01u\x00\x00\x01v\x00\x00\x01w\x00\x00\x01x\x00\x00\x01y\x00\x00\x01z\x00\x00\x01{\x00\x00\x01|\x00\x00\x01}\x00\x00\x01~\x00\x00\x01\x7f\x00\x00\x01\x80\x00\x00\x01\x81\x00\x00\x01\x82\x00\x00\x01\x83\x00\x00\x01\x84\x00\x00\x01\x85\x00\x00\x01\x86\x00\x00\x01\x87\x00\x00\x01\x88\x00\x00\x01\x89\x00\x00\x01\x8a\x00\x00\x01\x8b\x00\x00\x01\x8c\x00\x00\x01\x8d\x00\x00\x01\x8e\x00\x00\x01\x8f\x00\x00\x01\x90\x00\x00\x01\x91\x00\x00\x01\x92\x00\x00\x01\x93\x00\x00\x01\x94\x00\x00\x01\x95\x00\x00\x01\x96\x00\x00\x01\x97\x00\x00\x01\x98\x00\x00\x01\x99\x00\x00\x01\x9a\x00\x00\x01\x9b\x00\x00\x01\x9c\x00\x00\x01\x9d\x00\x00\x01\x9e\x00\x00\x01\x9f\x00\x00\x01\xa0\x00\x00\x01\xa1\x00\x00\x01\xa2\x00\x00\x01\xa3\x00\x00\x01\xa4\x00\x00\x01\xa5\x00\x00\x01\xa6\x00\x00\x01\xa7\x00\x00\x01\xa8\x00\x00\x01\xa9\x00\x00\x01\xaa\x00\x00\x01\xab\x00\x00\x01\xac\x00\x00\x01\xad\x00\x00\x01\xae\x00\x00\x01\xaf\x00\x00\x01\xb0\x00\x00\x01\xb1\x00\x00\x01\xb2\x00\x00\x01\xb3\x00\x00\x01\xb4\x00\x00\x01\xb5\x00\x00\x01\xb6\x00\x00\x01\xb7\x00\x00\x01\xb8\x00\x00\x01\xb9\x00\x00\x01\xba\x00\x00\x01\xbb\x00\x00\x01\xbc\x00\x00\x01\xbd\x00\x00\x01\xbe\x00\x00\x01\xbf\x00\x00\x01\xc0\x00\x00\x01\xc1\x00\x00\x01\xc2\x00\x00\x01\xc3\x00\x00\x01\xc4\x00\x00\x01\xc5\x00\x00\x01\xc6\x00\x00\x01\xc7\x00\x00\x01\xc8\x00\x00\x01\xc9\x00\x00\x01\xca\x00\x00\x01\xcb\x00\x00\x01\xcc\x00\x00\x01\xcd\x00\x00\x01\xce\x00\x00\x01\xcf\x00\x00\x01\xd0\x00\x00\x01\xd1\x00\x00\x01\xd2\x00\x00\x01\xd3\x00\x00\x01\xd4\x00\x00\x01\xd5\x00\x00\x01\xd6\x00\x00\x01\xd7\x00\x00\x01\xd8\x00\x00\x01\xd9\x00\x00\x01\xda\x00\x00\x01\xdb\x00\x00\x01\xdc\x00\x00\x01\xdd\x00\x00\x01\xde\x00\x00\x01\xdf\x00\x00\x01\xe0\x00\x00\x01\xe1\x00\x00\x01\xe2\x00\x00\x01\xe3\x00\x00\x01\xe4\x00\x00\x01\xe5\x00\x00\x01\xe6\x00\x00\x01\xe7\x00\x00\x01\xe8\x00\x00\x01\xe9\x00\x00\x01\xea\x00\x00\x01\xeb\x00\x00\x01\xec\x00\x00\x01\xed\x00\x00\x01\xee\x00\x00\x01\xef\x00\x00\x01\xf0\x00\x00\x01\xf1\x00\x00\x01\xf2\x00\x00\x01\xf3\x00\x00\x01\xf4\x00\x00\x01\xf5\x00\x00\x01\xf6\x00\x00\x01\xf7\x00\x00\x01\xf8\x00\x00\x01\xf9\x00\x00\x01\xfa\x00\x00\x01\xfb\x00\x00\x01\xfc\x00\x00\x01\xfd\x00\x00\x01\xfe\x00\x00\x01\xff" class TestOscMessage(unittest.TestCase): @@ -120,7 +112,7 @@ def test_complex_array_params(self): self.assertEqual(3, len(list(msg))) def test_raises_on_empty_datargram(self): - self.assertRaises(osc_message.ParseError, osc_message.OscMessage, b'') + self.assertRaises(osc_message.ParseError, osc_message.OscMessage, b"") def test_ignores_unknown_param(self): msg = osc_message.OscMessage(_DGRAM_UNKNOWN_PARAM_TYPE) @@ -130,16 +122,15 @@ def test_ignores_unknown_param(self): self.assertAlmostEqual(0.5, msg.params[0]) def test_raises_on_invalid_array(self): - self.assertRaises(osc_message.ParseError, - osc_message.OscMessage, - b"/SYNC\x00\x00\x00[]]\x00") - self.assertRaises(osc_message.ParseError, - osc_message.OscMessage, - b"/SYNC\x00\x00\x00[[]\x00") + self.assertRaises( + osc_message.ParseError, osc_message.OscMessage, b"/SYNC\x00\x00\x00[]]\x00" + ) + self.assertRaises( + osc_message.ParseError, osc_message.OscMessage, b"/SYNC\x00\x00\x00[[]\x00" + ) def test_raises_on_incorrect_datargram(self): - self.assertRaises( - osc_message.ParseError, osc_message.OscMessage, b'foobar') + self.assertRaises(osc_message.ParseError, osc_message.OscMessage, b"foobar") def test_parse_long_params_list(self): msg = osc_message.OscMessage(_DGRAM_LONG_LIST) diff --git a/pythonosc/test/test_osc_message_builder.py b/pythonosc/test/test_osc_message_builder.py index 5208ad9..abd2f3b 100644 --- a/pythonosc/test/test_osc_message_builder.py +++ b/pythonosc/test/test_osc_message_builder.py @@ -9,7 +9,7 @@ def test_just_address(self): self.assertEqual("/a/b/c", msg.address) self.assertEqual([], msg.params) # Messages with just an address should still contain the ",". - self.assertEqual(b'/a/b/c\x00\x00,\x00\x00\x00', msg.dgram) + self.assertEqual(b"/a/b/c\x00\x00,\x00\x00\x00", msg.dgram) def test_no_address_raises(self): builder = osc_message_builder.OscMessageBuilder("") @@ -20,8 +20,8 @@ def test_wrong_param_raise(self): self.assertRaises(ValueError, builder.add_arg, "what?", 1) def test_add_arg_invalid_infered_type(self): - builder = osc_message_builder.OscMessageBuilder('') - self.assertRaises(ValueError, builder.add_arg, {'name': 'John'}) + builder = osc_message_builder.OscMessageBuilder("") + self.assertRaises(ValueError, builder.add_arg, {"name": "John"}) def test_all_param_types(self): builder = osc_message_builder.OscMessageBuilder(address="/SYNC") @@ -49,13 +49,25 @@ def test_all_param_types(self): builder.add_arg(1e-9, builder.ARG_TYPE_DOUBLE) self.assertEqual(len("fihsTFb[i[s]]N") * 2 + 3, len(builder.args)) self.assertEqual("/SYNC", builder.address) - builder.address = '/SEEK' + builder.address = "/SEEK" msg = builder.build() self.assertEqual("/SEEK", msg.address) self.assertSequenceEqual( - [4.0, 2, 1099511627776, "value", True, False, b"\x01\x02\x03", [1, ["abc"]], None] * 2 + - [4278255360, (1, 145, 36, 125), 1e-9], - msg.params) + [ + 4.0, + 2, + 1099511627776, + "value", + True, + False, + b"\x01\x02\x03", + [1, ["abc"]], + None, + ] + * 2 + + [4278255360, (1, 145, 36, 125), 1e-9], + msg.params, + ) def test_long_list(self): huge_list = list(range(512)) @@ -67,18 +79,18 @@ def test_long_list(self): def test_build_wrong_type_raises(self): builder = osc_message_builder.OscMessageBuilder(address="/SYNC") - builder.add_arg('this is not a float', builder.ARG_TYPE_FLOAT) + builder.add_arg("this is not a float", builder.ARG_TYPE_FLOAT) self.assertRaises(osc_message_builder.BuildError, builder.build) def test_build_noarg_message(self): - msg = osc_message_builder.OscMessageBuilder(address='/SYNC').build() + msg = osc_message_builder.OscMessageBuilder(address="/SYNC").build() # This reference message was generated with Cycling 74's Max software # and then was intercepted with Wireshark - reference = bytearray.fromhex('2f53594e430000002c000000') + reference = bytearray.fromhex("2f53594e430000002c000000") self.assertSequenceEqual(msg._dgram, reference) def test_bool_encoding(self): - builder = osc_message_builder.OscMessageBuilder('') + builder = osc_message_builder.OscMessageBuilder("") builder.add_arg(0) builder.add_arg(1) builder.add_arg(False) diff --git a/pythonosc/test/test_osc_packet.py b/pythonosc/test/test_osc_packet.py index 997f26b..0d150f2 100644 --- a/pythonosc/test/test_osc_packet.py +++ b/pythonosc/test/test_osc_packet.py @@ -14,11 +14,10 @@ b"\x00\x00\x00\x10" b"/SYNC\x00\x00\x00" b",f\x00\x00" - b"?\x00\x00\x00") + b"?\x00\x00\x00" +) -_DGRAM_EMPTY_BUNDLE = ( - b"#bundle\x00" - b"\x00\x00\x00\x00\x00\x00\x00\x01") +_DGRAM_EMPTY_BUNDLE = b"#bundle\x00" b"\x00\x00\x00\x00\x00\x00\x00\x01" _DGRAM_NESTED_MESS = ( b"#bundle\x00" @@ -50,7 +49,8 @@ b"\x00\x00\x00\x10" b"/4444\x00\x00\x00" b",f\x00\x00" - b"?\x00\x00\x00") + b"?\x00\x00\x00" +) class TestOscPacket(unittest.TestCase): @@ -59,7 +59,7 @@ def test_two_messages_in_a_bundle(self): self.assertEqual(2, len(packet.messages)) def test_empty_dgram_raises_exception(self): - self.assertRaises(osc_packet.ParseError, osc_packet.OscPacket, b'') + self.assertRaises(osc_packet.ParseError, osc_packet.OscPacket, b"") def test_empty_bundle(self): packet = osc_packet.OscPacket(_DGRAM_EMPTY_BUNDLE) diff --git a/pythonosc/test/test_osc_server.py b/pythonosc/test/test_osc_server.py index 39ac294..1b38b1b 100644 --- a/pythonosc/test/test_osc_server.py +++ b/pythonosc/test/test_osc_server.py @@ -4,25 +4,19 @@ from pythonosc import dispatcher from pythonosc import osc_server -_SIMPLE_PARAM_INT_MSG = ( - b"/SYNC\x00\x00\x00" - b",i\x00\x00" - b"\x00\x00\x00\x04") +_SIMPLE_PARAM_INT_MSG = b"/SYNC\x00\x00\x00" b",i\x00\x00" b"\x00\x00\x00\x04" # Regression test for a datagram that should NOT be stripped, ever... -_SIMPLE_PARAM_INT_9 = b'/debug\x00\x00,i\x00\x00\x00\x00\x00\t' +_SIMPLE_PARAM_INT_9 = b"/debug\x00\x00,i\x00\x00\x00\x00\x00\t" _SIMPLE_MSG_NO_PARAMS = b"/SYNC\x00\x00\x00" class TestOscServer(unittest.TestCase): def test_is_valid_request(self): - self.assertTrue( - osc_server._is_valid_request((b'#bundle\x00foobar',))) - self.assertTrue( - osc_server._is_valid_request((b'/address/1/2/3,foobar',))) - self.assertFalse( - osc_server._is_valid_request((b'',))) + self.assertTrue(osc_server._is_valid_request((b"#bundle\x00foobar",))) + self.assertTrue(osc_server._is_valid_request((b"/address/1/2/3,foobar",))) + self.assertFalse(osc_server._is_valid_request((b"",))) class TestUDPHandler(unittest.TestCase): @@ -33,28 +27,32 @@ def setUp(self): self.server = unittest.mock.Mock(spec=osc_server.BlockingOSCUDPServer) # Need to attach property mocks to types, not objects... weird. type(self.server).dispatcher = unittest.mock.PropertyMock( - return_value=self.dispatcher) + return_value=self.dispatcher + ) self.client_address = ("127.0.0.1", 8080) def test_no_match(self): mock_meth = unittest.mock.MagicMock() self.dispatcher.map("/foobar", mock_meth) osc_server._UDPHandler( - [_SIMPLE_PARAM_INT_MSG, None], self.client_address, self.server) + [_SIMPLE_PARAM_INT_MSG, None], self.client_address, self.server + ) self.assertFalse(mock_meth.called) def test_match_with_args(self): mock_meth = unittest.mock.MagicMock() self.dispatcher.map("/SYNC", mock_meth, 1, 2, 3) osc_server._UDPHandler( - [_SIMPLE_PARAM_INT_MSG, None], self.client_address, self.server) + [_SIMPLE_PARAM_INT_MSG, None], self.client_address, self.server + ) mock_meth.assert_called_with("/SYNC", [1, 2, 3], 4) def test_match_int9(self): mock_meth = unittest.mock.MagicMock() self.dispatcher.map("/debug", mock_meth) osc_server._UDPHandler( - [_SIMPLE_PARAM_INT_9, None], self.client_address, self.server) + [_SIMPLE_PARAM_INT_9, None], self.client_address, self.server + ) self.assertTrue(mock_meth.called) mock_meth.assert_called_with("/debug", 9) @@ -62,14 +60,16 @@ def test_match_without_args(self): mock_meth = unittest.mock.MagicMock() self.dispatcher.map("/SYNC", mock_meth) osc_server._UDPHandler( - [_SIMPLE_MSG_NO_PARAMS, None], self.client_address, self.server) + [_SIMPLE_MSG_NO_PARAMS, None], self.client_address, self.server + ) mock_meth.assert_called_with("/SYNC") def test_match_default_handler(self): mock_meth = unittest.mock.MagicMock() self.dispatcher.set_default_handler(mock_meth) osc_server._UDPHandler( - [_SIMPLE_MSG_NO_PARAMS, None], self.client_address, self.server) + [_SIMPLE_MSG_NO_PARAMS, None], self.client_address, self.server + ) mock_meth.assert_called_with("/SYNC") diff --git a/pythonosc/test/test_udp_client.py b/pythonosc/test/test_udp_client.py index f4eb570..dece381 100644 --- a/pythonosc/test/test_udp_client.py +++ b/pythonosc/test/test_udp_client.py @@ -6,21 +6,21 @@ class TestUdpClient(unittest.TestCase): - @mock.patch('socket.socket') + @mock.patch("socket.socket") def test_send(self, mock_socket_ctor): mock_socket = mock_socket_ctor.return_value - client = udp_client.UDPClient('::1', 31337) + client = udp_client.UDPClient("::1", 31337) - msg = osc_message_builder.OscMessageBuilder('/').build() + msg = osc_message_builder.OscMessageBuilder("/").build() client.send(msg) self.assertTrue(mock_socket.sendto.called) - mock_socket.sendto.assert_called_once_with(msg.dgram, ('::1', 31337)) + mock_socket.sendto.assert_called_once_with(msg.dgram, ("::1", 31337)) class TestSimpleUdpClient(unittest.TestCase): def setUp(self): - self.patcher = mock.patch('pythonosc.udp_client.OscMessageBuilder') + self.patcher = mock.patch("pythonosc.udp_client.OscMessageBuilder") self.patcher.start() self.builder = udp_client.OscMessageBuilder.return_value self.msg = self.builder.build.return_value @@ -30,20 +30,21 @@ def tearDown(self): self.patcher.stop() def test_send_message_calls_send_with_msg(self): - udp_client.SimpleUDPClient.send_message(self.client, '/address', 1) + udp_client.SimpleUDPClient.send_message(self.client, "/address", 1) self.client.send.assert_called_once_with(self.msg) def test_send_message_calls_add_arg_with_value(self): - udp_client.SimpleUDPClient.send_message(self.client, '/address', 1) + udp_client.SimpleUDPClient.send_message(self.client, "/address", 1) self.builder.add_arg.assert_called_once_with(1) def test_send_message_calls_add_arg_once_with_string(self): - udp_client.SimpleUDPClient.send_message(self.client, '/address', 'hello') - self.builder.add_arg.assert_called_once_with('hello') + udp_client.SimpleUDPClient.send_message(self.client, "/address", "hello") + self.builder.add_arg.assert_called_once_with("hello") def test_send_message_calls_add_arg_multiple_times_with_list(self): - udp_client.SimpleUDPClient.send_message(self.client, '/address', - [1, 'john', True]) + udp_client.SimpleUDPClient.send_message( + self.client, "/address", [1, "john", True] + ) self.assertEqual(self.builder.add_arg.call_count, 3) diff --git a/pythonosc/udp_client.py b/pythonosc/udp_client.py index 20b0f17..c4cce00 100644 --- a/pythonosc/udp_client.py +++ b/pythonosc/udp_client.py @@ -19,7 +19,13 @@ class UDPClient(object): """OSC client to send :class:`OscMessage` or :class:`OscBundle` via UDP""" - def __init__(self, address: str, port: int, allow_broadcast: bool = False, family: socket.AddressFamily = socket.AF_UNSPEC) -> None: + def __init__( + self, + address: str, + port: int, + allow_broadcast: bool = False, + family: socket.AddressFamily = socket.AF_UNSPEC, + ) -> None: """Initialize client As this is UDP it will not actually make any attempt to connect to the @@ -32,7 +38,9 @@ def __init__(self, address: str, port: int, allow_broadcast: bool = False, famil family: address family parameter (passed to socket.getaddrinfo) """ - for addr in socket.getaddrinfo(address, port, type=socket.SOCK_DGRAM, family=family): + for addr in socket.getaddrinfo( + address, port, type=socket.SOCK_DGRAM, family=family + ): af, socktype, protocol, canonname, sa = addr try: diff --git a/scripts/print_datagrams_main.py b/scripts/print_datagrams_main.py index 5c2f63d..ff26d0c 100644 --- a/scripts/print_datagrams_main.py +++ b/scripts/print_datagrams_main.py @@ -6,15 +6,8 @@ def main(): parser = argparse.ArgumentParser() - parser.add_argument( - "--ip", - default="127.0.0.1", - help="The ip to listen on") - parser.add_argument( - "--port", - type=int, - default=5005, - help="The port to listen on") + parser.add_argument("--ip", default="127.0.0.1", help="The ip to listen on") + parser.add_argument("--port", type=int, default=5005, help="The port to listen on") args = parser.parse_args() _PrintOscMessages(args.ip, args.port)