From 7b2c94a475a61a2a114baa095d0dae8e27f82383 Mon Sep 17 00:00:00 2001 From: tfotakis-signaloid <213429317+tfotakis-signaloid@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:31:38 +0200 Subject: [PATCH 1/2] Updated to version `1.7.1` --- .flake8 | 9 +- .github/workflows/signaloid-python.yaml | 3 + poetry.lock | 337 ++++++++++++----- pyproject.toml | 5 +- src/signaloid/circuitpython/plot_wrapper.py | 55 ++- src/signaloid/distributional/__init__.py | 2 +- src/signaloid/distributional/dirac_delta.py | 17 +- .../distributional/dirac_delta_test.py | 5 +- .../distributional/distributional.py | 171 +++++---- .../distributional/distributional_test.py | 352 ++++++++++++------ .../plot_histogram_dirac_deltas.py | 151 ++++---- .../plot_histogram_dirac_deltas_test.py | 73 ++-- .../plot_wrapper.py | 27 +- .../plot_wrapper_test.py | 21 +- src/signaloid/uxdata_toolkit.py | 22 +- 15 files changed, 759 insertions(+), 491 deletions(-) diff --git a/.flake8 b/.flake8 index da459c2..d79ac3b 100644 --- a/.flake8 +++ b/.flake8 @@ -1,6 +1,6 @@ [flake8] -max-complexity = 20 -max-line-length = 79 +max-complexity = 10 +max-line-length = 88 extend-ignore = # Let formatting take care of line length (not flake8) @@ -8,5 +8,8 @@ extend-ignore = E203 per-file-ignores = - src/signaloid/distributional_information_plotting/*: F841 + # Ignore complex mains in these scripts for now + # We should aim is to address all of these in the future + src/signaloid/distributional_information_plotting/*: C901 + src/signaloid/distributional/*: C901 diff --git a/.github/workflows/signaloid-python.yaml b/.github/workflows/signaloid-python.yaml index 618af16..b6438be 100644 --- a/.github/workflows/signaloid-python.yaml +++ b/.github/workflows/signaloid-python.yaml @@ -65,6 +65,9 @@ jobs: - name: Lint run: poetry run flake8 src/ + - name: Check format + run: poetry run black --check src/ + - name: Typecheck run: poetry run mypy -p signaloid diff --git a/poetry.lock b/poetry.lock index ebf35ba..48016ff 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,72 @@ # This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. +[[package]] +name = "black" +version = "25.11.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "black-25.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ec311e22458eec32a807f029b2646f661e6859c3f61bc6d9ffb67958779f392e"}, + {file = "black-25.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1032639c90208c15711334d681de2e24821af0575573db2810b0763bcd62e0f0"}, + {file = "black-25.11.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c0f7c461df55cf32929b002335883946a4893d759f2df343389c4396f3b6b37"}, + {file = "black-25.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:f9786c24d8e9bd5f20dc7a7f0cdd742644656987f6ea6947629306f937726c03"}, + {file = "black-25.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:895571922a35434a9d8ca67ef926da6bc9ad464522a5fe0db99b394ef1c0675a"}, + {file = "black-25.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cb4f4b65d717062191bdec8e4a442539a8ea065e6af1c4f4d36f0cdb5f71e170"}, + {file = "black-25.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d81a44cbc7e4f73a9d6ae449ec2317ad81512d1e7dce7d57f6333fd6259737bc"}, + {file = "black-25.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:7eebd4744dfe92ef1ee349dc532defbf012a88b087bb7ddd688ff59a447b080e"}, + {file = "black-25.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:80e7486ad3535636657aa180ad32a7d67d7c273a80e12f1b4bfa0823d54e8fac"}, + {file = "black-25.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6cced12b747c4c76bc09b4db057c319d8545307266f41aaee665540bc0e04e96"}, + {file = "black-25.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb2d54a39e0ef021d6c5eef442e10fd71fcb491be6413d083a320ee768329dd"}, + {file = "black-25.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae263af2f496940438e5be1a0c1020e13b09154f3af4df0835ea7f9fe7bfa409"}, + {file = "black-25.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a1d40348b6621cc20d3d7530a5b8d67e9714906dfd7346338249ad9c6cedf2b"}, + {file = "black-25.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:51c65d7d60bb25429ea2bf0731c32b2a2442eb4bd3b2afcb47830f0b13e58bfd"}, + {file = "black-25.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:936c4dd07669269f40b497440159a221ee435e3fddcf668e0c05244a9be71993"}, + {file = "black-25.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:f42c0ea7f59994490f4dccd64e6b2dd49ac57c7c84f38b8faab50f8759db245c"}, + {file = "black-25.11.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:35690a383f22dd3e468c85dc4b915217f87667ad9cce781d7b42678ce63c4170"}, + {file = "black-25.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:dae49ef7369c6caa1a1833fd5efb7c3024bb7e4499bf64833f65ad27791b1545"}, + {file = "black-25.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bd4a22a0b37401c8e492e994bce79e614f91b14d9ea911f44f36e262195fdda"}, + {file = "black-25.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:aa211411e94fdf86519996b7f5f05e71ba34835d8f0c0f03c00a26271da02664"}, + {file = "black-25.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a3bb5ce32daa9ff0605d73b6f19da0b0e6c1f8f2d75594db539fdfed722f2b06"}, + {file = "black-25.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9815ccee1e55717fe9a4b924cae1646ef7f54e0f990da39a34fc7b264fcf80a2"}, + {file = "black-25.11.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:92285c37b93a1698dcbc34581867b480f1ba3a7b92acf1fe0467b04d7a4da0dc"}, + {file = "black-25.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:43945853a31099c7c0ff8dface53b4de56c41294fa6783c0441a8b1d9bf668bc"}, + {file = "black-25.11.0-py3-none-any.whl", hash = "sha256:e3f562da087791e96cefcd9dda058380a442ab322a02e222add53736451f604b"}, + {file = "black-25.11.0.tar.gz", hash = "sha256:9a323ac32f5dc75ce7470501b887250be5005a01602e931a15e45593f70f6e08"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +pytokens = ">=0.3.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.10)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "click" +version = "8.1.8" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + [[package]] name = "colorama" version = "0.4.6" @@ -7,7 +74,7 @@ description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["dev"] -markers = "sys_platform == \"win32\"" +markers = "platform_system == \"Windows\" or sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -393,89 +460,103 @@ files = [ [[package]] name = "librt" -version = "0.7.8" +version = "0.8.1" description = "Mypyc runtime library" optional = false python-versions = ">=3.9" groups = ["dev"] markers = "platform_python_implementation != \"PyPy\"" files = [ - {file = "librt-0.7.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b45306a1fc5f53c9330fbee134d8b3227fe5da2ab09813b892790400aa49352d"}, - {file = "librt-0.7.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:864c4b7083eeee250ed55135d2127b260d7eb4b5e953a9e5df09c852e327961b"}, - {file = "librt-0.7.8-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6938cc2de153bc927ed8d71c7d2f2ae01b4e96359126c602721340eb7ce1a92d"}, - {file = "librt-0.7.8-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:66daa6ac5de4288a5bbfbe55b4caa7bf0cd26b3269c7a476ffe8ce45f837f87d"}, - {file = "librt-0.7.8-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4864045f49dc9c974dadb942ac56a74cd0479a2aafa51ce272c490a82322ea3c"}, - {file = "librt-0.7.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a36515b1328dc5b3ffce79fe204985ca8572525452eacabee2166f44bb387b2c"}, - {file = "librt-0.7.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b7e7f140c5169798f90b80d6e607ed2ba5059784968a004107c88ad61fb3641d"}, - {file = "librt-0.7.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ff71447cb778a4f772ddc4ce360e6ba9c95527ed84a52096bd1bbf9fee2ec7c0"}, - {file = "librt-0.7.8-cp310-cp310-win32.whl", hash = "sha256:047164e5f68b7a8ebdf9fae91a3c2161d3192418aadd61ddd3a86a56cbe3dc85"}, - {file = "librt-0.7.8-cp310-cp310-win_amd64.whl", hash = "sha256:d6f254d096d84156a46a84861183c183d30734e52383602443292644d895047c"}, - {file = "librt-0.7.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ff3e9c11aa260c31493d4b3197d1e28dd07768594a4f92bec4506849d736248f"}, - {file = "librt-0.7.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ddb52499d0b3ed4aa88746aaf6f36a08314677d5c346234c3987ddc506404eac"}, - {file = "librt-0.7.8-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e9c0afebbe6ce177ae8edba0c7c4d626f2a0fc12c33bb993d163817c41a7a05c"}, - {file = "librt-0.7.8-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:631599598e2c76ded400c0a8722dec09217c89ff64dc54b060f598ed68e7d2a8"}, - {file = "librt-0.7.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c1ba843ae20db09b9d5c80475376168feb2640ce91cd9906414f23cc267a1ff"}, - {file = "librt-0.7.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b5b007bb22ea4b255d3ee39dfd06d12534de2fcc3438567d9f48cdaf67ae1ae3"}, - {file = "librt-0.7.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dbd79caaf77a3f590cbe32dc2447f718772d6eea59656a7dcb9311161b10fa75"}, - {file = "librt-0.7.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:87808a8d1e0bd62a01cafc41f0fd6818b5a5d0ca0d8a55326a81643cdda8f873"}, - {file = "librt-0.7.8-cp311-cp311-win32.whl", hash = "sha256:31724b93baa91512bd0a376e7cf0b59d8b631ee17923b1218a65456fa9bda2e7"}, - {file = "librt-0.7.8-cp311-cp311-win_amd64.whl", hash = "sha256:978e8b5f13e52cf23a9e80f3286d7546baa70bc4ef35b51d97a709d0b28e537c"}, - {file = "librt-0.7.8-cp311-cp311-win_arm64.whl", hash = "sha256:20e3946863d872f7cabf7f77c6c9d370b8b3d74333d3a32471c50d3a86c0a232"}, - {file = "librt-0.7.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9b6943885b2d49c48d0cff23b16be830ba46b0152d98f62de49e735c6e655a63"}, - {file = "librt-0.7.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:46ef1f4b9b6cc364b11eea0ecc0897314447a66029ee1e55859acb3dd8757c93"}, - {file = "librt-0.7.8-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:907ad09cfab21e3c86e8f1f87858f7049d1097f77196959c033612f532b4e592"}, - {file = "librt-0.7.8-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2991b6c3775383752b3ca0204842743256f3ad3deeb1d0adc227d56b78a9a850"}, - {file = "librt-0.7.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03679b9856932b8c8f674e87aa3c55ea11c9274301f76ae8dc4d281bda55cf62"}, - {file = "librt-0.7.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3968762fec1b2ad34ce57458b6de25dbb4142713e9ca6279a0d352fa4e9f452b"}, - {file = "librt-0.7.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bb7a7807523a31f03061288cc4ffc065d684c39db7644c676b47d89553c0d714"}, - {file = "librt-0.7.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad64a14b1e56e702e19b24aae108f18ad1bf7777f3af5fcd39f87d0c5a814449"}, - {file = "librt-0.7.8-cp312-cp312-win32.whl", hash = "sha256:0241a6ed65e6666236ea78203a73d800dbed896cf12ae25d026d75dc1fcd1dac"}, - {file = "librt-0.7.8-cp312-cp312-win_amd64.whl", hash = "sha256:6db5faf064b5bab9675c32a873436b31e01d66ca6984c6f7f92621656033a708"}, - {file = "librt-0.7.8-cp312-cp312-win_arm64.whl", hash = "sha256:57175aa93f804d2c08d2edb7213e09276bd49097611aefc37e3fa38d1fb99ad0"}, - {file = "librt-0.7.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4c3995abbbb60b3c129490fa985dfe6cac11d88fc3c36eeb4fb1449efbbb04fc"}, - {file = "librt-0.7.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:44e0c2cbc9bebd074cf2cdbe472ca185e824be4e74b1c63a8e934cea674bebf2"}, - {file = "librt-0.7.8-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4d2f1e492cae964b3463a03dc77a7fe8742f7855d7258c7643f0ee32b6651dd3"}, - {file = "librt-0.7.8-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:451e7ffcef8f785831fdb791bd69211f47e95dc4c6ddff68e589058806f044c6"}, - {file = "librt-0.7.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3469e1af9f1380e093ae06bedcbdd11e407ac0b303a56bbe9afb1d6824d4982d"}, - {file = "librt-0.7.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f11b300027ce19a34f6d24ebb0a25fd0e24a9d53353225a5c1e6cadbf2916b2e"}, - {file = "librt-0.7.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4adc73614f0d3c97874f02f2c7fd2a27854e7e24ad532ea6b965459c5b757eca"}, - {file = "librt-0.7.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:60c299e555f87e4c01b2eca085dfccda1dde87f5a604bb45c2906b8305819a93"}, - {file = "librt-0.7.8-cp313-cp313-win32.whl", hash = "sha256:b09c52ed43a461994716082ee7d87618096851319bf695d57ec123f2ab708951"}, - {file = "librt-0.7.8-cp313-cp313-win_amd64.whl", hash = "sha256:f8f4a901a3fa28969d6e4519deceab56c55a09d691ea7b12ca830e2fa3461e34"}, - {file = "librt-0.7.8-cp313-cp313-win_arm64.whl", hash = "sha256:43d4e71b50763fcdcf64725ac680d8cfa1706c928b844794a7aa0fa9ac8e5f09"}, - {file = "librt-0.7.8-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:be927c3c94c74b05128089a955fba86501c3b544d1d300282cc1b4bd370cb418"}, - {file = "librt-0.7.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7b0803e9008c62a7ef79058233db7ff6f37a9933b8f2573c05b07ddafa226611"}, - {file = "librt-0.7.8-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:79feb4d00b2a4e0e05c9c56df707934f41fcb5fe53fd9efb7549068d0495b758"}, - {file = "librt-0.7.8-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b9122094e3f24aa759c38f46bd8863433820654927370250f460ae75488b66ea"}, - {file = "librt-0.7.8-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7e03bea66af33c95ce3addf87a9bf1fcad8d33e757bc479957ddbc0e4f7207ac"}, - {file = "librt-0.7.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f1ade7f31675db00b514b98f9ab9a7698c7282dad4be7492589109471852d398"}, - {file = "librt-0.7.8-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a14229ac62adcf1b90a15992f1ab9c69ae8b99ffb23cb64a90878a6e8a2f5b81"}, - {file = "librt-0.7.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5bcaaf624fd24e6a0cb14beac37677f90793a96864c67c064a91458611446e83"}, - {file = "librt-0.7.8-cp314-cp314-win32.whl", hash = "sha256:7aa7d5457b6c542ecaed79cec4ad98534373c9757383973e638ccced0f11f46d"}, - {file = "librt-0.7.8-cp314-cp314-win_amd64.whl", hash = "sha256:3d1322800771bee4a91f3b4bd4e49abc7d35e65166821086e5afd1e6c0d9be44"}, - {file = "librt-0.7.8-cp314-cp314-win_arm64.whl", hash = "sha256:5363427bc6a8c3b1719f8f3845ea53553d301382928a86e8fab7984426949bce"}, - {file = "librt-0.7.8-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ca916919793a77e4a98d4a1701e345d337ce53be4a16620f063191f7322ac80f"}, - {file = "librt-0.7.8-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:54feb7b4f2f6706bb82325e836a01be805770443e2400f706e824e91f6441dde"}, - {file = "librt-0.7.8-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:39a4c76fee41007070f872b648cc2f711f9abf9a13d0c7162478043377b52c8e"}, - {file = "librt-0.7.8-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac9c8a458245c7de80bc1b9765b177055efff5803f08e548dd4bb9ab9a8d789b"}, - {file = "librt-0.7.8-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95b67aa7eff150f075fda09d11f6bfb26edffd300f6ab1666759547581e8f666"}, - {file = "librt-0.7.8-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:535929b6eff670c593c34ff435d5440c3096f20fa72d63444608a5aef64dd581"}, - {file = "librt-0.7.8-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:63937bd0f4d1cb56653dc7ae900d6c52c41f0015e25aaf9902481ee79943b33a"}, - {file = "librt-0.7.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cf243da9e42d914036fd362ac3fa77d80a41cadcd11ad789b1b5eec4daaf67ca"}, - {file = "librt-0.7.8-cp314-cp314t-win32.whl", hash = "sha256:171ca3a0a06c643bd0a2f62a8944e1902c94aa8e5da4db1ea9a8daf872685365"}, - {file = "librt-0.7.8-cp314-cp314t-win_amd64.whl", hash = "sha256:445b7304145e24c60288a2f172b5ce2ca35c0f81605f5299f3fa567e189d2e32"}, - {file = "librt-0.7.8-cp314-cp314t-win_arm64.whl", hash = "sha256:8766ece9de08527deabcd7cb1b4f1a967a385d26e33e536d6d8913db6ef74f06"}, - {file = "librt-0.7.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c7e8f88f79308d86d8f39c491773cbb533d6cb7fa6476f35d711076ee04fceb6"}, - {file = "librt-0.7.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:389bd25a0db916e1d6bcb014f11aa9676cedaa485e9ec3752dfe19f196fd377b"}, - {file = "librt-0.7.8-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:73fd300f501a052f2ba52ede721232212f3b06503fa12665408ecfc9d8fd149c"}, - {file = "librt-0.7.8-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d772edc6a5f7835635c7562f6688e031f0b97e31d538412a852c49c9a6c92d5"}, - {file = "librt-0.7.8-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde8a130bd0f239e45503ab39fab239ace094d63ee1d6b67c25a63d741c0f71"}, - {file = "librt-0.7.8-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fdec6e2368ae4f796fc72fad7fd4bd1753715187e6d870932b0904609e7c878e"}, - {file = "librt-0.7.8-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:00105e7d541a8f2ee5be52caacea98a005e0478cfe78c8080fbb7b5d2b340c63"}, - {file = "librt-0.7.8-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c6f8947d3dfd7f91066c5b4385812c18be26c9d5a99ca56667547f2c39149d94"}, - {file = "librt-0.7.8-cp39-cp39-win32.whl", hash = "sha256:41d7bb1e07916aeb12ae4a44e3025db3691c4149ab788d0315781b4d29b86afb"}, - {file = "librt-0.7.8-cp39-cp39-win_amd64.whl", hash = "sha256:e90a8e237753c83b8e484d478d9a996dc5e39fd5bd4c6ce32563bc8123f132be"}, - {file = "librt-0.7.8.tar.gz", hash = "sha256:1a4ede613941d9c3470b0368be851df6bb78ab218635512d0370b27a277a0862"}, + {file = "librt-0.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:81fd938344fecb9373ba1b155968c8a329491d2ce38e7ddb76f30ffb938f12dc"}, + {file = "librt-0.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5db05697c82b3a2ec53f6e72b2ed373132b0c2e05135f0696784e97d7f5d48e7"}, + {file = "librt-0.8.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d56bc4011975f7460bea7b33e1ff425d2f1adf419935ff6707273c77f8a4ada6"}, + {file = "librt-0.8.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdc0f588ff4b663ea96c26d2a230c525c6fc62b28314edaaaca8ed5af931ad0"}, + {file = "librt-0.8.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:97c2b54ff6717a7a563b72627990bec60d8029df17df423f0ed37d56a17a176b"}, + {file = "librt-0.8.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8f1125e6bbf2f1657d9a2f3ccc4a2c9b0c8b176965bb565dd4d86be67eddb4b6"}, + {file = "librt-0.8.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8f4bb453f408137d7581be309b2fbc6868a80e7ef60c88e689078ee3a296ae71"}, + {file = "librt-0.8.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c336d61d2fe74a3195edc1646d53ff1cddd3a9600b09fa6ab75e5514ba4862a7"}, + {file = "librt-0.8.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:eb5656019db7c4deacf0c1a55a898c5bb8f989be904597fcb5232a2f4828fa05"}, + {file = "librt-0.8.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c25d9e338d5bed46c1632f851babf3d13c78f49a225462017cf5e11e845c5891"}, + {file = "librt-0.8.1-cp310-cp310-win32.whl", hash = "sha256:aaab0e307e344cb28d800957ef3ec16605146ef0e59e059a60a176d19543d1b7"}, + {file = "librt-0.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:56e04c14b696300d47b3bc5f1d10a00e86ae978886d0cee14e5714fafb5df5d2"}, + {file = "librt-0.8.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:681dc2451d6d846794a828c16c22dc452d924e9f700a485b7ecb887a30aad1fd"}, + {file = "librt-0.8.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3b4350b13cc0e6f5bec8fa7caf29a8fb8cdc051a3bae45cfbfd7ce64f009965"}, + {file = "librt-0.8.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ac1e7817fd0ed3d14fd7c5df91daed84c48e4c2a11ee99c0547f9f62fdae13da"}, + {file = "librt-0.8.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:747328be0c5b7075cde86a0e09d7a9196029800ba75a1689332348e998fb85c0"}, + {file = "librt-0.8.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0af2bd2bc204fa27f3d6711d0f360e6b8c684a035206257a81673ab924aa11e"}, + {file = "librt-0.8.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d480de377f5b687b6b1bc0c0407426da556e2a757633cc7e4d2e1a057aa688f3"}, + {file = "librt-0.8.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d0ee06b5b5291f609ddb37b9750985b27bc567791bc87c76a569b3feed8481ac"}, + {file = "librt-0.8.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9e2c6f77b9ad48ce5603b83b7da9ee3e36b3ab425353f695cba13200c5d96596"}, + {file = "librt-0.8.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:439352ba9373f11cb8e1933da194dcc6206daf779ff8df0ed69c5e39113e6a99"}, + {file = "librt-0.8.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:82210adabbc331dbb65d7868b105185464ef13f56f7f76688565ad79f648b0fe"}, + {file = "librt-0.8.1-cp311-cp311-win32.whl", hash = "sha256:52c224e14614b750c0a6d97368e16804a98c684657c7518752c356834fff83bb"}, + {file = "librt-0.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:c00e5c884f528c9932d278d5c9cbbea38a6b81eb62c02e06ae53751a83a4d52b"}, + {file = "librt-0.8.1-cp311-cp311-win_arm64.whl", hash = "sha256:f7cdf7f26c2286ffb02e46d7bac56c94655540b26347673bea15fa52a6af17e9"}, + {file = "librt-0.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a28f2612ab566b17f3698b0da021ff9960610301607c9a5e8eaca62f5e1c350a"}, + {file = "librt-0.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60a78b694c9aee2a0f1aaeaa7d101cf713e92e8423a941d2897f4fa37908dab9"}, + {file = "librt-0.8.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:758509ea3f1eba2a57558e7e98f4659d0ea7670bff49673b0dde18a3c7e6c0eb"}, + {file = "librt-0.8.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:039b9f2c506bd0ab0f8725aa5ba339c6f0cd19d3b514b50d134789809c24285d"}, + {file = "librt-0.8.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bb54f1205a3a6ab41a6fd71dfcdcbd278670d3a90ca502a30d9da583105b6f7"}, + {file = "librt-0.8.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:05bd41cdee35b0c59c259f870f6da532a2c5ca57db95b5f23689fcb5c9e42440"}, + {file = "librt-0.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adfab487facf03f0d0857b8710cf82d0704a309d8ffc33b03d9302b4c64e91a9"}, + {file = "librt-0.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:153188fe98a72f206042be10a2c6026139852805215ed9539186312d50a8e972"}, + {file = "librt-0.8.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:dd3c41254ee98604b08bd5b3af5bf0a89740d4ee0711de95b65166bf44091921"}, + {file = "librt-0.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e0d138c7ae532908cbb342162b2611dbd4d90c941cd25ab82084aaf71d2c0bd0"}, + {file = "librt-0.8.1-cp312-cp312-win32.whl", hash = "sha256:43353b943613c5d9c49a25aaffdba46f888ec354e71e3529a00cca3f04d66a7a"}, + {file = "librt-0.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:ff8baf1f8d3f4b6b7257fcb75a501f2a5499d0dda57645baa09d4d0d34b19444"}, + {file = "librt-0.8.1-cp312-cp312-win_arm64.whl", hash = "sha256:0f2ae3725904f7377e11cc37722d5d401e8b3d5851fb9273d7f4fe04f6b3d37d"}, + {file = "librt-0.8.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e6bad1cd94f6764e1e21950542f818a09316645337fd5ab9a7acc45d99a8f35"}, + {file = "librt-0.8.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cf450f498c30af55551ba4f66b9123b7185362ec8b625a773b3d39aa1a717583"}, + {file = "librt-0.8.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eca45e982fa074090057132e30585a7e8674e9e885d402eae85633e9f449ce6c"}, + {file = "librt-0.8.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c3811485fccfda840861905b8c70bba5ec094e02825598bb9d4ca3936857a04"}, + {file = "librt-0.8.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e4af413908f77294605e28cfd98063f54b2c790561383971d2f52d113d9c363"}, + {file = "librt-0.8.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5212a5bd7fae98dae95710032902edcd2ec4dc994e883294f75c857b83f9aba0"}, + {file = "librt-0.8.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e692aa2d1d604e6ca12d35e51fdc36f4cda6345e28e36374579f7ef3611b3012"}, + {file = "librt-0.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4be2a5c926b9770c9e08e717f05737a269b9d0ebc5d2f0060f0fe3fe9ce47acb"}, + {file = "librt-0.8.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fd1a720332ea335ceb544cf0a03f81df92abd4bb887679fd1e460976b0e6214b"}, + {file = "librt-0.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2af9e01e0ef80d95ae3c720be101227edae5f2fe7e3dc63d8857fadfc5a1d"}, + {file = "librt-0.8.1-cp313-cp313-win32.whl", hash = "sha256:086a32dbb71336627e78cc1d6ee305a68d038ef7d4c39aaff41ae8c9aa46e91a"}, + {file = "librt-0.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:e11769a1dbda4da7b00a76cfffa67aa47cfa66921d2724539eee4b9ede780b79"}, + {file = "librt-0.8.1-cp313-cp313-win_arm64.whl", hash = "sha256:924817ab3141aca17893386ee13261f1d100d1ef410d70afe4389f2359fea4f0"}, + {file = "librt-0.8.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6cfa7fe54fd4d1f47130017351a959fe5804bda7a0bc7e07a2cdbc3fdd28d34f"}, + {file = "librt-0.8.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:228c2409c079f8c11fb2e5d7b277077f694cb93443eb760e00b3b83cb8b3176c"}, + {file = "librt-0.8.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7aae78ab5e3206181780e56912d1b9bb9f90a7249ce12f0e8bf531d0462dd0fc"}, + {file = "librt-0.8.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:172d57ec04346b047ca6af181e1ea4858086c80bdf455f61994c4aa6fc3f866c"}, + {file = "librt-0.8.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b1977c4ea97ce5eb7755a78fae68d87e4102e4aaf54985e8b56806849cc06a3"}, + {file = "librt-0.8.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:10c42e1f6fd06733ef65ae7bebce2872bcafd8d6e6b0a08fe0a05a23b044fb14"}, + {file = "librt-0.8.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4c8dfa264b9193c4ee19113c985c95f876fae5e51f731494fc4e0cf594990ba7"}, + {file = "librt-0.8.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:01170b6729a438f0dedc4a26ed342e3dc4f02d1000b4b19f980e1877f0c297e6"}, + {file = "librt-0.8.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:7b02679a0d783bdae30d443025b94465d8c3dc512f32f5b5031f93f57ac32071"}, + {file = "librt-0.8.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:190b109bb69592a3401fe1ffdea41a2e73370ace2ffdc4a0e8e2b39cdea81b78"}, + {file = "librt-0.8.1-cp314-cp314-win32.whl", hash = "sha256:e70a57ecf89a0f64c24e37f38d3fe217a58169d2fe6ed6d70554964042474023"}, + {file = "librt-0.8.1-cp314-cp314-win_amd64.whl", hash = "sha256:7e2f3edca35664499fbb36e4770650c4bd4a08abc1f4458eab9df4ec56389730"}, + {file = "librt-0.8.1-cp314-cp314-win_arm64.whl", hash = "sha256:0d2f82168e55ddefd27c01c654ce52379c0750ddc31ee86b4b266bcf4d65f2a3"}, + {file = "librt-0.8.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c74a2da57a094bd48d03fa5d196da83d2815678385d2978657499063709abe1"}, + {file = "librt-0.8.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a355d99c4c0d8e5b770313b8b247411ed40949ca44e33e46a4789b9293a907ee"}, + {file = "librt-0.8.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2eb345e8b33fb748227409c9f1233d4df354d6e54091f0e8fc53acdb2ffedeb7"}, + {file = "librt-0.8.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9be2f15e53ce4e83cc08adc29b26fb5978db62ef2a366fbdf716c8a6c8901040"}, + {file = "librt-0.8.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:785ae29c1f5c6e7c2cde2c7c0e148147f4503da3abc5d44d482068da5322fd9e"}, + {file = "librt-0.8.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d3a7da44baf692f0c6aeb5b2a09c5e6fc7a703bca9ffa337ddd2e2da53f7732"}, + {file = "librt-0.8.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fc48998000cbc39ec0d5311312dda93ecf92b39aaf184c5e817d5d440b29624"}, + {file = "librt-0.8.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e96baa6820280077a78244b2e06e416480ed859bbd8e5d641cf5742919d8beb4"}, + {file = "librt-0.8.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:31362dbfe297b23590530007062c32c6f6176f6099646bb2c95ab1b00a57c382"}, + {file = "librt-0.8.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc3656283d11540ab0ea01978378e73e10002145117055e03722417aeab30994"}, + {file = "librt-0.8.1-cp314-cp314t-win32.whl", hash = "sha256:738f08021b3142c2918c03692608baed43bc51144c29e35807682f8070ee2a3a"}, + {file = "librt-0.8.1-cp314-cp314t-win_amd64.whl", hash = "sha256:89815a22daf9c51884fb5dbe4f1ef65ee6a146e0b6a8df05f753e2e4a9359bf4"}, + {file = "librt-0.8.1-cp314-cp314t-win_arm64.whl", hash = "sha256:bf512a71a23504ed08103a13c941f763db13fb11177beb3d9244c98c29fb4a61"}, + {file = "librt-0.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3dff3d3ca8db20e783b1bc7de49c0a2ab0b8387f31236d6a026597d07fcd68ac"}, + {file = "librt-0.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:08eec3a1fc435f0d09c87b6bf1ec798986a3544f446b864e4099633a56fcd9ed"}, + {file = "librt-0.8.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e3f0a41487fd5fad7e760b9e8a90e251e27c2816fbc2cff36a22a0e6bcbbd9dd"}, + {file = "librt-0.8.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bacdb58d9939d95cc557b4dbaa86527c9db2ac1ed76a18bc8d26f6dc8647d851"}, + {file = "librt-0.8.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6d7ab1f01aa753188605b09a51faa44a3327400b00b8cce424c71910fc0a128"}, + {file = "librt-0.8.1-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4998009e7cb9e896569f4be7004f09d0ed70d386fa99d42b6d363f6d200501ac"}, + {file = "librt-0.8.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2cc68eeeef5e906839c7bb0815748b5b0a974ec27125beefc0f942715785b551"}, + {file = "librt-0.8.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0bf69d79a23f4f40b8673a947a234baeeb133b5078b483b7297c5916539cf5d5"}, + {file = "librt-0.8.1-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:22b46eabd76c1986ee7d231b0765ad387d7673bbd996aa0d0d054b38ac65d8f6"}, + {file = "librt-0.8.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:237796479f4d0637d6b9cbcb926ff424a97735e68ade6facf402df4ec93375ed"}, + {file = "librt-0.8.1-cp39-cp39-win32.whl", hash = "sha256:4beb04b8c66c6ae62f8c1e0b2f097c1ebad9295c929a8d5286c05eae7c2fc7dc"}, + {file = "librt-0.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:64548cde61b692dc0dc379f4b5f59a2f582c2ebe7890d09c1ae3b9e66fa015b7"}, + {file = "librt-0.8.1.tar.gz", hash = "sha256:be46a14693955b3bd96014ccbdb8339ee8c9346fbe11c1b78901b55125f14c73"}, ] [[package]] @@ -687,26 +768,26 @@ files = [ [[package]] name = "packaging" -version = "25.0" +version = "26.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" groups = ["main", "dev"] files = [ - {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, - {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, + {file = "packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529"}, + {file = "packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4"}, ] [[package]] name = "pathspec" -version = "1.0.3" +version = "1.0.4" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pathspec-1.0.3-py3-none-any.whl", hash = "sha256:e80767021c1cc524aa3fb14bedda9c34406591343cc42797b386ce7b9354fb6c"}, - {file = "pathspec-1.0.3.tar.gz", hash = "sha256:bac5cf97ae2c2876e2d25ebb15078eb04d76e4b98921ee31c6f85ade8b59444d"}, + {file = "pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723"}, + {file = "pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645"}, ] [package.extras] @@ -717,15 +798,15 @@ tests = ["pytest (>=9)", "typing-extensions (>=4.15)"] [[package]] name = "pex" -version = "2.87.0" +version = "2.90.0" description = "The PEX packaging toolchain." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,<3.16,>=2.7" groups = ["dev"] files = [ - {file = "pex-2.87.0-py2.py35.py36.py37.py38.py39.py310.py311-none-any.whl", hash = "sha256:e904d280dbf32c456188ebd525e4f2aabdd183ca450276293643855d59647e4a"}, - {file = "pex-2.87.0-py3.py312-none-any.whl", hash = "sha256:a3482bb4fee17e20cea78267dd4ad81099be406878eab7542e4e7b3dbba20705"}, - {file = "pex-2.87.0.tar.gz", hash = "sha256:4070046edf4afdf33fda4fd6c6406fd2e6d2b7bf1c1c1f33208a5a7e1529588e"}, + {file = "pex-2.90.0-py2.py35.py36.py37.py38.py39.py310.py311-none-any.whl", hash = "sha256:212356e1feb4ffd0977dde04e872ecefe99d8fef99688f77e7fd43c5c9ca9545"}, + {file = "pex-2.90.0-py3.py312-none-any.whl", hash = "sha256:99cc9603e3e56e9a166dd1d051ecedd6170cb1c377d5aa6dfddf7bde41ba7b18"}, + {file = "pex-2.90.0.tar.gz", hash = "sha256:1411041eedf7d162be894ca9201d0115f012182906e93c5818ce669dc229bc9f"}, ] [package.extras] @@ -857,6 +938,23 @@ tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "ole typing = ["typing-extensions ; python_version < \"3.10\""] xmp = ["defusedxml"] +[[package]] +name = "platformdirs" +version = "4.4.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85"}, + {file = "platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.14.1)"] + [[package]] name = "pluggy" version = "1.6.0" @@ -914,14 +1012,14 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyparsing" -version = "3.3.1" +version = "3.3.2" description = "pyparsing - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pyparsing-3.3.1-py3-none-any.whl", hash = "sha256:023b5e7e5520ad96642e2c6db4cb683d3970bd640cdf7115049a6e9c3682df82"}, - {file = "pyparsing-3.3.1.tar.gz", hash = "sha256:47fad0f17ac1e2cad3de3b458570fbc9b03560aa029ed5e16ee5554da9a2251c"}, + {file = "pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d"}, + {file = "pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc"}, ] [package.extras] @@ -966,6 +1064,61 @@ files = [ [package.dependencies] six = ">=1.5" +[[package]] +name = "pytokens" +version = "0.4.1" +description = "A Fast, spec compliant Python 3.14+ tokenizer that runs on older Pythons." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pytokens-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a44ed93ea23415c54f3face3b65ef2b844d96aeb3455b8a69b3df6beab6acc5"}, + {file = "pytokens-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:add8bf86b71a5d9fb5b89f023a80b791e04fba57960aa790cc6125f7f1d39dfe"}, + {file = "pytokens-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:670d286910b531c7b7e3c0b453fd8156f250adb140146d234a82219459b9640c"}, + {file = "pytokens-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4e691d7f5186bd2842c14813f79f8884bb03f5995f0575272009982c5ac6c0f7"}, + {file = "pytokens-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:27b83ad28825978742beef057bfe406ad6ed524b2d28c252c5de7b4a6dd48fa2"}, + {file = "pytokens-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d70e77c55ae8380c91c0c18dea05951482e263982911fc7410b1ffd1dadd3440"}, + {file = "pytokens-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a58d057208cb9075c144950d789511220b07636dd2e4708d5645d24de666bdc"}, + {file = "pytokens-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b49750419d300e2b5a3813cf229d4e5a4c728dae470bcc89867a9ad6f25a722d"}, + {file = "pytokens-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9907d61f15bf7261d7e775bd5d7ee4d2930e04424bab1972591918497623a16"}, + {file = "pytokens-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:ee44d0f85b803321710f9239f335aafe16553b39106384cef8e6de40cb4ef2f6"}, + {file = "pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083"}, + {file = "pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1"}, + {file = "pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1"}, + {file = "pytokens-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ad948d085ed6c16413eb5fec6b3e02fa00dc29a2534f088d3302c47eb59adf9"}, + {file = "pytokens-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f901fe783e06e48e8cbdc82d631fca8f118333798193e026a50ce1b3757ea68"}, + {file = "pytokens-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8bdb9d0ce90cbf99c525e75a2fa415144fd570a1ba987380190e8b786bc6ef9b"}, + {file = "pytokens-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5502408cab1cb18e128570f8d598981c68a50d0cbd7c61312a90507cd3a1276f"}, + {file = "pytokens-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29d1d8fb1030af4d231789959f21821ab6325e463f0503a61d204343c9b355d1"}, + {file = "pytokens-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b08dd6b86058b6dc07efe9e98414f5102974716232d10f32ff39701e841c4"}, + {file = "pytokens-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:9bd7d7f544d362576be74f9d5901a22f317efc20046efe2034dced238cbbfe78"}, + {file = "pytokens-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4a14d5f5fc78ce85e426aa159489e2d5961acf0e47575e08f35584009178e321"}, + {file = "pytokens-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f50fd18543be72da51dd505e2ed20d2228c74e0464e4262e4899797803d7fa"}, + {file = "pytokens-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc74c035f9bfca0255c1af77ddd2d6ae8419012805453e4b0e7513e17904545d"}, + {file = "pytokens-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f66a6bbe741bd431f6d741e617e0f39ec7257ca1f89089593479347cc4d13324"}, + {file = "pytokens-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:b35d7e5ad269804f6697727702da3c517bb8a5228afa450ab0fa787732055fc9"}, + {file = "pytokens-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8fcb9ba3709ff77e77f1c7022ff11d13553f3c30299a9fe246a166903e9091eb"}, + {file = "pytokens-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79fc6b8699564e1f9b521582c35435f1bd32dd06822322ec44afdeba666d8cb3"}, + {file = "pytokens-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d31b97b3de0f61571a124a00ffe9a81fb9939146c122c11060725bd5aea79975"}, + {file = "pytokens-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:967cf6e3fd4adf7de8fc73cd3043754ae79c36475c1c11d514fc72cf5490094a"}, + {file = "pytokens-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:584c80c24b078eec1e227079d56dc22ff755e0ba8654d8383b2c549107528918"}, + {file = "pytokens-0.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:da5baeaf7116dced9c6bb76dc31ba04a2dc3695f3d9f74741d7910122b456edc"}, + {file = "pytokens-0.4.1-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11edda0942da80ff58c4408407616a310adecae1ddd22eef8c692fe266fa5009"}, + {file = "pytokens-0.4.1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0fc71786e629cef478cbf29d7ea1923299181d0699dbe7c3c0f4a583811d9fc1"}, + {file = "pytokens-0.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dcafc12c30dbaf1e2af0490978352e0c4041a7cde31f4f81435c2a5e8b9cabb6"}, + {file = "pytokens-0.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:42f144f3aafa5d92bad964d471a581651e28b24434d184871bd02e3a0d956037"}, + {file = "pytokens-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:34bcc734bd2f2d5fe3b34e7b3c0116bfb2397f2d9666139988e7a3eb5f7400e3"}, + {file = "pytokens-0.4.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:941d4343bf27b605e9213b26bfa1c4bf197c9c599a9627eb7305b0defcfe40c1"}, + {file = "pytokens-0.4.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3ad72b851e781478366288743198101e5eb34a414f1d5627cdd585ca3b25f1db"}, + {file = "pytokens-0.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:682fa37ff4d8e95f7df6fe6fe6a431e8ed8e788023c6bcc0f0880a12eab80ad1"}, + {file = "pytokens-0.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:30f51edd9bb7f85c748979384165601d028b84f7bd13fe14d3e065304093916a"}, + {file = "pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de"}, + {file = "pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a"}, +] + +[package.extras] +dev = ["black", "build", "mypy", "pytest", "pytest-cov", "setuptools", "tox", "twine", "wheel"] + [[package]] name = "six" version = "1.17.0" @@ -1114,4 +1267,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">=3.9,<3.14" -content-hash = "3b7cb6bb3bf6ce2f30a29ca175522aab3852b6c1cb15546fabb6bbd62b701439" +content-hash = "63160cd2ba1b7a4bc3522f8e61c57b5850b9a7d65679156db664bfdfa8f0c1eb" diff --git a/pyproject.toml b/pyproject.toml index d666ed9..6bace64 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "signaloid" -version = "1.7.0" +version = "1.7.1" description = "" authors = [ "Signaloid " @@ -18,6 +18,7 @@ pytest = "^8.4.2" mypy = "^1.19.1" flake8 = "^7.3.0" toml = "^0.10.2" +black = {version = "^25.11.0", python = ">=3.9"} [build-system] requires = ["poetry_core>=1.0.0"] @@ -34,6 +35,8 @@ signaloid-uxdata-toolkit = "signaloid.uxdata_toolkit:main" [tool.mypy] warn_unused_configs = true strict = true +disallow_any_generics = false +python_version = "3.9" [[tool.mypy.overrides]] module = [ diff --git a/src/signaloid/circuitpython/plot_wrapper.py b/src/signaloid/circuitpython/plot_wrapper.py index 1d7cf96..8ccce65 100644 --- a/src/signaloid/circuitpython/plot_wrapper.py +++ b/src/signaloid/circuitpython/plot_wrapper.py @@ -34,9 +34,9 @@ from circuitpython_uplot.scatter import Pointer, Scatter from signaloid.circuitpython.extended_ulab_numpy import np -from signaloid.distributional_information_plotting.plot_histogram_dirac_deltas import \ - PlotData - +from signaloid.distributional_information_plotting.plot_histogram_dirac_deltas import ( + PlotData, +) # The background color of the plot BG_COLOR = 0xFFFFFF @@ -73,7 +73,7 @@ def apply_array_multiplier(arr, multiplier): - arr = np.divide(arr, 10 ** multiplier) + arr = np.divide(arr, 10**multiplier) return arr @@ -81,7 +81,7 @@ def apply_array_multiplier(arr, multiplier): def transform_array_with_multiplier(arr): max_value = max(np.abs(arr)) multiplier = int(math.log(max_value, 10)) + (-1 if max_value < 1 else 0) - arr = np.divide(arr, 10 ** multiplier) + arr = np.divide(arr, 10**multiplier) return arr, multiplier @@ -193,8 +193,8 @@ def render_histogram(plot, boundary_positions, bin_heights, width, align, edgeco def render_x_multiplier(g, c, multiplier): - anchored_x = c.points[1][0] + X_SHIFT - .5 * TICK_SIZE - anchored_y = c.points[1][1] - Y_SHIFT + .5 * TICK_SIZE + anchored_x = c.points[1][0] + X_SHIFT - 0.5 * TICK_SIZE + anchored_y = c.points[1][1] - Y_SHIFT + 0.5 * TICK_SIZE text_area = label.Label( font=terminalio.FONT, text=f"e{multiplier:+d}", @@ -209,7 +209,7 @@ def render_x_multiplier(g, c, multiplier): def render_y_multiplier(g, c, multiplier): minh = min(c.points[:][1]) - anchored_x = c.points[1][0] + X_SHIFT - .5 * TICK_SIZE + anchored_x = c.points[1][0] + X_SHIFT - 0.5 * TICK_SIZE anchored_y = minh - 2 * TICK_SIZE text_area = label.Label( font=terminalio.FONT, @@ -230,7 +230,10 @@ def render_non_finite_values(g, nan, neg_inf, pos_inf): color=TEXT_COLOR, line_spacing=0.8, anchor_point=(0.5, 1.0), - anchored_position=(board.DISPLAY.width // 2, board.DISPLAY.height - 1.5 * TICK_SIZE), + anchored_position=( + board.DISPLAY.width // 2, + board.DISPLAY.height - 1.5 * TICK_SIZE, + ), label_direction="LTR", ) g.append(text_area) @@ -342,7 +345,9 @@ def render_particle_value_value_label(g, particle_value): g.append(text_area) -def render_particle_value_line(plot, particle_value, bin_heights, width, rangex, rangey, facecolor): +def render_particle_value_line( + plot, particle_value, bin_heights, width, rangex, rangey, facecolor +): # To draw the particle value, we need to create a rectangle, the same # way we create the histogram bars @@ -389,18 +394,14 @@ def render_particle_value_line_label(g, c): def render_logo(g): # Add the Signaloid logo to the top right corner of the screen - bitmap = displayio.OnDiskBitmap( - open("assets/signaloid_logo_24x24.bmp", "rb") - ) + bitmap = displayio.OnDiskBitmap(open("assets/signaloid_logo_24x24.bmp", "rb")) sprite = displayio.TileGrid( bitmap, pixel_shader=bitmap.pixel_shader, width=1, height=1, ) - sprite.x = ( - board.DISPLAY.width - SIGNALOID_LOGO_SIZE - SIGNALOID_LOGO_MARGIN - ) + sprite.x = board.DISPLAY.width - SIGNALOID_LOGO_SIZE - SIGNALOID_LOGO_MARGIN sprite.y = SIGNALOID_LOGO_MARGIN g.append(sprite) @@ -442,17 +443,14 @@ def bar( render_bg_plot(g) plot = create_main_plot(g) - boundary_positions, boundary_multiplier = transform_array_with_multiplier(boundary_positions) + boundary_positions, boundary_multiplier = transform_array_with_multiplier( + boundary_positions + ) bin_heights, bin_heights_multiplier = transform_array_with_multiplier(bin_heights) width = apply_array_multiplier(width, boundary_multiplier) c, rangex, rangey = render_histogram( - plot, - boundary_positions, - bin_heights, - width, - align, - edgecolor + plot, boundary_positions, bin_heights, width, align, edgecolor ) render_x_multiplier(g, c, boundary_multiplier) @@ -463,7 +461,7 @@ def bar( g, plot_data.dist.nan_dirac_delta.mass, plot_data.dist.neg_inf_dirac_delta.mass, - plot_data.dist.pos_inf_dirac_delta.mass + plot_data.dist.pos_inf_dirac_delta.mass, ) render_title(g, title) @@ -472,11 +470,8 @@ def bar( render_y_axis_label(g) # Show the particle value - if ( - particle_value is not None - and np.isfinite(particle_value) - ): - particle_value_normalized = particle_value / (10 ** boundary_multiplier) + if particle_value is not None and np.isfinite(particle_value): + particle_value_normalized = particle_value / (10**boundary_multiplier) if ( particle_value_normalized >= rangex[0] and particle_value_normalized <= rangex[1] @@ -488,7 +483,7 @@ def bar( width, rangex, rangey, - facecolor + facecolor, ) render_particle_value_line_label(g, c) diff --git a/src/signaloid/distributional/__init__.py b/src/signaloid/distributional/__init__.py index c396678..5a50be9 100644 --- a/src/signaloid/distributional/__init__.py +++ b/src/signaloid/distributional/__init__.py @@ -1,4 +1,4 @@ from signaloid.distributional.distributional import DistributionalValue from signaloid.distributional.dirac_delta import DiracDelta -__all__ = ['DistributionalValue', 'DiracDelta'] +__all__ = ["DistributionalValue", "DiracDelta"] diff --git a/src/signaloid/distributional/dirac_delta.py b/src/signaloid/distributional/dirac_delta.py index d2fe185..00ea644 100644 --- a/src/signaloid/distributional/dirac_delta.py +++ b/src/signaloid/distributional/dirac_delta.py @@ -18,12 +18,11 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. +from __future__ import annotations import sys import math -if sys.implementation.name != 'circuitpython': - from typing import Optional - +if sys.implementation.name != "circuitpython": # Use numpy for accelerated computing import numpy as np else: @@ -36,10 +35,7 @@ class DiracDelta: def __init__( - self, - position: float, - raw_mass: Optional[int] = None, - mass: Optional[float] = None + self, position: float, raw_mass: int | None = None, mass: float | None = None ) -> None: """Initializes the Dirac Delta, given a position, and a mass in either a fixed-point or a floating point representation. If both representations @@ -50,10 +46,10 @@ def __init__( :type position: float :param raw_mass: The Dirac Delta mass in 64bit fixed-point representation, defaults to None. - :type raw_mass: Optional[int] + :type raw_mass: int | None :param mass: The Dirac Delta mass in floating-point representation, defaults to None. - :type mass: Optional[float] + :type mass: float | None """ self.position: float = position self._raw_mass: int = 0 @@ -124,8 +120,7 @@ def __add__(self, other: "DiracDelta") -> "DiracDelta": """ combined_mass: float = self.mass + other.mass combined_position: float = ( - self.position * self.mass - + other.position * other.mass + self.position * self.mass + other.position * other.mass ) / combined_mass return DiracDelta(position=combined_position, mass=combined_mass) diff --git a/src/signaloid/distributional/dirac_delta_test.py b/src/signaloid/distributional/dirac_delta_test.py index 3e39cc5..6f46ba8 100644 --- a/src/signaloid/distributional/dirac_delta_test.py +++ b/src/signaloid/distributional/dirac_delta_test.py @@ -67,10 +67,7 @@ def test_dirac_delta_operations(self) -> None: d3 = d1 + d2 combined_mass: float = 2.3 + 5.6 - combined_position: float = ( - 1.2 * 2.3 - + 4.5 * 5.6 - ) / combined_mass + combined_position: float = (1.2 * 2.3 + 4.5 * 5.6) / combined_mass self.assertTrue(d3.position == combined_position) self.assertTrue(d3.mass == combined_mass) diff --git a/src/signaloid/distributional/distributional.py b/src/signaloid/distributional/distributional.py index 0cda2ca..546fff0 100644 --- a/src/signaloid/distributional/distributional.py +++ b/src/signaloid/distributional/distributional.py @@ -18,17 +18,15 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. +from __future__ import annotations import math import sys import re import struct -if sys.implementation.name != 'circuitpython': - from typing import Optional, Union - +if sys.implementation.name != "circuitpython": # Use numpy for accelerated computing import numpy as np - from numpy.typing import NDArray else: # Use the extended version of ulab's numpy when running on CircuitPython from signaloid.circuitpython.extended_ulab_numpy import np # type: ignore[no-redef] @@ -57,37 +55,39 @@ "position_single": " None: - self.particle_value: Optional[float] = particle_value - self.UR_type: Optional[int] = UR_type - self._dirac_deltas: list[DiracDelta] = dirac_deltas if dirac_deltas is not None else [] + self.particle_value: float | None = particle_value + self.UR_type: int | None = UR_type + self._dirac_deltas: list[DiracDelta] = ( + dirac_deltas if dirac_deltas is not None else [] + ) self.double_precision = double_precision """ properties """ - self._mean: Optional[float] = None - self._variance: Optional[float] = None + self._mean: float | None = None + self._variance: float | None = None self.nan_dirac_delta: DiracDelta = DiracDelta(position=np.nan, mass=np.nan) self.neg_inf_dirac_delta: DiracDelta = DiracDelta(position=-np.inf, mass=np.nan) self.pos_inf_dirac_delta: DiracDelta = DiracDelta(position=np.inf, mass=np.nan) - self._has_no_zero_mass: Optional[bool] = None - self._is_finite: Optional[bool] = None - self._is_sorted: Optional[bool] = None - self._is_cured: Optional[bool] = None - self._is_full_valid_TTR: Optional[bool] = None + self._has_no_zero_mass: bool | None = None + self._is_finite: bool | None = None + self._is_sorted: bool | None = None + self._is_cured: bool | None = None + self._is_full_valid_TTR: bool | None = None @property def dirac_deltas(self) -> list[DiracDelta]: @@ -112,41 +112,47 @@ def finite_dirac_deltas(self) -> list[DiracDelta]: return self.dirac_deltas @property - def positions(self) -> NDArray[np.float64]: + def positions(self) -> np.ndarray: """The list af all the Dirac Delta positions. :return: The list of all the Dirac Delta positions. - :rtype: NDArray[np.float64] + :rtype: np.ndarray """ - arr: NDArray[np.float64] = np.array([dd.position for dd in self.dirac_deltas], dtype=np.float64) + arr: np.ndarray = np.array( + [dd.position for dd in self.dirac_deltas], dtype=np.float64 + ) return arr @property - def masses(self) -> NDArray[np.float64]: + def masses(self) -> np.ndarray: """The list af all the Dirac Delta floating-point masses. :return: The list of all the Dirac Delta floating-point masses. - :rtype: NDArray[np.float64] + :rtype: np.ndarray """ - arr: NDArray[np.float64] = np.array([dd.mass for dd in self.dirac_deltas], dtype=np.float64) + arr: np.ndarray = np.array( + [dd.mass for dd in self.dirac_deltas], dtype=np.float64 + ) return arr @property - def raw_masses(self) -> NDArray[np.uint64]: + def raw_masses(self) -> np.ndarray: """The list af all the Dirac Delta fixed-point masses. :return: The list of all the Dirac Delta fixed-point masses. - :rtype: NDArray[np.uint64] + :rtype: np.ndarray """ - arr: NDArray[np.uint64] = np.array([dd.raw_mass for dd in self.dirac_deltas], dtype=np.uint64) + arr: np.ndarray = np.array( + [dd.raw_mass for dd in self.dirac_deltas], dtype=np.uint64 + ) return arr @property - def mean(self) -> Optional[float]: + def mean(self) -> float | None: """The mean position of all the Dirac Deltas. :return: The mean position of all the Dirac Deltas. - :rtype: Optional[float] + :rtype: float | None """ if self._mean is None: self.calculate_mean() @@ -154,16 +160,16 @@ def mean(self) -> Optional[float]: return self._mean @mean.setter - def mean(self, mean: Optional[float]): + def mean(self, mean: float | None): """Sets the mean position of all the Dirac Deltas explicitly (it does not interfere with the Dirac Deltas list). :param mean: The mean value to use. - :type mean: Optional[float] + :type mean: float | None """ self._mean = mean - def calculate_mean(self) -> Optional[float]: + def calculate_mean(self) -> float | None: """Calculated the mean position of all the Dirac Deltas based on the Dirac Deltas list. @@ -199,38 +205,33 @@ def UR_order(self) -> int: return len(self.dirac_deltas) @property - def variance(self) -> Optional[float]: + def variance(self) -> float | None: """The positional variance of all the Dirac Deltas. :return: The positional variance of all the Dirac Deltas. - :rtype: Optional[float] + :rtype: float | None """ if self._variance is None: self.calculate_variance() return self._variance - def calculate_variance(self) -> Optional[float]: + def calculate_variance(self) -> float | None: """Calculates the positional variance of all the Dirac Deltas. :return: The calculated positional variance of all the Dirac Deltas. - :rtype: Optional[float] + :rtype: float | None """ # Calculate weighted sample variance - if ( - self.mean is None - or self.UR_order == 0 - or not np.isfinite(self.mean) - ): + if self.mean is None or self.UR_order == 0 or not np.isfinite(self.mean): self._variance = None else: total_mass: float = 0 total_weighted_squared_diffs: float = 0 for dd in self.dirac_deltas: total_weighted_squared_diffs += ( - ((dd.position - self.mean) ** 2) - * dd.mass - ) + (dd.position - self.mean) ** 2 + ) * dd.mass total_mass += dd.mass self._variance = total_weighted_squared_diffs / total_mass @@ -280,7 +281,7 @@ def __bytes__(self) -> bytes: result = self.export(to_str=False) return result if isinstance(result, bytes) else bytes() - def export(self, to_str: bool = True) -> Union[str, bytes]: + def export(self, to_str: bool = True) -> str | bytes: """ Constructs the Ux string/Ux bytes with particle value for the `DistributionalValue`. @@ -320,13 +321,17 @@ def export(self, to_str: bool = True) -> Union[str, bytes]: if to_str: # Particle value (double in string format) - UxString += str(self.particle_value) if self.particle_value is not None else "" + UxString += ( + str(self.particle_value) if self.particle_value is not None else "" + ) UxString += "Ux" fmt = STRUCT_FORMATS["str"] else: # Particle value (double) (8 bytes) - particle_value = self.particle_value if self.particle_value is not None else 0 + particle_value = ( + self.particle_value if self.particle_value is not None else 0 + ) fmt = STRUCT_FORMATS["bytes"] buffer += struct.pack(fmt["particle"], particle_value) @@ -344,7 +349,9 @@ def export(self, to_str: bool = True) -> Union[str, bytes]: buffer += struct.pack(fmt["UR_order"], self.UR_order) # Choose the format based on double_precision flag - position_format = fmt["position_double" if self.double_precision else "position_single"] + position_format = fmt[ + "position_double" if self.double_precision else "position_single" + ] # Pairs of: # - Support position (double or float) (8 or 4 bytes) @@ -363,9 +370,8 @@ def export(self, to_str: bool = True) -> Union[str, bytes]: @staticmethod def parse( - dist: Union[str, bytes], - double_precision: Optional[bool] = None - ) -> "Optional[DistributionalValue]": + dist: str | bytes, double_precision: bool | None = None + ) -> "DistributionalValue | None": """ Constructs a `DistributionalValue` after parsing an input that can be a UxString or a byte array. @@ -423,7 +429,7 @@ def parse( # Match an optional floating-point or integer number, followed by 'Ux', # and then hexadecimal characters - if sys.implementation.name == 'circuitpython': + if sys.implementation.name == "circuitpython": parts = dist.split("Ux") index = 0 if len(parts) == 2: @@ -432,12 +438,16 @@ def parse( buffer = bytes.fromhex(parts[index]) else: - pattern = r"^([-+]?\d*\.?\d+(?:e[-+]\d+)?|nan|[-+]?inf)?Ux([0-9A-Fa-f]+)$" + pattern = ( + r"^([-+]?\d*\.?\d+(?:e[-+]\d+)?|nan|[-+]?inf)?Ux([0-9A-Fa-f]+)$" + ) match = re.match(pattern, dist) if not match: return None - dist_value.particle_value = float(match.group(1)) if match.group(1) else None + dist_value.particle_value = ( + float(match.group(1)) if match.group(1) else None + ) buffer = bytes.fromhex(match.group(2)) elif isinstance(dist, (bytes, bytearray)): @@ -445,7 +455,9 @@ def parse( fmt = STRUCT_FORMATS["bytes"] buffer = dist - dist_value.particle_value = struct.unpack(fmt["particle"], buffer[offset:offset + 8])[0] + dist_value.particle_value = struct.unpack( + fmt["particle"], buffer[offset : offset + 8] + )[0] offset += 8 else: print("Error: ", type(dist)) @@ -457,26 +469,24 @@ def parse( if len(buffer) < min_length: return None - dist_value.UR_type = struct.unpack(fmt["UR_type"], buffer[offset:offset + 1])[0] + dist_value.UR_type = struct.unpack(fmt["UR_type"], buffer[offset : offset + 1])[ + 0 + ] offset += 1 # Not used, uncomment if needed # number_of_samples = struct.unpack(fmt["sample_count"], buffer[offset:offset + 8])[0] offset += 8 - dist_value.mean = struct.unpack(fmt["mean"], buffer[offset:offset + 8])[0] + dist_value.mean = struct.unpack(fmt["mean"], buffer[offset : offset + 8])[0] offset += 8 - UR_order = struct.unpack(fmt["UR_order"], buffer[offset:offset + 4])[0] + UR_order = struct.unpack(fmt["UR_order"], buffer[offset : offset + 4])[0] offset += 4 # Validate UR_order - reasonable upper limit to prevent processing # extremely large inputs that might be malicious - if ( - UR_order is None - or UR_order < 0 - or UR_order > 10000 - ): + if UR_order is None or UR_order < 0 or UR_order > 10000: return None # Calculate expected length based on UR_order @@ -497,14 +507,16 @@ def parse( if len(buffer) < expected_length: return None - position_format = fmt["position_double" if double_precision else "position_single"] + position_format = fmt[ + "position_double" if double_precision else "position_single" + ] for _ in range(UR_order): - support_position_bytes = buffer[offset:offset + bytes_per_position] + support_position_bytes = buffer[offset : offset + bytes_per_position] offset += bytes_per_position position = struct.unpack(position_format, support_position_bytes)[0] - mass_bytes = buffer[offset:offset + 8] + mass_bytes = buffer[offset : offset + 8] offset += 8 raw_mass = struct.unpack(fmt["mass"], mass_bytes)[0] @@ -545,7 +557,7 @@ def mean_relative_diff(self, other: "DistributionalValue") -> float: return abs((self.mean - other.mean) / other.mean) @property - def has_no_zero_mass(self) -> Optional[bool]: + def has_no_zero_mass(self) -> bool | None: """ The property that no Dirac delta of the `DistributionalValue` has a zero mass. @@ -557,7 +569,7 @@ def has_no_zero_mass(self) -> Optional[bool]: return self._has_no_zero_mass - def check_has_no_zero_mass(self) -> Optional[bool]: + def check_has_no_zero_mass(self) -> bool | None: """ Checks the property that no Dirac delta of the `DistributionalValue` has a zero mass. @@ -589,7 +601,7 @@ def drop_zero_mass_positions(self) -> None: self._has_no_zero_mass = True @property - def is_finite(self) -> Optional[bool]: + def is_finite(self) -> bool | None: """ The property that all Dirac deltas of the `DistributionalValue` have finite positions, i.e., no NaN, -Inf, or Inf values. @@ -603,7 +615,7 @@ def is_finite(self) -> Optional[bool]: return self._is_finite - def check_is_finite(self) -> Optional[bool]: + def check_is_finite(self) -> bool | None: """ Checks the property that all Dirac deltas of the `DistributionalValue` have finite positions, i.e., no NaN, -Inf, or Inf values. @@ -622,7 +634,7 @@ def check_is_finite(self) -> Optional[bool]: return True @property - def is_sorted(self) -> Optional[bool]: + def is_sorted(self) -> bool | None: """ The property that the Dirac deltas of the `DistributionalValue` are sorted according to their positions. The NaN, -Inf, and Inf positional values @@ -637,7 +649,7 @@ def is_sorted(self) -> Optional[bool]: return self._is_sorted - def check_is_sorted(self) -> Optional[bool]: + def check_is_sorted(self) -> bool | None: """ Checks The property that the Dirac deltas of the `DistributionalValue` are sorted according to their positions. The NaN, -Inf, and Inf positional values @@ -697,7 +709,7 @@ def sort(self) -> None: self._is_sorted = True @property - def is_cured(self) -> Optional[bool]: + def is_cured(self) -> bool | None: """ The property that no two Dirac deltas of the `DistributionalValue` have the same positional value, including NaN, -Inf, and Inf. @@ -711,7 +723,7 @@ def is_cured(self) -> Optional[bool]: return self._is_cured - def check_is_cured(self) -> Optional[bool]: + def check_is_cured(self) -> bool | None: """ Checks the property that no two Dirac deltas of the `DistributionalValue` have the same positional value, including NaN, -Inf, and Inf. @@ -773,9 +785,8 @@ def combine_dirac_deltas( mean_threshold = finite_mean * relative_mean_threshold range_threshold = ( - (self.finite_dirac_deltas[-1].position - self.dirac_deltas[0].position) - * relative_range_threshold - ) + self.finite_dirac_deltas[-1].position - self.dirac_deltas[0].position + ) * relative_range_threshold threshold = max(mean_threshold, range_threshold) @@ -797,7 +808,7 @@ def combine_dirac_deltas( self._is_cured = True @property - def is_full_valid_TTR(self) -> Optional[bool]: + def is_full_valid_TTR(self) -> bool | None: """ The property that the Dirac deltas of the `DistributionalValue` form a full valid TTR. "Full" means that there are 2^n Dirac deltas (after @@ -814,7 +825,7 @@ def is_full_valid_TTR(self) -> Optional[bool]: return self._is_full_valid_TTR - def check_is_full_valid_TTR(self) -> Optional[bool]: + def check_is_full_valid_TTR(self) -> bool | None: """ Checks the property that the Dirac deltas of the `DistributionalValue` form a full and valid TTR. "Full" means that there are 2^n Dirac deltas diff --git a/src/signaloid/distributional/distributional_test.py b/src/signaloid/distributional/distributional_test.py index 7e154f7..a3e97b6 100644 --- a/src/signaloid/distributional/distributional_test.py +++ b/src/signaloid/distributional/distributional_test.py @@ -18,27 +18,26 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. +from __future__ import annotations import csv -from typing import Optional import unittest - from signaloid.distributional.dirac_delta import DiracDelta from signaloid.distributional.distributional import DistributionalValue def read_string_bytes_pairs_from_csv( - csv_filename: str -) -> Optional[list[tuple[str, bytes]]]: + csv_filename: str, +) -> list[tuple[str, bytes]] | None: """ Reads pairs of Ux strings and Ux bytes(in hex format) from a csv file Args: csv_filename: The input csv file path Returns: - pairs: list of (string_value, bytearray_value) tuples + pairs: list of tuples of (string_value, bytearray_value) """ pairs: list[tuple[str, bytes]] = [] - with open(csv_filename, 'r') as csvfile: + with open(csv_filename, "r") as csvfile: reader = csv.reader(csvfile) for row in reader: if len(row) == 2: @@ -51,7 +50,7 @@ def read_string_bytes_pairs_from_csv( class TestUxParsing(unittest.TestCase): def test_parse_ux_strings_values( self, - input_filename: str = "src/signaloid/distributional/test_ux_value_pairs.csv" + input_filename: str = "src/signaloid/distributional/test_ux_value_pairs.csv", ) -> None: """ Test parsing Ux string values and converting them to Ux bytes @@ -71,7 +70,7 @@ def test_parse_ux_strings_values( def test_parse_ux_bytes_values( self, - input_filename: str = "src/signaloid/distributional/test_ux_value_pairs.csv" + input_filename: str = "src/signaloid/distributional/test_ux_value_pairs.csv", ) -> None: """ Test parsing Ux bytes and converting them to Ux strings @@ -94,150 +93,269 @@ def test_check_is_full_valid_TTR(self): Test checking DistributionalValues for Full & Valid TTR """ probabilitiesSlope = [ - 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.8, 0.7, 0.6, 0.5, 0.4, - 0.3, 0.2, 0.1 + 0.1, + 0.2, + 0.3, + 0.4, + 0.5, + 0.6, + 0.7, + 0.8, + 0.8, + 0.7, + 0.6, + 0.5, + 0.4, + 0.3, + 0.2, + 0.1, ] - dist = DistributionalValue(dirac_deltas=[ - DiracDelta(position=position, mass=mass) - for position, mass in enumerate(probabilitiesSlope) - ]) + dist = DistributionalValue( + dirac_deltas=[ + DiracDelta(position=position, mass=mass) + for position, mass in enumerate(probabilitiesSlope) + ] + ) self.assertFalse(dist.check_is_full_valid_TTR()) - dist = DistributionalValue(dirac_deltas=[ - DiracDelta(position=i, mass=0.1 * (i + 1)) - for i in range(16) - ]) + dist = DistributionalValue( + dirac_deltas=[DiracDelta(position=i, mass=0.1 * (i + 1)) for i in range(16)] + ) self.assertFalse(dist.check_is_full_valid_TTR()) - dist = DistributionalValue(dirac_deltas=[ - DiracDelta(position=i, mass=0.1) - for i in range(16) - ]) + dist = DistributionalValue( + dirac_deltas=[DiracDelta(position=i, mass=0.1) for i in range(16)] + ) self.assertTrue(dist.check_is_full_valid_TTR()) gaussianMotherTTR16Positions = [ - -2.2194097942437231, -1.5678879053053274, -1.1997100902860450, - -0.9205473016275229, -0.6859608829556935, -0.4772650338604341, - -0.2817093825097764, -0.0931705533484249, 0.0931705533484249, - 0.2817093825097764, 0.4772650338604341, 0.6859608829556935, - 0.9205473016275229, 1.1997100902860450, 1.5678879053053274, - 2.2194097942437231 + -2.2194097942437231, + -1.5678879053053274, + -1.1997100902860450, + -0.9205473016275229, + -0.6859608829556935, + -0.4772650338604341, + -0.2817093825097764, + -0.0931705533484249, + 0.0931705533484249, + 0.2817093825097764, + 0.4772650338604341, + 0.6859608829556935, + 0.9205473016275229, + 1.1997100902860450, + 1.5678879053053274, + 2.2194097942437231, ] gaussianMotherTTR16Probabilities = [ - 0.0339789420851602, 0.0520280112620429, 0.0601091352703015, - 0.0663526532241763, 0.0686569819948156, 0.0714941307381180, - 0.0732557829230397, 0.0741243625023456, 0.0741243625023456, - 0.0732557829230397, 0.0714941307381180, 0.0686569819948156, - 0.0663526532241763, 0.0601091352703015, 0.0520280112620429, - 0.0339789420851602 + 0.0339789420851602, + 0.0520280112620429, + 0.0601091352703015, + 0.0663526532241763, + 0.0686569819948156, + 0.0714941307381180, + 0.0732557829230397, + 0.0741243625023456, + 0.0741243625023456, + 0.0732557829230397, + 0.0714941307381180, + 0.0686569819948156, + 0.0663526532241763, + 0.0601091352703015, + 0.0520280112620429, + 0.0339789420851602, ] - dist = DistributionalValue(dirac_deltas=[ - DiracDelta(position=position, mass=mass) - for position, mass in zip( - gaussianMotherTTR16Positions, - gaussianMotherTTR16Probabilities - ) - ]) + dist = DistributionalValue( + dirac_deltas=[ + DiracDelta(position=position, mass=mass) + for position, mass in zip( + gaussianMotherTTR16Positions, gaussianMotherTTR16Probabilities + ) + ] + ) self.assertTrue(dist.check_is_full_valid_TTR()) exponentialMotherTTR16Positions = [ - 0.0463101200943282, 0.1434539976121732, 0.2473298485428934, - 0.3589406008993048, 0.4795601941139194, 0.6107690295987392, - 0.7545735507649249, 0.9136511262522184, 1.0940956889209921, - 1.3020972163662070, 1.5437301020205228, 1.8320038271142292, - 2.1944919248629803, 2.6809449590891815, 3.4180232931306736, - 5.0000000000000000 + 0.0463101200943282, + 0.1434539976121732, + 0.2473298485428934, + 0.3589406008993048, + 0.4795601941139194, + 0.6107690295987392, + 0.7545735507649249, + 0.9136511262522184, + 1.0940956889209921, + 1.3020972163662070, + 1.5437301020205228, + 1.8320038271142292, + 2.1944919248629803, + 2.6809449590891815, + 3.4180232931306736, + 5.0000000000000000, ] exponentialMotherTTR16Probabilities = [ - 0.0898043375672398, 0.0869428363237056, 0.0839866334859530, - 0.0809192993370894, 0.0777683023008333, 0.0744401048312553, - 0.0709620923605228, 0.0672969526219585, 0.0650216515596327, - 0.0606655024127962, 0.0559943437573481, 0.0508626602050525, - 0.0462377199658062, 0.0393104949029426, 0.0314714294791298, - 0.0183156388887342 + 0.0898043375672398, + 0.0869428363237056, + 0.0839866334859530, + 0.0809192993370894, + 0.0777683023008333, + 0.0744401048312553, + 0.0709620923605228, + 0.0672969526219585, + 0.0650216515596327, + 0.0606655024127962, + 0.0559943437573481, + 0.0508626602050525, + 0.0462377199658062, + 0.0393104949029426, + 0.0314714294791298, + 0.0183156388887342, ] - dist = DistributionalValue(dirac_deltas=[ - DiracDelta(position=position, mass=mass) - for position, mass in zip( - exponentialMotherTTR16Positions, - exponentialMotherTTR16Probabilities - ) - ]) + dist = DistributionalValue( + dirac_deltas=[ + DiracDelta(position=position, mass=mass) + for position, mass in zip( + exponentialMotherTTR16Positions, exponentialMotherTTR16Probabilities + ) + ] + ) self.assertTrue(dist.check_is_full_valid_TTR()) laplaceMotherTTR16Positions = [ - -4.0000000000000000, -2.4180232931306736, -1.6809449590891815, - -1.1944919248629803, -0.8320038271142292, -0.5437301020205228, - -0.3020972163662070, -0.0940956889209921, 0.0940956889209921, - 0.3020972163662070, 0.5437301020205228, 0.8320038271142292, - 1.1944919248629803, 1.6809449590891815, 2.4180232931306736, - 4.0000000000000000 + -4.0000000000000000, + -2.4180232931306736, + -1.6809449590891815, + -1.1944919248629803, + -0.8320038271142292, + -0.5437301020205228, + -0.3020972163662070, + -0.0940956889209921, + 0.0940956889209921, + 0.3020972163662070, + 0.5437301020205228, + 0.8320038271142292, + 1.1944919248629803, + 1.6809449590891815, + 2.4180232931306736, + 4.0000000000000000, ] laplaceMotherTTR16Probabilities = [ - 0.0248935341839320, 0.0427741074343744, 0.0534285019812003, - 0.0628435769862145, 0.0691295224912407, 0.0761042035660443, - 0.0824529664115212, 0.0883735869454727, 0.0883735869454727, - 0.0824529664115212, 0.0761042035660443, 0.0691295224912407, - 0.0628435769862145, 0.0534285019812003, 0.0427741074343744, - 0.0248935341839320 + 0.0248935341839320, + 0.0427741074343744, + 0.0534285019812003, + 0.0628435769862145, + 0.0691295224912407, + 0.0761042035660443, + 0.0824529664115212, + 0.0883735869454727, + 0.0883735869454727, + 0.0824529664115212, + 0.0761042035660443, + 0.0691295224912407, + 0.0628435769862145, + 0.0534285019812003, + 0.0427741074343744, + 0.0248935341839320, ] - dist = DistributionalValue(dirac_deltas=[ - DiracDelta(position=position, mass=mass) - for position, mass in zip( - laplaceMotherTTR16Positions, - laplaceMotherTTR16Probabilities - ) - ]) + dist = DistributionalValue( + dirac_deltas=[ + DiracDelta(position=position, mass=mass) + for position, mass in zip( + laplaceMotherTTR16Positions, laplaceMotherTTR16Probabilities + ) + ] + ) self.assertTrue(dist.check_is_full_valid_TTR()) logisticMotherTTR16Positions = [ - -4.5562387049543025, -2.9418421436602556, -2.1587856510880987, - -1.6144447065491812, -1.1828706566397532, -0.8138506279227880, - -0.4770709791304498, -0.1572607957522052, 0.1572607957522052, - 0.4770709791304498, 0.8138506279227880, 1.1828706566397532, - 1.6144447065491812, 2.1587856510880987, 2.9418421436602556, - 4.5562387049543025 + -4.5562387049543025, + -2.9418421436602556, + -2.1587856510880987, + -1.6144447065491812, + -1.1828706566397532, + -0.8138506279227880, + -0.4770709791304498, + -0.1572607957522052, + 0.1572607957522052, + 0.4770709791304498, + 0.8138506279227880, + 1.1828706566397532, + 1.6144447065491812, + 2.1587856510880987, + 2.9418421436602556, + 4.5562387049543025, ] logisticMotherTTR16Probabilities = [ - 0.0281433474818693, 0.0475738959372374, 0.0580005680032459, - 0.0662821885776473, 0.0702935070589577, 0.0743920703246041, - 0.0770073268795160, 0.0783070957369223, 0.0783070957369223, - 0.0770073268795160, 0.0743920703246041, 0.0702935070589577, - 0.0662821885776473, 0.0580005680032459, 0.0475738959372374, - 0.0281433474818693 + 0.0281433474818693, + 0.0475738959372374, + 0.0580005680032459, + 0.0662821885776473, + 0.0702935070589577, + 0.0743920703246041, + 0.0770073268795160, + 0.0783070957369223, + 0.0783070957369223, + 0.0770073268795160, + 0.0743920703246041, + 0.0702935070589577, + 0.0662821885776473, + 0.0580005680032459, + 0.0475738959372374, + 0.0281433474818693, ] - dist = DistributionalValue(dirac_deltas=[ - DiracDelta(position=position, mass=mass) - for position, mass in zip( - logisticMotherTTR16Positions, - logisticMotherTTR16Probabilities - ) - ]) + dist = DistributionalValue( + dirac_deltas=[ + DiracDelta(position=position, mass=mass) + for position, mass in zip( + logisticMotherTTR16Positions, logisticMotherTTR16Probabilities + ) + ] + ) self.assertTrue(dist.check_is_full_valid_TTR()) gumbel1MotherTTR16Positions = [ - -1.3722373849766128, -0.9285915299813774, -0.6394795296057504, - -0.3977265029274728, -0.1773165596233781, 0.0336306411453416, - 0.2453949715783402, 0.4637578398478052, 0.6941280516995109, - 0.9432140395136739, 1.2205265612985903, 1.5396243403711020, - 1.9288304844468449, 2.4378800713555984, 3.1930831163570588, - 4.7879260278453658 + -1.3722373849766128, + -0.9285915299813774, + -0.6394795296057504, + -0.3977265029274728, + -0.1773165596233781, + 0.0336306411453416, + 0.2453949715783402, + 0.4637578398478052, + 0.6941280516995109, + 0.9432140395136739, + 1.2205265612985903, + 1.5396243403711020, + 1.9288304844468449, + 2.4378800713555984, + 3.1930831163570588, + 4.7879260278453658, ] gumbel1MotherTTR16Probabilities = [ - 0.0476295697963972, 0.0667881624671499, 0.0730630564420902, - 0.0772153676471943, 0.0768815694664325, 0.0772987007741402, - 0.0765686001679291, 0.0749309749136895, 0.0721865495667472, - 0.0689189559863393, 0.0648623956919026, 0.0599040616210838, - 0.0552629494040690, 0.0475407218497456, 0.0384337406899792, - 0.0225146235151103 + 0.0476295697963972, + 0.0667881624671499, + 0.0730630564420902, + 0.0772153676471943, + 0.0768815694664325, + 0.0772987007741402, + 0.0765686001679291, + 0.0749309749136895, + 0.0721865495667472, + 0.0689189559863393, + 0.0648623956919026, + 0.0599040616210838, + 0.0552629494040690, + 0.0475407218497456, + 0.0384337406899792, + 0.0225146235151103, ] - dist = DistributionalValue(dirac_deltas=[ - DiracDelta(position=position, mass=mass) - for position, mass in zip( - gumbel1MotherTTR16Positions, - gumbel1MotherTTR16Probabilities - ) - ]) + dist = DistributionalValue( + dirac_deltas=[ + DiracDelta(position=position, mass=mass) + for position, mass in zip( + gumbel1MotherTTR16Positions, gumbel1MotherTTR16Probabilities + ) + ] + ) self.assertTrue(dist.check_is_full_valid_TTR()) diff --git a/src/signaloid/distributional_information_plotting/plot_histogram_dirac_deltas.py b/src/signaloid/distributional_information_plotting/plot_histogram_dirac_deltas.py index 027b533..5110306 100644 --- a/src/signaloid/distributional_information_plotting/plot_histogram_dirac_deltas.py +++ b/src/signaloid/distributional_information_plotting/plot_histogram_dirac_deltas.py @@ -18,15 +18,13 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. +from __future__ import annotations import sys import math -if sys.implementation.name != 'circuitpython': - from typing import Optional - +if sys.implementation.name != "circuitpython": # Use numpy for accelerated computing import numpy as np - from numpy.typing import NDArray else: # Use the extended version of ulab's numpy when running on CircuitPython from signaloid.circuitpython.extended_ulab_numpy import np # type: ignore[no-redef] @@ -37,62 +35,57 @@ class PlotData: def __init__( - self, - dist: DistributionalValue, - plotting_resolution: Optional[int] = None + self, dist: DistributionalValue, plotting_resolution: int | None = None ) -> None: - if ( - dist.mean is None - or dist.UR_order == 0 - ): + if dist.mean is None or dist.UR_order == 0: raise ValueError("Failed to load data") self.dist = dist - self.plotting_resolution: Optional[int] = plotting_resolution - self.plotting_ttr_order: Optional[int] = None + self.plotting_resolution: int | None = plotting_resolution + self.plotting_ttr_order: int | None = None - self._positions: NDArray[np.float64] = np.array([], dtype=np.float64) - self._masses: NDArray[np.float64] = np.array([], dtype=np.float64) - self._widths: NDArray[np.float64] = np.array([], dtype=np.float64) - self._max_value: Optional[float] = None + self._positions: np.ndarray = np.array([], dtype=np.float64) + self._masses: np.ndarray = np.array([], dtype=np.float64) + self._widths: np.ndarray = np.array([], dtype=np.float64) + self._max_value: float | None = None self._construct_plot_data() @property - def positions(self) -> NDArray[np.float64]: + def positions(self) -> np.ndarray: """The boundary positions list. :return: The boundary positions list. - :rtype: NDArray[np.float64] + :rtype: np.ndarray """ return self._positions @positions.setter - def positions(self, positions: NDArray[np.float64]) -> None: + def positions(self, positions: np.ndarray) -> None: """Sets the boundary positions list, resetting the widths to avoid faulty values. :param positions: The boundary positions list to use - :type positions: NDArray[np.float64] + :type positions: np.ndarray """ self._positions = positions self._widths = np.array([], dtype=np.float64) @property - def masses(self) -> NDArray[np.float64]: + def masses(self) -> np.ndarray: """The bin heights list. :return: The bin heights list. - :rtype: NDArray[np.float64] + :rtype: np.ndarray """ return self._masses @masses.setter - def masses(self, masses: NDArray[np.float64]) -> None: + def masses(self, masses: np.ndarray) -> None: """Sets the bin heights list, resetting the max value to avoid faulty value. :param masses: The bin heights list to use. - :type masses: NDArray[np.float64] + :type masses: np.ndarray """ self._masses = masses self._max_value = None @@ -144,11 +137,11 @@ def max_value(self) -> float: return self._max_value @property - def widths(self) -> NDArray[np.float64]: + def widths(self) -> np.ndarray: """The widths list between each pair of positions. :return: The widths list. - :rtype: NDArray[np.float64] + :rtype: np.ndarray """ if not self._widths.size > 0: self._widths = self.positions[1:] - self.positions[:-1] @@ -159,8 +152,8 @@ def widths(self) -> NDArray[np.float64]: def _determine_boundary_positions( finite_sorted_dirac_deltas: list[DiracDelta], exponent: int, - use_ttr_binning: bool - ) -> tuple[NDArray[np.float64], NDArray[np.float64]]: + use_ttr_binning: bool, + ) -> tuple[np.ndarray, np.ndarray]: """ If `use_ttr_binning` is true: Determines the internal boundary positions (and probabilities) using the @@ -204,8 +197,7 @@ def _determine_boundary_positions( step = 2**n for i in range(2 ** (n + 1), number_of_boundaries - 1, 2 ** (n + 2)): boundary_probabilities[i] = ( - boundary_probabilities[i - step] - + boundary_probabilities[i + step] + boundary_probabilities[i - step] + boundary_probabilities[i + step] ) boundary_positions[i] = ( boundary_probabilities[i - step] * boundary_positions[i - step] @@ -232,12 +224,12 @@ def _determine_boundary_positions( @staticmethod def _handle_extremal_bins( finite_sorted_dirac_deltas: list[DiracDelta], - boundary_positions: NDArray[np.float64], - boundary_probabilities: NDArray[np.float64], - bin_widths: NDArray[np.float64], - bin_heights: NDArray[np.float64], + boundary_positions: np.ndarray, + boundary_probabilities: np.ndarray, + bin_widths: np.ndarray, + bin_heights: np.ndarray, left: bool = True, - ) -> tuple[NDArray[np.float64], NDArray[np.float64], NDArray[np.float64]]: + ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: """ Checking if (d/dx)^2 = 0 boundary condition has a solution. If not, falling back to the boundary condition d/dx = 0. @@ -282,40 +274,35 @@ def _handle_extremal_bins( elif any(roots_positive): w0 = max(root1, root2) - if ( - w0 is None - or math.isinf(det) - or math.isnan(det) - ): + if w0 is None or math.isinf(det) or math.isnan(det): # The boundary condition d/dx = 0. - boundary_positions[0 if left else -1] = ( - boundary_positions[1 if left else -2] - + (-1 if left else 1) * ( - boundary_positions[2 if left else -2] - - boundary_positions[1 if left else -3] - ) + boundary_positions[0 if left else -1] = boundary_positions[ + 1 if left else -2 + ] + (-1 if left else 1) * ( + boundary_positions[2 if left else -2] + - boundary_positions[1 if left else -3] ) else: # The boundary condition (d/dx)^2 = 0. boundary_positions[0 if left else -1] = ( - boundary_positions[1 if left else -2] - + (-1 if left else 1) * w0 + boundary_positions[1 if left else -2] + (-1 if left else 1) * w0 ) bin_widths[0 if left else -1] = ( boundary_positions[1 if left else -1] - boundary_positions[0 if left else -2] ) - averageHeight = ( - finite_sorted_dirac_deltas[0 if left else -1].mass - / (bin_widths[0 if left else -1] + bin_widths[1 if left else -2]) + averageHeight = finite_sorted_dirac_deltas[0 if left else -1].mass / ( + bin_widths[0 if left else -1] + bin_widths[1 if left else -2] ) bin_heights[0 if left else -1] = ( - averageHeight * bin_widths[1 if left else -2] + averageHeight + * bin_widths[1 if left else -2] / bin_widths[0 if left else -1] ) bin_heights[1 if left else -2] = ( - averageHeight * bin_widths[0 if left else -1] + averageHeight + * bin_widths[0 if left else -1] / bin_widths[1 if left else -2] ) @@ -324,9 +311,9 @@ def _handle_extremal_bins( @staticmethod def _get_binning( finite_sorted_dirac_deltas: list[DiracDelta], - boundary_positions: NDArray[np.float64], - boundary_probabilities: NDArray[np.float64] - ) -> tuple[NDArray[np.float64], NDArray[np.float64], NDArray[np.float64]]: + boundary_positions: np.ndarray, + boundary_probabilities: np.ndarray, + ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: """ Finds the binning for the given finite and sorted Dirac deltas and the calculated internal boundary positions and probabilities. @@ -383,10 +370,10 @@ def _get_binning( @staticmethod def _create_binning( - finite_sorted_dirac_deltas: list[DiracDelta], - exponent: int, - use_ttr_binning: bool - ) -> tuple[NDArray[np.float64], NDArray[np.float64], NDArray[np.float64]]: + finite_sorted_dirac_deltas: list[DiracDelta], + exponent: int, + use_ttr_binning: bool, + ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: """ - If `use_ttr_binning` is true: Creates a binning using the TTR binning method. The TTR binning method @@ -411,7 +398,10 @@ def _create_binning( bin widths, and bin heights that describe the output binning. """ - boundary_positions, boundary_probabilities = PlotData._determine_boundary_positions( + ( + boundary_positions, + boundary_probabilities, + ) = PlotData._determine_boundary_positions( finite_sorted_dirac_deltas, exponent, use_ttr_binning ) @@ -423,9 +413,7 @@ def _create_binning( @staticmethod def _bin_pdf_expected_dirac_delta( - boundary_positions: NDArray[np.float64], - bin_widths: NDArray[np.float64], - bin_heights: NDArray[np.float64] + boundary_positions: np.ndarray, bin_widths: np.ndarray, bin_heights: np.ndarray ) -> DiracDelta: """ Computes the expected Dirac delta of an input bin PDF. @@ -448,16 +436,18 @@ def _bin_pdf_expected_dirac_delta( probability * (boundary_positions[i + 1] + boundary_positions[i]) / 2 ) - expected_dirac_delta = DiracDelta(moment_sum / probability_sum, mass=probability_sum) + expected_dirac_delta = DiracDelta( + moment_sum / probability_sum, mass=probability_sum + ) return expected_dirac_delta @staticmethod def _bin_pdf_to_ttr( - boundary_positions: NDArray[np.float64], - bin_widths: NDArray[np.float64], - bin_heights: NDArray[np.float64], - order: int + boundary_positions: np.ndarray, + bin_widths: np.ndarray, + bin_heights: np.ndarray, + order: int, ) -> list[DiracDelta]: """ Computes TTR for an input bin PDF. @@ -480,12 +470,12 @@ def _bin_pdf_to_ttr( if order == 0: return [expected_dirac_delta] - low_boundary_positions: NDArray[np.float64] = np.array([], dtype=np.float64) - low_bin_widths: NDArray[np.float64] = np.array([], dtype=np.float64) - low_bin_heights: NDArray[np.float64] = np.array([], dtype=np.float64) - high_boundary_positions: NDArray[np.float64] = np.array([], dtype=np.float64) - high_bin_widths: NDArray[np.float64] = np.array([], dtype=np.float64) - high_bin_heights: NDArray[np.float64] = np.array([], dtype=np.float64) + low_boundary_positions: np.ndarray = np.array([], dtype=np.float64) + low_bin_widths: np.ndarray = np.array([], dtype=np.float64) + low_bin_heights: np.ndarray = np.array([], dtype=np.float64) + high_boundary_positions: np.ndarray = np.array([], dtype=np.float64) + high_bin_widths: np.ndarray = np.array([], dtype=np.float64) + high_bin_heights: np.ndarray = np.array([], dtype=np.float64) for i, boundary_position in enumerate(boundary_positions): if boundary_position == expected_dirac_delta.position: @@ -544,7 +534,9 @@ def _construct_plot_data(self) -> None: return if len(finite_dirac_deltas) == 1: - self.positions = np.array([finite_dirac_deltas[0].position], dtype=np.float64) + self.positions = np.array( + [finite_dirac_deltas[0].position], dtype=np.float64 + ) self.masses = np.array([finite_dirac_deltas[0].mass], dtype=np.float64) return @@ -558,9 +550,8 @@ def _construct_plot_data(self) -> None: log2_of_plotting_resolution = self.plotting_resolution.bit_length() - 1 self.plotting_ttr_order = log2_of_plotting_resolution - 1 - if ( - self.plotting_resolution > 2 - and self.plotting_resolution > 2 ** (self.plotting_ttr_order + 1) + if self.plotting_resolution > 2 and self.plotting_resolution > 2 ** ( + self.plotting_ttr_order + 1 ): raise ValueError( "plot_histogram_dirac_deltas: plotting_resolution must be a power of 2!" diff --git a/src/signaloid/distributional_information_plotting/plot_histogram_dirac_deltas_test.py b/src/signaloid/distributional_information_plotting/plot_histogram_dirac_deltas_test.py index 3e1e288..8010b8d 100644 --- a/src/signaloid/distributional_information_plotting/plot_histogram_dirac_deltas_test.py +++ b/src/signaloid/distributional_information_plotting/plot_histogram_dirac_deltas_test.py @@ -24,7 +24,9 @@ import numpy as np from signaloid.distributional.dirac_delta import DiracDelta -from signaloid.distributional_information_plotting.plot_histogram_dirac_deltas import PlotData +from signaloid.distributional_information_plotting.plot_histogram_dirac_deltas import ( + PlotData, +) class TestCreateBinning(unittest.TestCase): @@ -55,8 +57,7 @@ def test_create_binning_property_dirac_deltas_average_of_bins(self) -> None: dirac_deltas = [ DiracDelta(position, mass=mass) - for position, mass in - zip(dirac_delta_positions, dirac_delta_masses) + for position, mass in zip(dirac_delta_positions, dirac_delta_masses) ] dirac_deltas.sort() @@ -69,21 +70,26 @@ def test_create_binning_property_dirac_deltas_average_of_bins(self) -> None: for j in range(number_of_dirac_deltas[i]): probability_under_first_bin = bin_widths[2 * j] * bin_heights[2 * j] - probability_under_second_bin = bin_widths[2 * j + 1] * bin_heights[2 * j + 1] - probability_under_bins = probability_under_first_bin + probability_under_second_bin + probability_under_second_bin = ( + bin_widths[2 * j + 1] * bin_heights[2 * j + 1] + ) + probability_under_bins = ( + probability_under_first_bin + probability_under_second_bin + ) mean_of_first_bin = boundary_positions[2 * j] + bin_widths[2 * j] / 2 - mean_of_second_bin = boundary_positions[2 * j + 1] + bin_widths[2 * j + 1] / 2 + mean_of_second_bin = ( + boundary_positions[2 * j + 1] + bin_widths[2 * j + 1] / 2 + ) mean_of_bins = ( - mean_of_first_bin * probability_under_first_bin + - mean_of_second_bin * probability_under_second_bin + mean_of_first_bin * probability_under_first_bin + + mean_of_second_bin * probability_under_second_bin ) / probability_under_bins self.assertLess( abs(input_ensemble[j].mass - probability_under_bins), - probability_threshold + probability_threshold, ) self.assertLess( - abs(input_ensemble[j].position - mean_of_bins), - position_threshold + abs(input_ensemble[j].position - mean_of_bins), position_threshold ) def test_create_binning_property_preserve_ttr(self) -> None: @@ -103,24 +109,23 @@ def test_create_binning_property_preserve_ttr(self) -> None: for i in range(number_of_testcases): gaussian_mean = np.random.uniform(*gaussian_mean_range) - gaussian_standard_deviation = np.random.uniform(*gaussian_standard_deviation_range) + gaussian_standard_deviation = np.random.uniform( + *gaussian_standard_deviation_range + ) dirac_delta_positions = np.random.normal( gaussian_mean, gaussian_standard_deviation, number_of_samples ) - dirac_delta_masses = [1/number_of_samples] * number_of_samples + dirac_delta_masses = [1 / number_of_samples] * number_of_samples ttr_order = random.sample(range(4, 11), 1)[0] input_dirac_deltas = [ DiracDelta(position, mass=mass) - for position, mass in - zip(dirac_delta_positions, dirac_delta_masses) + for position, mass in zip(dirac_delta_positions, dirac_delta_masses) ] - input_ttr_dirac_deltas = dirac_deltas_to_ttr( - input_dirac_deltas, ttr_order - ) + input_ttr_dirac_deltas = dirac_deltas_to_ttr(input_dirac_deltas, ttr_order) - if len(input_ttr_dirac_deltas) != 2 ** ttr_order: + if len(input_ttr_dirac_deltas) != 2**ttr_order: continue ttr_orders.append(ttr_order) input_ttrs.append(input_ttr_dirac_deltas) @@ -133,33 +138,29 @@ def test_create_binning_property_preserve_ttr(self) -> None: ) binning_dirac_deltas: list[DiracDelta] = [] - for position, width, height in zip(boundary_positions[:-1], bin_widths, bin_heights): - binning_dirac_deltas.append(DiracDelta( - position=position + width / 2, - mass=width * height - )) - - binning_ttr = dirac_deltas_to_ttr( - binning_dirac_deltas, exponent - ) + for position, width, height in zip( + boundary_positions[:-1], bin_widths, bin_heights + ): + binning_dirac_deltas.append( + DiracDelta(position=position + width / 2, mass=width * height) + ) + + binning_ttr = dirac_deltas_to_ttr(binning_dirac_deltas, exponent) self.assertEqual(len(input_ttr), len(binning_ttr)) for input_ttr_dd, binning_ttr_dd in zip(input_ttr, binning_ttr): self.assertLess( - abs(input_ttr_dd.mass - binning_ttr_dd.mass), - probability_threshold + abs(input_ttr_dd.mass - binning_ttr_dd.mass), probability_threshold ) self.assertLess( abs(input_ttr_dd.position - binning_ttr_dd.position), - position_threshold + position_threshold, ) def dirac_deltas_to_ttr( - dirac_deltas: list[DiracDelta], - order: int, - count: int = 0 + dirac_deltas: list[DiracDelta], order: int, count: int = 0 ) -> list[DiracDelta]: """ Computes the TTR for an input ensemble of Dirac deltas. @@ -198,7 +199,9 @@ def dirac_deltas_to_ttr( current_dirac_delta = [DiracDelta(average_position, mass=total_mass)] low_dirac_deltas = [dd for dd in dirac_deltas if dd.position < average_position] - high_dirac_deltas = [dd for dd in dirac_deltas if dd.position >= average_position] + high_dirac_deltas = [ + dd for dd in dirac_deltas if dd.position >= average_position + ] ttr: list[DiracDelta] = [] if order > 0: diff --git a/src/signaloid/distributional_information_plotting/plot_wrapper.py b/src/signaloid/distributional_information_plotting/plot_wrapper.py index 3809d83..8911208 100644 --- a/src/signaloid/distributional_information_plotting/plot_wrapper.py +++ b/src/signaloid/distributional_information_plotting/plot_wrapper.py @@ -24,13 +24,12 @@ import matplotlib import matplotlib.pyplot as plt -from signaloid.distributional_information_plotting.plot_histogram_dirac_deltas import PlotData +from signaloid.distributional_information_plotting.plot_histogram_dirac_deltas import ( + PlotData, +) -def printv( - verbose: bool, - formatString: str, - *args) -> None: +def printv(verbose: bool, formatString: str, *args) -> None: """ A wrapper for `print()` that allows for controlled verbosity. @@ -94,7 +93,9 @@ def plot( ncols=2 if plot_data.dist.has_special_values else 1, sharey=False, figsize=(10 + (3 if plot_data.dist.has_special_values else 0), 6), - gridspec_kw={"width_ratios": [4.2, 1]} if plot_data.dist.has_special_values else None, + gridspec_kw=( + {"width_ratios": [4.2, 1]} if plot_data.dist.has_special_values else None + ), ) if not plot_data.dist.has_special_values: @@ -111,11 +112,7 @@ def plot( text="", xy=(plot_data.positions[0], plot_data.masses[0]), xytext=(plot_data.positions[0], 0), - arrowprops={ - "arrowstyle": "->", - "facecolor": "black", - "lw": 3 - }, + arrowprops={"arrowstyle": "->", "facecolor": "black", "lw": 3}, ) else: # Plot the binning. @@ -126,7 +123,7 @@ def plot( align="edge", edgecolor="#33A333", facecolor="#33A333" + "40", - hatch="\\" + hatch="\\", ) # Default kwargs for plt.annotate @@ -157,11 +154,7 @@ def plot( if plot_data.dist.has_special_values: fig.sca(axes[1]) plt.bar( - x=[ - "NaN", - "-Inf", - "Inf" - ], + x=["NaN", "-Inf", "Inf"], height=[ plot_data.dist.nan_dirac_delta.mass, plot_data.dist.neg_inf_dirac_delta.mass, diff --git a/src/signaloid/distributional_information_plotting/plot_wrapper_test.py b/src/signaloid/distributional_information_plotting/plot_wrapper_test.py index e9b262f..87edcd0 100644 --- a/src/signaloid/distributional_information_plotting/plot_wrapper_test.py +++ b/src/signaloid/distributional_information_plotting/plot_wrapper_test.py @@ -18,22 +18,21 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. +from __future__ import annotations import csv import os import shutil import tempfile -from typing import Optional import unittest - from signaloid.distributional.distributional import DistributionalValue -from signaloid.distributional_information_plotting.plot_histogram_dirac_deltas import PlotData +from signaloid.distributional_information_plotting.plot_histogram_dirac_deltas import ( + PlotData, +) from .plot_wrapper import plot -def read_ux_strings_from_csv( - csv_filename: str -) -> Optional[list[str]]: +def read_ux_strings_from_csv(csv_filename: str) -> list[str] | None: """ Reads Ux strings from a csv file @@ -43,7 +42,7 @@ def read_ux_strings_from_csv( ux_strings: list of Ux strings """ ux_strings: list[str] = [] - with open(csv_filename, 'r') as csvfile: + with open(csv_filename, "r") as csvfile: reader = csv.reader(csvfile) for row in reader: ux_strings.append(row[0]) @@ -62,7 +61,7 @@ def tearDown(self) -> None: def test_plot_wrapper( self, - input_filename: str = "src/signaloid/distributional/test_ux_value_pairs.csv" + input_filename: str = "src/signaloid/distributional/test_ux_value_pairs.csv", ) -> None: """ Test parsing and plotting Ux Strings @@ -85,9 +84,11 @@ def test_plot_wrapper( plot_data = PlotData(distValue) self.assertIsNotNone(plot_data, "Failed to parse data") - filepath = os.path.join(self.test_dir, f'file{i}.png') + filepath = os.path.join(self.test_dir, f"file{i}.png") plot(plot_data, path=filepath, save=True) - self.assertTrue(os.path.exists(filepath), f"File was not created: {filepath}") + self.assertTrue( + os.path.exists(filepath), f"File was not created: {filepath}" + ) if __name__ == "__main__": diff --git a/src/signaloid/uxdata_toolkit.py b/src/signaloid/uxdata_toolkit.py index f811715..553756e 100644 --- a/src/signaloid/uxdata_toolkit.py +++ b/src/signaloid/uxdata_toolkit.py @@ -38,15 +38,16 @@ import matplotlib.pyplot as plt from signaloid.distributional.distributional import DistributionalValue -from signaloid.distributional_information_plotting.plot_histogram_dirac_deltas import \ - PlotData +from signaloid.distributional_information_plotting.plot_histogram_dirac_deltas import ( + PlotData, +) from signaloid.distributional_information_plotting.plot_wrapper import plot def parse_arguments() -> argparse.Namespace: # Create the parser parser = argparse.ArgumentParser( - description='Set of tools for working with Signaloid Ux data.' + description="Set of tools for working with Signaloid Ux data." ) command_subparsers = parser.add_subparsers( @@ -73,18 +74,19 @@ def command_plot_parser(command_subparsers: Any) -> None: %(prog)s 0.40007Ux0000000000000000013FD99AC12423C7C7000000013FD99AC12423C7C78000000000000000 %(prog)s 09168733bf9ad93f000100000000000000c7c72324c19ad93f01000000c7c72324c19ad93f0000000000000080 %(prog)s -o output.png 0.40007Ux0000000000000000013FD99AC12423C7C7000000013FD99AC12423C7C78000000000000000 - """ + """, ) plot_parser.add_argument( - '-o', '--output', + "-o", + "--output", type=str, - default='plot.png', - help='Output PNG filename (default: plot.png)' + default="plot.png", + help="Output PNG filename (default: plot.png)", ) plot_parser.add_argument( - 'ux_data', + "ux_data", type=str, help='Ux-string or Ux-bytes to plot (e.g., "90.6Ux04000000...")', ) @@ -154,14 +156,14 @@ def command_plot(args: argparse.Namespace) -> None: plot_data = PlotData(dist_value) # Set matplotlib to non-interactive backend for saving - matplotlib.use('Agg') + matplotlib.use("Agg") # Plot the distribution using the plot wrapper function print("Generating plot...") plot(plot_data) # Save the figure to file - plt.savefig(args.output, dpi=300, bbox_inches='tight') + plt.savefig(args.output, dpi=300, bbox_inches="tight") print(f"✓ Plot saved to: {args.output}") except Exception as e: print(f"\nError parsing or plotting Ux-data: {e}") From 9aae2bddc3981ac2d320cc7c1d06b49a6af21d20 Mon Sep 17 00:00:00 2001 From: tfotakis-signaloid <213429317+tfotakis-signaloid@users.noreply.github.com> Date: Wed, 18 Feb 2026 18:14:17 +0200 Subject: [PATCH 2/2] Updated to version `1.7.2` --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- .../plot_wrapper.py | 16 ++++++++-------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/poetry.lock b/poetry.lock index 48016ff..261d7a3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -798,15 +798,15 @@ tests = ["pytest (>=9)", "typing-extensions (>=4.15)"] [[package]] name = "pex" -version = "2.90.0" +version = "2.90.1" description = "The PEX packaging toolchain." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,<3.16,>=2.7" groups = ["dev"] files = [ - {file = "pex-2.90.0-py2.py35.py36.py37.py38.py39.py310.py311-none-any.whl", hash = "sha256:212356e1feb4ffd0977dde04e872ecefe99d8fef99688f77e7fd43c5c9ca9545"}, - {file = "pex-2.90.0-py3.py312-none-any.whl", hash = "sha256:99cc9603e3e56e9a166dd1d051ecedd6170cb1c377d5aa6dfddf7bde41ba7b18"}, - {file = "pex-2.90.0.tar.gz", hash = "sha256:1411041eedf7d162be894ca9201d0115f012182906e93c5818ce669dc229bc9f"}, + {file = "pex-2.90.1-py2.py35.py36.py37.py38.py39.py310.py311-none-any.whl", hash = "sha256:fb26165ae3e4260008e8058d2752b1a8d4e3a6085402682ec82246c439c1910a"}, + {file = "pex-2.90.1-py3.py312-none-any.whl", hash = "sha256:c80aa4144bafd126f619d578673df98bd11f12fe707d587427f746660b7dac2b"}, + {file = "pex-2.90.1.tar.gz", hash = "sha256:cbb9ebf6408bdc8112f4ad27914bd1cf90850ca960fe7af5f55f28c6807bae34"}, ] [package.extras] diff --git a/pyproject.toml b/pyproject.toml index 6bace64..d081532 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "signaloid" -version = "1.7.1" +version = "1.7.2" description = "" authors = [ "Signaloid " diff --git a/src/signaloid/distributional_information_plotting/plot_wrapper.py b/src/signaloid/distributional_information_plotting/plot_wrapper.py index 8911208..ec6b68a 100644 --- a/src/signaloid/distributional_information_plotting/plot_wrapper.py +++ b/src/signaloid/distributional_information_plotting/plot_wrapper.py @@ -18,9 +18,9 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. +from __future__ import annotations import math -from typing import Any, Optional, Union - +from typing import Any import matplotlib import matplotlib.pyplot as plt @@ -49,12 +49,12 @@ def plot( no_special_y: bool = False, save: bool = False, verbose: bool = False, - x_lim: Optional[tuple[float, float]] = None, - y_lim: Optional[tuple[float, float]] = None, - x_label: Optional[str] = None, - x_tick_label_rotation: Optional[float] = None, + x_lim: tuple[float, float] | None = None, + y_lim: tuple[float, float] | None = None, + x_label: str | None = None, + x_tick_label_rotation: float | None = None, font_size: int = 20, - matplotlib_rc_params_override: Optional[dict[str, str]] = None, + matplotlib_rc_params_override: dict[str, str] | None = None, ) -> bool: """ Args: @@ -75,7 +75,7 @@ def plot( `True` if successful, `False` else. """ - matplotlib_rcParams_update_defaults: dict[str, Union[int, str, bool]] = { + matplotlib_rcParams_update_defaults: dict[str, int | str | bool] = { "font.size": font_size, "figure.facecolor": "FFFFFF30", "axes.facecolor": "FFFFFF30",