Skip to content

Commit

Permalink
various cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
rsnodgrass committed Jan 22, 2024
1 parent 6f5d11c commit fed5904
Show file tree
Hide file tree
Showing 10 changed files with 62 additions and 58 deletions.
13 changes: 5 additions & 8 deletions example-async.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import coloredlogs

from pyavcontrol import DeviceClient, DeviceModelLibrary
from pyavcontrol.helper import construct_async_client

LOG = logging.getLogger(__name__)
coloredlogs.install(level='DEBUG')
Expand Down Expand Up @@ -41,15 +42,11 @@
async def main():
try:
loop = asyncio.get_event_loop()
library = DeviceModelLibrary.create(event_loop=loop)
model_def = await library.load_model(args.model)

client = DeviceClient.create(
model_def,
args.url,
connection_config_overrides={'baudrate': args.baud},
event_loop=loop,
)
# FIXME: connection!

config_overrides = {'baudrate': args.baud}
client = construct_async_client(args.model, args.url, loop, connection_config=config_overrides)

# help(client.power)
await client.send_raw(b'!PING?')
Expand Down
8 changes: 4 additions & 4 deletions example-sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import coloredlogs

from pyavcontrol import DeviceClient, DeviceModelLibrary
from pyavcontrol.helper import construct_synchronous_client

LOG = logging.getLogger(__name__)
coloredlogs.install(level='DEBUG')
Expand Down Expand Up @@ -37,10 +38,9 @@


def main():
model_def = DeviceModelLibrary.create().load_model(args.model)
client = DeviceClient.create(
model_def, args.url, connection_config_overrides={'baudrate': args.baud}
)
config_overrides = {'baudrate': args.baud}
client = construct_synchronous_client(args.model, args.url,
connection_config=config_overrides)

client.send_raw(b'!PING?')
print(client.ping.ping())
Expand Down
32 changes: 17 additions & 15 deletions pyavcontrol/client/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@
from ..core import (
camel_case,
generate_docs_for_action,
get_args_for_command,
missing_keys_in_dict,
substitute_fstring_vars,
substitute_fstring_vars, get_args_for_command,
)
from ..library.model import DeviceModel

Expand Down Expand Up @@ -82,6 +81,9 @@ def _inject_client_api(client: DeviceClient, model: DeviceModel):
"""
api = model.definition.get(CONFIG.api, {})
for group_name, group_actions in api.items():
if getattr(type(client), group_name):
raise RuntimeError(f'Injecting "{group_name}" failed as it already exists in class')

# LOG.debug(f'Adding property for group {group_name}')
group_class = _create_activity_group_class(
client, model, group_name, group_actions
Expand All @@ -90,7 +92,6 @@ def _inject_client_api(client: DeviceClient, model: DeviceModel):

return client


def _create_action_method(
client: DeviceClient,
cls_name: str,
Expand All @@ -106,6 +107,7 @@ def _create_action_method(
a synchronous method is returned by default. Calling code knows whether they
instantiated a synchronous or asynchronous client.
"""
# noinspection PyShadowingNames
LOG = logging.getLogger(cls_name)
required_args = get_args_for_command(action_def)
wait_for_response = False
Expand All @@ -123,12 +125,14 @@ def _prepare_request(**kwargs):
return request.encode(client.encoding())
return None

# noinspection PyUnusedLocal
def _activity_call_sync(self, **kwargs) -> None:
"""Synchronous version of making a client call"""
if request := _prepare_request(**kwargs):
return client.send_raw(request)
LOG.warning(f'Failed to make request for {group_name}.{action_name}')

# noinspection PyUnusedLocal
async def _activity_call_async(self, **kwargs) -> None:
"""
Asynchronous version of making a client call is used when an event_loop
Expand All @@ -152,9 +156,8 @@ class DeviceClient(ABC):
to control a device.
"""

def _new__(cls, *args, **kwargs):
def __new__(cls, *args, **kwargs):
return super().__new__(cls, *args, **kwargs)
# return

def __init__(self, model: DeviceModel, connection: DeviceConnection):
super().__init__()
Expand All @@ -177,15 +180,15 @@ def is_async(self):
"""
return False

@abstractmethod
def send_command(self, group: str, action: str, **kwargs) -> None:
"""
Call a command by the group/action and args as defined in the
device's protocol yaml. E.g.

