From 21735b548b3fb7bcdf91b24b7618f9af5aada98b Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Mon, 21 Oct 2024 19:26:50 -0400 Subject: [PATCH 01/10] Start packet handler thread immediately, and it takes ownership of receiver_queue --- src/pycbsdk/cbhw/device/nsp.py | 16 +++++----------- src/pycbsdk/cbhw/handler.py | 13 +++++++++---- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/pycbsdk/cbhw/device/nsp.py b/src/pycbsdk/cbhw/device/nsp.py index 0f45df9..74addde 100644 --- a/src/pycbsdk/cbhw/device/nsp.py +++ b/src/pycbsdk/cbhw/device/nsp.py @@ -286,9 +286,7 @@ def __init__(self, params: Params, **kwargs): self._monitor_state["time"] = 1 # Placeholders for IO - self._pkt_handler_thread = None self._sender_queue = None - self._receiver_queue = None self._io_thread = None self._register_basic_callbacks() @@ -317,6 +315,10 @@ def __init__(self, params: Params, **kwargs): self._params.inst_port, ) + # Start the packet handler thread. We don't expect it to receive any packets until `.connect()` is called. + self._pkt_handler_thread = PacketHandlerThread(self) + self._pkt_handler_thread.start() + @property def device_addr(self) -> tuple[str, int]: return self._device_addr @@ -1136,18 +1138,13 @@ def reset(self) -> int: # region IO def connect(self, startup_sequence: bool = True) -> int: - self._receiver_queue = queue.SimpleQueue() - - self._pkt_handler_thread = PacketHandlerThread(self._receiver_queue, self) self._io_thread = CerebusDatagramThread( - self._receiver_queue, + self._pkt_handler_thread.receiver_queue, self._local_addr, self._device_addr, self._params.protocol, self._params.recv_bufsize, ) - - self._pkt_handler_thread.start() self._io_thread.start() # _io_thread.start() returns immediately but takes a few moments until its send_q is created. time.sleep(0.5) @@ -1185,9 +1182,6 @@ def disconnect(self): self._io_thread.join() self._pkt_handler_thread.join() - del self._receiver_queue - self._receiver_queue = None - logger.info("Disconnected successfully.") def _startup_sequence(self) -> CBError: diff --git a/src/pycbsdk/cbhw/handler.py b/src/pycbsdk/cbhw/handler.py index 18312b9..9bc4fbd 100644 --- a/src/pycbsdk/cbhw/handler.py +++ b/src/pycbsdk/cbhw/handler.py @@ -24,17 +24,19 @@ class PacketHandlerThread(threading.Thread): and should use atomic operations only. """ - def __init__( - self, receiver_queue: queue.SimpleQueue, device: DeviceInterface, **kwargs - ): + def __init__(self, device: DeviceInterface, **kwargs): super().__init__(**kwargs) - self._recv_q = receiver_queue + self._recv_q = queue.SimpleQueue() self._device = device self._continue = False self._packet_factory = CBPacketFactory(protocol=device._params.protocol) self._stop_event = threading.Event() self.daemon = True + @property + def receiver_queue(self) -> queue.SimpleQueue: + return self._recv_q + def run(self) -> None: last_group_time = -1 last_group_data = None @@ -118,6 +120,9 @@ def run(self) -> None: ) self.warn_unhandled(pkt) + del self._recv_q + self._recv_q = None + def stop(self): self._stop_event.set() From 302a133baf0cbedff1e7f5e3b512ec1f07afdb22 Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Mon, 21 Oct 2024 19:27:05 -0400 Subject: [PATCH 02/10] Enable socket.SO_REUSEADDR --- src/pycbsdk/cbhw/io/datagram.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pycbsdk/cbhw/io/datagram.py b/src/pycbsdk/cbhw/io/datagram.py index f39b521..c6dbea5 100644 --- a/src/pycbsdk/cbhw/io/datagram.py +++ b/src/pycbsdk/cbhw/io/datagram.py @@ -143,6 +143,7 @@ async def _receiver_coro(self): ) sock.setsockopt(socket.SOL_SOCKET, socket.SO_DONTROUTE, True) sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, self._buff_size) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # sock.settimeout(10) # sock.setblocking(False) sock.bind(self._recv_addr) From eeddd0b2aa0f85ea9390fc8c09d4f264079ff288 Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Mon, 21 Oct 2024 19:27:20 -0400 Subject: [PATCH 03/10] Add diagram of pycbsdk design. --- docs/img/pycbsdk_design.svg | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 docs/img/pycbsdk_design.svg diff --git a/docs/img/pycbsdk_design.svg b/docs/img/pycbsdk_design.svg new file mode 100644 index 0000000..d9b9002 --- /dev/null +++ b/docs/img/pycbsdk_design.svg @@ -0,0 +1,4 @@ + + + +
create_params
create_params
Params
Params
get_device
get_device
NSPDevice
NSPDevice
._pkt_handler_thread
._pkt_handler_thread
._recv_q
._recv_q
._recv_q.get(...)
._recv_q.get(...)
callbacks
callbacks
._io_thread
._io_thread
._recv_q
._recv_q
._send_q
._send_q
._loop
._loop
._transport
._transport
._send_q.async_get()
._send_q.async_get()
._transport.sendto(device)
._transport.sendto(device)
sender_coro
sender_coro
receiver_coro
receiver_coro
CerebusDatagram
Protocol
CerebusDatagram...
datagram_received()
datagram_received()
._recv_q.put(...)
._recv_q.put(...)
.connect
.connect
..__init__
..__init__
._config_events
._config_events
.config
.config
.group_callbacks
.group_callbacks
.event_callbacks
.event_callbacks
.config_callbacks
.config_callbacks
.packet_factory
.packet_factory
connect
connect
Begin Here
Begin Here
set_<...>_config
set_<...>_config
create config pkt
create config pkt
set event
set event
io_thread send
io_thread send
wait for event clear via callback
wait for event clear v...
Text is not SVG - cannot display
\ No newline at end of file From e2ab495a89f4eca2d24408d90a93b6b21fe57035 Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Thu, 21 Nov 2024 10:08:30 -0500 Subject: [PATCH 04/10] Fix bug in error printing --- src/pycbsdk/cbhw/io/datagram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pycbsdk/cbhw/io/datagram.py b/src/pycbsdk/cbhw/io/datagram.py index c6dbea5..439132c 100644 --- a/src/pycbsdk/cbhw/io/datagram.py +++ b/src/pycbsdk/cbhw/io/datagram.py @@ -61,7 +61,7 @@ def datagram_received(self, data: bytes, addr: tuple[str, int]) -> None: self._recv_queue.put((pkt_time, chid, pkt_type, dlen, data)) def error_received(self, exc: Exception) -> None: - logger.error("Error received: ", exc) + logger.error(f"Error received: {exc}") def connection_lost(self, exc: Exception) -> None: logger.debug("Data receiver connection closed.") From 2bc26fc8be0c1f0893ccb664b7ee1bee7faf445a Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Thu, 21 Nov 2024 10:32:18 -0500 Subject: [PATCH 05/10] More verbose error when Central is running. --- src/pycbsdk/cbhw/io/datagram.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pycbsdk/cbhw/io/datagram.py b/src/pycbsdk/cbhw/io/datagram.py index 439132c..1feb282 100644 --- a/src/pycbsdk/cbhw/io/datagram.py +++ b/src/pycbsdk/cbhw/io/datagram.py @@ -146,7 +146,11 @@ async def _receiver_coro(self): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # sock.settimeout(10) # sock.setblocking(False) - sock.bind(self._recv_addr) + try: + sock.bind(self._recv_addr) + except OSError as e: + logger.error(f"Cannot bind to {self._recv_addr}. Central may have exclusive access to the port on " + f"this machine. Error: {e}") loop = asyncio.get_event_loop() # Create a future that should only return when the UDP connection is lost From 1d27cafb6c85dfdd40ef90e5b19ad10c59235283 Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Thu, 21 Nov 2024 18:13:44 -0500 Subject: [PATCH 06/10] Refactor as uv-managed project --- .github/workflows/publish-to-pypi.yml | 58 ++--- .gitignore | 2 + README.md | 2 +- pyproject.toml | 49 +++-- src/pycbsdk/__init__.py | 5 +- uv.lock | 292 ++++++++++++++++++++++++++ 6 files changed, 342 insertions(+), 66 deletions(-) create mode 100644 uv.lock diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml index 690b6fd..24fbc55 100644 --- a/.github/workflows/publish-to-pypi.yml +++ b/.github/workflows/publish-to-pypi.yml @@ -1,56 +1,26 @@ -name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI +name: Publish Python 🐍 distributions 📦 to PyPI on: - workflow_dispatch: {} - push: - branches: - - main - pull_request: - branches: - - main - types: - - closed + release: + types: [published] + workflow_dispatch: jobs: - build-n-publish: - name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI + build: + name: build and upload release to PyPI runs-on: ubuntu-latest - environment: - name: release + environment: "release" permissions: id-token: write # IMPORTANT: this permission is mandatory for trusted publishing + steps: - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.9" - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pytest - pip install -e . - - - name: Test with pytest - run: | - pytest - - - name: Install pypa/build - run: >- - pip install build --user - - - name: Build a source tarball and a binary wheel - run: >- - python3 -m build --sdist --wheel --outdir dist/ . + - name: Install uv + uses: astral-sh/setup-uv@v2 - - name: Publish distribution 📦 to Test PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - repository-url: https://test.pypi.org/legacy/ - skip-existing: true + - name: Build Package + run: uv build - - name: Publish distribution 📦 to PyPI - if: startsWith(github.ref, 'refs/tags/v') - uses: pypa/gh-action-pypi-publish@release/v1 + - name: Publish package distributions to PyPI + run: uv publish diff --git a/.gitignore b/.gitignore index e03db87..a9d0a40 100644 --- a/.gitignore +++ b/.gitignore @@ -159,3 +159,5 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. .idea/ # "I am become God." -Chad + +src/pycbsdk/__version__.py diff --git a/README.md b/README.md index bcd8947..58d74f0 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ config = cbsdk.get_config(nsp_obj) print(config) ``` -You may also try the provided test script with `python -m pycbsdk.examples.print_rates` or via the shortcut: `pycbsdk_print_rates`. +You may also try the provided test script with `python -m pycbsdk.examples.print_rates` or via the shortcut: `pycbsdk-rates`. ## Introduction diff --git a/pyproject.toml b/pyproject.toml index 9dbfb8a..7afc4ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,27 +1,42 @@ -[tool.poetry] +[project] name = "pycbsdk" -version = "0.1.4" description = "Pure Python interface to Blackrock Neurotech Cerebus devices" -authors = ["Chadwick Boulay "] +authors = [ + { name = "Chadwick Boulay", email = "chadwick.boulay@gmail.com" }, +] license = "MIT" readme = "README.md" -packages = [ - { include = "pycbsdk", from = "src" } +requires-python = ">=3.9" +dynamic = ["version"] +dependencies = [ + "numpy", + "aenum>=3.1.15", + "ifaddr>=0.2.0", ] -[tool.poetry.dependencies] -python = ">=3.9,<3.13" -numpy = "^1.26.4" -aenum = "^3.1.15" -ifaddr = "^0.2.0" +[project.optional-dependencies] +test = [ + "pytest>=8.3.3", +] -[tool.poetry.group.dev.dependencies] -typer = "^0.9.0" -pytest = "^8.1.1" +[project.scripts] +pycbsdk-rates = "pycbsdk.examples.print_rates:main" [build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" + +[tool.hatch.version] +source = "vcs" -[tool.poetry.scripts] -ezmsg-monitor = "pycbsdk.examples.print_rates:main" +[tool.hatch.build.hooks.vcs] +version-file = "src/pycbsdk/__version__.py" + +[tool.hatch.build.targets.wheel] +packages = ["src/pycbsdk"] + +[tool.uv] +dev-dependencies = [ + "ruff>=0.6.8", + "typer>=0.12.5", +] diff --git a/src/pycbsdk/__init__.py b/src/pycbsdk/__init__.py index c3d5ac3..7eb56b4 100644 --- a/src/pycbsdk/__init__.py +++ b/src/pycbsdk/__init__.py @@ -1,4 +1 @@ -import importlib.metadata - - -__version__ = importlib.metadata.version("pycbsdk") +from .__version__ import __version__ as __version__ diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..e650c18 --- /dev/null +++ b/uv.lock @@ -0,0 +1,292 @@ +version = 1 +requires-python = ">=3.9" + +[[package]] +name = "aenum" +version = "3.1.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/f8/33e75863394f42e429bb553e05fda7c59763f0fd6848de847a25b3fbccf6/aenum-3.1.15.tar.gz", hash = "sha256:8cbd76cd18c4f870ff39b24284d3ea028fbe8731a58df3aa581e434c575b9559", size = 134730 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/fa/ca0c66b388624ba9dbbf35aab3a9f326bfdf5e56a7237fe8f1b600da6864/aenum-3.1.15-py3-none-any.whl", hash = "sha256:e0dfaeea4c2bd362144b87377e2c61d91958c5ed0b4daf89cb6f45ae23af6288", size = 137633 }, +] + +[[package]] +name = "click" +version = "8.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "platform_system == 'Windows'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, +] + +[[package]] +name = "ifaddr" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/ac/fb4c578f4a3256561548cd825646680edcadb9440f3f68add95ade1eb791/ifaddr-0.2.0.tar.gz", hash = "sha256:cc0cbfcaabf765d44595825fb96a99bb12c79716b73b44330ea38ee2b0c4aed4", size = 10485 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/1f/19ebc343cc71a7ffa78f17018535adc5cbdd87afb31d7c34874680148b32/ifaddr-0.2.0-py3-none-any.whl", hash = "sha256:085e0305cfe6f16ab12d72e2024030f5d52674afad6911bb1eee207177b8a748", size = 12314 }, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, +] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, +] + +[[package]] +name = "numpy" +version = "2.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/75/10dd1f8116a8b796cb2c737b674e02d02e80454bda953fa7e65d8c12b016/numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78", size = 18902015 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/21/91/3495b3237510f79f5d81f2508f9f13fea78ebfdf07538fc7444badda173d/numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece", size = 21165245 }, + { url = "https://files.pythonhosted.org/packages/05/33/26178c7d437a87082d11019292dce6d3fe6f0e9026b7b2309cbf3e489b1d/numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04", size = 13738540 }, + { url = "https://files.pythonhosted.org/packages/ec/31/cc46e13bf07644efc7a4bf68df2df5fb2a1a88d0cd0da9ddc84dc0033e51/numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66", size = 5300623 }, + { url = "https://files.pythonhosted.org/packages/6e/16/7bfcebf27bb4f9d7ec67332ffebee4d1bf085c84246552d52dbb548600e7/numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b", size = 6901774 }, + { url = "https://files.pythonhosted.org/packages/f9/a3/561c531c0e8bf082c5bef509d00d56f82e0ea7e1e3e3a7fc8fa78742a6e5/numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd", size = 13907081 }, + { url = "https://files.pythonhosted.org/packages/fa/66/f7177ab331876200ac7563a580140643d1179c8b4b6a6b0fc9838de2a9b8/numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318", size = 19523451 }, + { url = "https://files.pythonhosted.org/packages/25/7f/0b209498009ad6453e4efc2c65bcdf0ae08a182b2b7877d7ab38a92dc542/numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8", size = 19927572 }, + { url = "https://files.pythonhosted.org/packages/3e/df/2619393b1e1b565cd2d4c4403bdd979621e2c4dea1f8532754b2598ed63b/numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326", size = 14400722 }, + { url = "https://files.pythonhosted.org/packages/22/ad/77e921b9f256d5da36424ffb711ae79ca3f451ff8489eeca544d0701d74a/numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97", size = 6472170 }, + { url = "https://files.pythonhosted.org/packages/10/05/3442317535028bc29cf0c0dd4c191a4481e8376e9f0db6bcf29703cadae6/numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131", size = 15905558 }, + { url = "https://files.pythonhosted.org/packages/8b/cf/034500fb83041aa0286e0fb16e7c76e5c8b67c0711bb6e9e9737a717d5fe/numpy-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:49ca4decb342d66018b01932139c0961a8f9ddc7589611158cb3c27cbcf76448", size = 21169137 }, + { url = "https://files.pythonhosted.org/packages/4a/d9/32de45561811a4b87fbdee23b5797394e3d1504b4a7cf40c10199848893e/numpy-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:11a76c372d1d37437857280aa142086476136a8c0f373b2e648ab2c8f18fb195", size = 13703552 }, + { url = "https://files.pythonhosted.org/packages/c1/ca/2f384720020c7b244d22508cb7ab23d95f179fcfff33c31a6eeba8d6c512/numpy-2.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:807ec44583fd708a21d4a11d94aedf2f4f3c3719035c76a2bbe1fe8e217bdc57", size = 5298957 }, + { url = "https://files.pythonhosted.org/packages/0e/78/a3e4f9fb6aa4e6fdca0c5428e8ba039408514388cf62d89651aade838269/numpy-2.0.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8cafab480740e22f8d833acefed5cc87ce276f4ece12fdaa2e8903db2f82897a", size = 6905573 }, + { url = "https://files.pythonhosted.org/packages/a0/72/cfc3a1beb2caf4efc9d0b38a15fe34025230da27e1c08cc2eb9bfb1c7231/numpy-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a15f476a45e6e5a3a79d8a14e62161d27ad897381fecfa4a09ed5322f2085669", size = 13914330 }, + { url = "https://files.pythonhosted.org/packages/ba/a8/c17acf65a931ce551fee11b72e8de63bf7e8a6f0e21add4c937c83563538/numpy-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e689d772146140a252c3a28501da66dfecd77490b498b168b501835041f951", size = 19534895 }, + { url = "https://files.pythonhosted.org/packages/ba/86/8767f3d54f6ae0165749f84648da9dcc8cd78ab65d415494962c86fac80f/numpy-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9ea91dfb7c3d1c56a0e55657c0afb38cf1eeae4544c208dc465c3c9f3a7c09f9", size = 19937253 }, + { url = "https://files.pythonhosted.org/packages/df/87/f76450e6e1c14e5bb1eae6836478b1028e096fd02e85c1c37674606ab752/numpy-2.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c1c9307701fec8f3f7a1e6711f9089c06e6284b3afbbcd259f7791282d660a15", size = 14414074 }, + { url = "https://files.pythonhosted.org/packages/5c/ca/0f0f328e1e59f73754f06e1adfb909de43726d4f24c6a3f8805f34f2b0fa/numpy-2.0.2-cp311-cp311-win32.whl", hash = "sha256:a392a68bd329eafac5817e5aefeb39038c48b671afd242710b451e76090e81f4", size = 6470640 }, + { url = "https://files.pythonhosted.org/packages/eb/57/3a3f14d3a759dcf9bf6e9eda905794726b758819df4663f217d658a58695/numpy-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:286cd40ce2b7d652a6f22efdfc6d1edf879440e53e76a75955bc0c826c7e64dc", size = 15910230 }, + { url = "https://files.pythonhosted.org/packages/45/40/2e117be60ec50d98fa08c2f8c48e09b3edea93cfcabd5a9ff6925d54b1c2/numpy-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b", size = 20895803 }, + { url = "https://files.pythonhosted.org/packages/46/92/1b8b8dee833f53cef3e0a3f69b2374467789e0bb7399689582314df02651/numpy-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e", size = 13471835 }, + { url = "https://files.pythonhosted.org/packages/7f/19/e2793bde475f1edaea6945be141aef6c8b4c669b90c90a300a8954d08f0a/numpy-2.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c", size = 5038499 }, + { url = "https://files.pythonhosted.org/packages/e3/ff/ddf6dac2ff0dd50a7327bcdba45cb0264d0e96bb44d33324853f781a8f3c/numpy-2.0.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c", size = 6633497 }, + { url = "https://files.pythonhosted.org/packages/72/21/67f36eac8e2d2cd652a2e69595a54128297cdcb1ff3931cfc87838874bd4/numpy-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692", size = 13621158 }, + { url = "https://files.pythonhosted.org/packages/39/68/e9f1126d757653496dbc096cb429014347a36b228f5a991dae2c6b6cfd40/numpy-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a", size = 19236173 }, + { url = "https://files.pythonhosted.org/packages/d1/e9/1f5333281e4ebf483ba1c888b1d61ba7e78d7e910fdd8e6499667041cc35/numpy-2.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c", size = 19634174 }, + { url = "https://files.pythonhosted.org/packages/71/af/a469674070c8d8408384e3012e064299f7a2de540738a8e414dcfd639996/numpy-2.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded", size = 14099701 }, + { url = "https://files.pythonhosted.org/packages/d0/3d/08ea9f239d0e0e939b6ca52ad403c84a2bce1bde301a8eb4888c1c1543f1/numpy-2.0.2-cp312-cp312-win32.whl", hash = "sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5", size = 6174313 }, + { url = "https://files.pythonhosted.org/packages/b2/b5/4ac39baebf1fdb2e72585c8352c56d063b6126be9fc95bd2bb5ef5770c20/numpy-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a", size = 15606179 }, + { url = "https://files.pythonhosted.org/packages/43/c1/41c8f6df3162b0c6ffd4437d729115704bd43363de0090c7f913cfbc2d89/numpy-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9059e10581ce4093f735ed23f3b9d283b9d517ff46009ddd485f1747eb22653c", size = 21169942 }, + { url = "https://files.pythonhosted.org/packages/39/bc/fd298f308dcd232b56a4031fd6ddf11c43f9917fbc937e53762f7b5a3bb1/numpy-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:423e89b23490805d2a5a96fe40ec507407b8ee786d66f7328be214f9679df6dd", size = 13711512 }, + { url = "https://files.pythonhosted.org/packages/96/ff/06d1aa3eeb1c614eda245c1ba4fb88c483bee6520d361641331872ac4b82/numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:2b2955fa6f11907cf7a70dab0d0755159bca87755e831e47932367fc8f2f2d0b", size = 5306976 }, + { url = "https://files.pythonhosted.org/packages/2d/98/121996dcfb10a6087a05e54453e28e58694a7db62c5a5a29cee14c6e047b/numpy-2.0.2-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:97032a27bd9d8988b9a97a8c4d2c9f2c15a81f61e2f21404d7e8ef00cb5be729", size = 6906494 }, + { url = "https://files.pythonhosted.org/packages/15/31/9dffc70da6b9bbf7968f6551967fc21156207366272c2a40b4ed6008dc9b/numpy-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e795a8be3ddbac43274f18588329c72939870a16cae810c2b73461c40718ab1", size = 13912596 }, + { url = "https://files.pythonhosted.org/packages/b9/14/78635daab4b07c0930c919d451b8bf8c164774e6a3413aed04a6d95758ce/numpy-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b258c385842546006213344c50655ff1555a9338e2e5e02a0756dc3e803dd", size = 19526099 }, + { url = "https://files.pythonhosted.org/packages/26/4c/0eeca4614003077f68bfe7aac8b7496f04221865b3a5e7cb230c9d055afd/numpy-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fec9451a7789926bcf7c2b8d187292c9f93ea30284802a0ab3f5be8ab36865d", size = 19932823 }, + { url = "https://files.pythonhosted.org/packages/f1/46/ea25b98b13dccaebddf1a803f8c748680d972e00507cd9bc6dcdb5aa2ac1/numpy-2.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9189427407d88ff25ecf8f12469d4d39d35bee1db5d39fc5c168c6f088a6956d", size = 14404424 }, + { url = "https://files.pythonhosted.org/packages/c8/a6/177dd88d95ecf07e722d21008b1b40e681a929eb9e329684d449c36586b2/numpy-2.0.2-cp39-cp39-win32.whl", hash = "sha256:905d16e0c60200656500c95b6b8dca5d109e23cb24abc701d41c02d74c6b3afa", size = 6476809 }, + { url = "https://files.pythonhosted.org/packages/ea/2b/7fc9f4e7ae5b507c1a3a21f0f15ed03e794c1242ea8a242ac158beb56034/numpy-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:a3f4ab0caa7f053f6797fcd4e1e25caee367db3112ef2b6ef82d749530768c73", size = 15911314 }, + { url = "https://files.pythonhosted.org/packages/8f/3b/df5a870ac6a3be3a86856ce195ef42eec7ae50d2a202be1f5a4b3b340e14/numpy-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f0a0c6f12e07fa94133c8a67404322845220c06a9e80e85999afe727f7438b8", size = 21025288 }, + { url = "https://files.pythonhosted.org/packages/2c/97/51af92f18d6f6f2d9ad8b482a99fb74e142d71372da5d834b3a2747a446e/numpy-2.0.2-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:312950fdd060354350ed123c0e25a71327d3711584beaef30cdaa93320c392d4", size = 6762793 }, + { url = "https://files.pythonhosted.org/packages/12/46/de1fbd0c1b5ccaa7f9a005b66761533e2f6a3e560096682683a223631fe9/numpy-2.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26df23238872200f63518dd2aa984cfca675d82469535dc7162dc2ee52d9dd5c", size = 19334885 }, + { url = "https://files.pythonhosted.org/packages/cc/dc/d330a6faefd92b446ec0f0dfea4c3207bb1fef3c4771d19cf4543efd2c78/numpy-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a46288ec55ebbd58947d31d72be2c63cbf839f0a63b49cb755022310792a3385", size = 15828784 }, +] + +[[package]] +name = "packaging" +version = "24.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, +] + +[[package]] +name = "pycbsdk" +version = "0.1.4.dev51+g2bc26fc.d20241121" +source = { editable = "." } +dependencies = [ + { name = "aenum" }, + { name = "ifaddr" }, + { name = "numpy" }, +] + +[package.optional-dependencies] +test = [ + { name = "pytest" }, +] + +[package.dev-dependencies] +dev = [ + { name = "ruff" }, + { name = "typer" }, +] + +[package.metadata] +requires-dist = [ + { name = "aenum", specifier = ">=3.1.15" }, + { name = "ifaddr", specifier = ">=0.2.0" }, + { name = "numpy" }, + { name = "pytest", marker = "extra == 'test'", specifier = ">=8.3.3" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "ruff", specifier = ">=0.6.8" }, + { name = "typer", specifier = ">=0.12.5" }, +] + +[[package]] +name = "pygments" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 }, +] + +[[package]] +name = "pytest" +version = "8.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/6c/62bbd536103af674e227c41a8f3dcd022d591f6eed5facb5a0f31ee33bbc/pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", size = 1442487 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2", size = 342341 }, +] + +[[package]] +name = "rich" +version = "13.9.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, +] + +[[package]] +name = "ruff" +version = "0.7.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/8b/bc4e0dfa1245b07cf14300e10319b98e958a53ff074c1dd86b35253a8c2a/ruff-0.7.4.tar.gz", hash = "sha256:cd12e35031f5af6b9b93715d8c4f40360070b2041f81273d0527683d5708fce2", size = 3275547 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/4b/f5094719e254829766b807dadb766841124daba75a37da83e292ae5ad12f/ruff-0.7.4-py3-none-linux_armv6l.whl", hash = "sha256:a4919925e7684a3f18e18243cd6bea7cfb8e968a6eaa8437971f681b7ec51478", size = 10447512 }, + { url = "https://files.pythonhosted.org/packages/9e/1d/3d2d2c9f601cf6044799c5349ff5267467224cefed9b35edf5f1f36486e9/ruff-0.7.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:cfb365c135b830778dda8c04fb7d4280ed0b984e1aec27f574445231e20d6c63", size = 10235436 }, + { url = "https://files.pythonhosted.org/packages/62/83/42a6ec6216ded30b354b13e0e9327ef75a3c147751aaf10443756cb690e9/ruff-0.7.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:63a569b36bc66fbadec5beaa539dd81e0527cb258b94e29e0531ce41bacc1f20", size = 9888936 }, + { url = "https://files.pythonhosted.org/packages/4d/26/e1e54893b13046a6ad05ee9b89ee6f71542ba250f72b4c7a7d17c3dbf73d/ruff-0.7.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d06218747d361d06fd2fdac734e7fa92df36df93035db3dc2ad7aa9852cb109", size = 10697353 }, + { url = "https://files.pythonhosted.org/packages/21/24/98d2e109c4efc02bfef144ec6ea2c3e1217e7ce0cfddda8361d268dfd499/ruff-0.7.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0cea28d0944f74ebc33e9f934238f15c758841f9f5edd180b5315c203293452", size = 10228078 }, + { url = "https://files.pythonhosted.org/packages/ad/b7/964c75be9bc2945fc3172241b371197bb6d948cc69e28bc4518448c368f3/ruff-0.7.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80094ecd4793c68b2571b128f91754d60f692d64bc0d7272ec9197fdd09bf9ea", size = 11264823 }, + { url = "https://files.pythonhosted.org/packages/12/8d/20abdbf705969914ce40988fe71a554a918deaab62c38ec07483e77866f6/ruff-0.7.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:997512325c6620d1c4c2b15db49ef59543ef9cd0f4aa8065ec2ae5103cedc7e7", size = 11951855 }, + { url = "https://files.pythonhosted.org/packages/b8/fc/6519ce58c57b4edafcdf40920b7273dfbba64fc6ebcaae7b88e4dc1bf0a8/ruff-0.7.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00b4cf3a6b5fad6d1a66e7574d78956bbd09abfd6c8a997798f01f5da3d46a05", size = 11516580 }, + { url = "https://files.pythonhosted.org/packages/37/1a/5ec1844e993e376a86eb2456496831ed91b4398c434d8244f89094758940/ruff-0.7.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7dbdc7d8274e1422722933d1edddfdc65b4336abf0b16dfcb9dedd6e6a517d06", size = 12692057 }, + { url = "https://files.pythonhosted.org/packages/50/90/76867152b0d3c05df29a74bb028413e90f704f0f6701c4801174ba47f959/ruff-0.7.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e92dfb5f00eaedb1501b2f906ccabfd67b2355bdf117fea9719fc99ac2145bc", size = 11085137 }, + { url = "https://files.pythonhosted.org/packages/c8/eb/0a7cb6059ac3555243bd026bb21785bbc812f7bbfa95a36c101bd72b47ae/ruff-0.7.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3bd726099f277d735dc38900b6a8d6cf070f80828877941983a57bca1cd92172", size = 10681243 }, + { url = "https://files.pythonhosted.org/packages/5e/76/2270719dbee0fd35780b05c08a07b7a726c3da9f67d9ae89ef21fc18e2e5/ruff-0.7.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2e32829c429dd081ee5ba39aef436603e5b22335c3d3fff013cd585806a6486a", size = 10319187 }, + { url = "https://files.pythonhosted.org/packages/9f/e5/39100f72f8ba70bec1bd329efc880dea8b6c1765ea1cb9d0c1c5f18b8d7f/ruff-0.7.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:662a63b4971807623f6f90c1fb664613f67cc182dc4d991471c23c541fee62dd", size = 10803715 }, + { url = "https://files.pythonhosted.org/packages/a5/89/40e904784f305fb56850063f70a998a64ebba68796d823dde67e89a24691/ruff-0.7.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:876f5e09eaae3eb76814c1d3b68879891d6fde4824c015d48e7a7da4cf066a3a", size = 11162912 }, + { url = "https://files.pythonhosted.org/packages/8d/1b/dd77503b3875c51e3dbc053fd8367b845ab8b01c9ca6d0c237082732856c/ruff-0.7.4-py3-none-win32.whl", hash = "sha256:75c53f54904be42dd52a548728a5b572344b50d9b2873d13a3f8c5e3b91f5cac", size = 8702767 }, + { url = "https://files.pythonhosted.org/packages/63/76/253ddc3e89e70165bba952ecca424b980b8d3c2598ceb4fc47904f424953/ruff-0.7.4-py3-none-win_amd64.whl", hash = "sha256:745775c7b39f914238ed1f1b0bebed0b9155a17cd8bc0b08d3c87e4703b990d6", size = 9497534 }, + { url = "https://files.pythonhosted.org/packages/aa/70/f8724f31abc0b329ca98b33d73c14020168babcf71b0cba3cded5d9d0e66/ruff-0.7.4-py3-none-win_arm64.whl", hash = "sha256:11bff065102c3ae9d3ea4dc9ecdfe5a5171349cdd0787c1fc64761212fc9cf1f", size = 8851590 }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 }, +] + +[[package]] +name = "tomli" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/e4/1b6cbcc82d8832dd0ce34767d5c560df8a3547ad8cbc427f34601415930a/tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8", size = 16622 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/f7/4da0ffe1892122c9ea096c57f64c2753ae5dd3ce85488802d11b0992cc6d/tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391", size = 13750 }, +] + +[[package]] +name = "typer" +version = "0.13.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/41/49ead3ad3310545e767bcb917c759b026ca9eada5d5c150c2fb6fc555568/typer-0.13.1.tar.gz", hash = "sha256:9d444cb96cc268ce6f8b94e13b4335084cef4c079998a9f4851a90229a3bd25c", size = 98631 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/69/e90a0b4d0c16e095901679216c8ecdc728110c7c54e7b5f43a623bc4c789/typer-0.13.1-py3-none-any.whl", hash = "sha256:5b59580fd925e89463a29d363e0a43245ec02765bde9fb77d39e5d0f29dd7157", size = 44723 }, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, +] From 0b626755f5c9bc1d7b9d2b872bfe487d87aefca3 Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Thu, 21 Nov 2024 18:40:54 -0500 Subject: [PATCH 07/10] Ruff formatting --- src/pycbsdk/cbhw/device/base.py | 6 +++--- src/pycbsdk/cbhw/io/datagram.py | 6 ++++-- src/pycbsdk/cbhw/packet/common.py | 4 ++-- src/pycbsdk/cbhw/packet/packets.py | 10 +++++++++- src/pycbsdk/cbhw/packet/v311.py | 2 +- src/pycbsdk/cbhw/packet/v41.py | 3 +-- src/pycbsdk/examples/print_rates.py | 2 +- 7 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/pycbsdk/cbhw/device/base.py b/src/pycbsdk/cbhw/device/base.py index 79ebba6..e6783f4 100644 --- a/src/pycbsdk/cbhw/device/base.py +++ b/src/pycbsdk/cbhw/device/base.py @@ -42,9 +42,9 @@ def __init__(self, params: Params): _: [] for _ in CBChannelType } # Init config_callbacks as a defaultdict that will create an empty list on-the-fly for unseen keys. - self.config_callbacks: defaultdict[ - CBPacketType, typing.List[CBPktCallBack] - ] = defaultdict(lambda: []) + self.config_callbacks: defaultdict[CBPacketType, typing.List[CBPktCallBack]] = ( + defaultdict(lambda: []) + ) self._params = params self.packet_factory = CBPacketFactory(protocol=self._params.protocol) self.pkts_received = 0 diff --git a/src/pycbsdk/cbhw/io/datagram.py b/src/pycbsdk/cbhw/io/datagram.py index 1feb282..4942926 100644 --- a/src/pycbsdk/cbhw/io/datagram.py +++ b/src/pycbsdk/cbhw/io/datagram.py @@ -149,8 +149,10 @@ async def _receiver_coro(self): try: sock.bind(self._recv_addr) except OSError as e: - logger.error(f"Cannot bind to {self._recv_addr}. Central may have exclusive access to the port on " - f"this machine. Error: {e}") + logger.error( + f"Cannot bind to {self._recv_addr}. Central may have exclusive access to the port on " + f"this machine. Error: {e}" + ) loop = asyncio.get_event_loop() # Create a future that should only return when the UDP connection is lost diff --git a/src/pycbsdk/cbhw/packet/common.py b/src/pycbsdk/cbhw/packet/common.py index 3cd742a..58c14ef 100644 --- a/src/pycbsdk/cbhw/packet/common.py +++ b/src/pycbsdk/cbhw/packet/common.py @@ -9,6 +9,7 @@ MAX_HOOPS = 4 DEFAULT_TIMEOUT = 0.2 + # Class that uses the @print_pretty decorator # must provide a _fields_ list of tuples this is ("name", type) def print_pretty(cls): @@ -238,7 +239,6 @@ class CBManualUnitMapping(Structure): @print_pretty class CBHoop(Structure): - # Not needed now, but may need to add this to other data classes that may need comparisions # Can probably make it cleaner with a decorator if needed throughout. def __eq__(self, other): @@ -248,7 +248,7 @@ def __eq__(self, other): return False return True return False - + _pack_ = 1 _fields_ = [ ("valid", c_uint16), # 0=undefined, 1 for valid diff --git a/src/pycbsdk/cbhw/packet/packets.py b/src/pycbsdk/cbhw/packet/packets.py index 8478741..b0ffc65 100644 --- a/src/pycbsdk/cbhw/packet/packets.py +++ b/src/pycbsdk/cbhw/packet/packets.py @@ -1,10 +1,18 @@ import typing from ctypes import * import struct + import numpy as np import numpy.typing + from .. import config -from .common import CBChannelType, CBPacketType, CBSpecialChan, CBManualUnitMapping, print_pretty +from .common import ( + CBChannelType, + CBPacketType, + CBSpecialChan, + CBManualUnitMapping, + print_pretty, +) from .abstract import CBPacketVarDataNDArray, CBPacketVarLen, CBPacketConfigFixed if config.protocol is None: diff --git a/src/pycbsdk/cbhw/packet/v311.py b/src/pycbsdk/cbhw/packet/v311.py index af430ac..6667da4 100644 --- a/src/pycbsdk/cbhw/packet/v311.py +++ b/src/pycbsdk/cbhw/packet/v311.py @@ -35,7 +35,7 @@ class CBPacketSysProtocolMonitor(CBPacketConfigFixed): ( "sentpkts", c_uint32, - ) # Packets sent since last cbPKT_SYSPROTOCOLMONITOR (or 0 if timestamp=0); + ), # Packets sent since last cbPKT_SYSPROTOCOLMONITOR (or 0 if timestamp=0); # the cbPKT_SYSPROTOCOLMONITOR packets are counted as well so this must # be equal to at least 1 ] diff --git a/src/pycbsdk/cbhw/packet/v41.py b/src/pycbsdk/cbhw/packet/v41.py index f5f7560..9f9b141 100644 --- a/src/pycbsdk/cbhw/packet/v41.py +++ b/src/pycbsdk/cbhw/packet/v41.py @@ -8,7 +8,7 @@ CBFiltDesc, print_pretty, MAX_HOOPS, - MAX_UNITS + MAX_UNITS, ) from .abstract import CBPacketConfigFixed from .header import CBPacketHeader @@ -32,7 +32,6 @@ def default_type(self): return CBPacketType.SYSPROTOCOLMONITOR - @print_pretty class CBChanMonitor(Structure): _fields_ = [ diff --git a/src/pycbsdk/examples/print_rates.py b/src/pycbsdk/examples/print_rates.py index ee15b78..1c12744 100644 --- a/src/pycbsdk/examples/print_rates.py +++ b/src/pycbsdk/examples/print_rates.py @@ -64,7 +64,7 @@ def main( loglevel: str = "debug", skip_startup: bool = False, update_interval: float = 1.0, - set_hoops: bool = False + set_hoops: bool = False, ): """ Run the application: From fd5ee54dda52e88e2cd9f14768a74ed677e41405 Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Thu, 21 Nov 2024 18:41:05 -0500 Subject: [PATCH 08/10] CI pipeline --- .github/workflows/python-tests.yml | 43 ++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/workflows/python-tests.yml diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml new file mode 100644 index 0000000..eab0945 --- /dev/null +++ b/.github/workflows/python-tests.yml @@ -0,0 +1,43 @@ +name: Test package + +on: + push: + branches: [main] + pull_request: + branches: + - main + - dev + workflow_dispatch: + +jobs: + build: + strategy: + matrix: + python-version: [3.9, "3.10", "3.11", "3.12"] + os: + - "ubuntu-latest" + - "windows-latest" + - "macos-latest" + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v2 + with: + enable-cache: true + cache-dependency-glob: "uv.lock" + + - name: Set up Python ${{ matrix.python-version }} + run: uv python install ${{ matrix.python-version }} + + - name: Install the project + run: uv sync --all-extras --dev + + - name: Lint + run: + uv tool run ruff check --output-format=github src + + - name: Run tests + run: uv run pytest tests From ec14307631e33b8fc949541d70556315412db14c Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Thu, 21 Nov 2024 18:45:02 -0500 Subject: [PATCH 09/10] Remove unused imports --- src/pycbsdk/cbhw/device/nsp.py | 11 +++++------ src/pycbsdk/cbhw/packet/abstract.py | 1 - src/pycbsdk/cbhw/packet/common.py | 1 - src/pycbsdk/cbsdk.py | 1 - src/pycbsdk/examples/print_rates.py | 1 - 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/pycbsdk/cbhw/device/nsp.py b/src/pycbsdk/cbhw/device/nsp.py index 74addde..2b414e2 100644 --- a/src/pycbsdk/cbhw/device/nsp.py +++ b/src/pycbsdk/cbhw/device/nsp.py @@ -26,11 +26,10 @@ import copy from ctypes import Structure, create_string_buffer import logging -import queue import socket from collections.abc import Callable -from enum import IntEnum, Flag, IntFlag -from typing import Optional, Type +from enum import IntEnum, IntFlag +from typing import Optional import struct import threading import time @@ -244,7 +243,7 @@ class LNCRate: def GetLNCRate(key) -> int: try: return LNCRate.lnc_rates[key] - except KeyError as e: + except KeyError: print("Error with LNC rate key.") return 0 @@ -1123,7 +1122,7 @@ def set_transport( event = self._config_events["sysrep"] logger.debug(f"Attempting to set transport to {transport.upper()}") if not self._send_packet(pkt, event=event, timeout=timeout): - logger.warning(f"Did not receive SYSREPTRANSPORT in expected timeout.") + logger.warning("Did not receive SYSREPTRANSPORT in expected timeout.") def get_transport(self, force_refresh=False) -> int: if force_refresh: @@ -1248,7 +1247,7 @@ def _send_packet( if event is not None: res = event.wait(timeout=timeout) if not res: - logger.debug(f"timeout expired waiting for event") + logger.debug("timeout expired waiting for event") return False return True diff --git a/src/pycbsdk/cbhw/packet/abstract.py b/src/pycbsdk/cbhw/packet/abstract.py index 73fbaed..0872b6d 100644 --- a/src/pycbsdk/cbhw/packet/abstract.py +++ b/src/pycbsdk/cbhw/packet/abstract.py @@ -3,7 +3,6 @@ import struct import numpy as np import numpy.typing -from .. import config from .common import ( CBPacketType, CBSpecialChan, diff --git a/src/pycbsdk/cbhw/packet/common.py b/src/pycbsdk/cbhw/packet/common.py index 58c14ef..1f50bf7 100644 --- a/src/pycbsdk/cbhw/packet/common.py +++ b/src/pycbsdk/cbhw/packet/common.py @@ -1,7 +1,6 @@ from ctypes import * from ctypes import _SimpleCData # not included with *, supposed to be 'private' from enum import IntEnum -from .. import config PKT_MAX_SIZE = 1024 # bytes diff --git a/src/pycbsdk/cbsdk.py b/src/pycbsdk/cbsdk.py index 69fce94..b5128f6 100644 --- a/src/pycbsdk/cbsdk.py +++ b/src/pycbsdk/cbsdk.py @@ -1,7 +1,6 @@ from ctypes import Structure from typing import Optional from collections.abc import Callable -import time from .cbhw.device.nsp import * from .cbhw.params import Params diff --git a/src/pycbsdk/examples/print_rates.py b/src/pycbsdk/examples/print_rates.py index 1c12744..b059057 100644 --- a/src/pycbsdk/examples/print_rates.py +++ b/src/pycbsdk/examples/print_rates.py @@ -1,5 +1,4 @@ import sys -import argparse import logging from pycbsdk import cbsdk import time From fe886cd1d7e91d7ceb4c83651e1ba36bf88a9ca3 Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Thu, 21 Nov 2024 18:46:23 -0500 Subject: [PATCH 10/10] Linter disabled because we have too many errors. This might not be the right project for linting. --- .github/workflows/python-tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index eab0945..cf4a132 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -35,9 +35,9 @@ jobs: - name: Install the project run: uv sync --all-extras --dev - - name: Lint - run: - uv tool run ruff check --output-format=github src +# - name: Lint +# run: +# uv tool run ruff check --output-format=github src - name: Run tests run: uv run pytest tests