Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
04d1e85
Update _is_sensor.py
ddkohler Feb 16, 2025
30f657e
Update _is_sensor.py
ddkohler Feb 16, 2025
d7d148b
Update _is_sensor.py
ddkohler Feb 16, 2025
b716abb
Update _is_sensor.py
ddkohler Feb 16, 2025
27141df
Update _is_sensor.py
ddkohler Feb 16, 2025
0aa71b5
Update _is_sensor.py
ddkohler Feb 17, 2025
c517765
Update _is_sensor.py
ddkohler Feb 17, 2025
c6b0b91
Update _is_sensor.py
ddkohler Feb 17, 2025
d98dc10
Update _is_sensor.py
ddkohler Feb 17, 2025
3c08c6e
Update _is_sensor.py
ddkohler Feb 17, 2025
415ba2b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 17, 2025
e054ab2
propagate to HasMeasureTrigger
ddkohler Feb 17, 2025
717ebb2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 17, 2025
3485320
Update _is_sensor.py
ddkohler Feb 17, 2025
05f034a
Merge branch 'ddkohler-patch-1' of https://github.com/yaq-project/yaq…
ddkohler Feb 17, 2025
f21d365
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 17, 2025
a57f059
remove MeasureType
ddkohler Feb 17, 2025
1cebbbc
Update CHANGELOG.md
ddkohler Feb 17, 2025
4304b6f
remove redundant actions
ddkohler Feb 17, 2025
864ea88
Update README.md
ddkohler Feb 17, 2025
c5c0dd8
expand test py versions
ddkohler Feb 17, 2025
686e2a9
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 17, 2025
318942c
Update pyproject.toml
ddkohler Feb 17, 2025
ed3f700
Merge branch 'ddkohler-patch-1' of https://github.com/yaq-project/yaq…
ddkohler Feb 17, 2025
94d1f57
initiate tests again
ddkohler Oct 19, 2025
66f12fc
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 19, 2025
58e5f40
try python 3.13
ddkohler Oct 20, 2025
473bfa0
Update _is_daemon.py
ddkohler Oct 20, 2025
01e7e31
Update _is_daemon.py
ddkohler Oct 20, 2025
2074108
Update _is_daemon.py
ddkohler Oct 20, 2025
6374e57
Update pyproject.toml
ddkohler Oct 20, 2025
dfe64b4
refactor asyncio loop
ddkohler Oct 20, 2025
9e49181
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 20, 2025
f97826c
Update _fake_sensor.py
ddkohler Oct 20, 2025
08cb06b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 20, 2025
5d2451f
Merge branch 'server_minimal' of https://github.com/yaq-project/yaq-p…
ddkohler Oct 20, 2025
bc4c797
cleanup
ddkohler Oct 20, 2025
ad71d33
Merge branch 'ddkohler-patch-1' into server_minimal
ddkohler Oct 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/python-pytest.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
name: pytest

on:
push:
pull_request:
types: [opened, reopened]
push:

jobs:
build:

strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}

Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/run-entry-points.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
name: run entry points

on:
push:
pull_request:
types: [opened, reopened]
push:

jobs:
build:

strategy:
matrix:
python-version: ["3.8", "3.9", "3.10"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Repository for yaq core python packages:

Each of these projects is distributed as a separate package.

These core packages are kept in one repository primarily such that, when needed, changes can be made simulatiously to multiple packages whithout breaking tests.
These core packages are kept in one repository primarily such that, when needed, changes can be made simultaneously to multiple packages without breaking tests.

Repository maintainers:
- [Kyle Sunden](https://github.com/ksunden)
Expand Down
3 changes: 3 additions & 0 deletions yaqd-core/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](https://keepachangelog.com/).

## [Unreleased]

### Fixed
- type hints for IsSensor attributes are appropriate for _n_-dimensional data

## [2023.11.0]

### Fixed
Expand Down
5 changes: 3 additions & 2 deletions yaqd-core/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "yaqd-core"
author = [{name="yaq developers"}]
authors = [{name="yaq developers"}]
requires-python = ">=3.7"
dependencies = ["platformdirs", "tomli", "tomli-w", "fastavro>=1.4.0"]
readme="README.md"
Expand All @@ -20,6 +20,7 @@ classifiers=[
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Scientific/Engineering",
]

Expand All @@ -37,7 +38,7 @@ path = "yaqd_core/__version__.py"

[tool.black]
line-length = 99
target-version = ['py37', 'py38']
target-version = ['py311', "py312"]
include = '\.pyi?$'
exclude = '''
/(
Expand Down
11 changes: 6 additions & 5 deletions yaqd-core/yaqd_core/_has_measure_trigger.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
from __future__ import annotations

__all__ = ["HasMeasureTrigger"]


import asyncio
import pathlib
from typing import Dict, Any, Optional
from typing import Any
from abc import ABC, abstractmethod

from yaqd_core import IsSensor, IsDaemon
from ._is_sensor import MeasureType


class HasMeasureTrigger(IsSensor, IsDaemon, ABC):
def __init__(
self, name: str, config: Dict[str, Any], config_filepath: pathlib.Path
self, name: str, config: dict[str, Any], config_filepath: pathlib.Path
):
super().__init__(name, config, config_filepath)
self._looping = False
if self._config["loop_at_startup"]:
self.measure(loop=True)

def get_measured(self) -> MeasureType:
def get_measured(self) -> dict:
return super().get_measured()

@abstractmethod
async def _measure(self) -> MeasureType:
async def _measure(self) -> dict:
"""Do measurement, filling _measured dictionary.

Returns dictionary with keys channel names, values numbers or arrays.
Expand Down
39 changes: 20 additions & 19 deletions yaqd-core/yaqd_core/_is_daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def __init__(
self._busy_sig = asyncio.Event()
self._not_busy_sig = asyncio.Event()

self._loop = asyncio.get_event_loop()
self._loop = asyncio.get_running_loop()

try:
self._state_filepath.parent.mkdir(parents=True, exist_ok=True)
Expand Down Expand Up @@ -123,17 +123,7 @@ def _traits(cls) -> List[str]:

@classmethod
def main(cls):
"""Run the event loop."""
loop = asyncio.get_event_loop()
if sys.platform.startswith("win"):
signals = ()
else:
signals = (signal.SIGHUP, signal.SIGTERM, signal.SIGINT)
for s in signals:
loop.add_signal_handler(
s, lambda s=s: asyncio.create_task(cls.shutdown_all(s, loop))
)

"""parse arguments and start the event loop"""
parser = argparse.ArgumentParser()
parser.add_argument(
"--config",
Expand Down Expand Up @@ -199,19 +189,26 @@ def main(cls):
with open(config_filepath, "rb") as f:
config_file = tomli.load(f)

loop.create_task(cls._main(config_filepath, config_file, args))
# Run the event loop
try:
loop.run_forever()
asyncio.run(cls._main(config_filepath, config_file, args))
except asyncio.CancelledError:
pass
finally:
loop.close()

@classmethod
async def _main(cls, config_filepath, config_file, args=None):
"""Parse command line arguments, start event loop tasks."""
loop = asyncio.get_running_loop()
cls.__servers = []
if sys.platform.startswith("win"):
signals = ()
else:
signals = (signal.SIGHUP, signal.SIGTERM, signal.SIGINT)
for s in signals:
loop.add_signal_handler(
s, lambda s=s: asyncio.create_task(cls.shutdown_all(s, loop))
)

cls.__servers = set()
for section in config_file:
if section == "shared-settings":
continue
Expand All @@ -225,7 +222,7 @@ async def _main(cls, config_filepath, config_file, args=None):

while cls.__servers:
awaiting = cls.__servers
cls.__servers = []
cls.__servers = set()
await asyncio.wait(awaiting)
await asyncio.sleep(1)
loop.stop()
Expand All @@ -252,7 +249,9 @@ def server(daemon):
server(daemon), config.get("host", ""), config.get("port", None)
)
daemon._server = ser
cls.__servers.append(asyncio.create_task(ser.serve_forever()))
task = asyncio.create_task(ser.serve_forever())
cls.__servers.add(task)
task.add_done_callback(cls.__servers.discard)

@classmethod
def _parse_config(cls, config_file, section, args=None):
Expand Down Expand Up @@ -298,6 +297,8 @@ async def shutdown_all(cls, sig, loop):
# are not themselves cancelled.
[d.close() for d in cls._daemons]
tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
for task in tasks:
logger.info(task.get_coro())
await asyncio.gather(*tasks, return_exceptions=True)
[d._save_state() for d in cls._daemons]
if hasattr(signal, "SIGHUP") and sig == signal.SIGHUP:
Expand Down
18 changes: 9 additions & 9 deletions yaqd-core/yaqd_core/_is_sensor.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
from __future__ import annotations

__all__ = ["IsSensor"]


import asyncio
import pathlib
from typing import Dict, Any, Union, Tuple, List
from typing import Any

import yaqd_core

MeasureType = Dict[str, Union[float]]


class IsSensor(yaqd_core.IsDaemon):
def __init__(
self, name: str, config: Dict[str, Any], config_filepath: pathlib.Path
self, name: str, config: dict[str, Any], config_filepath: pathlib.Path
):
super().__init__(name, config, config_filepath)
self._measured: MeasureType = dict() # values must be numbers or arrays
self._channel_names: List[str] = []
self._channel_units: Dict[str, str] = dict()
self._channel_shapes: Dict[str, Tuple[int]] = dict()
self._measured: dict = dict() # values must be numbers or arrays
self._channel_names: list[str] = []
self._channel_units: dict[str, str] = dict()
self._channel_shapes: dict[str, tuple[int, ...]] = dict()
self._measurement_id = 0
self._measured["measurement_id"] = self._measurement_id

Expand All @@ -37,7 +37,7 @@ def get_channel_units(self):
"""Get channel units."""
return self._channel_units

def get_measured(self) -> MeasureType:
def get_measured(self) -> dict:
assert "measurement_id" in self._measured
return self._measured

Expand Down
2 changes: 1 addition & 1 deletion yaqd-core/yaqd_core/_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def connection_made(self, transport):
self.transport = transport
self.unpacker = avrorpc.Unpacker(self._avro_protocol)
self._daemon._connection_made(peername)
self.task = asyncio.get_event_loop().create_task(self.process_requests())
self.task = asyncio.get_running_loop().create_task(self.process_requests())

def data_received(self, data):
"""Process an incomming request."""
Expand Down
2 changes: 1 addition & 1 deletion yaqd-fakes/yaqd_fakes/_fake_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def __init__(self, name, config, config_filepath):
self._channel_generators[name] = random_walk(min_, max_)
else:
raise Exception(f"channel kind {kwargs['kind']} not recognized")
asyncio.get_event_loop().create_task(self._update_measurements())
self._loop.create_task(self._update_measurements())

async def _update_measurements(self):
while True:
Expand Down