Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
83ba729
Update _is_sensor.py
ddkohler Feb 16, 2025
47459ae
Update _is_sensor.py
ddkohler Feb 16, 2025
5f726e5
Update _is_sensor.py
ddkohler Feb 16, 2025
192e7b1
Update _is_sensor.py
ddkohler Feb 16, 2025
ce21a95
Update _is_sensor.py
ddkohler Feb 16, 2025
575664a
Update _is_sensor.py
ddkohler Feb 17, 2025
f60c4e9
Update _is_sensor.py
ddkohler Feb 17, 2025
b4a1eff
Update _is_sensor.py
ddkohler Feb 17, 2025
e02fe2f
Update _is_sensor.py
ddkohler Feb 17, 2025
96698b4
Update _is_sensor.py
ddkohler Feb 17, 2025
806ee30
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 17, 2025
e1b857e
propagate to HasMeasureTrigger
ddkohler Feb 17, 2025
06a063b
Update _is_sensor.py
ddkohler Feb 17, 2025
dda4db2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 17, 2025
d07f6b1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 17, 2025
8d6e0e0
remove MeasureType
ddkohler Feb 17, 2025
40b241f
remove redundant actions
ddkohler Feb 17, 2025
8e6a4de
expand test py versions
ddkohler Feb 17, 2025
e657070
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 17, 2025
712e979
initiate tests again
ddkohler Oct 19, 2025
2e04c44
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 19, 2025
335f57c
try python 3.13
ddkohler Oct 20, 2025
862f2bc
Update _is_daemon.py
ddkohler Oct 20, 2025
03e3a6d
Update _is_daemon.py
ddkohler Oct 20, 2025
4c0c4fd
Update _is_daemon.py
ddkohler Oct 20, 2025
2e7e5a9
refactor asyncio loop
ddkohler Oct 20, 2025
1910f2d
Update _fake_sensor.py
ddkohler Oct 20, 2025
5a9fef1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 20, 2025
c375630
cleanup
ddkohler Oct 20, 2025
8ef3418
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 20, 2025
872935b
Update _is_daemon.py
ddkohler Oct 20, 2025
f8f04b8
peek at py3.8 tests
ddkohler Oct 21, 2025
073555f
Update .gitignore
ddkohler Oct 29, 2025
cd42c8c
Update CHANGELOG.md
ddkohler Nov 13, 2025
dd7b2b2
test with py3.14
ddkohler Nov 14, 2025
1cd2bf1
don't reach in and grab _loop
untzag Dec 19, 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
2 changes: 1 addition & 1 deletion .github/workflows/python-pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:

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

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ coverage.xml
# vim
*.sw?

/.vscode
1 change: 1 addition & 0 deletions yaqd-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
## [Unreleased]

### Fixed
- removed asyncio syntax that was removed in python 3.14
- type hints for IsSensor attributes are appropriate for _n_-dimensional data

## [2023.11.0]
Expand Down
48 changes: 19 additions & 29 deletions yaqd-core/yaqd_core/_is_daemon.py
100755 → 100644
Original file line number Diff line number Diff line change
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."""
"""Parse command line arguments, run event loop."""
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 @@ -297,16 +296,7 @@ async def shutdown_all(cls, sig, loop):
# This is done after cancelling so that shutdown tasks which require the 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()
and "serve_forever" not in t.get_coro().__repr__()
)
]
for task in tasks:
logger.info(task.get_coro())
tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
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
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())
asyncio.get_running_loop().create_task(self._update_measurements())

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