Skip to content

Commit

Permalink
cleanup mypy errors, address review comments, add response support to…
Browse files Browse the repository at this point in the history
… UDP server
  • Loading branch information
Bob Haddleton authored and Bob Haddleton committed Aug 17, 2024
1 parent d89c241 commit 7b5d8ea
Show file tree
Hide file tree
Showing 20 changed files with 767 additions and 367 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

## [Unreleased]

- Added TCP Client and Server support for OSC 1.0 and OSC 1.1 formats, with support for sending responses to the client
- Added response support to the existing UDP Client and Server code

## [1.8.3]

- Using trusted publisher setup to publish to pypi
Expand Down
26 changes: 24 additions & 2 deletions docs/client.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
Client
========

The client allows you to connect and send messages to an OSC server. The client class expects an :class:`OSCMessage` object, which is then sent out via UDP. Additionally, a simple client class exists that constructs the :class:`OSCMessage` object for you.
The client allows you to connect and exchange messages with an OSC server.
Client classes are available for UDP and TCP protocols.
The base client class ``send`` method expects an :class:`OSCMessage` object, which is then sent out over TCP or UDP.
Additionally, a simple client class exists that constructs the :class:`OSCMessage` object for you.

Example
See the examples folder for more use cases.

Examples
---------

.. code-block:: python
Expand All @@ -19,10 +24,27 @@ Example
client.send_message("/some/address", [1, 2., "hello"]) # Send message with int, float and string
.. code-block:: python
from pythonosc.tcp_client import SimpleTCPClient
ip = "127.0.0.1"
port = 1337
client = SimpleTCPClient(ip, port) # Create client
client.send_message("/some/address", 123) # Send float message
client.send_message("/some/address", [1, 2., "hello"]) # Send message with int, float and string
Client Module Documentation
---------------------------------

.. automodule:: pythonosc.udp_client
:special-members:
:members:
:exclude-members: __weakref__

.. automodule:: pythonosc.tcp_client
:special-members:
:members:
:exclude-members: __weakref__
12 changes: 12 additions & 0 deletions docs/dispatcher.rst
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@ The handler must have the same signature as map callbacks:
def some_callback(address: str, *osc_arguments: List[Any]) -> None:
Handler Responses
-----------------

Handler functions can return responses back to the client, when running on a server, or to the
server when running as a client. Handler functions should return one of:

* None
* An OSC address in string format
* A tuple containing a string OSC address and the associated arguments

If the handler function response is not None it will be encoded in an OSCMessage and sent to the
remote client or server.

Dispatcher Module Documentation
---------------------------------
Expand Down
7 changes: 6 additions & 1 deletion docs/server.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Server
=========

The server receives OSC Messages from connected clients and invoked the appropriate callback functions with the dispatcher. There are several server types available.

Server implementations are available for both UDP and TCP protocols.

Blocking Server
-----------------
Expand Down Expand Up @@ -123,6 +123,11 @@ Server Module Documentation
------------------------------

.. automodule:: pythonosc.osc_server
:special-members:
:members:
:exclude-members: __weakref__

.. automodule:: pythonosc.osc_tcp_server
:special-members:
:members:
:exclude-members: __weakref__
21 changes: 14 additions & 7 deletions examples/async_simple_tcp_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
sends 10 random values between 0.0 and 1.0 to the /filter address,
waiting for 1 seconds between each value in a second task.
"""

import argparse
import asyncio
import random
Expand All @@ -27,19 +28,25 @@ async def send_messages(client):

async def init_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("--mode", default="1.1",
help="The OSC protocol version of the server (default is 1.1)")
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(
"--mode",
default="1.1",
help="The OSC protocol version of the server (default is 1.1)",
)
args = parser.parse_args()

async with tcp_client.AsyncSimpleTCPClient(args.ip, args.port, mode=args.mode) as client:
async with tcp_client.AsyncSimpleTCPClient(
args.ip, args.port, mode=args.mode
) as client:
async with asyncio.TaskGroup() as tg:
tg.create_task(get_messages(client))
tg.create_task(send_messages(client))


if sys.version_info >= (3, 7):
asyncio.run(init_main())
else:
Expand Down
19 changes: 12 additions & 7 deletions examples/async_tcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,20 @@ async def loop():

async def init_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("--mode", default="1.1",
help="The OSC protocol version of the server (default is 1.1)")
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(
"--mode",
default="1.1",
help="The OSC protocol version of the server (default is 1.1)",
)
args = parser.parse_args()

async with AsyncOSCTCPServer(args.ip, args.port, dispatcher, mode=args.mode) as server:
async with AsyncOSCTCPServer(
args.ip, args.port, dispatcher, mode=args.mode
) as server:
async with asyncio.TaskGroup() as tg:
tg.create_task(server.start())
tg.create_task(loop())
Expand Down
27 changes: 27 additions & 0 deletions examples/simple_echo_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""Small example OSC client
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

from pythonosc import udp_client

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"
)
args = parser.parse_args()

client = udp_client.SimpleUDPClient(args.ip, args.port)

for x in range(10):
client.send_message("/filter", random.random())
reply = next(client.get_messages(2))
print(str(reply))
time.sleep(1)
30 changes: 30 additions & 0 deletions examples/simple_echo_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Small example OSC server
This program listens to several addresses, and prints some information about
received packets.
"""

import argparse
import math

from pythonosc.dispatcher import Dispatcher
from pythonosc import osc_server


def echo_handler(client_addr, unused_addr, args):
print(unused_addr, args)
return (unused_addr, args)


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")
args = parser.parse_args()

dispatcher = Dispatcher()
dispatcher.set_default_handler(echo_handler, True)

server = osc_server.ThreadingOSCUDPServer((args.ip, args.port), dispatcher)
print("Serving on {}".format(server.server_address))
server.serve_forever()
16 changes: 10 additions & 6 deletions examples/simple_tcp_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,23 @@
This program sends 10 random values between 0.0 and 1.0 to the /filter address,
and listens for incoming messages for 1 second between each value.
"""

import argparse
import random

from pythonosc import tcp_client

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("--mode", default="1.1",
help="The OSC protocol version of the server (default is 1.1)")
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(
"--mode",
default="1.1",
help="The OSC protocol version of the server (default is 1.1)",
)
args = parser.parse_args()

with tcp_client.SimpleTCPClient(args.ip, args.port, mode=args.mode) as client:
Expand Down
17 changes: 10 additions & 7 deletions examples/simple_tcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
This program listens to the specified address and port, and prints some information about
received packets.
"""

import argparse
import math

Expand All @@ -23,12 +24,13 @@ 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("--mode", default="1.1",
help="The OSC protocol version of the server (default is 1.1)")
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(
"--mode",
default="1.1",
help="The OSC protocol version of the server (default is 1.1)",
)

args = parser.parse_args()

Expand All @@ -38,6 +40,7 @@ def print_compute_handler(unused_addr, args, volume):
dispatcher.map("/logvolume", print_compute_handler, "Log volume", math.log)

server = osc_tcp_server.ThreadingOSCTCPServer(
(args.ip, args.port), dispatcher, mode=args.mode)
(args.ip, args.port), dispatcher, mode=args.mode
)
print("Serving on {}".format(server.server_address))
server.serve_forever()
Loading

0 comments on commit 7b5d8ea

Please sign in to comment.