client.send_command(group, action, arg1=one, my_arg=my_arg)
"""
raise NotImplementedError()
#@abstractmethod
#def send_command(self, group: str, action: str, **kwargs) -> None:
#"""
#Call a command by the group/action and args as defined in the
#device's protocol yaml. E.g.
#client.send_command(group, action, arg1=one, my_arg=my_arg)
#"""
#raise NotImplementedError()

@abstractmethod
def send_raw(self, data: bytes) -> None:
Expand Down Expand Up @@ -242,8 +245,7 @@ def create(
is returned.
:param model: DeviceModel
:param url: pyserial supported url for communication (e.g. '/dev/ttyUSB0' or 'socket://remote-host:4999/')
:param connection_config_overrides: dictionary of serial port configuration overrides (e.g. baudrate)
:param connection: connection to the device
:param event_loop: optionally to get an interface that can be used asynchronously, pass in an event loop
:return an instance of DeviceControllerBase
Expand Down
2 changes: 1 addition & 1 deletion pyavcontrol/client/sync_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def __init__(self, model: DeviceModel, connection: DeviceConnection):
def send_raw(self, data: bytes) -> None:
if LOG.isEnabledFor(logging.DEBUG):
LOG.debug(f'Sending {self._connection!r}: {data}')
self._connection.sent(data)
self._connection.send(data)

@synchronized
def send_command(self, group: str, action: str, **kwargs) -> None:
Expand Down
2 changes: 1 addition & 1 deletion pyavcontrol/config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import typing as t
from dataclasses import dataclass

# FIXME: also consider pydantic
Expand All @@ -15,6 +14,7 @@ class _Config:
timeout = 'timeout'
min_time_between_commands = 'min_time_between_commands'
format = 'format'
baudrate = 'baudrate'


CONFIG = _Config()
Expand Down
14 changes: 7 additions & 7 deletions pyavcontrol/connection/async_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ async def _connect(self) -> None:
self._url,
self._connection_config, # self._config,
self._connection_config,
self._connection_config.get(CONFIG.format, {}), # self._protocol_def,
self._event_loop,
)

Expand All @@ -72,7 +71,7 @@ async def send(self, data: bytes, callback=None):


async def async_get_rs232_connection(
serial_port: str, config: dict, connection_config: dict, protocol_def: dict, loop
serial_port: str, config: dict, connection_config: dict, loop
):
# ensure only a single, ordered command is sent to RS232 at a time (non-reentrant lock)
def locked_method(method):
Expand All @@ -97,8 +96,9 @@ async def wrapper(self, *method_args, **method_kwargs):
return wrapper

class RS232ControlProtocol(asyncio.Protocol):
# noinspection PyShadowingNames
def __init__(
self, serial_port, config, connection_config, protocol_config, loop
self, serial_port, config, connection_config, loop
):
super().__init__()

Expand Down Expand Up @@ -149,9 +149,9 @@ async def _reset_buffers(self):
@ensure_connected
async def send(self, data: bytes, callback=None, wait_for_reply=False):
@limits(calls=1, period=self._min_time_between_commands)
async def write_rate_limited(data: bytes):
LOG.debug(f'>> {self._url}: %s', data)
self._transport.serial.write(data)
async def write_rate_limited(data_bytes: bytes):
LOG.debug(f'>> {self._url}: %s', data_bytes)
self._transport.serial.write(data_bytes)

# clear all buffers of any data waiting to be read before sending the request
await self._reset_buffers()
Expand Down Expand Up @@ -186,7 +186,7 @@ def log_timeout():
raise

factory = functools.partial(
RS232ControlProtocol, serial_port, config, connection_config, protocol_def, loop
RS232ControlProtocol, serial_port, config, connection_config, loop
)

