DiamondLightSource / DiamondLightSource/tickit

Inconsistent error if 'interrupt' parameter in RegexCommand is incorrect

Open
#141 0 comments 0 reactions 1 assignee Claimed by @abbiemery View on GitHub
bug
Dominant language
Python
Stars
7
Forks
1
PR merge metrics
No merged PRs in 30d

Description

If the 'interrupt' parameter is True, when it ought to be False, the tickit device has a chance of triggering an exception that is not properly handled. This error will cause all future scheduled updates to fail to run.

I have tried to produce a minimum working example that raises the exception in question.

I have found the input / output field necessary for any tickit device; I am not sure why. It's called 'flux' as it was copied from an example.

Run the simulation:
`python -m tickit all ./temp_controller.yaml`

On a separate terminal, send the multiple requests:
`./test_comms.py`

Problematic code

```python

@RegexCommand(r"T\?", True, "utf-8") # Causes issues
@RegexCommand(r"T\?", False, "utf-8") # Works fine

```


Error messages

Benign messages:
```
DEBUG:tickit.core.management.schedulers.base:Scheduler (MasterScheduler) got Interrupt(source='tempcont')
DEBUG:tickit.core.management.schedulers.base:Scheduling tempcont for wakeup at 14296887047
```

Main error:
```
Task exception:
Traceback (most recent call last):
File "/venv/lib/python3.10/site-packages/tickit/core/runner.py", line 21, in run_with_error_handling
await awaitable
File "/venv/lib/python3.10/site-packages/tickit/core/management/schedulers/master.py", line 72, in run_forever
await self._do_tick()
File "/venv/lib/python3.10/site-packages/tickit/core/management/schedulers/master.py", line 88, in _do_tick
assert when is not None
AssertionError
```


device.py

```python
from dataclasses import dataclass

from tickit.adapters.composed import ComposedAdapter
from tickit.adapters.interpreters.command import CommandInterpreter
from tickit.adapters.interpreters.command.regex_command import RegexCommand
from tickit.adapters.servers.tcp import ByteFormat, TcpServer
from tickit.core.components.component import Component, ComponentConfig
from tickit.core.components.device_simulation import DeviceSimulation
from tickit.core.device import Device, DeviceUpdate
from tickit.core.typedefs import SimTime
from typing_extensions import TypedDict

class TempControllerDevice(Device):
Inputs: type = TypedDict("Inputs", {"flux": float})
Outputs: type = TypedDict("Outputs", {"flux": float})

def __init__(
self,
) -> None:
self._temp = 10.0

def get_temp(self):
return self._temp

def update(self, time: SimTime, inputs: Inputs) -> DeviceUpdate[Outputs]:
return DeviceUpdate(TempControllerDevice.Outputs(flux=inputs["flux"]), None)

class TempControllerAdapter(ComposedAdapter):
device: TempControllerDevice

def __init__(
self,
host: str = "localhost",
port: int = 25565,
) -> None:
super().__init__(
TcpServer(host, port, ByteFormat(b"%b\r\n")),
CommandInterpreter(),
)

@RegexCommand(r"T\?", True, "utf-8")
async def get_temperature(self) -> bytes:
return str(self.device.get_temp()).encode("utf-8")

@dataclass
class TempController(ComponentConfig):
host: str = "localhost"
port: int = 25565

def __call__(self) -> Component:
return DeviceSimulation(
name=self.name,
device=TempControllerDevice(),
adapters=[TempControllerAdapter(host=self.host, port=self.port)],
)
```


temp_controller.yaml

```
- tickit.devices.source.Source:
name: source
inputs: {}
value: 66.0
- device.TempController:
name: tempcont
inputs:
flux: source:value
- tickit.devices.sink.Sink:
name: sink
inputs:
flux: tempcont:flux
```


test_comms.py

```python
#! /bin/env python
import socket

HOSTNAME = "localhost"
PORT = 25565

COUNT = 10

def send_message(s):
message = b"T?\r\n"
s.sendall(message)
print(f"Sent: {message}")
response = s.recv(1024)
print(f"Received: {response}")

def send_commands():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOSTNAME, PORT))

for _ in range(COUNT):
send_message(s)

s.close()

if __name__ == "__main__":
send_commands()
```


Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.