diff --git a/CHANGELOG.md b/CHANGELOG.md index a99bfe2a..152be713 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## Version 0.7.14 + +- refactor: make `create_task` functional for the main application just like its + services + ## Version 0.7.13 - feat: #16 add volume chime diff --git a/poetry.lock b/poetry.lock index bb4ff7f0..2320f08f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -621,27 +621,27 @@ poetry-plugin = ["poetry (>=1.0,<2.0)"] [[package]] name = "psutil" -version = "5.9.7" +version = "5.9.8" description = "Cross-platform lib for process and system monitoring in Python." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "psutil-5.9.7-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0bd41bf2d1463dfa535942b2a8f0e958acf6607ac0be52265ab31f7923bcd5e6"}, - {file = "psutil-5.9.7-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:5794944462509e49d4d458f4dbfb92c47539e7d8d15c796f141f474010084056"}, - {file = "psutil-5.9.7-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:fe361f743cb3389b8efda21980d93eb55c1f1e3898269bc9a2a1d0bb7b1f6508"}, - {file = "psutil-5.9.7-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:e469990e28f1ad738f65a42dcfc17adaed9d0f325d55047593cb9033a0ab63df"}, - {file = "psutil-5.9.7-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:3c4747a3e2ead1589e647e64aad601981f01b68f9398ddf94d01e3dc0d1e57c7"}, - {file = "psutil-5.9.7-cp27-none-win32.whl", hash = "sha256:1d4bc4a0148fdd7fd8f38e0498639ae128e64538faa507df25a20f8f7fb2341c"}, - {file = "psutil-5.9.7-cp27-none-win_amd64.whl", hash = "sha256:4c03362e280d06bbbfcd52f29acd79c733e0af33d707c54255d21029b8b32ba6"}, - {file = "psutil-5.9.7-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ea36cc62e69a13ec52b2f625c27527f6e4479bca2b340b7a452af55b34fcbe2e"}, - {file = "psutil-5.9.7-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1132704b876e58d277168cd729d64750633d5ff0183acf5b3c986b8466cd0284"}, - {file = "psutil-5.9.7-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8b7f07948f1304497ce4f4684881250cd859b16d06a1dc4d7941eeb6233bfe"}, - {file = "psutil-5.9.7-cp36-cp36m-win32.whl", hash = "sha256:b27f8fdb190c8c03914f908a4555159327d7481dac2f01008d483137ef3311a9"}, - {file = "psutil-5.9.7-cp36-cp36m-win_amd64.whl", hash = "sha256:44969859757f4d8f2a9bd5b76eba8c3099a2c8cf3992ff62144061e39ba8568e"}, - {file = "psutil-5.9.7-cp37-abi3-win32.whl", hash = "sha256:c727ca5a9b2dd5193b8644b9f0c883d54f1248310023b5ad3e92036c5e2ada68"}, - {file = "psutil-5.9.7-cp37-abi3-win_amd64.whl", hash = "sha256:f37f87e4d73b79e6c5e749440c3113b81d1ee7d26f21c19c47371ddea834f414"}, - {file = "psutil-5.9.7-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:032f4f2c909818c86cea4fe2cc407f1c0f0cde8e6c6d702b28b8ce0c0d143340"}, - {file = "psutil-5.9.7.tar.gz", hash = "sha256:3f02134e82cfb5d089fddf20bb2e03fd5cd52395321d1c8458a9e58500ff417c"}, + {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, + {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, + {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, + {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, + {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, + {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, + {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, + {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, + {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, + {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, ] [package.extras] @@ -797,13 +797,13 @@ files = [ [[package]] name = "python-redux" -version = "0.9.11" +version = "0.9.12" description = "Redux implementation for Python" optional = false python-versions = ">=3.9,<4.0" files = [ - {file = "python_redux-0.9.11-py3-none-any.whl", hash = "sha256:e661c68e502a51985ae0600a3a845bccf029577499619773f6fdbdce95472c54"}, - {file = "python_redux-0.9.11.tar.gz", hash = "sha256:1b7ad0bc2d91e96b83a088998c5e5179df9e4e3fcedf71c01bf093aeba4bbb10"}, + {file = "python_redux-0.9.12-py3-none-any.whl", hash = "sha256:219160590ca1f0b01f8e81b60e2f36a0d0835f69ac563f9abceb3fdf6b9c9f6a"}, + {file = "python_redux-0.9.12.tar.gz", hash = "sha256:4502228edde6cf48ba27b47b27060ba5e8417a51211c9cb7cd0bfda1839996a1"}, ] [package.dependencies] @@ -892,28 +892,28 @@ files = [ [[package]] name = "ruff" -version = "0.1.13" +version = "0.1.14" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.1.13-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e3fd36e0d48aeac672aa850045e784673449ce619afc12823ea7868fcc41d8ba"}, - {file = "ruff-0.1.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9fb6b3b86450d4ec6a6732f9f60c4406061b6851c4b29f944f8c9d91c3611c7a"}, - {file = "ruff-0.1.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b13ba5d7156daaf3fd08b6b993360a96060500aca7e307d95ecbc5bb47a69296"}, - {file = "ruff-0.1.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9ebb40442f7b531e136d334ef0851412410061e65d61ca8ce90d894a094feb22"}, - {file = "ruff-0.1.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226b517f42d59a543d6383cfe03cccf0091e3e0ed1b856c6824be03d2a75d3b6"}, - {file = "ruff-0.1.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5f0312ba1061e9b8c724e9a702d3c8621e3c6e6c2c9bd862550ab2951ac75c16"}, - {file = "ruff-0.1.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2f59bcf5217c661254bd6bc42d65a6fd1a8b80c48763cb5c2293295babd945dd"}, - {file = "ruff-0.1.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6894b00495e00c27b6ba61af1fc666f17de6140345e5ef27dd6e08fb987259d"}, - {file = "ruff-0.1.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a1600942485c6e66119da294c6294856b5c86fd6df591ce293e4a4cc8e72989"}, - {file = "ruff-0.1.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ee3febce7863e231a467f90e681d3d89210b900d49ce88723ce052c8761be8c7"}, - {file = "ruff-0.1.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dcaab50e278ff497ee4d1fe69b29ca0a9a47cd954bb17963628fa417933c6eb1"}, - {file = "ruff-0.1.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f57de973de4edef3ad3044d6a50c02ad9fc2dff0d88587f25f1a48e3f72edf5e"}, - {file = "ruff-0.1.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7a36fa90eb12208272a858475ec43ac811ac37e91ef868759770b71bdabe27b6"}, - {file = "ruff-0.1.13-py3-none-win32.whl", hash = "sha256:a623349a505ff768dad6bd57087e2461be8db58305ebd5577bd0e98631f9ae69"}, - {file = "ruff-0.1.13-py3-none-win_amd64.whl", hash = "sha256:f988746e3c3982bea7f824c8fa318ce7f538c4dfefec99cd09c8770bd33e6539"}, - {file = "ruff-0.1.13-py3-none-win_arm64.whl", hash = "sha256:6bbbc3042075871ec17f28864808540a26f0f79a4478c357d3e3d2284e832998"}, - {file = "ruff-0.1.13.tar.gz", hash = "sha256:e261f1baed6291f434ffb1d5c6bd8051d1c2a26958072d38dfbec39b3dda7352"}, + {file = "ruff-0.1.14-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:96f76536df9b26622755c12ed8680f159817be2f725c17ed9305b472a757cdbb"}, + {file = "ruff-0.1.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ab3f71f64498c7241123bb5a768544cf42821d2a537f894b22457a543d3ca7a9"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7060156ecc572b8f984fd20fd8b0fcb692dd5d837b7606e968334ab7ff0090ab"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a53d8e35313d7b67eb3db15a66c08434809107659226a90dcd7acb2afa55faea"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bea9be712b8f5b4ebed40e1949379cfb2a7d907f42921cf9ab3aae07e6fba9eb"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2270504d629a0b064247983cbc495bed277f372fb9eaba41e5cf51f7ba705a6a"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80258bb3b8909b1700610dfabef7876423eed1bc930fe177c71c414921898efa"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:653230dd00aaf449eb5ff25d10a6e03bc3006813e2cb99799e568f55482e5cae"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b3acc6c4e6928459ba9eb7459dd4f0c4bf266a053c863d72a44c33246bfdbf"}, + {file = "ruff-0.1.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6b3dadc9522d0eccc060699a9816e8127b27addbb4697fc0c08611e4e6aeb8b5"}, + {file = "ruff-0.1.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1c8eca1a47b4150dc0fbec7fe68fc91c695aed798532a18dbb1424e61e9b721f"}, + {file = "ruff-0.1.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:62ce2ae46303ee896fc6811f63d6dabf8d9c389da0f3e3f2bce8bc7f15ef5488"}, + {file = "ruff-0.1.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b2027dde79d217b211d725fc833e8965dc90a16d0d3213f1298f97465956661b"}, + {file = "ruff-0.1.14-py3-none-win32.whl", hash = "sha256:722bafc299145575a63bbd6b5069cb643eaa62546a5b6398f82b3e4403329cab"}, + {file = "ruff-0.1.14-py3-none-win_amd64.whl", hash = "sha256:e3d241aa61f92b0805a7082bd89a9990826448e4d0398f0e2bc8f05c75c63d99"}, + {file = "ruff-0.1.14-py3-none-win_arm64.whl", hash = "sha256:269302b31ade4cde6cf6f9dd58ea593773a37ed3f7b97e793c8594b262466b67"}, + {file = "ruff-0.1.14.tar.gz", hash = "sha256:ad3f8088b2dfd884820289a06ab718cde7d38b94972212cc4ba90d5fbc9955f3"}, ] [[package]] @@ -1038,4 +1038,4 @@ dev = ["headless-kivy-pi", "headless-kivy-pi", "ubo-gui", "ubo-gui"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "41bcb2e3efa66816c24371e0fa268147c94648cf27e64624ea5db8cc12370ecc" +content-hash = "24c8a8c7536d62c41749cb4f2ca78c4b8142b0305efe21c234cd168dee427905" diff --git a/pyproject.toml b/pyproject.toml index 1cd329dd..6dedd182 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "ubo-app" -version = "0.7.13" +version = "0.7.14" description = "Ubo main app, running on device initialization. A platform for running other apps." authors = ["Sassan Haradji "] license = "Apache-2.0" @@ -29,7 +29,7 @@ headless-kivy-pi = [ 'dev', ] }, ] -python-redux = "^0.9.11" +python-redux = "^0.9.12" pyzbar = "^0.1.9" sdbus-networkmanager = { version = "^2.0.0", markers = "platform_machine=='aarch64'" } rpi_ws281x = { version = "^5.0.0", markers = "platform_machine=='aarch64'" } diff --git a/ubo_app/_loop.py b/ubo_app/_loop.py deleted file mode 100644 index c2cb65d0..00000000 --- a/ubo_app/_loop.py +++ /dev/null @@ -1,8 +0,0 @@ -# ruff: noqa: D100, D101, D102, D103, D104, D107, N999 -from asyncio import Handle -from typing import Awaitable - - -def create_task(task: Awaitable) -> Handle: - msg = f"Current thread is not an ubo service thread, can't run task {task}" - raise NotImplementedError(msg) diff --git a/ubo_app/load_services.py b/ubo_app/load_services.py index 6d67bbb6..a2d60234 100644 --- a/ubo_app/load_services.py +++ b/ubo_app/load_services.py @@ -48,9 +48,10 @@ def __init__(self: UboServiceLoopLoader, thread: UboServiceThread) -> None: self.thread = thread def exec_module(self: UboServiceLoopLoader, module: ModuleType) -> None: - cast(Any, module).create_task = ( - lambda *args: self.thread.loop.call_soon_threadsafe( - lambda: self.thread.loop.create_task(*args), + cast(Any, module)._create_task = ( # noqa: SLF001 + lambda task: self.thread.loop.call_soon_threadsafe( + self.thread.loop.create_task, + task, ) ) @@ -62,39 +63,39 @@ class UboServiceFinder(importlib.abc.MetaPathFinder): def find_spec( self: UboServiceFinder, fullname: str, - path: Sequence[str] | None, + _: Sequence[str] | None, target: ModuleType | None = None, ) -> ModuleSpec | None: - if path is None: - stack = traceback.extract_stack() - matching_path = next( - ( - registered_path - for stack_path in stack[::-1] - for registered_path in REGISTERED_PATHS - if stack_path.filename.startswith(registered_path.as_posix()) - ), - None, - ) - if matching_path: - thread = REGISTERED_PATHS[matching_path] - module_name = f'{thread.service_id}:{fullname}' - - if fullname == '_loop': - return importlib.util.spec_from_loader( - module_name, - UboServiceLoopLoader(thread), - ) - - spec = PathFinder.find_spec( - fullname, - [matching_path.as_posix()], - target, + stack = traceback.extract_stack() + matching_path = next( + ( + registered_path + for stack_path in stack[::-1] + for registered_path in REGISTERED_PATHS + if stack_path.filename.startswith(registered_path.as_posix()) + ), + None, + ) + + if matching_path: + thread = REGISTERED_PATHS[matching_path] + module_name = f'{thread.service_id}:{fullname}' + + if fullname == 'ubo_app.utils.loop': + return importlib.util.spec_from_loader( + module_name, + UboServiceLoopLoader(thread), ) - if spec and spec.origin: - spec.name = module_name - spec.loader = UboServiceModuleLoader(fullname, spec.origin) - return spec + + spec = PathFinder.find_spec( + fullname, + [matching_path.as_posix()], + target, + ) + if spec and spec.origin: + spec.name = module_name + spec.loader = UboServiceModuleLoader(fullname, spec.origin) + return spec return None @@ -111,6 +112,7 @@ def __init__( self.service_id = service_id self.path = path self.loop = asyncio.new_event_loop() + self.module = None if DEBUG_MODE: self.loop.set_debug(enabled=True) try: @@ -188,7 +190,7 @@ def load_services() -> None: service_id = uuid.uuid4().hex if not service_path.is_dir(): continue - current_path = os.curdir + current_path = Path().absolute() os.chdir(service_path.as_posix()) thread = UboServiceThread( diff --git a/ubo_app/menu_central.py b/ubo_app/menu_central.py index 3ed7a739..d49ff8b1 100644 --- a/ubo_app/menu_central.py +++ b/ubo_app/menu_central.py @@ -1,17 +1,15 @@ # ruff: noqa: D100, D101, D102, D103, D104, D107 from __future__ import annotations -import asyncio import pathlib -import threading from functools import cached_property from threading import Thread -from typing import TYPE_CHECKING, Self, Sequence +from typing import TYPE_CHECKING, Sequence from debouncer import DebounceOptions, debounce from kivy.app import Builder from kivy.clock import Clock -from redux import EventSubscriptionOptions, FinishEvent +from redux import EventSubscriptionOptions from ubo_gui.app import UboApp from ubo_gui.gauge import GaugeWidget from ubo_gui.menu import MenuWidget @@ -38,7 +36,7 @@ class HomePage(PageWidget): def __init__( - self: Self, + self: HomePage, items: Sequence[Item] | None = None, *args: object, **kwargs: object, @@ -56,7 +54,7 @@ def sync_output_volume(selector_result: float) -> None: volume_widget.value = selector_result * 100 @cached_property - def cpu_gauge(self: Self) -> GaugeWidget: + def cpu_gauge(self: HomePage) -> GaugeWidget: import psutil gauge = GaugeWidget(value=0, fill_color='#24D636', label='CPU') @@ -79,7 +77,7 @@ def calculate_value() -> None: return gauge @cached_property - def ram_gauge(self: Self) -> GaugeWidget: + def ram_gauge(self: HomePage) -> GaugeWidget: import psutil gauge = GaugeWidget( @@ -97,7 +95,7 @@ def set_value(_: int) -> None: class MenuWidgetWithHomePage(MenuWidget): - def get_current_screen(self: Self) -> Screen | None: + def get_current_screen(self: MenuWidgetWithHomePage) -> Screen | None: if self.depth == 0: return HomePage( self.current_menu_items, @@ -121,23 +119,6 @@ def set_path(_: MenuWidget, stack: list[tuple[Menu, int] | PageWidget]) -> None: ) -class WorkerThread(threading.Thread): - def __init__(self: WorkerThread) -> None: - super().__init__() - self.loop = asyncio.new_event_loop() - if DEBUG_MODE: - self.loop.set_debug(enabled=True) - - def run(self: WorkerThread) -> None: - asyncio.set_event_loop(self.loop) - - subscribe_event(FinishEvent, lambda _: self.stop()) - self.loop.run_forever() - - def stop(self: WorkerThread) -> None: - self.loop.call_soon_threadsafe(self.loop.stop) - - class MenuAppCentral(UboApp): @cached_property def central(self: MenuAppCentral) -> Widget | None: @@ -151,13 +132,8 @@ async def sync_current_menu(menu: Menu | None) -> None: return Clock.schedule_once(lambda _: self.menu_widget.set_root_menu(menu)) - thread = WorkerThread() - thread.start() - sync_current_menu.subscribe( - lambda task: thread.loop.call_soon_threadsafe( - lambda: thread.loop.create_task(task), - ), - ) + create_task(sync_current_menu.value) + sync_current_menu.subscribe(lambda task: create_task(task)) def handle_title_change(_: MenuWidget, title: str) -> None: self.root.title = title diff --git a/ubo_app/utils/async_.py b/ubo_app/utils/async_.py index 089ff2af..51385adc 100644 --- a/ubo_app/utils/async_.py +++ b/ubo_app/utils/async_.py @@ -32,8 +32,8 @@ async def wrapper() -> None: }, ) - import _loop + import ubo_app.utils.loop - handle = _loop.create_task(wrapper()) + handle = ubo_app.utils.loop._create_task(wrapper()) # noqa: SLF001 background_tasks.add(handle) return handle diff --git a/ubo_app/utils/loop.py b/ubo_app/utils/loop.py new file mode 100644 index 00000000..532ceab9 --- /dev/null +++ b/ubo_app/utils/loop.py @@ -0,0 +1,42 @@ +# ruff: noqa: D100, D101, D102, D103, D104, D107, N999 +from __future__ import annotations + +import asyncio +import threading +from typing import TYPE_CHECKING, Coroutine + +from redux import FinishEvent + +from ubo_app.constants import DEBUG_MODE +from ubo_app.store import subscribe_event + +if TYPE_CHECKING: + from asyncio import Handle + + +class WorkerThread(threading.Thread): + def __init__(self: WorkerThread) -> None: + super().__init__() + self.loop = asyncio.new_event_loop() + if DEBUG_MODE: + self.loop.set_debug(enabled=True) + + def run(self: WorkerThread) -> None: + asyncio.set_event_loop(self.loop) + + subscribe_event(FinishEvent, lambda _: self.stop()) + self.loop.run_forever() + + def run_task(self: WorkerThread, task: Coroutine) -> Handle: + return self.loop.call_soon_threadsafe(self.loop.create_task, task) + + def stop(self: WorkerThread) -> None: + self.loop.call_soon_threadsafe(self.loop.stop) + + +thread = WorkerThread() +thread.start() + + +def _create_task(task: Coroutine) -> Handle: + return thread.run_task(task)