LOG.info(f'Connecting to {serial_port}: {connection_config}')
Expand Down
21 changes: 12 additions & 9 deletions pyavcontrol/connection/sync_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,24 @@ class SyncDeviceConnection(DeviceConnection, ABC):
Synchronous device connection implementation (NOT YET IMPLEMENTED)
"""

def __init__(self, url: str, config: dict, connection_config: dict):
def __init__(self, url: str, connection_config: dict):
"""
:param url: pyserial compatible url
"""
super.__init__()
super().__init__()

self._url = url
self._config = config
self._connection_config = connection_config

self._encoding = connection_config.get(CONFIG.encoding, DEFAULT_ENCODING)

# FIXME: remove the following
config = connection_config # FIXME: remove
self._eol = config.get(CONFIG.response_eol, DEFAULT_EOL).encode(self._encoding)

# FIXME: all min time between commands should probably be at the client level and
# not at the raw connection... move up!
self._min_time_between_commands = self._config.get(
self._min_time_between_commands = config.get(
CONFIG.min_time_between_commands, 0
)

Expand All @@ -69,16 +71,17 @@ def _reset_buffers(self):

def send(self, data: bytes, callback=None, wait_for_response=False):
"""
:param data: request that is sent to the device
:param skip: number of bytes to skip for end of transmission decoding
:param data: data bytes sent to the device
:param callback: (optional)
:param wait_for_response: (optional)
:return: string returned by device
"""

@limits(calls=1, period=self._min_time_between_commands)
def write_rate_limited(data: bytes):
LOG.debug(f'>> {self._url}: %s', data)
def write_rate_limited(data_bytes: bytes):
LOG.debug(f'>> {self._url}: %s', data_bytes)
# send data and force flush to send immediately
self._port.write(data)
self._port.write(data_bytes)
self._port.flush()

# clear any pending transactions
Expand Down
2 changes: 1 addition & 1 deletion pyavcontrol/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

LOG = logging.getLogger(__name__)

NAMED_REGEX_PATTERN = re.compile(r'\(\?P\<(?P<name>.+)\>(?P<regex>.+)\)')
NAMED_REGEX_PATTERN = re.compile(r'\(\?P<(?P<name>.+)>(?P<regex>.+)\)')
FSTRING_ARG_PATTERN = re.compile(r'{(?P<arg_name>.+)}')


Expand Down
18 changes: 10 additions & 8 deletions pyavcontrol/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ async def construct_async_client(
:param connection_config: pyserial configuration overrides (defaults come from for model_def)
:param event_loop: (optional) event loop if an asynchronous client is desired
"""
from pyavcontrol.connection.async_connection import AsyncDeviceConnection

if not connection_config:
connection_config = {}

# load the model and settings for interacting with the device
library = DeviceModelLibrary.create(event_loop=event_loop)
model = await library.load_model(model_id)
# FIXME: err handling

from pyavcontrol.connection.async_connection import AsyncDeviceConnection
# FIXME: need to load connection_config also from the model!?
if not connection_config:
connection_config = {}

connection = AsyncDeviceConnection(url, connection_config, event_loop)

Expand All @@ -49,15 +50,16 @@ def construct_synchronous_client(
:param url: The pyserial compatible connection URL
:param connection_config: pyserial configuration overrides (defaults come from for model_def)
"""
if not connection_config:
connection_config = {}
from pyavcontrol.connection.sync_connection import SyncDeviceConnection

# load the model
# load the model and settings for interacting with the device
library = DeviceModelLibrary.create()
model_def = library.load_model(model_id)
# FIXME: err handling

from pyavcontrol.connection.sync_connection import SyncDeviceConnection
# FIXME: need to load connection_config also from the model!?
if not connection_config:
connection_config = {}

connection = SyncDeviceConnection(url, connection_config)

Expand Down
8 changes: 4 additions & 4 deletions pyavcontrol/library/docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
FIXME: We may want to move this to tools/ or docs/
"""
from . import DeviceClient, DeviceModelLibrary
from . import DeviceModelLibrary
from .. import DeviceClient
from ..connection import NullConnection

MODELS = [
"hdfury_vrroom",
Expand All @@ -32,7 +34,5 @@
model_def = DeviceModelLibrary.create().load_model(model_id)
MODEL_DEFS.append(model_def)

url = "/dev/null"

client = DeviceClient.create(model_def, url)
client = DeviceClient.create(model_def, NullConnection())
CLIENTS.append(client)

0 comments on commit fed5904

Please sign in to comment.