From dc4459ce08f7d4e7944cadcdc0e817adde0ae79b Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Sun, 5 May 2024 20:16:38 +0800 Subject: [PATCH 01/20] Added the possibility of building the project on Mac devices and connecting to the Radiacode via USB --- README.md | 5 + poetry.lock | 952 +++++++++++++++--------------- pyproject.toml | 2 +- radiacode-examples/basic.py | 36 +- radiacode/radiacode.py | 8 +- radiacode/transports/bluetooth.py | 96 +-- radiacode/transports/usb.py | 5 +- 7 files changed, 561 insertions(+), 543 deletions(-) diff --git a/README.md b/README.md index 5e3d9a4..30e992b 100644 --- a/README.md +++ b/README.md @@ -35,3 +35,8 @@ $ python3 -m radiacode-examples.narodmon --bluetooth-mac 52:43:01:02:03:04 $ poetry install $ poetry run python3 radiacode-examples/basic.py --bluetooth-mac 52:43:01:02:03:04 # or without --bluetooth-mac for USB connection ``` + +## MacOS +The library used to communicate over Bluetooh (```bluepy```) is [not supported](https://github.com/IanHarvey/bluepy/issues/44) on MacOS. Only the USB connection is available on Apple devices. A ```USB Serial Number```, obtainable from the ```Device Info``` menu on the device itself, can be specified if more than one Radiacode is connected via USB at the same time. + +Make sure ```libusb``` is installed on your system, if you use ```Brew``` you can run: ```brew install libusb``` \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index adbfb8b..7d6c2ad 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,89 +1,88 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aiohttp" -version = "3.9.1" +version = "3.9.5" description = "Async http client/server framework (asyncio)" -category = "main" optional = true python-versions = ">=3.8" files = [ - {file = "aiohttp-3.9.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e1f80197f8b0b846a8d5cf7b7ec6084493950d0882cc5537fb7b96a69e3c8590"}, - {file = "aiohttp-3.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c72444d17777865734aa1a4d167794c34b63e5883abb90356a0364a28904e6c0"}, - {file = "aiohttp-3.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9b05d5cbe9dafcdc733262c3a99ccf63d2f7ce02543620d2bd8db4d4f7a22f83"}, - {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c4fa235d534b3547184831c624c0b7c1e262cd1de847d95085ec94c16fddcd5"}, - {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:289ba9ae8e88d0ba16062ecf02dd730b34186ea3b1e7489046fc338bdc3361c4"}, - {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bff7e2811814fa2271be95ab6e84c9436d027a0e59665de60edf44e529a42c1f"}, - {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81b77f868814346662c96ab36b875d7814ebf82340d3284a31681085c051320f"}, - {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b9c7426923bb7bd66d409da46c41e3fb40f5caf679da624439b9eba92043fa6"}, - {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8d44e7bf06b0c0a70a20f9100af9fcfd7f6d9d3913e37754c12d424179b4e48f"}, - {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22698f01ff5653fe66d16ffb7658f582a0ac084d7da1323e39fd9eab326a1f26"}, - {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ca7ca5abfbfe8d39e653870fbe8d7710be7a857f8a8386fc9de1aae2e02ce7e4"}, - {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:8d7f98fde213f74561be1d6d3fa353656197f75d4edfbb3d94c9eb9b0fc47f5d"}, - {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5216b6082c624b55cfe79af5d538e499cd5f5b976820eac31951fb4325974501"}, - {file = "aiohttp-3.9.1-cp310-cp310-win32.whl", hash = "sha256:0e7ba7ff228c0d9a2cd66194e90f2bca6e0abca810b786901a569c0de082f489"}, - {file = "aiohttp-3.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:c7e939f1ae428a86e4abbb9a7c4732bf4706048818dfd979e5e2839ce0159f23"}, - {file = "aiohttp-3.9.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:df9cf74b9bc03d586fc53ba470828d7b77ce51b0582d1d0b5b2fb673c0baa32d"}, - {file = "aiohttp-3.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ecca113f19d5e74048c001934045a2b9368d77b0b17691d905af18bd1c21275e"}, - {file = "aiohttp-3.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8cef8710fb849d97c533f259103f09bac167a008d7131d7b2b0e3a33269185c0"}, - {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bea94403a21eb94c93386d559bce297381609153e418a3ffc7d6bf772f59cc35"}, - {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91c742ca59045dce7ba76cab6e223e41d2c70d79e82c284a96411f8645e2afff"}, - {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6c93b7c2e52061f0925c3382d5cb8980e40f91c989563d3d32ca280069fd6a87"}, - {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee2527134f95e106cc1653e9ac78846f3a2ec1004cf20ef4e02038035a74544d"}, - {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11ff168d752cb41e8492817e10fb4f85828f6a0142b9726a30c27c35a1835f01"}, - {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b8c3a67eb87394386847d188996920f33b01b32155f0a94f36ca0e0c635bf3e3"}, - {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c7b5d5d64e2a14e35a9240b33b89389e0035e6de8dbb7ffa50d10d8b65c57449"}, - {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:69985d50a2b6f709412d944ffb2e97d0be154ea90600b7a921f95a87d6f108a2"}, - {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:c9110c06eaaac7e1f5562caf481f18ccf8f6fdf4c3323feab28a93d34cc646bd"}, - {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737e69d193dac7296365a6dcb73bbbf53bb760ab25a3727716bbd42022e8d7a"}, - {file = "aiohttp-3.9.1-cp311-cp311-win32.whl", hash = "sha256:4ee8caa925aebc1e64e98432d78ea8de67b2272252b0a931d2ac3bd876ad5544"}, - {file = "aiohttp-3.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:a34086c5cc285be878622e0a6ab897a986a6e8bf5b67ecb377015f06ed316587"}, - {file = "aiohttp-3.9.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f800164276eec54e0af5c99feb9494c295118fc10a11b997bbb1348ba1a52065"}, - {file = "aiohttp-3.9.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:500f1c59906cd142d452074f3811614be04819a38ae2b3239a48b82649c08821"}, - {file = "aiohttp-3.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0b0a6a36ed7e164c6df1e18ee47afbd1990ce47cb428739d6c99aaabfaf1b3af"}, - {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69da0f3ed3496808e8cbc5123a866c41c12c15baaaead96d256477edf168eb57"}, - {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:176df045597e674fa950bf5ae536be85699e04cea68fa3a616cf75e413737eb5"}, - {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b796b44111f0cab6bbf66214186e44734b5baab949cb5fb56154142a92989aeb"}, - {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f27fdaadce22f2ef950fc10dcdf8048407c3b42b73779e48a4e76b3c35bca26c"}, - {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcb6532b9814ea7c5a6a3299747c49de30e84472fa72821b07f5a9818bce0f66"}, - {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:54631fb69a6e44b2ba522f7c22a6fb2667a02fd97d636048478db2fd8c4e98fe"}, - {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4b4c452d0190c5a820d3f5c0f3cd8a28ace48c54053e24da9d6041bf81113183"}, - {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:cae4c0c2ca800c793cae07ef3d40794625471040a87e1ba392039639ad61ab5b"}, - {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:565760d6812b8d78d416c3c7cfdf5362fbe0d0d25b82fed75d0d29e18d7fc30f"}, - {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54311eb54f3a0c45efb9ed0d0a8f43d1bc6060d773f6973efd90037a51cd0a3f"}, - {file = "aiohttp-3.9.1-cp312-cp312-win32.whl", hash = "sha256:85c3e3c9cb1d480e0b9a64c658cd66b3cfb8e721636ab8b0e746e2d79a7a9eed"}, - {file = "aiohttp-3.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:11cb254e397a82efb1805d12561e80124928e04e9c4483587ce7390b3866d213"}, - {file = "aiohttp-3.9.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8a22a34bc594d9d24621091d1b91511001a7eea91d6652ea495ce06e27381f70"}, - {file = "aiohttp-3.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:598db66eaf2e04aa0c8900a63b0101fdc5e6b8a7ddd805c56d86efb54eb66672"}, - {file = "aiohttp-3.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c9376e2b09895c8ca8b95362283365eb5c03bdc8428ade80a864160605715f1"}, - {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41473de252e1797c2d2293804e389a6d6986ef37cbb4a25208de537ae32141dd"}, - {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c5857612c9813796960c00767645cb5da815af16dafb32d70c72a8390bbf690"}, - {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffcd828e37dc219a72c9012ec44ad2e7e3066bec6ff3aaa19e7d435dbf4032ca"}, - {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:219a16763dc0294842188ac8a12262b5671817042b35d45e44fd0a697d8c8361"}, - {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f694dc8a6a3112059258a725a4ebe9acac5fe62f11c77ac4dcf896edfa78ca28"}, - {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bcc0ea8d5b74a41b621ad4a13d96c36079c81628ccc0b30cfb1603e3dfa3a014"}, - {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:90ec72d231169b4b8d6085be13023ece8fa9b1bb495e4398d847e25218e0f431"}, - {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:cf2a0ac0615842b849f40c4d7f304986a242f1e68286dbf3bd7a835e4f83acfd"}, - {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:0e49b08eafa4f5707ecfb321ab9592717a319e37938e301d462f79b4e860c32a"}, - {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2c59e0076ea31c08553e868cec02d22191c086f00b44610f8ab7363a11a5d9d8"}, - {file = "aiohttp-3.9.1-cp38-cp38-win32.whl", hash = "sha256:4831df72b053b1eed31eb00a2e1aff6896fb4485301d4ccb208cac264b648db4"}, - {file = "aiohttp-3.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:3135713c5562731ee18f58d3ad1bf41e1d8883eb68b363f2ffde5b2ea4b84cc7"}, - {file = "aiohttp-3.9.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cfeadf42840c1e870dc2042a232a8748e75a36b52d78968cda6736de55582766"}, - {file = "aiohttp-3.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:70907533db712f7aa791effb38efa96f044ce3d4e850e2d7691abd759f4f0ae0"}, - {file = "aiohttp-3.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cdefe289681507187e375a5064c7599f52c40343a8701761c802c1853a504558"}, - {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7481f581251bb5558ba9f635db70908819caa221fc79ee52a7f58392778c636"}, - {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49f0c1b3c2842556e5de35f122fc0f0b721334ceb6e78c3719693364d4af8499"}, - {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d406b01a9f5a7e232d1b0d161b40c05275ffbcbd772dc18c1d5a570961a1ca4"}, - {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d8e4450e7fe24d86e86b23cc209e0023177b6d59502e33807b732d2deb6975f"}, - {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c0266cd6f005e99f3f51e583012de2778e65af6b73860038b968a0a8888487a"}, - {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab221850108a4a063c5b8a70f00dd7a1975e5a1713f87f4ab26a46e5feac5a0e"}, - {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c88a15f272a0ad3d7773cf3a37cc7b7d077cbfc8e331675cf1346e849d97a4e5"}, - {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:237533179d9747080bcaad4d02083ce295c0d2eab3e9e8ce103411a4312991a0"}, - {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:02ab6006ec3c3463b528374c4cdce86434e7b89ad355e7bf29e2f16b46c7dd6f"}, - {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04fa38875e53eb7e354ece1607b1d2fdee2d175ea4e4d745f6ec9f751fe20c7c"}, - {file = "aiohttp-3.9.1-cp39-cp39-win32.whl", hash = "sha256:82eefaf1a996060602f3cc1112d93ba8b201dbf5d8fd9611227de2003dddb3b7"}, - {file = "aiohttp-3.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:9b05d33ff8e6b269e30a7957bd3244ffbce2a7a35a81b81c382629b80af1a8bf"}, - {file = "aiohttp-3.9.1.tar.gz", hash = "sha256:8fc49a87ac269d4529da45871e2ffb6874e87779c3d0e2ccd813c0899221239d"}, + {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7"}, + {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c"}, + {file = "aiohttp-3.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10"}, + {file = "aiohttp-3.9.5-cp310-cp310-win32.whl", hash = "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb"}, + {file = "aiohttp-3.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb"}, + {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342"}, + {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d"}, + {file = "aiohttp-3.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75"}, + {file = "aiohttp-3.9.5-cp311-cp311-win32.whl", hash = "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6"}, + {file = "aiohttp-3.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a"}, + {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678"}, + {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c"}, + {file = "aiohttp-3.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da"}, + {file = "aiohttp-3.9.5-cp312-cp312-win32.whl", hash = "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59"}, + {file = "aiohttp-3.9.5-cp312-cp312-win_amd64.whl", hash = "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888"}, + {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8"}, + {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8"}, + {file = "aiohttp-3.9.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe"}, + {file = "aiohttp-3.9.5-cp38-cp38-win32.whl", hash = "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da"}, + {file = "aiohttp-3.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a"}, + {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed"}, + {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a"}, + {file = "aiohttp-3.9.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2"}, + {file = "aiohttp-3.9.5-cp39-cp39-win32.whl", hash = "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09"}, + {file = "aiohttp-3.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1"}, + {file = "aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551"}, ] [package.dependencies] @@ -101,7 +100,6 @@ speedups = ["Brotli", "aiodns", "brotlicffi"] name = "aiosignal" version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -116,7 +114,6 @@ frozenlist = ">=1.1.0" name = "async-timeout" version = "4.0.3" description = "Timeout context manager for asyncio programs" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -128,7 +125,6 @@ files = [ name = "attrs" version = "23.2.0" description = "Classes Without Boilerplate" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -148,7 +144,6 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p name = "bluepy" version = "1.3.0" description = "Python module for interfacing with BLE devices through Bluez" -category = "main" optional = false python-versions = "*" files = [ @@ -157,65 +152,64 @@ files = [ [[package]] name = "contourpy" -version = "1.2.0" +version = "1.2.1" description = "Python library for calculating contours of 2D quadrilateral grids" -category = "main" optional = true python-versions = ">=3.9" files = [ - {file = "contourpy-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8"}, - {file = "contourpy-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa"}, - {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9"}, - {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab"}, - {file = "contourpy-1.2.0-cp310-cp310-win32.whl", hash = "sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488"}, - {file = "contourpy-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41"}, - {file = "contourpy-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727"}, - {file = "contourpy-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686"}, - {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286"}, - {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95"}, - {file = "contourpy-1.2.0-cp311-cp311-win32.whl", hash = "sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6"}, - {file = "contourpy-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de"}, - {file = "contourpy-1.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0"}, - {file = "contourpy-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0"}, - {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0"}, - {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431"}, - {file = "contourpy-1.2.0-cp312-cp312-win32.whl", hash = "sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f"}, - {file = "contourpy-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9"}, - {file = "contourpy-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc"}, - {file = "contourpy-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5"}, - {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e"}, - {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808"}, - {file = "contourpy-1.2.0-cp39-cp39-win32.whl", hash = "sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4"}, - {file = "contourpy-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843"}, - {file = "contourpy-1.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108"}, - {file = "contourpy-1.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776"}, - {file = "contourpy-1.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956"}, - {file = "contourpy-1.2.0.tar.gz", hash = "sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a"}, + {file = "contourpy-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bd7c23df857d488f418439686d3b10ae2fbf9bc256cd045b37a8c16575ea1040"}, + {file = "contourpy-1.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5b9eb0ca724a241683c9685a484da9d35c872fd42756574a7cfbf58af26677fd"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c75507d0a55378240f781599c30e7776674dbaf883a46d1c90f37e563453480"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11959f0ce4a6f7b76ec578576a0b61a28bdc0696194b6347ba3f1c53827178b9"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb3315a8a236ee19b6df481fc5f997436e8ade24a9f03dfdc6bd490fea20c6da"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b"}, + {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:94b34f32646ca0414237168d68a9157cb3889f06b096612afdd296003fdd32fd"}, + {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:457499c79fa84593f22454bbd27670227874cd2ff5d6c84e60575c8b50a69619"}, + {file = "contourpy-1.2.1-cp310-cp310-win32.whl", hash = "sha256:ac58bdee53cbeba2ecad824fa8159493f0bf3b8ea4e93feb06c9a465d6c87da8"}, + {file = "contourpy-1.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9cffe0f850e89d7c0012a1fb8730f75edd4320a0a731ed0c183904fe6ecfc3a9"}, + {file = "contourpy-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5"}, + {file = "contourpy-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6150ffa5c767bc6332df27157d95442c379b7dce3a38dff89c0f39b63275696f"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c863140fafc615c14a4bf4efd0f4425c02230eb8ef02784c9a156461e62c965"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:00e5388f71c1a0610e6fe56b5c44ab7ba14165cdd6d695429c5cd94021e390b2"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4492d82b3bc7fbb7e3610747b159869468079fe149ec5c4d771fa1f614a14df"}, + {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:49e70d111fee47284d9dd867c9bb9a7058a3c617274900780c43e38d90fe1205"}, + {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b59c0ffceff8d4d3996a45f2bb6f4c207f94684a96bf3d9728dbb77428dd8cb8"}, + {file = "contourpy-1.2.1-cp311-cp311-win32.whl", hash = "sha256:7b4182299f251060996af5249c286bae9361fa8c6a9cda5efc29fe8bfd6062ec"}, + {file = "contourpy-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2855c8b0b55958265e8b5888d6a615ba02883b225f2227461aa9127c578a4922"}, + {file = "contourpy-1.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:62828cada4a2b850dbef89c81f5a33741898b305db244904de418cc957ff05dc"}, + {file = "contourpy-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:309be79c0a354afff9ff7da4aaed7c3257e77edf6c1b448a779329431ee79d7e"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e785e0f2ef0d567099b9ff92cbfb958d71c2d5b9259981cd9bee81bd194c9a4"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cac0a8f71a041aa587410424ad46dfa6a11f6149ceb219ce7dd48f6b02b87a7"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af3f4485884750dddd9c25cb7e3915d83c2db92488b38ccb77dd594eac84c4a0"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ce6889abac9a42afd07a562c2d6d4b2b7134f83f18571d859b25624a331c90b"}, + {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a1eea9aecf761c661d096d39ed9026574de8adb2ae1c5bd7b33558af884fb2ce"}, + {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:187fa1d4c6acc06adb0fae5544c59898ad781409e61a926ac7e84b8f276dcef4"}, + {file = "contourpy-1.2.1-cp312-cp312-win32.whl", hash = "sha256:c2528d60e398c7c4c799d56f907664673a807635b857df18f7ae64d3e6ce2d9f"}, + {file = "contourpy-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce"}, + {file = "contourpy-1.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb6834cbd983b19f06908b45bfc2dad6ac9479ae04abe923a275b5f48f1a186b"}, + {file = "contourpy-1.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1d59e739ab0e3520e62a26c60707cc3ab0365d2f8fecea74bfe4de72dc56388f"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd3db01f59fdcbce5b22afad19e390260d6d0222f35a1023d9adc5690a889364"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a12a813949e5066148712a0626895c26b2578874e4cc63160bb007e6df3436fe"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe0ccca550bb8e5abc22f530ec0466136379c01321fd94f30a22231e8a48d985"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d59258c3c67c865435d8fbeb35f8c59b8bef3d6f46c1f29f6123556af28445"}, + {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f32c38afb74bd98ce26de7cc74a67b40afb7b05aae7b42924ea990d51e4dac02"}, + {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d31a63bc6e6d87f77d71e1abbd7387ab817a66733734883d1fc0021ed9bfa083"}, + {file = "contourpy-1.2.1-cp39-cp39-win32.whl", hash = "sha256:ddcb8581510311e13421b1f544403c16e901c4e8f09083c881fab2be80ee31ba"}, + {file = "contourpy-1.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:10a37ae557aabf2509c79715cd20b62e4c7c28b8cd62dd7d99e5ed3ce28c3fd9"}, + {file = "contourpy-1.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a31f94983fecbac95e58388210427d68cd30fe8a36927980fab9c20062645609"}, + {file = "contourpy-1.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef2b055471c0eb466033760a521efb9d8a32b99ab907fc8358481a1dd29e3bd3"}, + {file = "contourpy-1.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b33d2bc4f69caedcd0a275329eb2198f560b325605810895627be5d4b876bf7f"}, + {file = "contourpy-1.2.1.tar.gz", hash = "sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c"}, ] [package.dependencies] -numpy = ">=1.20,<2.0" +numpy = ">=1.20" [package.extras] bokeh = ["bokeh", "selenium"] docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.6.1)", "types-Pillow"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.8.0)", "types-Pillow"] test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] @@ -223,7 +217,6 @@ test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] name = "cycler" version = "0.12.1" description = "Composable style cycles" -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -237,61 +230,60 @@ tests = ["pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "fonttools" -version = "4.47.2" +version = "4.51.0" description = "Tools to manipulate font files" -category = "main" optional = true python-versions = ">=3.8" files = [ - {file = "fonttools-4.47.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3b629108351d25512d4ea1a8393a2dba325b7b7d7308116b605ea3f8e1be88df"}, - {file = "fonttools-4.47.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c19044256c44fe299d9a73456aabee4b4d06c6b930287be93b533b4737d70aa1"}, - {file = "fonttools-4.47.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8be28c036b9f186e8c7eaf8a11b42373e7e4949f9e9f370202b9da4c4c3f56c"}, - {file = "fonttools-4.47.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f83a4daef6d2a202acb9bf572958f91cfde5b10c8ee7fb1d09a4c81e5d851fd8"}, - {file = "fonttools-4.47.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a5a5318ba5365d992666ac4fe35365f93004109d18858a3e18ae46f67907670"}, - {file = "fonttools-4.47.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8f57ecd742545362a0f7186774b2d1c53423ed9ece67689c93a1055b236f638c"}, - {file = "fonttools-4.47.2-cp310-cp310-win32.whl", hash = "sha256:a1c154bb85dc9a4cf145250c88d112d88eb414bad81d4cb524d06258dea1bdc0"}, - {file = "fonttools-4.47.2-cp310-cp310-win_amd64.whl", hash = "sha256:3e2b95dce2ead58fb12524d0ca7d63a63459dd489e7e5838c3cd53557f8933e1"}, - {file = "fonttools-4.47.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:29495d6d109cdbabe73cfb6f419ce67080c3ef9ea1e08d5750240fd4b0c4763b"}, - {file = "fonttools-4.47.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0a1d313a415eaaba2b35d6cd33536560deeebd2ed758b9bfb89ab5d97dc5deac"}, - {file = "fonttools-4.47.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90f898cdd67f52f18049250a6474185ef6544c91f27a7bee70d87d77a8daf89c"}, - {file = "fonttools-4.47.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3480eeb52770ff75140fe7d9a2ec33fb67b07efea0ab5129c7e0c6a639c40c70"}, - {file = "fonttools-4.47.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0255dbc128fee75fb9be364806b940ed450dd6838672a150d501ee86523ac61e"}, - {file = "fonttools-4.47.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f791446ff297fd5f1e2247c188de53c1bfb9dd7f0549eba55b73a3c2087a2703"}, - {file = "fonttools-4.47.2-cp311-cp311-win32.whl", hash = "sha256:740947906590a878a4bde7dd748e85fefa4d470a268b964748403b3ab2aeed6c"}, - {file = "fonttools-4.47.2-cp311-cp311-win_amd64.whl", hash = "sha256:63fbed184979f09a65aa9c88b395ca539c94287ba3a364517698462e13e457c9"}, - {file = "fonttools-4.47.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4ec558c543609e71b2275c4894e93493f65d2f41c15fe1d089080c1d0bb4d635"}, - {file = "fonttools-4.47.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e040f905d542362e07e72e03612a6270c33d38281fd573160e1003e43718d68d"}, - {file = "fonttools-4.47.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6dd58cc03016b281bd2c74c84cdaa6bd3ce54c5a7f47478b7657b930ac3ed8eb"}, - {file = "fonttools-4.47.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32ab2e9702dff0dd4510c7bb958f265a8d3dd5c0e2547e7b5f7a3df4979abb07"}, - {file = "fonttools-4.47.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3a808f3c1d1df1f5bf39be869b6e0c263570cdafb5bdb2df66087733f566ea71"}, - {file = "fonttools-4.47.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ac71e2e201df041a2891067dc36256755b1229ae167edbdc419b16da78732c2f"}, - {file = "fonttools-4.47.2-cp312-cp312-win32.whl", hash = "sha256:69731e8bea0578b3c28fdb43dbf95b9386e2d49a399e9a4ad736b8e479b08085"}, - {file = "fonttools-4.47.2-cp312-cp312-win_amd64.whl", hash = "sha256:b3e1304e5f19ca861d86a72218ecce68f391646d85c851742d265787f55457a4"}, - {file = "fonttools-4.47.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:254d9a6f7be00212bf0c3159e0a420eb19c63793b2c05e049eb337f3023c5ecc"}, - {file = "fonttools-4.47.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eabae77a07c41ae0b35184894202305c3ad211a93b2eb53837c2a1143c8bc952"}, - {file = "fonttools-4.47.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a86a5ab2873ed2575d0fcdf1828143cfc6b977ac448e3dc616bb1e3d20efbafa"}, - {file = "fonttools-4.47.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13819db8445a0cec8c3ff5f243af6418ab19175072a9a92f6cc8ca7d1452754b"}, - {file = "fonttools-4.47.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4e743935139aa485fe3253fc33fe467eab6ea42583fa681223ea3f1a93dd01e6"}, - {file = "fonttools-4.47.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d49ce3ea7b7173faebc5664872243b40cf88814ca3eb135c4a3cdff66af71946"}, - {file = "fonttools-4.47.2-cp38-cp38-win32.whl", hash = "sha256:94208ea750e3f96e267f394d5588579bb64cc628e321dbb1d4243ffbc291b18b"}, - {file = "fonttools-4.47.2-cp38-cp38-win_amd64.whl", hash = "sha256:0f750037e02beb8b3569fbff701a572e62a685d2a0e840d75816592280e5feae"}, - {file = "fonttools-4.47.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3d71606c9321f6701642bd4746f99b6089e53d7e9817fc6b964e90d9c5f0ecc6"}, - {file = "fonttools-4.47.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:86e0427864c6c91cf77f16d1fb9bf1bbf7453e824589e8fb8461b6ee1144f506"}, - {file = "fonttools-4.47.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a00bd0e68e88987dcc047ea31c26d40a3c61185153b03457956a87e39d43c37"}, - {file = "fonttools-4.47.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5d77479fb885ef38a16a253a2f4096bc3d14e63a56d6246bfdb56365a12b20c"}, - {file = "fonttools-4.47.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5465df494f20a7d01712b072ae3ee9ad2887004701b95cb2cc6dcb9c2c97a899"}, - {file = "fonttools-4.47.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4c811d3c73b6abac275babb8aa439206288f56fdb2c6f8835e3d7b70de8937a7"}, - {file = "fonttools-4.47.2-cp39-cp39-win32.whl", hash = "sha256:5b60e3afa9635e3dfd3ace2757039593e3bd3cf128be0ddb7a1ff4ac45fa5a50"}, - {file = "fonttools-4.47.2-cp39-cp39-win_amd64.whl", hash = "sha256:7ee48bd9d6b7e8f66866c9090807e3a4a56cf43ffad48962725a190e0dd774c8"}, - {file = "fonttools-4.47.2-py3-none-any.whl", hash = "sha256:7eb7ad665258fba68fd22228a09f347469d95a97fb88198e133595947a20a184"}, - {file = "fonttools-4.47.2.tar.gz", hash = "sha256:7df26dd3650e98ca45f1e29883c96a0b9f5bb6af8d632a6a108bc744fa0bd9b3"}, + {file = "fonttools-4.51.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:84d7751f4468dd8cdd03ddada18b8b0857a5beec80bce9f435742abc9a851a74"}, + {file = "fonttools-4.51.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8b4850fa2ef2cfbc1d1f689bc159ef0f45d8d83298c1425838095bf53ef46308"}, + {file = "fonttools-4.51.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5b48a1121117047d82695d276c2af2ee3a24ffe0f502ed581acc2673ecf1037"}, + {file = "fonttools-4.51.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:180194c7fe60c989bb627d7ed5011f2bef1c4d36ecf3ec64daec8302f1ae0716"}, + {file = "fonttools-4.51.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:96a48e137c36be55e68845fc4284533bda2980f8d6f835e26bca79d7e2006438"}, + {file = "fonttools-4.51.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:806e7912c32a657fa39d2d6eb1d3012d35f841387c8fc6cf349ed70b7c340039"}, + {file = "fonttools-4.51.0-cp310-cp310-win32.whl", hash = "sha256:32b17504696f605e9e960647c5f64b35704782a502cc26a37b800b4d69ff3c77"}, + {file = "fonttools-4.51.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7e91abdfae1b5c9e3a543f48ce96013f9a08c6c9668f1e6be0beabf0a569c1b"}, + {file = "fonttools-4.51.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a8feca65bab31479d795b0d16c9a9852902e3a3c0630678efb0b2b7941ea9c74"}, + {file = "fonttools-4.51.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ac27f436e8af7779f0bb4d5425aa3535270494d3bc5459ed27de3f03151e4c2"}, + {file = "fonttools-4.51.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e19bd9e9964a09cd2433a4b100ca7f34e34731e0758e13ba9a1ed6e5468cc0f"}, + {file = "fonttools-4.51.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2b92381f37b39ba2fc98c3a45a9d6383bfc9916a87d66ccb6553f7bdd129097"}, + {file = "fonttools-4.51.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5f6bc991d1610f5c3bbe997b0233cbc234b8e82fa99fc0b2932dc1ca5e5afec0"}, + {file = "fonttools-4.51.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9696fe9f3f0c32e9a321d5268208a7cc9205a52f99b89479d1b035ed54c923f1"}, + {file = "fonttools-4.51.0-cp311-cp311-win32.whl", hash = "sha256:3bee3f3bd9fa1d5ee616ccfd13b27ca605c2b4270e45715bd2883e9504735034"}, + {file = "fonttools-4.51.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f08c901d3866a8905363619e3741c33f0a83a680d92a9f0e575985c2634fcc1"}, + {file = "fonttools-4.51.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4060acc2bfa2d8e98117828a238889f13b6f69d59f4f2d5857eece5277b829ba"}, + {file = "fonttools-4.51.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1250e818b5f8a679ad79660855528120a8f0288f8f30ec88b83db51515411fcc"}, + {file = "fonttools-4.51.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76f1777d8b3386479ffb4a282e74318e730014d86ce60f016908d9801af9ca2a"}, + {file = "fonttools-4.51.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b5ad456813d93b9c4b7ee55302208db2b45324315129d85275c01f5cb7e61a2"}, + {file = "fonttools-4.51.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:68b3fb7775a923be73e739f92f7e8a72725fd333eab24834041365d2278c3671"}, + {file = "fonttools-4.51.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8e2f1a4499e3b5ee82c19b5ee57f0294673125c65b0a1ff3764ea1f9db2f9ef5"}, + {file = "fonttools-4.51.0-cp312-cp312-win32.whl", hash = "sha256:278e50f6b003c6aed19bae2242b364e575bcb16304b53f2b64f6551b9c000e15"}, + {file = "fonttools-4.51.0-cp312-cp312-win_amd64.whl", hash = "sha256:b3c61423f22165541b9403ee39874dcae84cd57a9078b82e1dce8cb06b07fa2e"}, + {file = "fonttools-4.51.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1621ee57da887c17312acc4b0e7ac30d3a4fb0fec6174b2e3754a74c26bbed1e"}, + {file = "fonttools-4.51.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e9d9298be7a05bb4801f558522adbe2feea1b0b103d5294ebf24a92dd49b78e5"}, + {file = "fonttools-4.51.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee1af4be1c5afe4c96ca23badd368d8dc75f611887fb0c0dac9f71ee5d6f110e"}, + {file = "fonttools-4.51.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c18b49adc721a7d0b8dfe7c3130c89b8704baf599fb396396d07d4aa69b824a1"}, + {file = "fonttools-4.51.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:de7c29bdbdd35811f14493ffd2534b88f0ce1b9065316433b22d63ca1cd21f14"}, + {file = "fonttools-4.51.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cadf4e12a608ef1d13e039864f484c8a968840afa0258b0b843a0556497ea9ed"}, + {file = "fonttools-4.51.0-cp38-cp38-win32.whl", hash = "sha256:aefa011207ed36cd280babfaa8510b8176f1a77261833e895a9d96e57e44802f"}, + {file = "fonttools-4.51.0-cp38-cp38-win_amd64.whl", hash = "sha256:865a58b6e60b0938874af0968cd0553bcd88e0b2cb6e588727117bd099eef836"}, + {file = "fonttools-4.51.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:60a3409c9112aec02d5fb546f557bca6efa773dcb32ac147c6baf5f742e6258b"}, + {file = "fonttools-4.51.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f7e89853d8bea103c8e3514b9f9dc86b5b4120afb4583b57eb10dfa5afbe0936"}, + {file = "fonttools-4.51.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fc244f2585d6c00b9bcc59e6593e646cf095a96fe68d62cd4da53dd1287b55"}, + {file = "fonttools-4.51.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d145976194a5242fdd22df18a1b451481a88071feadf251221af110ca8f00ce"}, + {file = "fonttools-4.51.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c5b8cab0c137ca229433570151b5c1fc6af212680b58b15abd797dcdd9dd5051"}, + {file = "fonttools-4.51.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:54dcf21a2f2d06ded676e3c3f9f74b2bafded3a8ff12f0983160b13e9f2fb4a7"}, + {file = "fonttools-4.51.0-cp39-cp39-win32.whl", hash = "sha256:0118ef998a0699a96c7b28457f15546815015a2710a1b23a7bf6c1be60c01636"}, + {file = "fonttools-4.51.0-cp39-cp39-win_amd64.whl", hash = "sha256:599bdb75e220241cedc6faebfafedd7670335d2e29620d207dd0378a4e9ccc5a"}, + {file = "fonttools-4.51.0-py3-none-any.whl", hash = "sha256:15c94eeef6b095831067f72c825eb0e2d48bb4cea0647c1b05c981ecba2bf39f"}, + {file = "fonttools-4.51.0.tar.gz", hash = "sha256:dc0673361331566d7a663d7ce0f6fdcbfbdc1f59c6e3ed1165ad7202ca183c68"}, ] [package.extras] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] graphite = ["lz4 (>=1.7.4.2)"] interpolatable = ["munkres", "pycairo", "scipy"] -lxml = ["lxml (>=4.0,<5)"] +lxml = ["lxml (>=4.0)"] pathops = ["skia-pathops (>=0.5.0)"] plot = ["matplotlib"] repacker = ["uharfbuzz (>=0.23.0)"] @@ -305,7 +297,6 @@ woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] name = "frozenlist" version = "1.4.1" description = "A list-like structure which implements collections.abc.MutableSequence" -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -390,26 +381,24 @@ files = [ [[package]] name = "idna" -version = "3.6" +version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = true python-versions = ">=3.5" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] name = "importlib-resources" -version = "6.1.1" +version = "6.4.0" description = "Read resources from Python packages" -category = "main" optional = true python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.1-py3-none-any.whl", hash = "sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6"}, - {file = "importlib_resources-6.1.1.tar.gz", hash = "sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a"}, + {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, + {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, ] [package.dependencies] @@ -417,13 +406,12 @@ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff", "zipp (>=3.17)"] +testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] [[package]] name = "kiwisolver" version = "1.4.5" description = "A fast implementation of the Cassowary constraint solver" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -535,40 +523,39 @@ files = [ [[package]] name = "matplotlib" -version = "3.8.2" +version = "3.8.4" description = "Python plotting package" -category = "main" optional = true python-versions = ">=3.9" files = [ - {file = "matplotlib-3.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:09796f89fb71a0c0e1e2f4bdaf63fb2cefc84446bb963ecdeb40dfee7dfa98c7"}, - {file = "matplotlib-3.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9c6976748a25e8b9be51ea028df49b8e561eed7809146da7a47dbecebab367"}, - {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b78e4f2cedf303869b782071b55fdde5987fda3038e9d09e58c91cc261b5ad18"}, - {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e208f46cf6576a7624195aa047cb344a7f802e113bb1a06cfd4bee431de5e31"}, - {file = "matplotlib-3.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46a569130ff53798ea5f50afce7406e91fdc471ca1e0e26ba976a8c734c9427a"}, - {file = "matplotlib-3.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:830f00640c965c5b7f6bc32f0d4ce0c36dfe0379f7dd65b07a00c801713ec40a"}, - {file = "matplotlib-3.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d86593ccf546223eb75a39b44c32788e6f6440d13cfc4750c1c15d0fcb850b63"}, - {file = "matplotlib-3.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a5430836811b7652991939012f43d2808a2db9b64ee240387e8c43e2e5578c8"}, - {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9576723858a78751d5aacd2497b8aef29ffea6d1c95981505877f7ac28215c6"}, - {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba9cbd8ac6cf422f3102622b20f8552d601bf8837e49a3afed188d560152788"}, - {file = "matplotlib-3.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:03f9d160a29e0b65c0790bb07f4f45d6a181b1ac33eb1bb0dd225986450148f0"}, - {file = "matplotlib-3.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:3773002da767f0a9323ba1a9b9b5d00d6257dbd2a93107233167cfb581f64717"}, - {file = "matplotlib-3.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4c318c1e95e2f5926fba326f68177dee364aa791d6df022ceb91b8221bd0a627"}, - {file = "matplotlib-3.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:091275d18d942cf1ee9609c830a1bc36610607d8223b1b981c37d5c9fc3e46a4"}, - {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b0f3b8ea0e99e233a4bcc44590f01604840d833c280ebb8fe5554fd3e6cfe8d"}, - {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7b1704a530395aaf73912be741c04d181f82ca78084fbd80bc737be04848331"}, - {file = "matplotlib-3.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533b0e3b0c6768eef8cbe4b583731ce25a91ab54a22f830db2b031e83cca9213"}, - {file = "matplotlib-3.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:0f4fc5d72b75e2c18e55eb32292659cf731d9d5b312a6eb036506304f4675630"}, - {file = "matplotlib-3.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:deaed9ad4da0b1aea77fe0aa0cebb9ef611c70b3177be936a95e5d01fa05094f"}, - {file = "matplotlib-3.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:172f4d0fbac3383d39164c6caafd3255ce6fa58f08fc392513a0b1d3b89c4f89"}, - {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7d36c2209d9136cd8e02fab1c0ddc185ce79bc914c45054a9f514e44c787917"}, - {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5864bdd7da445e4e5e011b199bb67168cdad10b501750367c496420f2ad00843"}, - {file = "matplotlib-3.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ef8345b48e95cee45ff25192ed1f4857273117917a4dcd48e3905619bcd9c9b8"}, - {file = "matplotlib-3.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:7c48d9e221b637c017232e3760ed30b4e8d5dfd081daf327e829bf2a72c731b4"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa11b3c6928a1e496c1a79917d51d4cd5d04f8a2e75f21df4949eeefdf697f4b"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1095fecf99eeb7384dabad4bf44b965f929a5f6079654b681193edf7169ec20"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:bddfb1db89bfaa855912261c805bd0e10218923cc262b9159a49c29a7a1c1afa"}, - {file = "matplotlib-3.8.2.tar.gz", hash = "sha256:01a978b871b881ee76017152f1f1a0cbf6bd5f7b8ff8c96df0df1bd57d8755a1"}, + {file = "matplotlib-3.8.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:abc9d838f93583650c35eca41cfcec65b2e7cb50fd486da6f0c49b5e1ed23014"}, + {file = "matplotlib-3.8.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f65c9f002d281a6e904976007b2d46a1ee2bcea3a68a8c12dda24709ddc9106"}, + {file = "matplotlib-3.8.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce1edd9f5383b504dbc26eeea404ed0a00656c526638129028b758fd43fc5f10"}, + {file = "matplotlib-3.8.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecd79298550cba13a43c340581a3ec9c707bd895a6a061a78fa2524660482fc0"}, + {file = "matplotlib-3.8.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:90df07db7b599fe7035d2f74ab7e438b656528c68ba6bb59b7dc46af39ee48ef"}, + {file = "matplotlib-3.8.4-cp310-cp310-win_amd64.whl", hash = "sha256:ac24233e8f2939ac4fd2919eed1e9c0871eac8057666070e94cbf0b33dd9c338"}, + {file = "matplotlib-3.8.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:72f9322712e4562e792b2961971891b9fbbb0e525011e09ea0d1f416c4645661"}, + {file = "matplotlib-3.8.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:232ce322bfd020a434caaffbd9a95333f7c2491e59cfc014041d95e38ab90d1c"}, + {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6addbd5b488aedb7f9bc19f91cd87ea476206f45d7116fcfe3d31416702a82fa"}, + {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc4ccdc64e3039fc303defd119658148f2349239871db72cd74e2eeaa9b80b71"}, + {file = "matplotlib-3.8.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b7a2a253d3b36d90c8993b4620183b55665a429da8357a4f621e78cd48b2b30b"}, + {file = "matplotlib-3.8.4-cp311-cp311-win_amd64.whl", hash = "sha256:8080d5081a86e690d7688ffa542532e87f224c38a6ed71f8fbed34dd1d9fedae"}, + {file = "matplotlib-3.8.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6485ac1f2e84676cff22e693eaa4fbed50ef5dc37173ce1f023daef4687df616"}, + {file = "matplotlib-3.8.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c89ee9314ef48c72fe92ce55c4e95f2f39d70208f9f1d9db4e64079420d8d732"}, + {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50bac6e4d77e4262c4340d7a985c30912054745ec99756ce213bfbc3cb3808eb"}, + {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f51c4c869d4b60d769f7b4406eec39596648d9d70246428745a681c327a8ad30"}, + {file = "matplotlib-3.8.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b12ba985837e4899b762b81f5b2845bd1a28f4fdd1a126d9ace64e9c4eb2fb25"}, + {file = "matplotlib-3.8.4-cp312-cp312-win_amd64.whl", hash = "sha256:7a6769f58ce51791b4cb8b4d7642489df347697cd3e23d88266aaaee93b41d9a"}, + {file = "matplotlib-3.8.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:843cbde2f0946dadd8c5c11c6d91847abd18ec76859dc319362a0964493f0ba6"}, + {file = "matplotlib-3.8.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c13f041a7178f9780fb61cc3a2b10423d5e125480e4be51beaf62b172413b67"}, + {file = "matplotlib-3.8.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb44f53af0a62dc80bba4443d9b27f2fde6acfdac281d95bc872dc148a6509cc"}, + {file = "matplotlib-3.8.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:606e3b90897554c989b1e38a258c626d46c873523de432b1462f295db13de6f9"}, + {file = "matplotlib-3.8.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9bb0189011785ea794ee827b68777db3ca3f93f3e339ea4d920315a0e5a78d54"}, + {file = "matplotlib-3.8.4-cp39-cp39-win_amd64.whl", hash = "sha256:6209e5c9aaccc056e63b547a8152661324404dd92340a6e479b3a7f24b42a5d0"}, + {file = "matplotlib-3.8.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c7064120a59ce6f64103c9cefba8ffe6fba87f2c61d67c401186423c9a20fd35"}, + {file = "matplotlib-3.8.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0e47eda4eb2614300fc7bb4657fced3e83d6334d03da2173b09e447418d499f"}, + {file = "matplotlib-3.8.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:493e9f6aa5819156b58fce42b296ea31969f2aab71c5b680b4ea7a3cb5c07d94"}, + {file = "matplotlib-3.8.4.tar.gz", hash = "sha256:8aac397d5e9ec158960e31c381c5ffc52ddd52bd9a47717e2a694038167dffea"}, ] [package.dependencies] @@ -577,7 +564,7 @@ cycler = ">=0.10" fonttools = ">=4.22.0" importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} kiwisolver = ">=1.3.1" -numpy = ">=1.21,<2" +numpy = ">=1.21" packaging = ">=20.0" pillow = ">=8" pyparsing = ">=2.3.1" @@ -585,123 +572,137 @@ python-dateutil = ">=2.7" [[package]] name = "multidict" -version = "6.0.4" +version = "6.0.5" description = "multidict implementation" -category = "main" optional = true python-versions = ">=3.7" files = [ - {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"}, - {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"}, - {file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"}, - {file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"}, - {file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"}, - {file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"}, - {file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"}, - {file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"}, - {file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"}, - {file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"}, - {file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"}, - {file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"}, - {file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"}, - {file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"}, - {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, + {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, + {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, + {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, + {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, + {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, + {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, + {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, + {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, + {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, + {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, + {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, + {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, + {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, + {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, + {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, ] [[package]] name = "mypy" -version = "1.8.0" +version = "1.10.0" description = "Optional static typing for Python" -category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, - {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, - {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, - {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, - {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, - {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, - {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, - {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, - {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, - {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, - {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, - {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, - {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, - {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, - {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, - {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, - {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, - {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, - {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, + {file = "mypy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2"}, + {file = "mypy-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99"}, + {file = "mypy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2"}, + {file = "mypy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9"}, + {file = "mypy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051"}, + {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, + {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, + {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, + {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, + {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, + {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, + {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, + {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, + {file = "mypy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9fd50226364cd2737351c79807775136b0abe084433b55b2e29181a4c3c878c0"}, + {file = "mypy-1.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f90cff89eea89273727d8783fef5d4a934be2fdca11b47def50cf5d311aff727"}, + {file = "mypy-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcfc70599efde5c67862a07a1aaf50e55bce629ace26bb19dc17cece5dd31ca4"}, + {file = "mypy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:075cbf81f3e134eadaf247de187bd604748171d6b79736fa9b6c9685b4083061"}, + {file = "mypy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:3f298531bca95ff615b6e9f2fc0333aae27fa48052903a0ac90215021cdcfa4f"}, + {file = "mypy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976"}, + {file = "mypy-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec"}, + {file = "mypy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821"}, + {file = "mypy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746"}, + {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"}, + {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, + {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, ] [package.dependencies] @@ -719,7 +720,6 @@ reports = ["lxml"] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -729,138 +729,136 @@ files = [ [[package]] name = "numpy" -version = "1.26.3" +version = "1.26.4" description = "Fundamental package for array computing in Python" -category = "main" optional = true python-versions = ">=3.9" files = [ - {file = "numpy-1.26.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:806dd64230dbbfaca8a27faa64e2f414bf1c6622ab78cc4264f7f5f028fee3bf"}, - {file = "numpy-1.26.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02f98011ba4ab17f46f80f7f8f1c291ee7d855fcef0a5a98db80767a468c85cd"}, - {file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d45b3ec2faed4baca41c76617fcdcfa4f684ff7a151ce6fc78ad3b6e85af0a6"}, - {file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdd2b45bf079d9ad90377048e2747a0c82351989a2165821f0c96831b4a2a54b"}, - {file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:211ddd1e94817ed2d175b60b6374120244a4dd2287f4ece45d49228b4d529178"}, - {file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1240f767f69d7c4c8a29adde2310b871153df9b26b5cb2b54a561ac85146485"}, - {file = "numpy-1.26.3-cp310-cp310-win32.whl", hash = "sha256:21a9484e75ad018974a2fdaa216524d64ed4212e418e0a551a2d83403b0531d3"}, - {file = "numpy-1.26.3-cp310-cp310-win_amd64.whl", hash = "sha256:9e1591f6ae98bcfac2a4bbf9221c0b92ab49762228f38287f6eeb5f3f55905ce"}, - {file = "numpy-1.26.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b831295e5472954104ecb46cd98c08b98b49c69fdb7040483aff799a755a7374"}, - {file = "numpy-1.26.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e87562b91f68dd8b1c39149d0323b42e0082db7ddb8e934ab4c292094d575d6"}, - {file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c66d6fec467e8c0f975818c1796d25c53521124b7cfb760114be0abad53a0a2"}, - {file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f25e2811a9c932e43943a2615e65fc487a0b6b49218899e62e426e7f0a57eeda"}, - {file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:af36e0aa45e25c9f57bf684b1175e59ea05d9a7d3e8e87b7ae1a1da246f2767e"}, - {file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:51c7f1b344f302067b02e0f5b5d2daa9ed4a721cf49f070280ac202738ea7f00"}, - {file = "numpy-1.26.3-cp311-cp311-win32.whl", hash = "sha256:7ca4f24341df071877849eb2034948459ce3a07915c2734f1abb4018d9c49d7b"}, - {file = "numpy-1.26.3-cp311-cp311-win_amd64.whl", hash = "sha256:39763aee6dfdd4878032361b30b2b12593fb445ddb66bbac802e2113eb8a6ac4"}, - {file = "numpy-1.26.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a7081fd19a6d573e1a05e600c82a1c421011db7935ed0d5c483e9dd96b99cf13"}, - {file = "numpy-1.26.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12c70ac274b32bc00c7f61b515126c9205323703abb99cd41836e8125ea0043e"}, - {file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f784e13e598e9594750b2ef6729bcd5a47f6cfe4a12cca13def35e06d8163e3"}, - {file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f24750ef94d56ce6e33e4019a8a4d68cfdb1ef661a52cdaee628a56d2437419"}, - {file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:77810ef29e0fb1d289d225cabb9ee6cf4d11978a00bb99f7f8ec2132a84e0166"}, - {file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8ed07a90f5450d99dad60d3799f9c03c6566709bd53b497eb9ccad9a55867f36"}, - {file = "numpy-1.26.3-cp312-cp312-win32.whl", hash = "sha256:f73497e8c38295aaa4741bdfa4fda1a5aedda5473074369eca10626835445511"}, - {file = "numpy-1.26.3-cp312-cp312-win_amd64.whl", hash = "sha256:da4b0c6c699a0ad73c810736303f7fbae483bcb012e38d7eb06a5e3b432c981b"}, - {file = "numpy-1.26.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1666f634cb3c80ccbd77ec97bc17337718f56d6658acf5d3b906ca03e90ce87f"}, - {file = "numpy-1.26.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18c3319a7d39b2c6a9e3bb75aab2304ab79a811ac0168a671a62e6346c29b03f"}, - {file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b7e807d6888da0db6e7e75838444d62495e2b588b99e90dd80c3459594e857b"}, - {file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4d362e17bcb0011738c2d83e0a65ea8ce627057b2fdda37678f4374a382a137"}, - {file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b8c275f0ae90069496068c714387b4a0eba5d531aace269559ff2b43655edd58"}, - {file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cc0743f0302b94f397a4a65a660d4cd24267439eb16493fb3caad2e4389bccbb"}, - {file = "numpy-1.26.3-cp39-cp39-win32.whl", hash = "sha256:9bc6d1a7f8cedd519c4b7b1156d98e051b726bf160715b769106661d567b3f03"}, - {file = "numpy-1.26.3-cp39-cp39-win_amd64.whl", hash = "sha256:867e3644e208c8922a3be26fc6bbf112a035f50f0a86497f98f228c50c607bb2"}, - {file = "numpy-1.26.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3c67423b3703f8fbd90f5adaa37f85b5794d3366948efe9a5190a5f3a83fc34e"}, - {file = "numpy-1.26.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46f47ee566d98849323f01b349d58f2557f02167ee301e5e28809a8c0e27a2d0"}, - {file = "numpy-1.26.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a8474703bffc65ca15853d5fd4d06b18138ae90c17c8d12169968e998e448bb5"}, - {file = "numpy-1.26.3.tar.gz", hash = "sha256:697df43e2b6310ecc9d95f05d5ef20eacc09c7c4ecc9da3f235d39e71b7da1e4"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] name = "packaging" -version = "23.2" +version = "24.0" description = "Core utilities for Python packages" -category = "main" optional = true python-versions = ">=3.7" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, ] [[package]] name = "pillow" -version = "10.2.0" +version = "10.3.0" description = "Python Imaging Library (Fork)" -category = "main" optional = true python-versions = ">=3.8" files = [ - {file = "pillow-10.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e"}, - {file = "pillow-10.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2"}, - {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c"}, - {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0"}, - {file = "pillow-10.2.0-cp310-cp310-win32.whl", hash = "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023"}, - {file = "pillow-10.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72"}, - {file = "pillow-10.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad"}, - {file = "pillow-10.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5"}, - {file = "pillow-10.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311"}, - {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1"}, - {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757"}, - {file = "pillow-10.2.0-cp311-cp311-win32.whl", hash = "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068"}, - {file = "pillow-10.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56"}, - {file = "pillow-10.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1"}, - {file = "pillow-10.2.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef"}, - {file = "pillow-10.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04"}, - {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f"}, - {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb"}, - {file = "pillow-10.2.0-cp312-cp312-win32.whl", hash = "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f"}, - {file = "pillow-10.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9"}, - {file = "pillow-10.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48"}, - {file = "pillow-10.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9"}, - {file = "pillow-10.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d"}, - {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6"}, - {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe"}, - {file = "pillow-10.2.0-cp38-cp38-win32.whl", hash = "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e"}, - {file = "pillow-10.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39"}, - {file = "pillow-10.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67"}, - {file = "pillow-10.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13"}, - {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7"}, - {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591"}, - {file = "pillow-10.2.0-cp39-cp39-win32.whl", hash = "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516"}, - {file = "pillow-10.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8"}, - {file = "pillow-10.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6"}, - {file = "pillow-10.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868"}, - {file = "pillow-10.2.0.tar.gz", hash = "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e"}, + {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"}, + {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"}, + {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"}, + {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"}, + {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"}, + {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"}, + {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"}, + {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"}, + {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"}, + {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"}, + {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"}, + {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"}, + {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"}, + {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"}, + {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"}, + {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"}, + {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"}, + {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"}, + {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"}, + {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"}, + {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"}, + {file = "pillow-10.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b"}, + {file = "pillow-10.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd"}, + {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d"}, + {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3"}, + {file = "pillow-10.3.0-cp38-cp38-win32.whl", hash = "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b"}, + {file = "pillow-10.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999"}, + {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"}, + {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"}, + {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"}, + {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"}, + {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"}, + {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"}, + {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"}, + {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, ] [package.extras] @@ -875,7 +873,6 @@ xmp = ["defusedxml"] name = "prometheus-client" version = "0.19.0" description = "Python client for the Prometheus monitoring system." -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -888,14 +885,13 @@ twisted = ["twisted"] [[package]] name = "pyparsing" -version = "3.1.1" +version = "3.1.2" description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "main" optional = true python-versions = ">=3.6.8" files = [ - {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, - {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, + {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, + {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, ] [package.extras] @@ -903,14 +899,13 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" -category = "main" optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -920,7 +915,6 @@ six = ">=1.5" name = "pyusb" version = "1.2.1" description = "Python USB access module" -category = "main" optional = false python-versions = ">=3.6.0" files = [ @@ -932,7 +926,6 @@ files = [ name = "pyyaml" version = "6.0.1" description = "YAML parser and emitter for Python" -category = "main" optional = true python-versions = ">=3.6" files = [ @@ -954,6 +947,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -990,36 +984,34 @@ files = [ [[package]] name = "ruff" -version = "0.1.14" +version = "0.1.15" description = "An extremely fast Python linter and code formatter, written in Rust." -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.1.14-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:96f76536df9b26622755c12ed8680f159817be2f725c17ed9305b472a757cdbb"}, - {file = "ruff-0.1.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ab3f71f64498c7241123bb5a768544cf42821d2a537f894b22457a543d3ca7a9"}, - {file = "ruff-0.1.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7060156ecc572b8f984fd20fd8b0fcb692dd5d837b7606e968334ab7ff0090ab"}, - {file = "ruff-0.1.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a53d8e35313d7b67eb3db15a66c08434809107659226a90dcd7acb2afa55faea"}, - {file = "ruff-0.1.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bea9be712b8f5b4ebed40e1949379cfb2a7d907f42921cf9ab3aae07e6fba9eb"}, - {file = "ruff-0.1.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2270504d629a0b064247983cbc495bed277f372fb9eaba41e5cf51f7ba705a6a"}, - {file = "ruff-0.1.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80258bb3b8909b1700610dfabef7876423eed1bc930fe177c71c414921898efa"}, - {file = "ruff-0.1.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:653230dd00aaf449eb5ff25d10a6e03bc3006813e2cb99799e568f55482e5cae"}, - {file = "ruff-0.1.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b3acc6c4e6928459ba9eb7459dd4f0c4bf266a053c863d72a44c33246bfdbf"}, - {file = "ruff-0.1.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6b3dadc9522d0eccc060699a9816e8127b27addbb4697fc0c08611e4e6aeb8b5"}, - {file = "ruff-0.1.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1c8eca1a47b4150dc0fbec7fe68fc91c695aed798532a18dbb1424e61e9b721f"}, - {file = "ruff-0.1.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:62ce2ae46303ee896fc6811f63d6dabf8d9c389da0f3e3f2bce8bc7f15ef5488"}, - {file = "ruff-0.1.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b2027dde79d217b211d725fc833e8965dc90a16d0d3213f1298f97465956661b"}, - {file = "ruff-0.1.14-py3-none-win32.whl", hash = "sha256:722bafc299145575a63bbd6b5069cb643eaa62546a5b6398f82b3e4403329cab"}, - {file = "ruff-0.1.14-py3-none-win_amd64.whl", hash = "sha256:e3d241aa61f92b0805a7082bd89a9990826448e4d0398f0e2bc8f05c75c63d99"}, - {file = "ruff-0.1.14-py3-none-win_arm64.whl", hash = "sha256:269302b31ade4cde6cf6f9dd58ea593773a37ed3f7b97e793c8594b262466b67"}, - {file = "ruff-0.1.14.tar.gz", hash = "sha256:ad3f8088b2dfd884820289a06ab718cde7d38b94972212cc4ba90d5fbc9955f3"}, + {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5fe8d54df166ecc24106db7dd6a68d44852d14eb0729ea4672bb4d96c320b7df"}, + {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6f0bfbb53c4b4de117ac4d6ddfd33aa5fc31beeaa21d23c45c6dd249faf9126f"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0d432aec35bfc0d800d4f70eba26e23a352386be3a6cf157083d18f6f5881c8"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9405fa9ac0e97f35aaddf185a1be194a589424b8713e3b97b762336ec79ff807"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66ec24fe36841636e814b8f90f572a8c0cb0e54d8b5c2d0e300d28a0d7bffec"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6f8ad828f01e8dd32cc58bc28375150171d198491fc901f6f98d2a39ba8e3ff5"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86811954eec63e9ea162af0ffa9f8d09088bab51b7438e8b6488b9401863c25e"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd4025ac5e87d9b80e1f300207eb2fd099ff8200fa2320d7dc066a3f4622dc6b"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b17b93c02cdb6aeb696effecea1095ac93f3884a49a554a9afa76bb125c114c1"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ddb87643be40f034e97e97f5bc2ef7ce39de20e34608f3f829db727a93fb82c5"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:abf4822129ed3a5ce54383d5f0e964e7fef74a41e48eb1dfad404151efc130a2"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6c629cf64bacfd136c07c78ac10a54578ec9d1bd2a9d395efbee0935868bf852"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1bab866aafb53da39c2cadfb8e1c4550ac5340bb40300083eb8967ba25481447"}, + {file = "ruff-0.1.15-py3-none-win32.whl", hash = "sha256:2417e1cb6e2068389b07e6fa74c306b2810fe3ee3476d5b8a96616633f40d14f"}, + {file = "ruff-0.1.15-py3-none-win_amd64.whl", hash = "sha256:3837ac73d869efc4182d9036b1405ef4c73d9b1f88da2413875e34e0d6919587"}, + {file = "ruff-0.1.15-py3-none-win_arm64.whl", hash = "sha256:9a933dfb1c14ec7a33cceb1e49ec4a16b51ce3c20fd42663198746efc0427360"}, + {file = "ruff-0.1.15.tar.gz", hash = "sha256:f6dfa8c1b21c913c326919056c390966648b680966febcb796cc9d1aaab8564e"}, ] [[package]] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -1031,7 +1023,6 @@ files = [ name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1041,21 +1032,19 @@ files = [ [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.11.0" description = "Backported and Experimental Type Hints for Python 3.8+" -category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, + {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, ] [[package]] name = "yarl" version = "1.9.4" description = "Yet another URL library" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -1157,19 +1146,18 @@ multidict = ">=4.0" [[package]] name = "zipp" -version = "3.17.0" +version = "3.18.1" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" optional = true python-versions = ">=3.8" files = [ - {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, - {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, + {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, + {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [extras] examples = ["aiohttp", "matplotlib", "numpy", "prometheus-client", "pyyaml"] @@ -1177,4 +1165,4 @@ examples = ["aiohttp", "matplotlib", "numpy", "prometheus-client", "pyyaml"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "ca84ec3a714d09c134a9fe46af02303ea86a5a2aeb898ac0abc846a992587025" +content-hash = "c1f54f063b1ab0b860b9f8bca0c295cacb07ed0547ad15975264f4dd4cd0e6c7" diff --git a/pyproject.toml b/pyproject.toml index c73da13..6027321 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ include = ["radiacode-examples/*"] [tool.poetry.dependencies] python = "^3.9" -bluepy = "^1.3" +bluepy = { version = "^1.3", markers = "sys_platform != 'darwin'" } pyusb = "^1.2" aiohttp = {version = "^3.9", optional = true} prometheus-client = {version = "^0.19", optional = true} diff --git a/radiacode-examples/basic.py b/radiacode-examples/basic.py index c7693a0..07a8799 100644 --- a/radiacode-examples/basic.py +++ b/radiacode-examples/basic.py @@ -1,20 +1,40 @@ import argparse -import time +import time, platform from radiacode import RadiaCode - +from radiacode.transports.usb import DeviceNotFound as DeviceNotFoundUSB +from radiacode.transports.bluetooth import DeviceNotFound as DeviceNotFoundBT def main(): parser = argparse.ArgumentParser() - parser.add_argument('--bluetooth-mac', type=str, required=False, help='bluetooth MAC address of radiascan device') + + if platform.system() != 'Darwin': + parser.add_argument('--bluetooth-mac', type=str, required=False, help='bluetooth MAC address of radiascan device (e.g. 00:11:22:33:44:55)') + + parser.add_argument('--serial', type=str, required=False, + help='serial number of radiascan device (e.g. "RC-10x-xxxxxx"). Useful in case of multiple devices.') + args = parser.parse_args() - if args.bluetooth_mac: - print('will use Bluetooth connection') - rc = RadiaCode(bluetooth_mac=args.bluetooth_mac) + if hasattr(args, 'bluetooth_mac') and getattr(args, 'bluetooth_mac', None): + print(f'Connecting to Radiacode via Bluetooth (MAC address: {args.bluetooth_mac})') + + try: + rc = RadiaCode(bluetooth_mac=args.bluetooth_mac) + except DeviceNotFoundBT as e: + print(e) + return + except ValueError as e: + print(e) + return else: - print('will use USB connection') - rc = RadiaCode() + print('Connecting to Radiacode via USB' + (f' (serial number: {args.serial})' if args.serial else '')) + + try: + rc = RadiaCode(serial_number=args.serial) + except DeviceNotFoundUSB: + print('Device not found, check your USB connection') + return serial = rc.serial_number() print(f'### Serial number: {serial}') diff --git a/radiacode/radiacode.py b/radiacode/radiacode.py index 02a5814..1873178 100644 --- a/radiacode/radiacode.py +++ b/radiacode/radiacode.py @@ -1,5 +1,5 @@ import datetime -import struct +import struct, platform from typing import List, Optional, Union from radiacode.bytes_buffer import BytesBuffer @@ -25,7 +25,11 @@ def __init__( ignore_firmware_compatibility_check: bool = False, ): self._seq = 0 - if bluetooth_mac is not None: + + # Bluepy doesn't support MacOS: https://github.com/IanHarvey/bluepy/issues/44 + self._bt_supported = False if platform.system() == 'Darwin' else True + + if bluetooth_mac is not None and self._bt_supported == True: self._connection = Bluetooth(bluetooth_mac) else: self._connection = Usb(serial_number=serial_number) diff --git a/radiacode/transports/bluetooth.py b/radiacode/transports/bluetooth.py index 9661dad..eb82033 100644 --- a/radiacode/transports/bluetooth.py +++ b/radiacode/transports/bluetooth.py @@ -1,52 +1,56 @@ import struct - -from bluepy.btle import BTLEDisconnectError, DefaultDelegate, Peripheral - -from radiacode.bytes_buffer import BytesBuffer - +import platform class DeviceNotFound(Exception): pass - -class Bluetooth(DefaultDelegate): - def __init__(self, mac): - self._resp_buffer = b'' - self._resp_size = 0 - self._response = None - - try: - self.p = Peripheral(mac) - except BTLEDisconnectError as ex: - raise DeviceNotFound('Device not found or bluetooth adapter is not powered on') from ex - - self.p.withDelegate(self) - - service = self.p.getServiceByUUID('e63215e5-7003-49d8-96b0-b024798fb901') - self.write_fd = service.getCharacteristics('e63215e6-7003-49d8-96b0-b024798fb901')[0].getHandle() - notify_fd = service.getCharacteristics('e63215e7-7003-49d8-96b0-b024798fb901')[0].getHandle() - self.p.writeCharacteristic(notify_fd + 1, b'\x01\x00') - - def handleNotification(self, chandle, data): - if self._resp_size == 0: - self._resp_size = 4 + struct.unpack('= 0 - if self._resp_size == 0: - self._response = self._resp_buffer +if platform.system() == 'Darwin': + class Bluetooth: + def __init__(self): + # Create an empty class if we are on MacOS + pass +else: + from bluepy.btle import BTLEDisconnectError, DefaultDelegate, Peripheral + from radiacode.bytes_buffer import BytesBuffer + + class Bluetooth(DefaultDelegate): + def __init__(self, mac): self._resp_buffer = b'' - - def execute(self, req) -> BytesBuffer: - for pos in range(0, len(req), 18): - rp = req[pos : min(pos + 18, len(req))] - self.p.writeCharacteristic(self.write_fd, rp) - - while self._response is None: - self.p.waitForNotifications(2.0) - - br = BytesBuffer(self._response) - self._response = None - return br + self._resp_size = 0 + self._response = None + + try: + self.p = Peripheral(mac) + except BTLEDisconnectError as ex: + raise DeviceNotFound('Device not found or bluetooth adapter is not powered on') from ex + + self.p.withDelegate(self) + + service = self.p.getServiceByUUID('e63215e5-7003-49d8-96b0-b024798fb901') + self.write_fd = service.getCharacteristics('e63215e6-7003-49d8-96b0-b024798fb901')[0].getHandle() + notify_fd = service.getCharacteristics('e63215e7-7003-49d8-96b0-b024798fb901')[0].getHandle() + self.p.writeCharacteristic(notify_fd + 1, b'\x01\x00') + + def handleNotification(self, chandle, data): + if self._resp_size == 0: + self._resp_size = 4 + struct.unpack('= 0 + if self._resp_size == 0: + self._response = self._resp_buffer + self._resp_buffer = b'' + + def execute(self, req) -> BytesBuffer: + for pos in range(0, len(req), 18): + rp = req[pos : min(pos + 18, len(req))] + self.p.writeCharacteristic(self.write_fd, rp) + + while self._response is None: + self.p.waitForNotifications(2.0) + + br = BytesBuffer(self._response) + self._response = None + return br diff --git a/radiacode/transports/usb.py b/radiacode/transports/usb.py index a16ec57..471cd86 100644 --- a/radiacode/transports/usb.py +++ b/radiacode/transports/usb.py @@ -1,14 +1,11 @@ import struct - import usb.core from radiacode.bytes_buffer import BytesBuffer - class DeviceNotFound(Exception): pass - class MultipleUSBReadFailure(Exception): """Raised when max. number of USB read failues reached""" @@ -16,8 +13,8 @@ def __init__(self, message=None): self.message = 'Multiple USB Read Failures' if message is None else message super().__init__(self.message) - class Usb: + def __init__(self, serial_number=None, timeout_ms=3000): _vid = 0x0483 _pid = 0xF123 From ab4abf5cdf3d2cf049f9e0e148248a418b784909 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Tue, 7 May 2024 13:58:45 +0800 Subject: [PATCH 02/20] Added initial support for BT on Mac --- .gitignore | 1 + poetry.lock | 387 +++++++++++++++++++++++++++++- pyproject.toml | 3 +- radiacode-examples/basic.py | 53 ++-- radiacode/radiacode.py | 180 ++++++++------ radiacode/transports/bluetooth.py | 122 +++++++++- 6 files changed, 651 insertions(+), 95 deletions(-) diff --git a/.gitignore b/.gitignore index 5191513..11f42c2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ __pycache__/ *.py[cod] *.egg-info/ .mypy_cache/ +.venv/ dist/ diff --git a/poetry.lock b/poetry.lock index 7d6c2ad..5b8a017 100644 --- a/poetry.lock +++ b/poetry.lock @@ -114,7 +114,7 @@ frozenlist = ">=1.1.0" name = "async-timeout" version = "4.0.3" description = "Timeout context manager for asyncio programs" -optional = true +optional = false python-versions = ">=3.7" files = [ {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, @@ -140,6 +140,54 @@ tests = ["attrs[tests-no-zope]", "zope-interface"] tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +[[package]] +name = "bleak" +version = "0.22.0" +description = "Bluetooth Low Energy platform Agnostic Klient" +optional = false +python-versions = "<3.13,>=3.8" +files = [ + {file = "bleak-0.22.0-py3-none-any.whl", hash = "sha256:c7d85e90b55529e1eccede1d01c1a2af178306a973121b04a3fe6d3d4ece2a01"}, + {file = "bleak-0.22.0.tar.gz", hash = "sha256:8439f5a34ecba350485a64c9bf6be5a66fb58f2b1dc597b61f224f6635ffad99"}, +] + +[package.dependencies] +async-timeout = {version = ">=3.0.0,<5", markers = "python_version < \"3.11\""} +bleak-winrt = {version = ">=1.2.0,<2.0.0", markers = "platform_system == \"Windows\" and python_version < \"3.12\""} +dbus-fast = {version = ">=1.83.0,<3", markers = "platform_system == \"Linux\""} +pyobjc-core = {version = ">=10.0,<11.0", markers = "platform_system == \"Darwin\""} +pyobjc-framework-CoreBluetooth = {version = ">=10.0,<11.0", markers = "platform_system == \"Darwin\""} +pyobjc-framework-libdispatch = {version = ">=10.0,<11.0", markers = "platform_system == \"Darwin\""} +typing-extensions = {version = ">=4.7.0", markers = "python_version < \"3.12\""} +winrt-runtime = {version = ">=2,<3", markers = "platform_system == \"Windows\" and python_version >= \"3.12\""} +"winrt-Windows.Devices.Bluetooth" = {version = ">=2,<3", markers = "platform_system == \"Windows\" and python_version >= \"3.12\""} +"winrt-Windows.Devices.Bluetooth.Advertisement" = {version = ">=2,<3", markers = "platform_system == \"Windows\" and python_version >= \"3.12\""} +"winrt-Windows.Devices.Bluetooth.GenericAttributeProfile" = {version = ">=2,<3", markers = "platform_system == \"Windows\" and python_version >= \"3.12\""} +"winrt-Windows.Devices.Enumeration" = {version = ">=2,<3", markers = "platform_system == \"Windows\" and python_version >= \"3.12\""} +"winrt-Windows.Foundation" = {version = ">=2,<3", markers = "platform_system == \"Windows\" and python_version >= \"3.12\""} +"winrt-Windows.Foundation.Collections" = {version = ">=2,<3", markers = "platform_system == \"Windows\" and python_version >= \"3.12\""} +"winrt-Windows.Storage.Streams" = {version = ">=2,<3", markers = "platform_system == \"Windows\" and python_version >= \"3.12\""} + +[[package]] +name = "bleak-winrt" +version = "1.2.0" +description = "Python WinRT bindings for Bleak" +optional = false +python-versions = "*" +files = [ + {file = "bleak-winrt-1.2.0.tar.gz", hash = "sha256:0577d070251b9354fc6c45ffac57e39341ebb08ead014b1bdbd43e211d2ce1d6"}, + {file = "bleak_winrt-1.2.0-cp310-cp310-win32.whl", hash = "sha256:a2ae3054d6843ae0cfd3b94c83293a1dfd5804393977dd69bde91cb5099fc47c"}, + {file = "bleak_winrt-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:677df51dc825c6657b3ae94f00bd09b8ab88422b40d6a7bdbf7972a63bc44e9a"}, + {file = "bleak_winrt-1.2.0-cp311-cp311-win32.whl", hash = "sha256:9449cdb942f22c9892bc1ada99e2ccce9bea8a8af1493e81fefb6de2cb3a7b80"}, + {file = "bleak_winrt-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:98c1b5a6a6c431ac7f76aa4285b752fe14a1c626bd8a1dfa56f66173ff120bee"}, + {file = "bleak_winrt-1.2.0-cp37-cp37m-win32.whl", hash = "sha256:623ac511696e1f58d83cb9c431e32f613395f2199b3db7f125a3d872cab968a4"}, + {file = "bleak_winrt-1.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:13ab06dec55469cf51a2c187be7b630a7a2922e1ea9ac1998135974a7239b1e3"}, + {file = "bleak_winrt-1.2.0-cp38-cp38-win32.whl", hash = "sha256:5a36ff8cd53068c01a795a75d2c13054ddc5f99ce6de62c1a97cd343fc4d0727"}, + {file = "bleak_winrt-1.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:810c00726653a962256b7acd8edf81ab9e4a3c66e936a342ce4aec7dbd3a7263"}, + {file = "bleak_winrt-1.2.0-cp39-cp39-win32.whl", hash = "sha256:dd740047a08925bde54bec357391fcee595d7b8ca0c74c87170a5cbc3f97aa0a"}, + {file = "bleak_winrt-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:63130c11acfe75c504a79c01f9919e87f009f5e742bfc7b7a5c2a9c72bf591a7"}, +] + [[package]] name = "bluepy" version = "1.3.0" @@ -228,6 +276,49 @@ files = [ docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] tests = ["pytest", "pytest-cov", "pytest-xdist"] +[[package]] +name = "dbus-fast" +version = "2.21.1" +description = "A faster version of dbus-next" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "dbus_fast-2.21.1-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:b04b88be594dad81b33f6770283eed2125763632515c5112f8aa30f259cd334c"}, + {file = "dbus_fast-2.21.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7333896544a4d0a3d708bd092f8c05eb3599dc2b34ae6e4c4b44d04d5514b0ec"}, + {file = "dbus_fast-2.21.1-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:4591e0962c272d42d305ab3fb8889f13d47255e412fd3b9839620836662c91fe"}, + {file = "dbus_fast-2.21.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:52641305461660c8969c6bb12364206a108c5c9e014c9220c70b99c4f48b6750"}, + {file = "dbus_fast-2.21.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:237db4ab0b90e5284ea7659264630d693273cdbda323a40368f320869bf6470f"}, + {file = "dbus_fast-2.21.1-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:999fed45cb391126107b804be0e344e75556fceaee4cc30a0ca06d77309bdf3c"}, + {file = "dbus_fast-2.21.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2309b9cafba799e9d343fdfdd5ae46276adf3929fef60f296f23b97ed1aa2f6"}, + {file = "dbus_fast-2.21.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b7d1f35218549762e52a782c0b548e0681332beee773d3dfffe2efc38b2ee960"}, + {file = "dbus_fast-2.21.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:47aa28520fe274414b655c74cbe2e91d8b76e22f40cd41a758bb6975e526827b"}, + {file = "dbus_fast-2.21.1-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:0ff6c72bcd6539d798015bda33c7ce35c7de76276b9bd45e48db13672713521a"}, + {file = "dbus_fast-2.21.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36d8cd43b3799e766158f1bb0b27cc4eef685fd892417b0382b7fdfdd94f1e6c"}, + {file = "dbus_fast-2.21.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d4da8d58064f0a3dd07bfc283ba912b9d5a4cb38f1c0fcd9ecb2b9d43111243c"}, + {file = "dbus_fast-2.21.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:66e160f496ac79248feb09a0acf4aab5d139d823330cbd9377f6e19ae007330a"}, + {file = "dbus_fast-2.21.1-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:670b5c4d78c9c2d25e7ba650d212d98bf24d40292f91fe4e2f3ad4f80dc6d7e5"}, + {file = "dbus_fast-2.21.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15d62adfab7c6f4a491085f53f9634d24745ca5a2772549945b7e2de27c0d534"}, + {file = "dbus_fast-2.21.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:54e8771e31ee1deb01feef2475c12123cab770c371ecc97af98eb6ca10a2858e"}, + {file = "dbus_fast-2.21.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2db4d0d60a891a8b20a4c6de68a088efe73b29ab4a5949fe6aad2713c131e174"}, + {file = "dbus_fast-2.21.1-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:65e76b20099c33352d5e7734a219982858873cf66fe510951d9bd27cb690190f"}, + {file = "dbus_fast-2.21.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:927f294b1dc7cea9372ef8c7c46ebeb5c7e6c1c7345358f952e7499bdbdf7eb4"}, + {file = "dbus_fast-2.21.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9e9a43ea42b8a9f2c62ca50ce05582de7b4f1f7eb27091f904578c29124af246"}, + {file = "dbus_fast-2.21.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:78c84ecf19459571784fd6a8ad8b3e9006cf96c3282e8220bc49098866ef4cc7"}, + {file = "dbus_fast-2.21.1-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:a5b3895ea12c4e636dfaacf75fa5bd1e8450b2ffb97507520991eaf1989d102e"}, + {file = "dbus_fast-2.21.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85be33bb04e918833ac6f28f68f83a1e83425eb6e08b9c482cc3318820dfd55f"}, + {file = "dbus_fast-2.21.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:13ab6a0f64d345cb42c489239962261f724bd441458bef245b39828ed94ea6f4"}, + {file = "dbus_fast-2.21.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c585e7a94bb723a70b4966677b882be8bda324cc41bd129765e3ceab428889bb"}, + {file = "dbus_fast-2.21.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:62331ee3871f6881f517ca65ae185fb2462a0bf2fe78acc4a4d621fc4da08396"}, + {file = "dbus_fast-2.21.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbfd6892fa092cbd6f52edcb24797af62fba8baa50995db856b0a342184c850d"}, + {file = "dbus_fast-2.21.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:a999e35628988ad4f81af36192cd592b8fd1e72e1bbc76a64d80808e6f4b9540"}, + {file = "dbus_fast-2.21.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9cae9a6b9bb54f3f89424fdd960b60ac53239b9e5d4a5d9a598d222fbf8d3173"}, + {file = "dbus_fast-2.21.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:39a3f3662391b49553bf9d9d2e9a6cb31e0d7d337557ee0c0be5c558a3c7d230"}, + {file = "dbus_fast-2.21.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffc2b6beb212d0d231816dcb7bd8bcdafccd04750ba8f5e915f40ad312f5adf2"}, + {file = "dbus_fast-2.21.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:c938eb7130067ca3b74b248ee376228776d8f013a206ae78e6fc644c9db0f4f5"}, + {file = "dbus_fast-2.21.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fae9609d972f0c2b72017796a8140b8a6fb842426f0aed4f43f0fa7d780a16f"}, + {file = "dbus_fast-2.21.1.tar.gz", hash = "sha256:87b852d2005f1d59399ca51c5f3538f28a4742d739d7abe82b7ae8d01d8a5d02"}, +] + [[package]] name = "fonttools" version = "4.51.0" @@ -883,6 +974,78 @@ files = [ [package.extras] twisted = ["twisted"] +[[package]] +name = "pyobjc-core" +version = "10.2" +description = "Python<->ObjC Interoperability Module" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyobjc-core-10.2.tar.gz", hash = "sha256:0153206e15d0e0d7abd53ee8a7fbaf5606602a032e177a028fc8589516a8771c"}, + {file = "pyobjc_core-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b8eab50ce7f17017a0f1d68c3b7e88bb1bb033415fdff62b8e0a9ee4ab72f242"}, + {file = "pyobjc_core-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f2115971463073426ab926416e17e5c16de5b90d1a1f2a2d8724637eb1c21308"}, + {file = "pyobjc_core-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a70546246177c23acb323c9324330e37638f1a0a3d13664abcba3bb75e43012c"}, + {file = "pyobjc_core-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a9b5a215080d13bd7526031d21d5eb27a410780878d863f486053a0eba7ca9a5"}, + {file = "pyobjc_core-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:eb1ab700a44bcc4ceb125091dfaae0b998b767b49990df5fdc83eb58158d8e3f"}, + {file = "pyobjc_core-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c9a7163aff9c47d654f835f80361c1b112886ec754800d34e75d1e02ff52c3d7"}, +] + +[[package]] +name = "pyobjc-framework-cocoa" +version = "10.2" +description = "Wrappers for the Cocoa frameworks on macOS" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyobjc-framework-Cocoa-10.2.tar.gz", hash = "sha256:6383141379636b13855dca1b39c032752862b829f93a49d7ddb35046abfdc035"}, + {file = "pyobjc_framework_Cocoa-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9227b4f271fda2250f5a88cbc686ff30ae02c0f923bb7854bb47972397496b2"}, + {file = "pyobjc_framework_Cocoa-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6a6042b7703bdc33b7491959c715c1e810a3f8c7a560c94b36e00ef321480797"}, + {file = "pyobjc_framework_Cocoa-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:18886d5013cd7dc7ecd6e0df5134c767569b5247fc10a5e293c72ee3937b217b"}, + {file = "pyobjc_framework_Cocoa-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ecf01400ee698d2e0ff4c907bcf9608d9d710e97203fbb97b37d208507a9362"}, + {file = "pyobjc_framework_Cocoa-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:0def036a7b24e3ae37a244c77bec96b7c9c8384bf6bb4d33369f0a0c8807a70d"}, + {file = "pyobjc_framework_Cocoa-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f47ecc393bc1019c4b47e8653207188df784ac006ad54d8c2eb528906ff7013"}, +] + +[package.dependencies] +pyobjc-core = ">=10.2" + +[[package]] +name = "pyobjc-framework-corebluetooth" +version = "10.2" +description = "Wrappers for the framework CoreBluetooth on macOS" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyobjc-framework-CoreBluetooth-10.2.tar.gz", hash = "sha256:fb69d2c61082935b2b12827c1ba4bb22146eb3d251695fa1d58bbd5835260729"}, + {file = "pyobjc_framework_CoreBluetooth-10.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:6e118f08ae08289195841e0066389632206b68a8377ac384b30ac0c7e262b779"}, + {file = "pyobjc_framework_CoreBluetooth-10.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:411de4f937264b5e2935be25b78362c58118e2ab9f6a7af4d4d005813c458354"}, + {file = "pyobjc_framework_CoreBluetooth-10.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:81da4426a492089f9dd9ca50814766101f97574675782f7be7ce1a63197d497a"}, +] + +[package.dependencies] +pyobjc-core = ">=10.2" +pyobjc-framework-Cocoa = ">=10.2" + +[[package]] +name = "pyobjc-framework-libdispatch" +version = "10.2" +description = "Wrappers for libdispatch on macOS" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyobjc-framework-libdispatch-10.2.tar.gz", hash = "sha256:ae17602efbe628fa0432bcf436ee8137d2239a70669faefad420cd527e3ad567"}, + {file = "pyobjc_framework_libdispatch-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:955d3e3e5ee74f6707ab06cc76ad3fae27e78c180dea13f1b85e2659f9135889"}, + {file = "pyobjc_framework_libdispatch-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:011736d708067d9b21a4722bae0ed776cbf84c8625fc81648de26228ca093f6b"}, + {file = "pyobjc_framework_libdispatch-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:28c2a2ab2b4d2930f7c7865ad96c1157ad50ac93c58ffff64d889f769917a280"}, + {file = "pyobjc_framework_libdispatch-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6cb0879e1f6773ad0bbeb82d495ad0d76d8c24b196a314ac9a6eab8eed1736e0"}, + {file = "pyobjc_framework_libdispatch-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:aa921cd469a1c2e20d8ba9118989fe4e827cbb98e947fd11ae0392f36db3afcc"}, + {file = "pyobjc_framework_libdispatch-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6f3d57d24f81878d1b5dcb00a13f85465ede5b91589394f4f1b9dcf312f3bd99"}, +] + +[package.dependencies] +pyobjc-core = ">=10.2" +pyobjc-framework-Cocoa = ">=10.2" + [[package]] name = "pyparsing" version = "3.1.2" @@ -1041,6 +1204,224 @@ files = [ {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, ] +[[package]] +name = "winrt-runtime" +version = "2.0.1" +description = "Python projection of Windows Runtime (WinRT) APIs" +optional = false +python-versions = "<3.13,>=3.9" +files = [ + {file = "winrt_runtime-2.0.1-cp310-cp310-win32.whl", hash = "sha256:b1d8c2c01b40755b8f546eaf01fef2c722af4fb6934e4ce7ad7e5eb7ba404846"}, + {file = "winrt_runtime-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:66bd7b98b5e2e2a0ae81089c26b5c284ee5f36603121584c82f2d1e0dfbfec37"}, + {file = "winrt_runtime-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:6136966a7c9f01c6cd55c7e2bc3b67573069b7f8b8ee910f1f791bece09ad597"}, + {file = "winrt_runtime-2.0.1-cp311-cp311-win32.whl", hash = "sha256:136142cecca5a87e13571277bace0ced0eee73f6d16dda967bc142bb7d4a0091"}, + {file = "winrt_runtime-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:d67360b744b1cc82efbe168ee21ed067483263f466aaab2f6321d9148b1b0552"}, + {file = "winrt_runtime-2.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:33d9b3cb99bf96082e883af0db97adc74a7f0fc7339f9ab9d28f64d59bba1212"}, + {file = "winrt_runtime-2.0.1-cp312-cp312-win32.whl", hash = "sha256:0947009e5f049bd7f3dd6284bb4161f644304877c9527c140f26e6daf9755767"}, + {file = "winrt_runtime-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:72e3ddcda15b35e77b4e334c6cdbf345e76b12e176510cc9c3b7c61a08fb6ce8"}, + {file = "winrt_runtime-2.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:e13d3ba43f3a63b506965b32353589968507f608c6c6484fa2684eb4cb9a230a"}, + {file = "winrt_runtime-2.0.1-cp39-cp39-win32.whl", hash = "sha256:a734860406b445325168b7fd9b7e98539cec6c24dc8095e3b6e6db84b2c1a656"}, + {file = "winrt_runtime-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:5dec5fc5e5f1be8fb7fd062ff30707500ff684b5fd5063fe4d7e9a196fdb9594"}, + {file = "winrt_runtime-2.0.1-cp39-cp39-win_arm64.whl", hash = "sha256:c13f40456b78f25934392a72b87cca3e50380c06732afedb7a18698f281ccd25"}, + {file = "winrt_runtime-2.0.1.tar.gz", hash = "sha256:4d485fe7d2528ae220aca621a94aeafa28d938ed679599b8c4bbad0fc8877d9d"}, +] + +[[package]] +name = "winrt-windows-devices-bluetooth" +version = "2.0.1" +description = "Python projection of Windows Runtime (WinRT) APIs" +optional = false +python-versions = "<3.13,>=3.9" +files = [ + {file = "winrt_Windows.Devices.Bluetooth-2.0.1-cp310-cp310-win32.whl", hash = "sha256:80ef50eb1d82cb869b6dc1f312bb5cd28a4c1f88946fc3abe7fc3c4f7ef2e4c8"}, + {file = "winrt_Windows.Devices.Bluetooth-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:838f66afb145e6a93fa5151f1e5883e55a781c5f1fdf37d2d903fcee7680565f"}, + {file = "winrt_Windows.Devices.Bluetooth-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:81971d961f41b71ca9999f3a6c03f35f50f9939bc144455ec6a7aea63aba8167"}, + {file = "winrt_Windows.Devices.Bluetooth-2.0.1-cp311-cp311-win32.whl", hash = "sha256:89042d64cc556ac1c49fef46b0a25ad969a66a2c473ddd5fd5f4cbd735c30c77"}, + {file = "winrt_Windows.Devices.Bluetooth-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:b6bac9fa687ab2ab4a98de2d7e96e21dfa7291bb388fcff4247096c099327cd6"}, + {file = "winrt_Windows.Devices.Bluetooth-2.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:03b461fd1d2005ff22f212ee418cc9d387502f1ea86ace9a347e81554dc95822"}, + {file = "winrt_Windows.Devices.Bluetooth-2.0.1-cp312-cp312-win32.whl", hash = "sha256:695e62296d87c676d385d427374d4f8452fc457b58d5ecd3118af01e3829370d"}, + {file = "winrt_Windows.Devices.Bluetooth-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:f80dcbd2f297e2789f367ad1fd4033e0d69057eb9dfc631327215915a95ba0b4"}, + {file = "winrt_Windows.Devices.Bluetooth-2.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:5a5bc9e541f23151255bd82ee3bffa319c35e9ba95879cdedf597cc8cc903f94"}, + {file = "winrt_Windows.Devices.Bluetooth-2.0.1-cp39-cp39-win32.whl", hash = "sha256:dffff7e6801b8e69e694b36fe1d147094fb6ac29ce54fd3ca3e52ab417473cc4"}, + {file = "winrt_Windows.Devices.Bluetooth-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:62bae806ecdf3021e1ec685d5a44012657c0961ca2027eeb1c37864f53577e51"}, + {file = "winrt_Windows.Devices.Bluetooth-2.0.1-cp39-cp39-win_arm64.whl", hash = "sha256:7f3b102e9b4bea1915cc922b571e0c226956c161102d228ec1788e3caf4e226d"}, + {file = "winrt_windows_devices_bluetooth-2.0.1.tar.gz", hash = "sha256:c91b3f54bfe1ed7e1e597566b83a625d32efe397b21473668046ccb4b57f5a28"}, +] + +[package.dependencies] +winrt-runtime = "2.0.1" + +[package.extras] +all = ["winrt-Windows.Devices.Bluetooth.GenericAttributeProfile[all] (==2.0.1)", "winrt-Windows.Devices.Bluetooth.Rfcomm[all] (==2.0.1)", "winrt-Windows.Devices.Enumeration[all] (==2.0.1)", "winrt-Windows.Devices.Radios[all] (==2.0.1)", "winrt-Windows.Foundation.Collections[all] (==2.0.1)", "winrt-Windows.Foundation[all] (==2.0.1)", "winrt-Windows.Networking[all] (==2.0.1)", "winrt-Windows.Storage.Streams[all] (==2.0.1)"] + +[[package]] +name = "winrt-windows-devices-bluetooth-advertisement" +version = "2.0.1" +description = "Python projection of Windows Runtime (WinRT) APIs" +optional = false +python-versions = "<3.13,>=3.9" +files = [ + {file = "winrt_Windows.Devices.Bluetooth.Advertisement-2.0.1-cp310-cp310-win32.whl", hash = "sha256:a63919f00fb15574443886be32295a1e95656eeda5c0a6299169338a276d03b0"}, + {file = "winrt_Windows.Devices.Bluetooth.Advertisement-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:266755af11ecb01c0c8a626da5072011ab4e1aea90426f80e1269107b8e8780a"}, + {file = "winrt_Windows.Devices.Bluetooth.Advertisement-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:856b00087a93763db157441eda78a308dc21cee816cbcf51ca7b4b07fde6cdb5"}, + {file = "winrt_Windows.Devices.Bluetooth.Advertisement-2.0.1-cp311-cp311-win32.whl", hash = "sha256:480050e8928da6c7f1f99a2b60206fbfb3252817fee0a9123142c9f8754e5687"}, + {file = "winrt_Windows.Devices.Bluetooth.Advertisement-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9272aa9ca77b356892218f32d1ffac0215fcdf331802d3bed842fd4d1448aeef"}, + {file = "winrt_Windows.Devices.Bluetooth.Advertisement-2.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:231af49fc2154a6a248d3e7c2a3ea131ac3fb870a1701c3fa5be65f258eb70e0"}, + {file = "winrt_Windows.Devices.Bluetooth.Advertisement-2.0.1-cp312-cp312-win32.whl", hash = "sha256:3038f08fc6151055b4d11468b0dda3ee46ae6080b25221c4ea54c11b255a0f50"}, + {file = "winrt_Windows.Devices.Bluetooth.Advertisement-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:b547929477be00350118589f25dfc49f825e5df5da618afec465cede6af7e0a5"}, + {file = "winrt_Windows.Devices.Bluetooth.Advertisement-2.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:ea5c861e11bc6d565ab5fe6a4af6e6064c1812fee1d0e8f9c6dff2daafbcc046"}, + {file = "winrt_Windows.Devices.Bluetooth.Advertisement-2.0.1-cp39-cp39-win32.whl", hash = "sha256:86d11fd5c055f76eefac7f6cc02450832811503b83280e26a83613afe1d17c92"}, + {file = "winrt_Windows.Devices.Bluetooth.Advertisement-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:c8495ce12fda8fce3da130664917eb199d19ca1ebf7d5ab996f5df584b5e3a1f"}, + {file = "winrt_Windows.Devices.Bluetooth.Advertisement-2.0.1-cp39-cp39-win_arm64.whl", hash = "sha256:0e91160a98e5b0fffae196982b5670e678ac919a6e14eb7e9798fdcbff45f8d2"}, + {file = "winrt_windows_devices_bluetooth_advertisement-2.0.1.tar.gz", hash = "sha256:130e6238a1897bfef98a711cdb1b02694fa0e18eb67d8fd4019a64a53685b331"}, +] + +[package.dependencies] +winrt-runtime = "2.0.1" + +[package.extras] +all = ["winrt-Windows.Devices.Bluetooth[all] (==2.0.1)", "winrt-Windows.Foundation.Collections[all] (==2.0.1)", "winrt-Windows.Foundation[all] (==2.0.1)", "winrt-Windows.Storage.Streams[all] (==2.0.1)"] + +[[package]] +name = "winrt-windows-devices-bluetooth-genericattributeprofile" +version = "2.0.1" +description = "Python projection of Windows Runtime (WinRT) APIs" +optional = false +python-versions = "<3.13,>=3.9" +files = [ + {file = "winrt_Windows.Devices.Bluetooth.GenericAttributeProfile-2.0.1-cp310-cp310-win32.whl", hash = "sha256:0a5118852dce4d50fd8d6c73ff3dc2c68403899b86060c0a85f7f0da284230cb"}, + {file = "winrt_Windows.Devices.Bluetooth.GenericAttributeProfile-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:0695c73f0f20745c83ec9d7b5b8a6f55efd0df974dea81ad8382fad193f71275"}, + {file = "winrt_Windows.Devices.Bluetooth.GenericAttributeProfile-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:8a6385cc8a1749f049f29037b2cfcce781bc80721ca4734de8ef0375b55ca1e5"}, + {file = "winrt_Windows.Devices.Bluetooth.GenericAttributeProfile-2.0.1-cp311-cp311-win32.whl", hash = "sha256:858e48931713ddfb2ad52614bb87a653d91c30f602e335a3ed27daca15860b54"}, + {file = "winrt_Windows.Devices.Bluetooth.GenericAttributeProfile-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:494000287b9b4e1b89fb4feb1379d95b2147dbf4bd4b1942f88c6c56afc2ba97"}, + {file = "winrt_Windows.Devices.Bluetooth.GenericAttributeProfile-2.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:26270ea815c26df35c5c74ad7f10a99dd976e27031cc7316350a0c0395b19ee6"}, + {file = "winrt_Windows.Devices.Bluetooth.GenericAttributeProfile-2.0.1-cp312-cp312-win32.whl", hash = "sha256:21e8c0f158adcf0b40c4b5bfd5144aa312e5edaaf759d6599c85c118ebf60214"}, + {file = "winrt_Windows.Devices.Bluetooth.GenericAttributeProfile-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:b05d929b819e83e91299b0e5b937ea1ca524b15486791ee5b513ae026ef25efa"}, + {file = "winrt_Windows.Devices.Bluetooth.GenericAttributeProfile-2.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:944215e5623d0c746a6c2e356dec36cf3a7281933f0819a3b4f2fbbddb4af382"}, + {file = "winrt_Windows.Devices.Bluetooth.GenericAttributeProfile-2.0.1-cp39-cp39-win32.whl", hash = "sha256:3e2a54db384dcf05265a855a2548e2abd9b7726c8ec4b9ad06059606c5d90409"}, + {file = "winrt_Windows.Devices.Bluetooth.GenericAttributeProfile-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:2bdbb55d4bef15c762a5d5b4e27b534146ec6580075ed9cc681e75e6ff0d5a97"}, + {file = "winrt_Windows.Devices.Bluetooth.GenericAttributeProfile-2.0.1-cp39-cp39-win_arm64.whl", hash = "sha256:01e74c76d4f16b4490d78c8c7509f2570c843366c1c6bf196a5b729520a31258"}, + {file = "winrt_windows_devices_bluetooth_genericattributeprofile-2.0.1.tar.gz", hash = "sha256:69d7dabd53fbf9acdc2d206def60f5c9777416a9d6911c3420be700aaff4e492"}, +] + +[package.dependencies] +winrt-runtime = "2.0.1" + +[package.extras] +all = ["winrt-Windows.Devices.Bluetooth[all] (==2.0.1)", "winrt-Windows.Devices.Enumeration[all] (==2.0.1)", "winrt-Windows.Foundation.Collections[all] (==2.0.1)", "winrt-Windows.Foundation[all] (==2.0.1)", "winrt-Windows.Storage.Streams[all] (==2.0.1)"] + +[[package]] +name = "winrt-windows-devices-enumeration" +version = "2.0.1" +description = "Python projection of Windows Runtime (WinRT) APIs" +optional = false +python-versions = "<3.13,>=3.9" +files = [ + {file = "winrt_Windows.Devices.Enumeration-2.0.1-cp310-cp310-win32.whl", hash = "sha256:828456ed950d8b427d78dfedd54bf7514e9793019dbf6a5a8f725560be364578"}, + {file = "winrt_Windows.Devices.Enumeration-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:217c9d14e94aea5e497f7aa8cd808e9255df98e28a12417194729debe0b77e65"}, + {file = "winrt_Windows.Devices.Enumeration-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:751c20ad01a58a3bb5f273c3cf653475448d8f77f7331b96af7fc87204f1bc6a"}, + {file = "winrt_Windows.Devices.Enumeration-2.0.1-cp311-cp311-win32.whl", hash = "sha256:8b28f4bc052a7442fdd7e3113021a264de972ca5421cc08ba53dd724f3826174"}, + {file = "winrt_Windows.Devices.Enumeration-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:e3c0316f8487547fab36556b9ac94dec75551c70e0c977b92c4eb47c12d86bb0"}, + {file = "winrt_Windows.Devices.Enumeration-2.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:572b0918f9babc9d2c31d8df800a988df2cf18492e462de602babc5d97639b16"}, + {file = "winrt_Windows.Devices.Enumeration-2.0.1-cp312-cp312-win32.whl", hash = "sha256:6b6108466574846c969ba7d14e1d085948c1724cd087a494e1913315fb3ea4e0"}, + {file = "winrt_Windows.Devices.Enumeration-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:8af4510ef393c3d97c71f082fc31412cf8b1cc8d8b74a30bab4144a5fd2edfe7"}, + {file = "winrt_Windows.Devices.Enumeration-2.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:b3d36f47715550ba980fb1be43cdfbac17a833744cb2f08c634349a8a31feb9c"}, + {file = "winrt_Windows.Devices.Enumeration-2.0.1-cp39-cp39-win32.whl", hash = "sha256:9301f5e00bd2562b063e0f6e0de6f0596b7fb3eabc443bd7e115772de6cc08f9"}, + {file = "winrt_Windows.Devices.Enumeration-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:9999d93ae9441d35c564d498bb4d6767b593254a92b7c1559058a7450a0c304e"}, + {file = "winrt_Windows.Devices.Enumeration-2.0.1-cp39-cp39-win_arm64.whl", hash = "sha256:504ca45a9b90387a2f4f727dbbeefcf79beb013ac7a29081bb14c8ab13e10367"}, + {file = "winrt_windows_devices_enumeration-2.0.1.tar.gz", hash = "sha256:ed227dd22ece253db913de24e4fc5194d9f3272e2a5959a2450ae79e81bf7949"}, +] + +[package.dependencies] +winrt-runtime = "2.0.1" + +[package.extras] +all = ["winrt-Windows.ApplicationModel.Background[all] (==2.0.1)", "winrt-Windows.Foundation.Collections[all] (==2.0.1)", "winrt-Windows.Foundation[all] (==2.0.1)", "winrt-Windows.Security.Credentials[all] (==2.0.1)", "winrt-Windows.Storage.Streams[all] (==2.0.1)", "winrt-Windows.UI.Popups[all] (==2.0.1)", "winrt-Windows.UI[all] (==2.0.1)"] + +[[package]] +name = "winrt-windows-foundation" +version = "2.0.1" +description = "Python projection of Windows Runtime (WinRT) APIs" +optional = false +python-versions = "<3.13,>=3.9" +files = [ + {file = "winrt_Windows.Foundation-2.0.1-cp310-cp310-win32.whl", hash = "sha256:f8cdc6f1f81e241a8a4d19f9d323828e61d75bd77fecfbe0c4d735e385326c4e"}, + {file = "winrt_Windows.Foundation-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:b8868c73642c66798c18ce8021796acb9beea59b6d2361344e8776c27ab847c7"}, + {file = "winrt_Windows.Foundation-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:4b5df8a9f69b15c71fe9b6f4f8e8589fe043d4d7ab843bb73607c7a4adde68f1"}, + {file = "winrt_Windows.Foundation-2.0.1-cp311-cp311-win32.whl", hash = "sha256:28ad6cd21126cc75cfb28527489e06699b36d8d6d5fdea5487e51c85ea9cc358"}, + {file = "winrt_Windows.Foundation-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:75d5a4974662ca11eab1438a711433951bef2e7db156b0c7ca34f47fbd19f117"}, + {file = "winrt_Windows.Foundation-2.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:d129a9fdfe5205bff2e9ccad705539fabd485ce6a8e47ded876aa664545b5216"}, + {file = "winrt_Windows.Foundation-2.0.1-cp312-cp312-win32.whl", hash = "sha256:a1dd4c93f435fd2f8f6e180af1cd2d3af8d22518b4c25c843e0b850b38e8be0f"}, + {file = "winrt_Windows.Foundation-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c54ac18fea4a488dae8a3261f6633c17ed2a632c35d15112caa9294f8c5560d"}, + {file = "winrt_Windows.Foundation-2.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:29f648a66a3e3285fcb5fdd1821582d60f6b3021e5dcc02acb008c8f48f15e7a"}, + {file = "winrt_Windows.Foundation-2.0.1-cp39-cp39-win32.whl", hash = "sha256:7abbf10666d6da5dbfb6a47125786a05dac267731a3d38feb8faddade9bf1151"}, + {file = "winrt_Windows.Foundation-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:aab18ad12de63a353ab1847aff3216ba4e5499e328da5edcb72c8007da6bdb02"}, + {file = "winrt_Windows.Foundation-2.0.1-cp39-cp39-win_arm64.whl", hash = "sha256:bde9ecfc1c75410d669ee3124a84ba101d5a8ab1911807ad227658624fc22ffb"}, + {file = "winrt_windows_foundation-2.0.1.tar.gz", hash = "sha256:6e4da10cff652ac17740753c38ebe69565f5f970f60100106469b2e004ef312c"}, +] + +[package.dependencies] +winrt-runtime = "2.0.1" + +[package.extras] +all = ["winrt-Windows.Foundation.Collections[all] (==2.0.1)"] + +[[package]] +name = "winrt-windows-foundation-collections" +version = "2.0.1" +description = "Python projection of Windows Runtime (WinRT) APIs" +optional = false +python-versions = "<3.13,>=3.9" +files = [ + {file = "winrt_Windows.Foundation.Collections-2.0.1-cp310-cp310-win32.whl", hash = "sha256:805f8d9a2f61276eb8e4284d439c61893c5acca0c17265f6dc10b8747c89bc39"}, + {file = "winrt_Windows.Foundation.Collections-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:2464c2b67e732f7e05497ea04ee43b9926743f10e8766c90a279270a3afe4b6a"}, + {file = "winrt_Windows.Foundation.Collections-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:ab1094c0091c573b1ecf72fd3cd8380d6eef9e6d0f59ccc5e676c697702eddc2"}, + {file = "winrt_Windows.Foundation.Collections-2.0.1-cp311-cp311-win32.whl", hash = "sha256:be0bd1b45252da5142b6ee80e3e488ad50931c6595e70674556ccad36080f2a9"}, + {file = "winrt_Windows.Foundation.Collections-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:a4f299a006266632240cc66ade8d82db6167a769fb1b5ec76cf22f2dfb43777a"}, + {file = "winrt_Windows.Foundation.Collections-2.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:84d66f1e2c8896534cfca80eaf4508e25d34e34b37b1e2eb4beb7462220edf78"}, + {file = "winrt_Windows.Foundation.Collections-2.0.1-cp312-cp312-win32.whl", hash = "sha256:d36a49ee53c8726148cac1920bf57a95b07eab576275b5efb0e97adea6fdacb2"}, + {file = "winrt_Windows.Foundation.Collections-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:c63e46569024e1504cc8e3b4f233e69162bc92e0428b4e92cb7dbc7cdc89db5f"}, + {file = "winrt_Windows.Foundation.Collections-2.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:5f5aac867f2b2fbc65e453c942bfde5bb158e60f47d2615455143fab335694e8"}, + {file = "winrt_Windows.Foundation.Collections-2.0.1-cp39-cp39-win32.whl", hash = "sha256:c26ab7b3342669dc09be62db5c5434e7194fb6eb1ec5b03fba1163f6b3e7b843"}, + {file = "winrt_Windows.Foundation.Collections-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:2f9bc7e28f3ade1c1f3113939dbf630bfef5e3c3018c039a404d7e4d39aae4cb"}, + {file = "winrt_Windows.Foundation.Collections-2.0.1-cp39-cp39-win_arm64.whl", hash = "sha256:1f3e76f3298bec3938d94e4857c29af9776ec78112bdd09bb7794f06fd38bb13"}, + {file = "winrt_windows_foundation_collections-2.0.1.tar.gz", hash = "sha256:7d18955f161ba27d785c8fe2ef340f338b6edd2c5226fe2b005840e2a855e708"}, +] + +[package.dependencies] +winrt-runtime = "2.0.1" + +[package.extras] +all = ["winrt-Windows.Foundation[all] (==2.0.1)"] + +[[package]] +name = "winrt-windows-storage-streams" +version = "2.0.1" +description = "Python projection of Windows Runtime (WinRT) APIs" +optional = false +python-versions = "<3.13,>=3.9" +files = [ + {file = "winrt_Windows.Storage.Streams-2.0.1-cp310-cp310-win32.whl", hash = "sha256:9e88593f17983b5714957c6f48e7ecdc8fb4410d57cd4b097aded722dc5243d3"}, + {file = "winrt_Windows.Storage.Streams-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:23bfecd91c2b4355f2281dc0cf8a29a32f1783d61f7df8162c29516a30df98a2"}, + {file = "winrt_Windows.Storage.Streams-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:4bbbb6476e25563395834ca0d18a674f3ae97dde8b10e1713f569ec60557ed92"}, + {file = "winrt_Windows.Storage.Streams-2.0.1-cp311-cp311-win32.whl", hash = "sha256:ed64b2215b6a1ff21c6849948e02fd7f31d1dbf81a4c25871d87dbb97029410e"}, + {file = "winrt_Windows.Storage.Streams-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ba46b0c7ca819598d2559c2374be9fb1e374a0d866a4fdca15fc1900d83e080"}, + {file = "winrt_Windows.Storage.Streams-2.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:0e802596bac1b59476a4a5a0cd68c7bd0483c4c3b4e4a2489768108729213113"}, + {file = "winrt_Windows.Storage.Streams-2.0.1-cp312-cp312-win32.whl", hash = "sha256:8d04759f1370514f95e486c7fad1ec33047dc8db275dd839bb906d79d2ee6088"}, + {file = "winrt_Windows.Storage.Streams-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:af2a459bdef54702972e05d9ba3bdc3583816404bddb79831f4a7b9a74e37ff1"}, + {file = "winrt_Windows.Storage.Streams-2.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:0a5446194fb88125569e293657f6bac926731d8ff6126f1b693848fbd2c72167"}, + {file = "winrt_Windows.Storage.Streams-2.0.1-cp39-cp39-win32.whl", hash = "sha256:f6dec418ad0118c258a1b2999fc8d4fc0d9575e6353a75a242ff8cc63c9b2146"}, + {file = "winrt_Windows.Storage.Streams-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:9fbc40f600ab44a45cda47b698bd8e494e80e221446a5958c4d8d59a8d46f117"}, + {file = "winrt_Windows.Storage.Streams-2.0.1-cp39-cp39-win_arm64.whl", hash = "sha256:08059774c6d49d195ce00c3802d19364f418a6f3e42b94373621551792d2da60"}, + {file = "winrt_windows_storage_streams-2.0.1.tar.gz", hash = "sha256:3de8351ed3a9cfcfd1d028ce97ffe90bb95744f906eef025b06e7f4431943ee6"}, +] + +[package.dependencies] +winrt-runtime = "2.0.1" + +[package.extras] +all = ["winrt-Windows.Foundation.Collections[all] (==2.0.1)", "winrt-Windows.Foundation[all] (==2.0.1)", "winrt-Windows.Storage[all] (==2.0.1)", "winrt-Windows.System[all] (==2.0.1)"] + [[package]] name = "yarl" version = "1.9.4" @@ -1164,5 +1545,5 @@ examples = ["aiohttp", "matplotlib", "numpy", "prometheus-client", "pyyaml"] [metadata] lock-version = "2.0" -python-versions = "^3.9" -content-hash = "c1f54f063b1ab0b860b9f8bca0c295cacb07ed0547ad15975264f4dd4cd0e6c7" +python-versions = ">=3.9,<3.13" +content-hash = "1954f372f219b6c2ec7a96c8ff6554138902f9fed15bb76d5ed0ebe43efb54a2" diff --git a/pyproject.toml b/pyproject.toml index 6027321..64cdcca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,8 +14,9 @@ classifiers = [ include = ["radiacode-examples/*"] [tool.poetry.dependencies] -python = "^3.9" +python = ">=3.9,<3.13" bluepy = { version = "^1.3", markers = "sys_platform != 'darwin'" } +bleak = { version = "^0.22.0", markers = "sys_platform == 'darwin'" } pyusb = "^1.2" aiohttp = {version = "^3.9", optional = true} prometheus-client = {version = "^0.19", optional = true} diff --git a/radiacode-examples/basic.py b/radiacode-examples/basic.py index 07a8799..daf67be 100644 --- a/radiacode-examples/basic.py +++ b/radiacode-examples/basic.py @@ -1,21 +1,11 @@ import argparse -import time, platform +import time, platform, asyncio from radiacode import RadiaCode from radiacode.transports.usb import DeviceNotFound as DeviceNotFoundUSB from radiacode.transports.bluetooth import DeviceNotFound as DeviceNotFoundBT -def main(): - parser = argparse.ArgumentParser() - - if platform.system() != 'Darwin': - parser.add_argument('--bluetooth-mac', type=str, required=False, help='bluetooth MAC address of radiascan device (e.g. 00:11:22:33:44:55)') - - parser.add_argument('--serial', type=str, required=False, - help='serial number of radiascan device (e.g. "RC-10x-xxxxxx"). Useful in case of multiple devices.') - - args = parser.parse_args() - +async def main(args: argparse.Namespace): if hasattr(args, 'bluetooth_mac') and getattr(args, 'bluetooth_mac', None): print(f'Connecting to Radiacode via Bluetooth (MAC address: {args.bluetooth_mac})') @@ -27,6 +17,20 @@ def main(): except ValueError as e: print(e) return + elif hasattr(args, 'bluetooth') and getattr(args, 'bluetooth', None): + if args.bluetooth is None: + print('Scanning for devices. We will try to connect to the first Radiacode available via Bluetooth') + else: + print(f'Scanning for devices. We will try to connect to: {args.bluetooth}') + + try: + rc = await RadiaCode.BT(args.bluetooth) + except DeviceNotFoundBT as e: + print(e) + return + except ValueError as e: + print(e) + return else: print('Connecting to Radiacode via USB' + (f' (serial number: {args.serial})' if args.serial else '')) @@ -36,24 +40,39 @@ def main(): print('Device not found, check your USB connection') return - serial = rc.serial_number() + await rc.set_sound_on(False) + + serial = await rc.serial_number() print(f'### Serial number: {serial}') print('--------') - fw_version = rc.fw_version() + fw_version = await rc.fw_version() print(f'### Firmware: {fw_version}') print('--------') - spectrum = rc.spectrum() + spectrum = await rc.spectrum() print(f'### Spectrum: {spectrum}') print('--------') print('### DataBuf:') while True: - for v in rc.data_buf(): + for v in await rc.data_buf(): print(v.dt.isoformat(), v) time.sleep(2) if __name__ == '__main__': - main() + parser = argparse.ArgumentParser() + + if platform.system() != 'Darwin': + parser.add_argument('--bluetooth-mac', type=str, required=False, help='bluetooth MAC address of radiascan device (e.g. 00:11:22:33:44:55)') + else: + parser.add_argument('--bluetooth', type=str, required=False, help='Radiacode Serial (e.g. "RC-10x-xxxxxx"). \ + Since MacOS does not show Bluetooth MACs, the device has to be identified via its serial number.') + + parser.add_argument('--serial', type=str, required=False, + help='serial number of Radiacode device (e.g. "RC-10x-xxxxxx"). Useful in case of multiple devices.') + + args = parser.parse_args() + + asyncio.run(main(args)) diff --git a/radiacode/radiacode.py b/radiacode/radiacode.py index 1873178..8a4d7c8 100644 --- a/radiacode/radiacode.py +++ b/radiacode/radiacode.py @@ -21,41 +21,79 @@ class RadiaCode: def __init__( self, bluetooth_mac: Optional[str] = None, + bluetooth_serial: Optional[str] = None, serial_number: Optional[str] = None, ignore_firmware_compatibility_check: bool = False, ): self._seq = 0 - # Bluepy doesn't support MacOS: https://github.com/IanHarvey/bluepy/issues/44 - self._bt_supported = False if platform.system() == 'Darwin' else True - - if bluetooth_mac is not None and self._bt_supported == True: - self._connection = Bluetooth(bluetooth_mac) + if bluetooth_mac is not None: + if platform.system() != 'Darwin': + self._connection = Bluetooth(bluetooth_mac) + else: + self._connection = None + elif bluetooth_serial is not None: + self._connection = None + return else: self._connection = Usb(serial_number=serial_number) - # init - self.execute(b'\x07\x00', b'\x01\xff\x12\xff') + # Linux and Windows + if platform.system() != 'Darwin': + # init + self.execute(b'\x07\x00', b'\x01\xff\x12\xff') + self._base_time = datetime.datetime.now() + self.set_local_time(self._base_time) + self.device_time(0) + + (_, (vmaj, vmin, _)) = self.fw_version() + if ignore_firmware_compatibility_check is False and vmaj < 4 or (vmaj == 4 and vmin < 8): + raise Exception( + f'Incompatible firmware version {vmaj}.{vmin}, >=4.8 required. Upgrade device firmware or use radiacode==0.2.2' + ) + + self._spectrum_format_version = 0 + for line in self.configuration().split('\n'): + if line.startswith('SpecFormatVersion'): + self._spectrum_format_version = int(line.split('=')[1]) + break + + # Only called on Mac + async def _connect(self, bluetooth_serial, ignore_firmware_compatibility_check = False): + bt = Bluetooth() + await bt.connect(bluetooth_serial) + self._connection = bt + + # Init the rest here + await self.execute(b'\x07\x00', b'\x01\xff\x12\xff') self._base_time = datetime.datetime.now() - self.set_local_time(self._base_time) - self.device_time(0) + await self.set_local_time(self._base_time) + await self.device_time(0) - (_, (vmaj, vmin, _)) = self.fw_version() + (_, (vmaj, vmin, _)) = await self.fw_version() if ignore_firmware_compatibility_check is False and vmaj < 4 or (vmaj == 4 and vmin < 8): raise Exception( f'Incompatible firmware version {vmaj}.{vmin}, >=4.8 required. Upgrade device firmware or use radiacode==0.2.2' ) self._spectrum_format_version = 0 - for line in self.configuration().split('\n'): + lines = await self.configuration() + + for line in lines.split('\n'): if line.startswith('SpecFormatVersion'): self._spectrum_format_version = int(line.split('=')[1]) break + @classmethod + async def BT(cls, bluetooth_serial): + self = cls(bluetooth_serial) + await self._connect(bluetooth_serial) + return self + def base_time(self) -> datetime.datetime: return self._base_time - def execute(self, reqtype: bytes, args: Optional[bytes] = None) -> BytesBuffer: + async def execute(self, reqtype: bytes, args: Optional[bytes] = None) -> BytesBuffer: assert len(reqtype) == 2 req_seq_no = 0x80 + self._seq self._seq = (self._seq + 1) % 32 @@ -64,13 +102,13 @@ def execute(self, reqtype: bytes, args: Optional[bytes] = None) -> BytesBuffer: request = req_header + (args or b'') full_request = struct.pack(' BytesBuffer: - r = self.execute(b'\x26\x08', struct.pack(' BytesBuffer: + r = await self.execute(b'\x26\x08', struct.pack(' BytesBuffer: assert r.size() == flen, f'{command_id}: got size {r.size()}, expect {flen}' return r - def write_request(self, command_id: Union[int, VSFR], data: Optional[bytes] = None) -> None: - r = self.execute(b'\x25\x08', struct.pack(' None: + r = await self.execute(b'\x25\x08', struct.pack(' List[int]: + async def batch_read_vsfrs(self, vsfr_ids: List[VSFR]) -> List[int]: assert len(vsfr_ids) - r = self.execute(b'\x2a\x08', b''.join(struct.pack(' str: - r = self.execute(b'\x05\x00') + async def status(self) -> str: + r = await self.execute(b'\x05\x00') flags = r.unpack(' None: + async def set_local_time(self, dt: datetime.datetime) -> None: d = struct.pack(' str: - r = self.execute(b'\x01\x01') + async def fw_signature(self) -> str: + r = await self.execute(b'\x01\x01') signature = r.unpack(' tuple[tuple[int, int, str], tuple[int, int, str]]: - r = self.execute(b'\x0a\x00') + async def fw_version(self) -> tuple[tuple[int, int, str], tuple[int, int, str]]: + r = await self.execute(b'\x0a\x00') boot_minor, boot_major = r.unpack(' tuple[tuple[int, int, str], tuple[int, int, str]]: assert r.size() == 0 return ((boot_major, boot_minor, boot_date), (target_major, target_minor, target_date.strip('\x00'))) - def hw_serial_number(self) -> str: - r = self.execute(b'\x0b\x00') + async def hw_serial_number(self) -> str: + r = await self.execute(b'\x0b\x00') serial_len = r.unpack(' str: - r = self.read_request(VS.CONFIGURATION) + async def configuration(self) -> str: + r = await self.read_request(VS.CONFIGURATION) return r.data().decode('cp1251') - def text_message(self) -> str: - r = self.read_request(VS.TEXT_MESSAGE) + async def text_message(self) -> str: + r = await self.read_request(VS.TEXT_MESSAGE) return r.data().decode('ascii') - def serial_number(self) -> str: - r = self.read_request(8) + async def serial_number(self) -> str: + r = await self.read_request(8) return r.data().decode('ascii') - def commands(self) -> str: - br = self.read_request(257) + async def commands(self) -> str: + br = await self.read_request(257) return br.data().decode('ascii') # called with 0 after init! - def device_time(self, v: int) -> None: - self.write_request(VSFR.DEVICE_TIME, struct.pack(' None: + await self.write_request(VSFR.DEVICE_TIME, struct.pack(' List[Union[DoseRateDB, RareData, RealTimeData, RawData, Event]]: - r = self.read_request(VS.DATA_BUF) + async def data_buf(self) -> List[Union[DoseRateDB, RareData, RealTimeData, RawData, Event]]: + r = await self.read_request(VS.DATA_BUF) return decode_VS_DATA_BUF(r, self._base_time) - def spectrum(self) -> Spectrum: - r = self.read_request(VS.SPECTRUM) + async def spectrum(self) -> Spectrum: + r = await self.read_request(VS.SPECTRUM) return decode_RC_VS_SPECTRUM(r, self._spectrum_format_version) - def spectrum_accum(self) -> Spectrum: - r = self.read_request(VS.SPEC_ACCUM) + async def spectrum_accum(self) -> Spectrum: + r = await self.read_request(VS.SPEC_ACCUM) return decode_RC_VS_SPECTRUM(r, self._spectrum_format_version) - def dose_reset(self) -> None: - self.write_request(VSFR.DOSE_RESET) + async def dose_reset(self) -> None: + await self.write_request(VSFR.DOSE_RESET) - def spectrum_reset(self) -> None: - r = self.execute(b'\x27\x08', struct.pack(' None: + r = await self.execute(b'\x27\x08', struct.pack(' List[float]: - r = self.read_request(VS.ENERGY_CALIB) + async def energy_calib(self) -> List[float]: + r = await self.read_request(VS.ENERGY_CALIB) return list(r.unpack(' None: + async def set_energy_calib(self, coef: List[float]) -> None: assert len(coef) == 3 pc = struct.pack(' None: + async def set_language(self, lang='en') -> None: assert lang in {'ru', 'en'}, 'unsupported lang value - use "ru" or "en"' - self.write_request(VSFR.DEVICE_LANG, struct.pack(' None: - self.write_request(VSFR.SOUND_ON, struct.pack(' None: + await self.write_request(VSFR.SOUND_ON, struct.pack(' None: - self.write_request(VSFR.SOUND_ON, struct.pack(' None: + await self.write_request(VSFR.SOUND_ON, struct.pack(' None: + async def set_sound_ctrl(self, ctrls: List[CTRL]) -> None: flags = 0 for c in ctrls: flags |= int(c) - self.write_request(VSFR.SOUND_CTRL, struct.pack(' None: + async def set_display_off_time(self, seconds: int) -> None: assert seconds in {5, 10, 15, 30} v = 3 if seconds == 30 else (seconds // 5) - 1 - self.write_request(VSFR.DISP_OFF_TIME, struct.pack(' None: + async def set_display_brightness(self, brightness: int) -> None: assert 0 <= brightness and brightness <= 9 - self.write_request(VSFR.DISP_BRT, struct.pack(' None: + async def set_display_direction(self, direction: DisplayDirection) -> None: assert isinstance(direction, DisplayDirection) - self.write_request(VSFR.DISP_DIR, struct.pack(' None: + async def set_vibro_ctrl(self, ctrls: List[CTRL]) -> None: flags = 0 for c in ctrls: assert c != CTRL.CLICKS, 'CTRL.CLICKS not supported for vibro' flags |= int(c) - self.write_request(VSFR.VIBRO_CTRL, struct.pack('= 0 + + if self._resp_size == 0: + self._response = self._resp_buffer + self._resp_buffer = b'' + + #print(f'{tok} Notification: {characteristic.description}: {self._resp_buffer}') + + async def execute(self, req) -> BytesBuffer: + # for pos in range(0, len(req), 18): + # rp = req[pos : min(pos + 18, len(req))] + # self.p.writeCharacteristic(self.write_fd, rp) + if self.client is None or self.client.is_connected == False: + await self.client.connect() + + if self.client.is_connected == False: + raise DeviceNotFound(f'{tnok} Connection to the device not active') + + # Request data + self._response = [] + await self.client.write_gatt_char(self.writefd, req, response=False) + await asyncio.sleep(2.0) + #await self.client.stop_notify(notif) + + br = BytesBuffer(self._response) + self._response = None + return br + else: from bluepy.btle import BTLEDisconnectError, DefaultDelegate, Peripheral from radiacode.bytes_buffer import BytesBuffer From 54d4fec86a70ed536d342a2030ed679332b457fb Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Tue, 7 May 2024 20:00:18 +0800 Subject: [PATCH 03/20] Migrating the framework to Bleak --- radiacode-examples/basic.py | 77 ++++------ radiacode-examples/webserver.py | 102 +++++++------ radiacode/radiacode.py | 90 +++++------ radiacode/transports/bluetooth.py | 241 ++++++++++++++---------------- radiacode/transports/usb.py | 5 +- 5 files changed, 251 insertions(+), 264 deletions(-) diff --git a/radiacode-examples/basic.py b/radiacode-examples/basic.py index daf67be..f651f30 100644 --- a/radiacode-examples/basic.py +++ b/radiacode-examples/basic.py @@ -1,46 +1,39 @@ import argparse -import time, platform, asyncio +import time, asyncio from radiacode import RadiaCode from radiacode.transports.usb import DeviceNotFound as DeviceNotFoundUSB from radiacode.transports.bluetooth import DeviceNotFound as DeviceNotFoundBT async def main(args: argparse.Namespace): - if hasattr(args, 'bluetooth_mac') and getattr(args, 'bluetooth_mac', None): - print(f'Connecting to Radiacode via Bluetooth (MAC address: {args.bluetooth_mac})') - - try: - rc = RadiaCode(bluetooth_mac=args.bluetooth_mac) - except DeviceNotFoundBT as e: - print(e) - return - except ValueError as e: - print(e) - return - elif hasattr(args, 'bluetooth') and getattr(args, 'bluetooth', None): - if args.bluetooth is None: - print('Scanning for devices. We will try to connect to the first Radiacode available via Bluetooth') + try: + if args.bluetooth_mac: + print(f'Connecting to Radiacode via Bluetooth (MAC address: {args.bluetooth_mac})') + rc = await RadiaCode.connect(bluetooth_mac=args.bluetooth_mac) + elif args.bluetooth_uuid: + print(f'Connecting to Radiacode via Bluetooth (UUID: {args.bluetooth_uuid})') + rc = await RadiaCode.connect(bluetooth_uuid=args.bluetooth_uuid) + elif args.bluetooth_serial: + print(f'Connecting to Radiacode via Bluetooth (Serial: {args.bluetooth_serial})') + rc = await RadiaCode.connect(bluetooth_serial=args.bluetooth_serial) + elif args.serial: + print(f'Connecting to Radiacode via USB (Serial: {args.serial})') + rc = await RadiaCode.connect(serial_number=args.serial) else: - print(f'Scanning for devices. We will try to connect to: {args.bluetooth}') - - try: - rc = await RadiaCode.BT(args.bluetooth) - except DeviceNotFoundBT as e: - print(e) - return - except ValueError as e: - print(e) - return - else: - print('Connecting to Radiacode via USB' + (f' (serial number: {args.serial})' if args.serial else '')) - - try: - rc = RadiaCode(serial_number=args.serial) - except DeviceNotFoundUSB: - print('Device not found, check your USB connection') - return - - await rc.set_sound_on(False) + print('Connecting to Radiacode via USB') + rc = await RadiaCode.connect() + except DeviceNotFoundBT as e: + print(e) + return + except DeviceNotFoundUSB: + print('Radiacode not found, check your USB connection') + return + except ValueError as e: + print(e) + return + except Exception as e: + print(e) + return serial = await rc.serial_number() print(f'### Serial number: {serial}') @@ -60,18 +53,14 @@ async def main(args: argparse.Namespace): print(v.dt.isoformat(), v) time.sleep(2) - if __name__ == '__main__': parser = argparse.ArgumentParser() - if platform.system() != 'Darwin': - parser.add_argument('--bluetooth-mac', type=str, required=False, help='bluetooth MAC address of radiascan device (e.g. 00:11:22:33:44:55)') - else: - parser.add_argument('--bluetooth', type=str, required=False, help='Radiacode Serial (e.g. "RC-10x-xxxxxx"). \ - Since MacOS does not show Bluetooth MACs, the device has to be identified via its serial number.') - - parser.add_argument('--serial', type=str, required=False, - help='serial number of Radiacode device (e.g. "RC-10x-xxxxxx"). Useful in case of multiple devices.') + parser.add_argument('--bluetooth-mac', type=str, required=False, help='Radiacode Bluetooth MAC address (e.g. 00:11:22:33:44:55). MacOS does not support BT MACs, use Serial Number or UUID instead.') + parser.add_argument('--bluetooth-serial', type=str, required=False, help='Connect via Bluetooth using Radiacode Serial (e.g. "RC-10x-xxxxxx").') + parser.add_argument('--bluetooth-uuid', type=str, required=False, help='Connect via Bluetooth using Radiacode UUID (e.g. "11111111-2222-3333-4444-56789ABCDEF").') + parser.add_argument('--serial', type=str, required=False, help='Connect via USB using Radiacode Serial (e.g. "RC-10x-xxxxxx").') + parser.add_argument('--usb', type=str, required=False, help='(default) Connect via USB to the first Radiacode available.') args = parser.parse_args() diff --git a/radiacode-examples/webserver.py b/radiacode-examples/webserver.py index 687e8ac..9a805ae 100644 --- a/radiacode-examples/webserver.py +++ b/radiacode-examples/webserver.py @@ -7,55 +7,55 @@ from radiacode import RadiaCode, RealTimeData - async def handle_index(request): return web.FileResponse(pathlib.Path(__file__).parent.absolute() / 'webserver.html') - async def handle_ws(request): ws = web.WebSocketResponse() await ws.prepare(request) - request.app.ws_clients.append(ws) - async for _ in ws: - pass - request.app.ws_clients.remove(ws) - return ws + request.app['ws_clients'].append(ws) + try: + async for _ in ws: + pass + finally: + request.app['ws_clients'].remove(ws) + + return ws async def handle_spectrum(request): - cn = request.app.rc_conn + cn = request.app['rc_conn'] accum = request.query.get('accum') == 'true' - spectrum = cn.spectrum_accum() if accum else cn.spectrum() + spectrum = await (cn.spectrum_accum() if accum else await cn.spectrum()) + # apexcharts can't handle 0 in logarithmic view spectrum_data = [(channel, cnt if cnt > 0 else 0.5) for channel, cnt in enumerate(spectrum.counts)] - print('Spectrum updated') - return web.json_response( - { - 'coef': [spectrum.a0, spectrum.a1, spectrum.a2], - 'duration': spectrum.duration.total_seconds(), - 'series': [{'name': 'spectrum', 'data': spectrum_data}], - }, - ) - + + return web.json_response({ + 'coef': [spectrum.a0, spectrum.a1, spectrum.a2], + 'duration': spectrum.duration.total_seconds(), + 'series': [{'name': 'spectrum', 'data': spectrum_data}], + }) async def handle_spectrum_reset(request): - cn = request.app.rc_conn - cn.spectrum_reset() - print('Spectrum reset') - return web.json_response({}) - + cn = request.app['rc_conn'] + await cn.spectrum_reset() + return web.json_response({'message': 'Spectrum reset'}) async def process(app): max_history_size = 128 history = [] + while True: - databuf = app.rc_conn.data_buf() + databuf = await app['rc_conn'].data_buf() + for v in databuf: if isinstance(v, RealTimeData): history.append(v) history.sort(key=lambda x: x.dt) history = history[-max_history_size:] + jdata = json.dumps( { 'series': [ @@ -70,37 +70,45 @@ async def process(app): ], }, ) - print(f'Rates updated, sending to {len(app.ws_clients)} connected clients') - await asyncio.gather(*[ws.send_str(jdata) for ws in app.ws_clients], asyncio.sleep(1.0)) + + print(f'Rates updated, sending to {len(app["ws_clients"])} connected clients') + await asyncio.gather(*(ws.send_str(jdata) for ws in app['ws_clients'])) + await asyncio.sleep(1.0) async def on_startup(app): - asyncio.create_task(process(app)) + app['process_task'] = asyncio.create_task(process(app)) + app['ws_clients'] = [] +async def init_connection(app): + if app['args'].bluetooth_mac: + print('will use Bluetooth connection') + app['rc_conn'] = await RadiaCode.connect(bluetooth_mac=app['args'].bluetooth_mac) + else: + print('will use USB connection') + app['rc_conn'] = await RadiaCode.connect() -if __name__ == '__main__': +def main(): parser = argparse.ArgumentParser() - parser.add_argument('--bluetooth-mac', type=str, required=False, help='bluetooth MAC address of radiascan device') - parser.add_argument('--listen-host', type=str, required=False, default='0.0.0.0', help='listen host for webserver') - parser.add_argument('--listen-port', type=int, required=False, default=8080, help='listen port for webserver') + parser.add_argument('--bluetooth-mac', type=str, required=False, help='Bluetooth MAC address of radiascan device') + parser.add_argument('--listen-host', type=str, required=False, default='127.0.0.1', help='Listen host for webserver') + parser.add_argument('--listen-port', type=int, required=False, default=8080, help='Listen port for webserver') args = parser.parse_args() app = web.Application() - app.ws_clients = [] - if args.bluetooth_mac: - print('will use Bluetooth connection') - app.rc_conn = RadiaCode(bluetooth_mac=args.bluetooth_mac) - else: - print('will use USB connection') - app.rc_conn = RadiaCode() - + app['args'] = args + app.on_startup.append(init_connection) app.on_startup.append(on_startup) - app.add_routes( - [ - web.get('/', handle_index), - web.get('/spectrum', handle_spectrum), - web.post('/spectrum/reset', handle_spectrum_reset), - web.get('/ws', handle_ws), - ], - ) + + app.add_routes([ + web.get('/', handle_index), + web.get('/spectrum', handle_spectrum), + web.post('/spectrum/reset', handle_spectrum_reset), + web.get('/ws', handle_ws), + ]) + web.run_app(app, host=args.listen_host, port=args.listen_port) + +if __name__ == '__main__': + main() + diff --git a/radiacode/radiacode.py b/radiacode/radiacode.py index 8a4d7c8..b22556b 100644 --- a/radiacode/radiacode.py +++ b/radiacode/radiacode.py @@ -1,5 +1,5 @@ import datetime -import struct, platform +import struct, platform, binascii from typing import List, Optional, Union from radiacode.bytes_buffer import BytesBuffer @@ -9,12 +9,15 @@ from radiacode.transports.usb import Usb from radiacode.types import CTRL, VS, VSFR, DisplayDirection, DoseRateDB, Event, RareData, RawData, RealTimeData, Spectrum +tok = '[\033[1;32m\N{check mark}\033[0m]' +tnok = '[\033[1;31m\N{aegean check mark}\033[0m]' +tinfo = '[\033[1;34m\N{information source}\033[0m]' +twarn = '[\033[1;35m\N{warning sign}\033[0m]' # channel number -> kEv def spectrum_channel_to_energy(channel_number: int, a0: float, a1: float, a2: float) -> float: return a0 + a1 * channel_number + a2 * channel_number * channel_number - class RadiaCode: _connection: Union[Bluetooth, Usb] @@ -22,50 +25,55 @@ def __init__( self, bluetooth_mac: Optional[str] = None, bluetooth_serial: Optional[str] = None, - serial_number: Optional[str] = None, - ignore_firmware_compatibility_check: bool = False, + bluetooth_uuid: Optional[str] = None, + serial_number: Optional[str] = None ): self._seq = 0 + self._usb = False if bluetooth_mac is not None: - if platform.system() != 'Darwin': - self._connection = Bluetooth(bluetooth_mac) - else: - self._connection = None + self._connection = Bluetooth(bluetooth_mac=bluetooth_mac) elif bluetooth_serial is not None: - self._connection = None - return + self._connection = Bluetooth(bluetooth_serial=bluetooth_serial) + elif bluetooth_uuid is not None: + self._connection = Bluetooth(bluetooth_uuid=bluetooth_uuid) else: + self._usb = True + # Connect over USB self._connection = Usb(serial_number=serial_number) - # Linux and Windows - if platform.system() != 'Darwin': - # init - self.execute(b'\x07\x00', b'\x01\xff\x12\xff') - self._base_time = datetime.datetime.now() - self.set_local_time(self._base_time) - self.device_time(0) - - (_, (vmaj, vmin, _)) = self.fw_version() - if ignore_firmware_compatibility_check is False and vmaj < 4 or (vmaj == 4 and vmin < 8): - raise Exception( - f'Incompatible firmware version {vmaj}.{vmin}, >=4.8 required. Upgrade device firmware or use radiacode==0.2.2' - ) - - self._spectrum_format_version = 0 - for line in self.configuration().split('\n'): - if line.startswith('SpecFormatVersion'): - self._spectrum_format_version = int(line.split('=')[1]) - break - - # Only called on Mac - async def _connect(self, bluetooth_serial, ignore_firmware_compatibility_check = False): - bt = Bluetooth() - await bt.connect(bluetooth_serial) - self._connection = bt - - # Init the rest here + @classmethod + async def connect(cls, + bluetooth_mac: Optional[str] = None, + bluetooth_serial: Optional[str] = None, + bluetooth_uuid: Optional[str] = None, + serial_number: Optional[str] = None, + ignore_firmware_compatibility_check: bool = False): + + if platform.system() == 'Darwin' and bluetooth_mac: + print(f'{tnok} You bluetooth connection using MAC address, but you appear to be on a Mac.') + print(f'{tnok} Apple does not expose Bluetooth MAC addresses anymore, so this method will not work.') + print(f'{tnok} Try connecting to the device using another option (UUID or Serial).') + + raise Exception(f'Exception: The chosen connection method does not work on this platform.') + + self = cls(bluetooth_mac=bluetooth_mac, + bluetooth_serial=bluetooth_serial, + bluetooth_uuid=bluetooth_uuid, + serial_number=serial_number) + + await self._init_device(ignore_firmware_compatibility_check) + return self + + async def _init_device(self, ignore_firmware_compatibility_check = False): + if self._usb is False: + # Connect over Bluetooth + await self._connection.connect() + + # Init + print(f'{tinfo} Initializing Radiacode...') await self.execute(b'\x07\x00', b'\x01\xff\x12\xff') + self._base_time = datetime.datetime.now() await self.set_local_time(self._base_time) await self.device_time(0) @@ -84,11 +92,7 @@ async def _connect(self, bluetooth_serial, ignore_firmware_compatibility_check = self._spectrum_format_version = int(line.split('=')[1]) break - @classmethod - async def BT(cls, bluetooth_serial): - self = cls(bluetooth_serial) - await self._connect(bluetooth_serial) - return self + print(f'{tok} Initialization completed') def base_time(self) -> datetime.datetime: return self._base_time @@ -111,10 +115,12 @@ async def read_request(self, command_id: Union[int, VS, VSFR]) -> BytesBuffer: r = await self.execute(b'\x26\x08', struct.pack(' None: + if self.bluetooth_mac: + if len(self.bluetooth_uuid) != 17: + print(f'{twarn} The provided MAC address does not seem to be valid, but we will try anyway') + + self.client = BleakClient(self.bluetooth_mac) + elif self.bluetooth_serial: + if len(self.bluetooth_serial) < 6: + print(f'{twarn} To improve reliability, try to provide at least 6 digits of your Radiacode serial number') - # self.p.writeCharacteristic(notify_fd + 1, b'\x01\x00') - - async def connect(self, serial=None): bt_devices = await self._scan() if len(bt_devices) == 0: - raise DeviceNotFound(f'{tnok} No valid Radiacodes found. Check that bluetooth is enabled.') + raise DeviceNotFound(f'{tnok} No Radiacodes found. Check that bluetooth is enabled and that the Radiacode is not connected to another device.') - ble, adv = (None, None) + ble, _ = (None, None) - if serial is not None: - for b, a in bt_devices: - if serial in str(a.local_name): - ble, adv = b, a - break - else: # Pick the first device if no serial is specified - ble, adv = bt_devices[0] + # Find the requested device in the list + for b, a in bt_devices: + if self.bluetooth_serial in str(a.local_name): + ble = b + break if ble is None: - raise DeviceNotFound(f'{tnok} No valid Radiacodes found while scanning. Check that the Radiacode is not connected to other devices then try again.') + raise DeviceNotFound(f'{tnok} No matching serial found while scanning. We were looking for: {self.bluetooth_serial}') self.client = BleakClient(ble) - await self.client.connect() - - if self.client.is_connected: - print(f'{tok} Connected via Bluetooth to {adv.local_name}') - else: - raise DeviceNotFound(f'{tnok} Cannot connect to {adv.local_name} - UUID: {ble[0]}') - - # Start notifications - self.notiffd = self.client.services.get_characteristic(RADIACODE_NOTIFYFD_UUID) - await self.client.start_notify(self.notiffd, self.handleNotification) + elif self.bluetooth_uuid: + if len(self.bluetooth_uuid) != 36: + print(f'{twarn} The provided UUID does not seem to be valid, but we will try anyway') - self.writefd = self.client.services.get_characteristic(RADIACODE_WRITEFD_UUID) + self.client = BleakClient(self.bluetooth_uuid) + else: + raise DeviceNotFound(f'{tnok} No connection parameters specified.') - print(f'{tok} Notifications started') + # Attempt connection + await self.client.connect() + + if self.client.is_connected: + print(f'{tok} Connected to Radiacode via bluetooth using address: {self.client.address}') + else: + raise DeviceNotFound(f'{tnok} Cannot connect to the requested Radiacode') - async def _scan(self): - radiacodes = [] + # Start notifications + self.notiffd = self.client.services.get_characteristic(RADIACODE_NOTIFYFD_UUID) + await self.client.start_notify(self.notiffd, self.handleNotification) - print(f'{tinfo} Scan started...') - devices = await BleakScanner.discover(return_adv=True, cb=dict(use_bdaddr=False)) + self.writefd = self.client.services.get_characteristic(RADIACODE_WRITEFD_UUID) - for ble, adv in devices.values(): - if "RadiaCode" in str(adv.local_name): - radiacodes.append((ble, adv)) + print(f'{tok} Notifications started') + + async def _scan(self) -> List[Tuple[BLEDevice, AdvertisementData]]: + """ Returns a list of Tuples of valid Radiacodes """ + radiacodes = [] - if len(radiacodes) == 0: - raise DeviceNotFound(f'{tnok} No RadiaCode found. Make ensure that bluetooth is active and that the RadiaCode is not already connected to another device') - - bt_devices = [] + print(f'{tinfo} Scan started...') + devices = await BleakScanner.discover(return_adv=True, cb=dict(use_bdaddr=False)) - for r in radiacodes: - ble, adv = r + for ble, adv in devices.values(): + if "RadiaCode" in str(adv.local_name): + radiacodes.append((ble, adv)) - if RADIACODE_SERVICE_UUID not in adv.service_uuids: - print(f'{tnok} No valid service found for device {adv.local_name} - UUID: {ble.address}') - continue - else: - print(f'{tok} Active service found for device {adv.local_name} - UUID: {ble.address}') + if len(radiacodes) == 0: + return [] + + bt_devices = [] - bt_devices.append(r) - - return bt_devices + for r in radiacodes: + ble, adv = r - def handleNotification(self, characteristic, data): - if self._resp_size == 0: - self._resp_size = 4 + struct.unpack('= 0 + bt_devices.append(r) - if self._resp_size == 0: - self._response = self._resp_buffer - self._resp_buffer = b'' + return bt_devices - #print(f'{tok} Notification: {characteristic.description}: {self._resp_buffer}') - - async def execute(self, req) -> BytesBuffer: - # for pos in range(0, len(req), 18): - # rp = req[pos : min(pos + 18, len(req))] - # self.p.writeCharacteristic(self.write_fd, rp) - if self.client is None or self.client.is_connected == False: - await self.client.connect() - - if self.client.is_connected == False: - raise DeviceNotFound(f'{tnok} Connection to the device not active') - - # Request data - self._response = [] - await self.client.write_gatt_char(self.writefd, req, response=False) - await asyncio.sleep(2.0) - #await self.client.stop_notify(notif) - - br = BytesBuffer(self._response) - self._response = None - return br - -else: - from bluepy.btle import BTLEDisconnectError, DefaultDelegate, Peripheral - from radiacode.bytes_buffer import BytesBuffer - - class Bluetooth(DefaultDelegate): - def __init__(self, mac): + def handleNotification(self, characteristic, data) -> None: + if self._resp_size == 0: + self._resp_size = 4 + struct.unpack('= 0 + + if self._resp_size == 0: + self._response = self._resp_buffer self._resp_buffer = b'' - self._resp_size = 0 - self._response = None + + #self._response_event.set() - try: - self.p = Peripheral(mac) - except BTLEDisconnectError as ex: - raise DeviceNotFound('Device not found or bluetooth adapter is not powered on') from ex + #print(f'{tok} Notification: {characteristic.description}: {self._resp_buffer}') + + async def execute(self, req) -> BytesBuffer: + if self.client is None or self.client.is_connected == False: + await self.client.connect() - self.p.withDelegate(self) + if self.client.is_connected == False: + raise DeviceNotFound(f'{tnok} Connection to the device not active') - service = self.p.getServiceByUUID('e63215e5-7003-49d8-96b0-b024798fb901') - self.write_fd = service.getCharacteristics('e63215e6-7003-49d8-96b0-b024798fb901')[0].getHandle() - notify_fd = service.getCharacteristics('e63215e7-7003-49d8-96b0-b024798fb901')[0].getHandle() - self.p.writeCharacteristic(notify_fd + 1, b'\x01\x00') + # Request data + self._response = [] + await self.client.write_gatt_char(self.writefd, req, response=False) + await asyncio.sleep(1.5) + #await self._response_event.wait() + + #await self.client.stop_notify(notif) - def handleNotification(self, chandle, data): - if self._resp_size == 0: - self._resp_size = 4 + struct.unpack('= 0 - if self._resp_size == 0: - self._response = self._resp_buffer - self._resp_buffer = b'' - - def execute(self, req) -> BytesBuffer: - for pos in range(0, len(req), 18): - rp = req[pos : min(pos + 18, len(req))] - self.p.writeCharacteristic(self.write_fd, rp) - - while self._response is None: - self.p.waitForNotifications(2.0) - - br = BytesBuffer(self._response) - self._response = None - return br + br = BytesBuffer(self._response) + self._response = None + return br \ No newline at end of file diff --git a/radiacode/transports/usb.py b/radiacode/transports/usb.py index 471cd86..5529d2b 100644 --- a/radiacode/transports/usb.py +++ b/radiacode/transports/usb.py @@ -14,7 +14,6 @@ def __init__(self, message=None): super().__init__(self.message) class Usb: - def __init__(self, serial_number=None, timeout_ms=3000): _vid = 0x0483 _pid = 0xF123 @@ -34,17 +33,19 @@ def __init__(self, serial_number=None, timeout_ms=3000): except usb.core.USBTimeoutError: break - def execute(self, request: bytes) -> BytesBuffer: + async def execute(self, request: bytes) -> BytesBuffer: self._device.write(0x1, request) trials = 0 max_trials = 3 + while trials < max_trials: # repeat until non-zero lenght data received data = self._device.read(0x81, 256, timeout=self._timeout_ms).tobytes() if len(data) != 0: break else: trials += 1 + if trials >= max_trials: raise MultipleUSBReadFailure(str(trials) + ' USB Read Failures in sequence') From a0f83f97a1da44ff659501e4ae96498b688e27dd Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Wed, 8 May 2024 19:14:54 +0800 Subject: [PATCH 04/20] Small refactoring of webserver and show-spectrum to make them work with asyncio. Added a find-radiacode.py script to help find a Radiacode over bluetooth. Added a simple Logger class for nicer outputs --- radiacode-examples/find-radiacode.py | 21 ++++++ radiacode-examples/show-spectrum.py | 101 ++++++++++++++++----------- radiacode-examples/webserver.html | 18 +++-- radiacode-examples/webserver.py | 9 ++- radiacode/logger.py | 33 +++++++++ radiacode/radiacode.py | 18 ++--- radiacode/transports/bluetooth.py | 32 ++++----- radiacode/transports/usb.py | 3 + 8 files changed, 159 insertions(+), 76 deletions(-) create mode 100644 radiacode-examples/find-radiacode.py create mode 100644 radiacode/logger.py diff --git a/radiacode-examples/find-radiacode.py b/radiacode-examples/find-radiacode.py new file mode 100644 index 0000000..a780fe6 --- /dev/null +++ b/radiacode-examples/find-radiacode.py @@ -0,0 +1,21 @@ +""" + Simple scanner to find a Radiacode over bluetooth. + If a Radiacode is found, the library will print out both the device's serial number and the UUID. + On Mac the UUID is specific to a computer-radiacode pair. A scan from a different computer will return a different UUID. +""" +import asyncio + +from radiacode.transports.bluetooth import Bluetooth +from radiacode.logger import Logger + +async def main(): + Logger.info('Looking for Radiacodes over Bluetooth') + radiacodes = await Bluetooth()._scan() + + if len(radiacodes) == 0: + Logger.error('No Radiacodes found, make sure Bluetooth is active on both your device and the Radiacode. Make sure the Radiacode is not connected to other devices.') + else: + Logger.notify(f'{len(radiacodes)} Radiacode(s) found') + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/radiacode-examples/show-spectrum.py b/radiacode-examples/show-spectrum.py index 9b6895d..599f389 100755 --- a/radiacode-examples/show-spectrum.py +++ b/radiacode-examples/show-spectrum.py @@ -42,14 +42,17 @@ import sys import time import numpy as np -import yaml +import yaml, asyncio import matplotlib as mpl import matplotlib.pyplot as plt import matplotlib.patches as patches + from radiacode import RadiaCode +from radiacode.transports.usb import DeviceNotFound as DeviceNotFoundUSB +from radiacode.transports.bluetooth import DeviceNotFound as DeviceNotFoundBT # set backend and matplotlib style -mpl.use('Qt5Agg') +#mpl.use('Qt5Agg') plt.style.use('dark_background') # some constants @@ -74,7 +77,7 @@ class appColors: auxline = 'red' -def plot_RC102Spectrum(): +async def plot_RC102Spectrum(args: argparse.Namespace): # Helper functions for conversion of channel numbers to energies global a0, a1, a2 # calibration constants # approx. calibration, overwritten by first retrieved spectrum @@ -104,59 +107,54 @@ def on_mpl_window_closed(ax): # end helpers --------------------------------------- - # ------ - # parse command line arguments - # ------ - parser = argparse.ArgumentParser( - description='Read and display gamma energy spectrum from RadioCode 102, ' - + 'show differential and updated cumulative spectrum, ' - + 'optionally store data to file in yaml format.' - ) - parser.add_argument('-b', '--bluetooth-mac', type=str, required=False, help='bluetooth MAC address of device') - parser.add_argument('-s', '--serial-number', type=str, required=False, help='serial number of device') - parser.add_argument('-r', '--restart', action='store_true', help='restart spectrum accumulation') - parser.add_argument('-R', '--Reset', action='store_true', help='reset spectrum stored in device') - parser.add_argument('-q', '--quiet', action='store_true', help='no status output to terminal') - parser.add_argument('-i', '--interval', type=float, default=1.0, help='update interval') - parser.add_argument('-f', '--file', type=str, default='', help='file to store results') - parser.add_argument('-t', '--time', type=int, default=36000, help='run time in seconds') - parser.add_argument('-H', '--history', type=int, default=500, help='number of rate-history points to store in file') - args = parser.parse_args() bluetooth_mac = args.bluetooth_mac + bluetooth_uuid = args.bluetooth_uuid + bluetooth_serial = args.bluetooth_serial serial_number = args.serial_number restart_accumulation = args.restart reset_device_spectrum = args.Reset quiet = args.quiet dt_wait = args.interval timestamp = time.strftime('%y%m%d-%H%M', time.localtime()) + print(args.file) + filename = args.file + '_' + timestamp + '.yaml' if args.file != '' else '' NHistory = args.history run_time = args.time rate_history = np.zeros(NHistory) - if not quiet: - print(f'\n *==* script {sys.argv[0]} executing') - if bluetooth_mac is not None: - print(f' connecting via Bluetooth, MAC {bluetooth_mac}') - elif serial_number is not None: - print(f' connect via USB to device with SN {serial_number}') - else: - print(' connect via USB') - # ------ # initialize and connect to RC10x device # ------ - rc = RadiaCode(bluetooth_mac=bluetooth_mac, serial_number=serial_number) - serial = rc.serial_number() - fw_version = rc.fw_version() - status_flags = eval(rc.status().split(':')[1])[0] - a0, a1, a2 = rc.energy_calib() + try: + rc = await RadiaCode.connect(bluetooth_mac=bluetooth_mac, bluetooth_uuid=bluetooth_uuid, bluetooth_serial=bluetooth_serial, serial_number=serial_number) + except DeviceNotFoundBT as e: + print(e) + return + except DeviceNotFoundUSB: + print('Radiacode not found, check your USB connection') + return + except ValueError as e: + print(e) + return + except Exception as e: + print(e) + return + + serial = await rc.serial_number() + fw_version = await rc.fw_version() + status = await rc.status() + status_flags = eval(status.split(':')[1])[0] + a0, a1, a2 = await rc.energy_calib() + # get initial spectrum and meta-data if reset_device_spectrum: - rc.spectrum_reset() - spectrum = rc.spectrum() + await rc.spectrum_reset() + + spectrum = await rc.spectrum() + # print(f'### Spectrum: {spectrum}') counts0 = np.asarray(spectrum.counts) NChannels = len(counts0) @@ -286,7 +284,7 @@ def on_mpl_window_closed(ax): # dt = _t - _t0 # last time interval _t0 = _t total_time = int(10 * (_t - T0)) / 10 # active time rounded to 0.1s - spectrum = rc.spectrum() + spectrum = await rc.spectrum() actual_counts = np.asarray(spectrum.counts) if not any(actual_counts): time.sleep(dt_wait) @@ -372,9 +370,32 @@ def on_mpl_window_closed(ax): input(' type to close down graphics window --> ') ### get dose info from device - # for v in rc.data_buf(): + # for v in await rc.data_buf(): # print(v.dt.isoformat(), v) if __name__ == '__main__': - plot_RC102Spectrum() + parser = argparse.ArgumentParser() + + # ------ + # parse command line arguments + # ------ + parser = argparse.ArgumentParser( + description='Read and display gamma energy spectrum from RadioCode 102, ' + + 'show differential and updated cumulative spectrum, ' + + 'optionally store data to file in yaml format.' + ) + parser.add_argument('-b', '--bluetooth-mac', type=str, required=False, help='Radiacode Bluetooth MAC address (e.g. 00:11:22:33:44:55). MacOS does not support BT MACs, use Serial Number or UUID instead.') + parser.add_argument('-u', '--bluetooth-uuid', type=str, required=False, help='Connect via Bluetooth using Radiacode UUID (e.g. "11111111-2222-3333-4444-56789ABCDEF").') + parser.add_argument('-e', '--bluetooth-serial', type=str, required=False, help='Connect via Bluetooth using Radiacode Serial (e.g. "RC-10x-xxxxxx").') + parser.add_argument('-s', '--serial-number', type=str, required=False, help='Connect via USB using Radiacode Serial (e.g. "RC-10x-xxxxxx").') + parser.add_argument('-r', '--restart', action='store_true', help='Restart spectrum accumulation') + parser.add_argument('-R', '--Reset', action='store_true', help='Reset spectrum stored in device') + parser.add_argument('-q', '--quiet', action='store_true', help='No status output to terminal') + parser.add_argument('-i', '--interval', type=float, default=1.0, help='Update interval (s)') + parser.add_argument('-f', '--file', type=str, default='', help='Filename to store results (.yaml extension will be automatically added to the name)') + parser.add_argument('-t', '--time', type=int, default=36000, help='Run time in seconds') + parser.add_argument('-H', '--history', type=int, default=500, help='Number of rate-history points to store in file') + args = parser.parse_args() + + asyncio.run(plot_RC102Spectrum(args)) \ No newline at end of file diff --git a/radiacode-examples/webserver.html b/radiacode-examples/webserver.html index 879acf9..2d64394 100644 --- a/radiacode-examples/webserver.html +++ b/radiacode-examples/webserver.html @@ -21,12 +21,18 @@ padding: 0; margin-left: 20px; } +#app .view_controls { + padding-bottom: 1.5em; +} +#app .control_buttons { + padding-bottom: 1.5em; +}
-
+
@@ -45,12 +51,16 @@
- - +
+ + +
- +
+ +
diff --git a/radiacode-examples/webserver.py b/radiacode-examples/webserver.py index 9a805ae..104989f 100644 --- a/radiacode-examples/webserver.py +++ b/radiacode-examples/webserver.py @@ -26,7 +26,7 @@ async def handle_ws(request): async def handle_spectrum(request): cn = request.app['rc_conn'] accum = request.query.get('accum') == 'true' - spectrum = await (cn.spectrum_accum() if accum else await cn.spectrum()) + spectrum = await (cn.spectrum_accum() if accum else cn.spectrum()) # apexcharts can't handle 0 in logarithmic view spectrum_data = [(channel, cnt if cnt > 0 else 0.5) for channel, cnt in enumerate(spectrum.counts)] @@ -75,15 +75,17 @@ async def process(app): await asyncio.gather(*(ws.send_str(jdata) for ws in app['ws_clients'])) await asyncio.sleep(1.0) - async def on_startup(app): app['process_task'] = asyncio.create_task(process(app)) app['ws_clients'] = [] async def init_connection(app): if app['args'].bluetooth_mac: - print('will use Bluetooth connection') + print('will use Bluetooth connection via MAC address') app['rc_conn'] = await RadiaCode.connect(bluetooth_mac=app['args'].bluetooth_mac) + elif app['args'].bluetooth_uuid: + print('will use Bluetooth connection via UUID') + app['rc_conn'] = await RadiaCode.connect(bluetooth_uuid=app['args'].bluetooth_uuid) else: print('will use USB connection') app['rc_conn'] = await RadiaCode.connect() @@ -91,6 +93,7 @@ async def init_connection(app): def main(): parser = argparse.ArgumentParser() parser.add_argument('--bluetooth-mac', type=str, required=False, help='Bluetooth MAC address of radiascan device') + parser.add_argument('--bluetooth-uuid', type=str, required=False, help='Bluetooth UUID of radiascan device') parser.add_argument('--listen-host', type=str, required=False, default='127.0.0.1', help='Listen host for webserver') parser.add_argument('--listen-port', type=int, required=False, default=8080, help='Listen port for webserver') args = parser.parse_args() diff --git a/radiacode/logger.py b/radiacode/logger.py new file mode 100644 index 0000000..762d533 --- /dev/null +++ b/radiacode/logger.py @@ -0,0 +1,33 @@ +from enum import Enum + +class LogLevel(Enum): + Notification = ('notification', '[\033[1;32m\N{check mark}\033[0m]') + Error = ('error', '[\033[1;31m\N{aegean check mark}\033[0m]') + Info = ('info', '[\033[1;34m\N{information source}\033[0m]') + Warning = ('warning', '[\033[1;35m\N{warning sign}\033[0m]') + +class Logger: + @staticmethod + def log(message): + print(message) + + @staticmethod + def notify(message): + Logger._log_level(message, LogLevel.Notification) + + @staticmethod + def error(message): + Logger._log_level(message, LogLevel.Error) + + @staticmethod + def info(message): + Logger._log_level(message, LogLevel.Info) + + @staticmethod + def warning(message): + Logger._log_level(message, LogLevel.Warning) + + @staticmethod + def _log_level(message, level): + prefix = level.value[1] + print(f'{prefix} {message}') \ No newline at end of file diff --git a/radiacode/radiacode.py b/radiacode/radiacode.py index b22556b..f745eb0 100644 --- a/radiacode/radiacode.py +++ b/radiacode/radiacode.py @@ -2,6 +2,7 @@ import struct, platform, binascii from typing import List, Optional, Union +from radiacode.logger import Logger from radiacode.bytes_buffer import BytesBuffer from radiacode.decoders.databuf import decode_VS_DATA_BUF from radiacode.decoders.spectrum import decode_RC_VS_SPECTRUM @@ -9,11 +10,6 @@ from radiacode.transports.usb import Usb from radiacode.types import CTRL, VS, VSFR, DisplayDirection, DoseRateDB, Event, RareData, RawData, RealTimeData, Spectrum -tok = '[\033[1;32m\N{check mark}\033[0m]' -tnok = '[\033[1;31m\N{aegean check mark}\033[0m]' -tinfo = '[\033[1;34m\N{information source}\033[0m]' -twarn = '[\033[1;35m\N{warning sign}\033[0m]' - # channel number -> kEv def spectrum_channel_to_energy(channel_number: int, a0: float, a1: float, a2: float) -> float: return a0 + a1 * channel_number + a2 * channel_number * channel_number @@ -51,11 +47,11 @@ async def connect(cls, ignore_firmware_compatibility_check: bool = False): if platform.system() == 'Darwin' and bluetooth_mac: - print(f'{tnok} You bluetooth connection using MAC address, but you appear to be on a Mac.') - print(f'{tnok} Apple does not expose Bluetooth MAC addresses anymore, so this method will not work.') - print(f'{tnok} Try connecting to the device using another option (UUID or Serial).') + Logger.warning('You bluetooth connection using MAC address, but you appear to be on a Mac.') + Logger.warning('Apple does not expose Bluetooth MAC addresses anymore, so this method will not work.') + Logger.warning('Try connecting to the device using another option (UUID or Serial).') - raise Exception(f'Exception: The chosen connection method does not work on this platform.') + raise Exception('Exception: The chosen connection method does not work on this platform.') self = cls(bluetooth_mac=bluetooth_mac, bluetooth_serial=bluetooth_serial, @@ -71,7 +67,7 @@ async def _init_device(self, ignore_firmware_compatibility_check = False): await self._connection.connect() # Init - print(f'{tinfo} Initializing Radiacode...') + Logger.info('Initializing Radiacode...') await self.execute(b'\x07\x00', b'\x01\xff\x12\xff') self._base_time = datetime.datetime.now() @@ -92,7 +88,7 @@ async def _init_device(self, ignore_firmware_compatibility_check = False): self._spectrum_format_version = int(line.split('=')[1]) break - print(f'{tok} Initialization completed') + Logger.notify('Initialization completed') def base_time(self) -> datetime.datetime: return self._base_time diff --git a/radiacode/transports/bluetooth.py b/radiacode/transports/bluetooth.py index a126824..a3f8276 100644 --- a/radiacode/transports/bluetooth.py +++ b/radiacode/transports/bluetooth.py @@ -3,6 +3,7 @@ from typing import Optional, List, Tuple from radiacode.bytes_buffer import BytesBuffer +from radiacode.logger import Logger from bleak import BleakScanner, BleakClient from bleak.backends.scanner import AdvertisementData, BLEDevice @@ -10,11 +11,6 @@ RADIACODE_WRITEFD_UUID = 'e63215e6-7003-49d8-96b0-b024798fb901' # Handle: 13, (write-without-response, write), Max write w/o rsp size: 217 RADIACODE_NOTIFYFD_UUID = 'e63215e7-7003-49d8-96b0-b024798fb901' # Handle: 15, notify -tok = '[\033[1;32m\N{check mark}\033[0m]' -tnok = '[\033[1;31m\N{aegean check mark}\033[0m]' -tinfo = '[\033[1;34m\N{information source}\033[0m]' -twarn = '[\033[1;35m\N{warning sign}\033[0m]' - class DeviceNotFound(Exception): pass @@ -39,17 +35,17 @@ def __init__(self, async def connect(self) -> None: if self.bluetooth_mac: if len(self.bluetooth_uuid) != 17: - print(f'{twarn} The provided MAC address does not seem to be valid, but we will try anyway') + Logger.warning('The provided MAC address does not seem to be valid, but we will try anyway') self.client = BleakClient(self.bluetooth_mac) elif self.bluetooth_serial: if len(self.bluetooth_serial) < 6: - print(f'{twarn} To improve reliability, try to provide at least 6 digits of your Radiacode serial number') + Logger.warning('To improve reliability, try to provide at least 6 digits of your Radiacode serial number') bt_devices = await self._scan() if len(bt_devices) == 0: - raise DeviceNotFound(f'{tnok} No Radiacodes found. Check that bluetooth is enabled and that the Radiacode is not connected to another device.') + raise DeviceNotFound('No Radiacodes found. Check that bluetooth is enabled and that the Radiacode is not connected to another device.') ble, _ = (None, None) @@ -60,24 +56,24 @@ async def connect(self) -> None: break if ble is None: - raise DeviceNotFound(f'{tnok} No matching serial found while scanning. We were looking for: {self.bluetooth_serial}') + raise DeviceNotFound(f'No matching serial found while scanning. We were looking for: {self.bluetooth_serial}') self.client = BleakClient(ble) elif self.bluetooth_uuid: if len(self.bluetooth_uuid) != 36: - print(f'{twarn} The provided UUID does not seem to be valid, but we will try anyway') + Logger.warning('The provided UUID does not seem to be valid, but we will try anyway') self.client = BleakClient(self.bluetooth_uuid) else: - raise DeviceNotFound(f'{tnok} No connection parameters specified.') + raise DeviceNotFound('No connection parameters specified.') # Attempt connection await self.client.connect() if self.client.is_connected: - print(f'{tok} Connected to Radiacode via bluetooth using address: {self.client.address}') + Logger.notify(f'Connected to Radiacode via bluetooth using address: {self.client.address}') else: - raise DeviceNotFound(f'{tnok} Cannot connect to the requested Radiacode') + raise DeviceNotFound('Cannot connect to the requested Radiacode') # Start notifications self.notiffd = self.client.services.get_characteristic(RADIACODE_NOTIFYFD_UUID) @@ -85,13 +81,13 @@ async def connect(self) -> None: self.writefd = self.client.services.get_characteristic(RADIACODE_WRITEFD_UUID) - print(f'{tok} Notifications started') + Logger.notify(f'Notifications started') async def _scan(self) -> List[Tuple[BLEDevice, AdvertisementData]]: """ Returns a list of Tuples of valid Radiacodes """ radiacodes = [] - print(f'{tinfo} Scan started...') + Logger.info(f'Scan started...') devices = await BleakScanner.discover(return_adv=True, cb=dict(use_bdaddr=False)) for ble, adv in devices.values(): @@ -107,10 +103,10 @@ async def _scan(self) -> List[Tuple[BLEDevice, AdvertisementData]]: ble, adv = r if RADIACODE_SERVICE_UUID not in adv.service_uuids: - print(f'{tnok} No valid service found for device {adv.local_name} - UUID: {ble.address}') + Logger.error(f'No valid service found for device ID: {adv.local_name} - UUID: {ble.address}') continue else: - print(f'{tok} Active service found for device {adv.local_name} - UUID: {ble.address}') + Logger.notify(f'Active service found for device ID: {adv.local_name} - UUID: {ble.address}') bt_devices.append(r) @@ -140,7 +136,7 @@ async def execute(self, req) -> BytesBuffer: await self.client.connect() if self.client.is_connected == False: - raise DeviceNotFound(f'{tnok} Connection to the device not active') + raise DeviceNotFound('Connection to the device not active') # Request data self._response = [] diff --git a/radiacode/transports/usb.py b/radiacode/transports/usb.py index 5529d2b..48c4a32 100644 --- a/radiacode/transports/usb.py +++ b/radiacode/transports/usb.py @@ -24,9 +24,12 @@ def __init__(self, serial_number=None, timeout_ms=3000): # usb.core.find(..., serial_number=None) will attempt to match against a value of None, # rather than ignoring it as a match condition. self._device = usb.core.find(idVendor=_vid, idProduct=_pid) + self._timeout_ms = timeout_ms + if self._device is None: raise DeviceNotFound + while True: try: self._device.read(0x81, 256, timeout=100) From 34930a4c6046e864bf8c6dc023d161b009a55841 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Wed, 8 May 2024 19:47:58 +0800 Subject: [PATCH 05/20] Updated bleak version and fixed a mistake in bluetooth.py --- poetry.lock | 18 ++++-------------- pyproject.toml | 3 +-- radiacode/transports/bluetooth.py | 4 ++-- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5b8a017..3a47339 100644 --- a/poetry.lock +++ b/poetry.lock @@ -142,13 +142,13 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p [[package]] name = "bleak" -version = "0.22.0" +version = "0.22.1" description = "Bluetooth Low Energy platform Agnostic Klient" optional = false python-versions = "<3.13,>=3.8" files = [ - {file = "bleak-0.22.0-py3-none-any.whl", hash = "sha256:c7d85e90b55529e1eccede1d01c1a2af178306a973121b04a3fe6d3d4ece2a01"}, - {file = "bleak-0.22.0.tar.gz", hash = "sha256:8439f5a34ecba350485a64c9bf6be5a66fb58f2b1dc597b61f224f6635ffad99"}, + {file = "bleak-0.22.1-py3-none-any.whl", hash = "sha256:4afb5420847713535381ed2f04e7a70a1d1459153bb76e396a311964fde4aa4f"}, + {file = "bleak-0.22.1.tar.gz", hash = "sha256:73c2e774c22345e170d36a55a9dd06f6633c88b4184d5f86140a8224f12282d4"}, ] [package.dependencies] @@ -188,16 +188,6 @@ files = [ {file = "bleak_winrt-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:63130c11acfe75c504a79c01f9919e87f009f5e742bfc7b7a5c2a9c72bf591a7"}, ] -[[package]] -name = "bluepy" -version = "1.3.0" -description = "Python module for interfacing with BLE devices through Bluez" -optional = false -python-versions = "*" -files = [ - {file = "bluepy-1.3.0.tar.gz", hash = "sha256:2a71edafe103565fb990256ff3624c1653036a837dfc90e1e32b839f83971cec"}, -] - [[package]] name = "contourpy" version = "1.2.1" @@ -1546,4 +1536,4 @@ examples = ["aiohttp", "matplotlib", "numpy", "prometheus-client", "pyyaml"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.13" -content-hash = "1954f372f219b6c2ec7a96c8ff6554138902f9fed15bb76d5ed0ebe43efb54a2" +content-hash = "5c4c27c493340ddb0a804cda7204e854413708947bf24ed1734ddda0123cd31a" diff --git a/pyproject.toml b/pyproject.toml index 64cdcca..6a76a4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,8 +15,7 @@ include = ["radiacode-examples/*"] [tool.poetry.dependencies] python = ">=3.9,<3.13" -bluepy = { version = "^1.3", markers = "sys_platform != 'darwin'" } -bleak = { version = "^0.22.0", markers = "sys_platform == 'darwin'" } +bleak = {version = "^0.22.1"} pyusb = "^1.2" aiohttp = {version = "^3.9", optional = true} prometheus-client = {version = "^0.19", optional = true} diff --git a/radiacode/transports/bluetooth.py b/radiacode/transports/bluetooth.py index a3f8276..9ca2f4e 100644 --- a/radiacode/transports/bluetooth.py +++ b/radiacode/transports/bluetooth.py @@ -34,7 +34,7 @@ def __init__(self, async def connect(self) -> None: if self.bluetooth_mac: - if len(self.bluetooth_uuid) != 17: + if len(self.bluetooth_mac) != 17: Logger.warning('The provided MAC address does not seem to be valid, but we will try anyway') self.client = BleakClient(self.bluetooth_mac) @@ -71,7 +71,7 @@ async def connect(self) -> None: await self.client.connect() if self.client.is_connected: - Logger.notify(f'Connected to Radiacode via bluetooth using address: {self.client.address}') + Logger.notify(f'Connected to Radiacode via bluetooth to: {self.client.address}') else: raise DeviceNotFound('Cannot connect to the requested Radiacode') From 4e01a8f4adfc60dc268758b6e982ecde58e7a886 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Wed, 8 May 2024 20:19:31 +0800 Subject: [PATCH 06/20] Readme update --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 30e992b..ec1f02a 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,8 @@ $ poetry install $ poetry run python3 radiacode-examples/basic.py --bluetooth-mac 52:43:01:02:03:04 # or without --bluetooth-mac for USB connection ``` -## MacOS -The library used to communicate over Bluetooh (```bluepy```) is [not supported](https://github.com/IanHarvey/bluepy/issues/44) on MacOS. Only the USB connection is available on Apple devices. A ```USB Serial Number```, obtainable from the ```Device Info``` menu on the device itself, can be specified if more than one Radiacode is connected via USB at the same time. +### Examples +To install the dependencies required to run the examples: ```poetry install -E examples``` -Make sure ```libusb``` is installed on your system, if you use ```Brew``` you can run: ```brew install libusb``` \ No newline at end of file +## MacOS +Make sure ```libusb``` is installed in your system, if you use ```Brew``` you can run: ```brew install libusb``` \ No newline at end of file From f5dd43f2696a01e59f25493398dbba37d736e009 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Thu, 9 May 2024 14:33:52 +0800 Subject: [PATCH 07/20] Expanded the README with a list of supported OS and instructions --- README.md | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ec1f02a..fff66be 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [Описание на русском языке](README_ru.md) -This is a library to work with the radiation detector and spectrometer [RadiaCode-101](https://scan-electronics.com/dosimeters/radiacode/radiacode-101). +This is a library to work with the radiation detector and spectrometer [RadiaCode](https://scan-electronics.com/dosimeters/radiacode/radiacode-101) (101, 102, 103). ***The project is still under development and not stable. Thus, the API might change in the future.*** @@ -33,11 +33,74 @@ $ python3 -m radiacode-examples.narodmon --bluetooth-mac 52:43:01:02:03:04 - install and run: ``` $ poetry install -$ poetry run python3 radiacode-examples/basic.py --bluetooth-mac 52:43:01:02:03:04 # or without --bluetooth-mac for USB connection + +$ poetry run python radiacode-examples/find-radiacode.py # To find your Radiacode over Bluetooth and discover its MAC address or UUID + +$ poetry run python radiacode-examples/basic.py --help # To see all options + +$ poetry run python radiacode-examples/basic.py --bluetooth-mac 52:43:01:02:03:04 # or without --bluetooth-mac for USB connection + +$ poetry run python radiacode-examples/basic.py --bluetooth-uuid 1EDA584E-652C-2011-1211-B213EFADEED0 # on Mac for bluetooth connection ``` ### Examples To install the dependencies required to run the examples: ```poetry install -E examples``` -## MacOS -Make sure ```libusb``` is installed in your system, if you use ```Brew``` you can run: ```brew install libusb``` \ No newline at end of file +### Supported OS + +| OS | Bluetooth | USB | Notes | +| :--- | :---: | :---: | :--- | +| Mac OS (Silicon/Intel) | :white_check_mark: | :white_check_mark: | BT only with UUID, Mac OS does not expose MAC addresses | +| Linux | :white_check_mark: | :white_check_mark: | USB requires ```libusb```| +| Windows | :white_check_mark: | :white_check_mark: | USB required ```libusb``` | +| Windows (WSL) | :x: | :question: | WSL does not provide direct access to hardware| + +### Windows +Make sure ```libusb``` is installed: +- Download the [latest stable](https://github.com/libusb/libusb/releases) version +- Use [7-Zip](https://www.7-zip.org/download.html) to unpack it +- Pick the most recent ```libusb-1.0.dll``` file (for a *Windows 10/11 64-bit* installation, it should be in: ```libusb-1.x.xx\VS2022\MS64\dll```) +- Copy the ```.dll``` in your ```C:\Windows\System32``` folder +- Run scripts as usual + +### Mac Silicon/Intel +Make sure ```libusb``` is installed on your system, if you use [Homebrew](https://brew.sh/) you can run: +- ```brew install libusb``` + +*Note:* Mac OS does not expose Bluetooth MAC addresses anymore. In order to connect to your device via Bluetooth you will need to supply either its ```serial number``` (or part of it) or it's ```UUID```. + +- Serial number: you can obtain it directly from the device itself, navigate to the **Info** menu, it should be in the form of: ```RC-10x-xxxxxx``` +- UUID: the UUID depends on both devices and it will change if you try to connect to the *Radiacode* from another computer (in this case, you will just need to rediscover it) + +Discovering the UUID of your *Radiacode* is quite easy: +- Make sure the *Radiacode* is **disconnected** from other devices (such as your phone, so kill the *Radiacode app* and its background tasks) +- Run: ```poetry run python radiacode-examples/find-radiacode.py``` + +The script will return the UUIDs of all available Radiacodes. + +### Linux +Make sure ```libusb``` is installed on your system. For *Debian/Ubuntu/Raspberry PI*: +- ```sudo apt install libusb``` + +You might have to tweak your ```udev``` configuration. On ```Debian/Ubuntu/Raspberry PI```: +- ```sudo nano /etc/udev/rules.d/99-com.rules``` + +Then add anywhere the following lines: + +``` +# Radiacode +SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="f123", MODE="0666" +``` + +Simply unplug and replug the Radiacode and run the scripts as per usual. + +#### Bluetooth +To enable Bluetooth on a *Raspberry Pi*: +- ```sudo apt install bluetooth pi-bluetooth bluez blueman``` + +On *Debian/Ubuntu* you should have all necessary packages by default, otherwise just try: +- ```sudo apt install bluetooth bluez``` + +## UUID and MAC Address +On `Windows` and `Linux` both `UUID` and `MAC addresses` can be used interchangeably, the library is flexible enough that it will try to establish a connection even if you supply a `UUID` where a `MAC address` is expected (e.g.: if you provide a `MAC address` while specifying `--bluetooth-uuid`). You will receive a warning anyway. + From d934d6a5c16b54380e319e827f860470cebe24e3 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Thu, 9 May 2024 14:37:52 +0800 Subject: [PATCH 08/20] Spelling corrections --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fff66be..f93b208 100644 --- a/README.md +++ b/README.md @@ -67,16 +67,16 @@ Make sure ```libusb``` is installed: Make sure ```libusb``` is installed on your system, if you use [Homebrew](https://brew.sh/) you can run: - ```brew install libusb``` -*Note:* Mac OS does not expose Bluetooth MAC addresses anymore. In order to connect to your device via Bluetooth you will need to supply either its ```serial number``` (or part of it) or it's ```UUID```. +*Note:* Mac OS does not expose Bluetooth MAC addresses anymore. In order to connect to your device via Bluetooth you will need to supply either its ```serial number``` (or part of it) or its ```UUID```. -- Serial number: you can obtain it directly from the device itself, navigate to the **Info** menu, it should be in the form of: ```RC-10x-xxxxxx``` -- UUID: the UUID depends on both devices and it will change if you try to connect to the *Radiacode* from another computer (in this case, you will just need to rediscover it) +- **Serial number**: you can obtain it directly from the device, navigate to the **Info** menu, it should be in the form of: ```RC-10x-xxxxxx``` +- **UUID**: the UUID depends on both devices and it will change if you try to connect to the *Radiacode* from another computer (in this case, you will just need to rediscover) Discovering the UUID of your *Radiacode* is quite easy: - Make sure the *Radiacode* is **disconnected** from other devices (such as your phone, so kill the *Radiacode app* and its background tasks) - Run: ```poetry run python radiacode-examples/find-radiacode.py``` -The script will return the UUIDs of all available Radiacodes. +The script will return UUIDs for all available Radiacodes. ### Linux Make sure ```libusb``` is installed on your system. For *Debian/Ubuntu/Raspberry PI*: From 4f866a517b4ca484548ce10f16d65b36f9c92122 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Thu, 9 May 2024 15:09:34 +0800 Subject: [PATCH 09/20] Remove ununsed import --- radiacode/radiacode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radiacode/radiacode.py b/radiacode/radiacode.py index f745eb0..d5dd94b 100644 --- a/radiacode/radiacode.py +++ b/radiacode/radiacode.py @@ -1,5 +1,5 @@ import datetime -import struct, platform, binascii +import struct, platform from typing import List, Optional, Union from radiacode.logger import Logger From e7cfb4a1d04afff8356a799757c5d48783dd9ea0 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Sat, 11 May 2024 12:22:23 +0800 Subject: [PATCH 10/20] Fixed ruff errors --- radiacode-examples/basic.py | 3 ++- radiacode-examples/find-radiacode.py | 2 +- radiacode-examples/show-spectrum.py | 4 ++-- radiacode/radiacode.py | 3 ++- radiacode/transports/bluetooth.py | 10 +++++----- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/radiacode-examples/basic.py b/radiacode-examples/basic.py index f651f30..f842c95 100644 --- a/radiacode-examples/basic.py +++ b/radiacode-examples/basic.py @@ -1,5 +1,6 @@ import argparse -import time, asyncio +import time +import asyncio from radiacode import RadiaCode from radiacode.transports.usb import DeviceNotFound as DeviceNotFoundUSB diff --git a/radiacode-examples/find-radiacode.py b/radiacode-examples/find-radiacode.py index a780fe6..db9faff 100644 --- a/radiacode-examples/find-radiacode.py +++ b/radiacode-examples/find-radiacode.py @@ -17,5 +17,5 @@ async def main(): else: Logger.notify(f'{len(radiacodes)} Radiacode(s) found') -if __name__ == "__main__": +if __name__ == '__main__': asyncio.run(main()) \ No newline at end of file diff --git a/radiacode-examples/show-spectrum.py b/radiacode-examples/show-spectrum.py index 599f389..1a70d33 100755 --- a/radiacode-examples/show-spectrum.py +++ b/radiacode-examples/show-spectrum.py @@ -42,8 +42,8 @@ import sys import time import numpy as np -import yaml, asyncio -import matplotlib as mpl +import yaml +import asyncio import matplotlib.pyplot as plt import matplotlib.patches as patches diff --git a/radiacode/radiacode.py b/radiacode/radiacode.py index d5dd94b..b9f0bbc 100644 --- a/radiacode/radiacode.py +++ b/radiacode/radiacode.py @@ -1,5 +1,6 @@ import datetime -import struct, platform +import struct +import platform from typing import List, Optional, Union from radiacode.logger import Logger diff --git a/radiacode/transports/bluetooth.py b/radiacode/transports/bluetooth.py index 9ca2f4e..45bf731 100644 --- a/radiacode/transports/bluetooth.py +++ b/radiacode/transports/bluetooth.py @@ -81,17 +81,17 @@ async def connect(self) -> None: self.writefd = self.client.services.get_characteristic(RADIACODE_WRITEFD_UUID) - Logger.notify(f'Notifications started') + Logger.notify('Notifications started') async def _scan(self) -> List[Tuple[BLEDevice, AdvertisementData]]: """ Returns a list of Tuples of valid Radiacodes """ radiacodes = [] - Logger.info(f'Scan started...') + Logger.info('Scan started...') devices = await BleakScanner.discover(return_adv=True, cb=dict(use_bdaddr=False)) for ble, adv in devices.values(): - if "RadiaCode" in str(adv.local_name): + if 'RadiaCode' in str(adv.local_name): radiacodes.append((ble, adv)) if len(radiacodes) == 0: @@ -132,10 +132,10 @@ def handleNotification(self, characteristic, data) -> None: #print(f'{tok} Notification: {characteristic.description}: {self._resp_buffer}') async def execute(self, req) -> BytesBuffer: - if self.client is None or self.client.is_connected == False: + if self.client is None or self.client.is_connected is False: await self.client.connect() - if self.client.is_connected == False: + if self.client.is_connected is False: raise DeviceNotFound('Connection to the device not active') # Request data From a541d4813482e4a2213fbfa47a115052ec9bc3c7 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Sat, 11 May 2024 15:00:48 +0800 Subject: [PATCH 11/20] Refactored the main library code to be used in both synchronous and asynchronous apps --- radiacode-examples/basic.py | 23 +- radiacode-examples/find-radiacode.py | 8 +- radiacode-examples/narodmon.py | 57 +++-- radiacode-examples/radiacode-exporter.py | 43 +++- radiacode-examples/show-spectrum.py | 23 +- radiacode-examples/webserver.py | 12 +- radiacode/radiacode.py | 270 ++++++++++++++++------- radiacode/transports/bluetooth.py | 9 +- 8 files changed, 309 insertions(+), 136 deletions(-) mode change 100755 => 100644 radiacode-examples/show-spectrum.py diff --git a/radiacode-examples/basic.py b/radiacode-examples/basic.py index f842c95..48829d2 100644 --- a/radiacode-examples/basic.py +++ b/radiacode-examples/basic.py @@ -1,28 +1,27 @@ import argparse import time -import asyncio from radiacode import RadiaCode from radiacode.transports.usb import DeviceNotFound as DeviceNotFoundUSB from radiacode.transports.bluetooth import DeviceNotFound as DeviceNotFoundBT -async def main(args: argparse.Namespace): +def main(args: argparse.Namespace): try: if args.bluetooth_mac: print(f'Connecting to Radiacode via Bluetooth (MAC address: {args.bluetooth_mac})') - rc = await RadiaCode.connect(bluetooth_mac=args.bluetooth_mac) + rc = RadiaCode(bluetooth_mac=args.bluetooth_mac) elif args.bluetooth_uuid: print(f'Connecting to Radiacode via Bluetooth (UUID: {args.bluetooth_uuid})') - rc = await RadiaCode.connect(bluetooth_uuid=args.bluetooth_uuid) + rc = RadiaCode(bluetooth_uuid=args.bluetooth_uuid) elif args.bluetooth_serial: print(f'Connecting to Radiacode via Bluetooth (Serial: {args.bluetooth_serial})') - rc = await RadiaCode.connect(bluetooth_serial=args.bluetooth_serial) + rc = RadiaCode(bluetooth_serial=args.bluetooth_serial) elif args.serial: print(f'Connecting to Radiacode via USB (Serial: {args.serial})') - rc = await RadiaCode.connect(serial_number=args.serial) + rc = RadiaCode(serial_number=args.serial) else: print('Connecting to Radiacode via USB') - rc = await RadiaCode.connect() + rc = RadiaCode() except DeviceNotFoundBT as e: print(e) return @@ -36,21 +35,21 @@ async def main(args: argparse.Namespace): print(e) return - serial = await rc.serial_number() + serial = rc.serial_number() print(f'### Serial number: {serial}') print('--------') - fw_version = await rc.fw_version() + fw_version = rc.fw_version() print(f'### Firmware: {fw_version}') print('--------') - spectrum = await rc.spectrum() + spectrum = rc.spectrum() print(f'### Spectrum: {spectrum}') print('--------') print('### DataBuf:') while True: - for v in await rc.data_buf(): + for v in rc.data_buf(): print(v.dt.isoformat(), v) time.sleep(2) @@ -65,4 +64,4 @@ async def main(args: argparse.Namespace): args = parser.parse_args() - asyncio.run(main(args)) + main(args) diff --git a/radiacode-examples/find-radiacode.py b/radiacode-examples/find-radiacode.py index db9faff..5ae8dc9 100644 --- a/radiacode-examples/find-radiacode.py +++ b/radiacode-examples/find-radiacode.py @@ -3,14 +3,12 @@ If a Radiacode is found, the library will print out both the device's serial number and the UUID. On Mac the UUID is specific to a computer-radiacode pair. A scan from a different computer will return a different UUID. """ -import asyncio - from radiacode.transports.bluetooth import Bluetooth from radiacode.logger import Logger -async def main(): +def main(): Logger.info('Looking for Radiacodes over Bluetooth') - radiacodes = await Bluetooth()._scan() + radiacodes = Bluetooth()._scan() if len(radiacodes) == 0: Logger.error('No Radiacodes found, make sure Bluetooth is active on both your device and the Radiacode. Make sure the Radiacode is not connected to other devices.') @@ -18,4 +16,4 @@ async def main(): Logger.notify(f'{len(radiacodes)} Radiacode(s) found') if __name__ == '__main__': - asyncio.run(main()) \ No newline at end of file + main() \ No newline at end of file diff --git a/radiacode-examples/narodmon.py b/radiacode-examples/narodmon.py index e4b26ad..d9b4326 100644 --- a/radiacode-examples/narodmon.py +++ b/radiacode-examples/narodmon.py @@ -1,11 +1,11 @@ import argparse import asyncio import time - import aiohttp from radiacode import RealTimeData, RadiaCode - +from radiacode.transports.usb import DeviceNotFound as DeviceNotFoundUSB +from radiacode.transports.bluetooth import DeviceNotFound as DeviceNotFoundBT def sensors_data(rc_conn): databuf = rc_conn.data_buf() @@ -44,23 +44,49 @@ async def send_data(d): async with session.post('https://narodmon.ru/json', json=d) as resp: return await resp.text() - def main(): parser = argparse.ArgumentParser() - parser.add_argument('--bluetooth-mac', type=str, required=True, help='MAC address of radiascan device') - parser.add_argument('--connection', choices=['usb', 'bluetooth'], default='bluetooth', help='device connection type') - parser.add_argument('--interval', type=int, required=False, default=600, help='send interval, seconds') + parser.add_argument('--bluetooth-mac', type=str, required=False, help='Radiacode Bluetooth MAC address (e.g. 00:11:22:33:44:55). MacOS does not support BT MACs, use Serial Number or UUID instead.') + parser.add_argument('--bluetooth-serial', type=str, required=False, help='Connect via Bluetooth using Radiacode Serial (e.g. "RC-10x-xxxxxx").') + parser.add_argument('--bluetooth-uuid', type=str, required=False, help='Connect via Bluetooth using Radiacode UUID (e.g. "11111111-2222-3333-4444-56789ABCDEF").') + parser.add_argument('--serial', type=str, required=False, help='Connect via USB using Radiacode Serial (e.g. "RC-10x-xxxxxx").') + parser.add_argument('--usb', type=str, required=False, help='(default) Connect via USB to the first Radiacode available.') + parser.add_argument('--interval', type=int, required=False, default=600, help='Send interval, seconds') args = parser.parse_args() - if args.connection == 'usb': - print('will use USB connection') - rc_conn = RadiaCode() - else: - print('will use Bluetooth connection') - rc_conn = RadiaCode(bluetooth_mac=args.bluetooth_mac) - + try: + if args.bluetooth_mac: + print(f'Connecting to Radiacode via Bluetooth (MAC address: {args.bluetooth_mac})') + rc = RadiaCode(bluetooth_mac=args.bluetooth_mac) + elif args.bluetooth_uuid: + print(f'Connecting to Radiacode via Bluetooth (UUID: {args.bluetooth_uuid})') + rc = RadiaCode(bluetooth_uuid=args.bluetooth_uuid) + elif args.bluetooth_serial: + print(f'Connecting to Radiacode via Bluetooth (Serial: {args.bluetooth_serial})') + rc = RadiaCode(bluetooth_serial=args.bluetooth_serial) + elif args.serial: + print(f'Connecting to Radiacode via USB (Serial: {args.serial})') + rc = RadiaCode(serial_number=args.serial) + else: + print('Connecting to Radiacode via USB') + rc = RadiaCode() + except DeviceNotFoundBT as e: + print(e) + return + except DeviceNotFoundUSB: + print('Radiacode not found, check your USB connection') + return + except ValueError as e: + print(e) + return + except Exception as e: + print(e) + return + + mac = args.bluetooth_mac.replace(':', '-') if args.bluetooth_mac else '00-00-00-00-00-00' + device_data = { - 'mac': args.bluetooth_mac.replace(':', '-'), + 'mac': mac, 'name': 'RadiaCode-101', } @@ -69,11 +95,10 @@ def main(): 'devices': [ { **device_data, - 'sensors': sensors_data(rc_conn), + 'sensors': sensors_data(rc), }, ], } - print(f'Sending {d}') try: r = asyncio.run(send_data(d)) diff --git a/radiacode-examples/radiacode-exporter.py b/radiacode-examples/radiacode-exporter.py index 5934310..b5e7d74 100644 --- a/radiacode-examples/radiacode-exporter.py +++ b/radiacode-examples/radiacode-exporter.py @@ -4,21 +4,48 @@ import prometheus_client from radiacode import RealTimeData, RadiaCode - +from radiacode.transports.usb import DeviceNotFound as DeviceNotFoundUSB +from radiacode.transports.bluetooth import DeviceNotFound as DeviceNotFoundBT def main(): parser = argparse.ArgumentParser() - parser.add_argument('--bluetooth-mac', type=str, required=False, help='bluetooth MAC address of radiascan device') + parser.add_argument('--bluetooth-mac', type=str, required=False, help='Radiacode Bluetooth MAC address (e.g. 00:11:22:33:44:55). MacOS does not support BT MACs, use Serial Number or UUID instead.') + parser.add_argument('--bluetooth-serial', type=str, required=False, help='Connect via Bluetooth using Radiacode Serial (e.g. "RC-10x-xxxxxx").') + parser.add_argument('--bluetooth-uuid', type=str, required=False, help='Connect via Bluetooth using Radiacode UUID (e.g. "11111111-2222-3333-4444-56789ABCDEF").') + parser.add_argument('--serial', type=str, required=False, help='Connect via USB using Radiacode Serial (e.g. "RC-10x-xxxxxx").') parser.add_argument('--update-interval', type=int, default=3, required=False, help='update interval (seconds)') parser.add_argument('--port', type=int, default=5432, required=False, help='prometheus http port') + args = parser.parse_args() - if args.bluetooth_mac: - print('will use Bluetooth connection') - rc = RadiaCode(bluetooth_mac=args.bluetooth_mac) - else: - print('will use USB connection') - rc = RadiaCode() + try: + if args.bluetooth_mac: + print(f'Connecting to Radiacode via Bluetooth (MAC address: {args.bluetooth_mac})') + rc = RadiaCode(bluetooth_mac=args.bluetooth_mac) + elif args.bluetooth_uuid: + print(f'Connecting to Radiacode via Bluetooth (UUID: {args.bluetooth_uuid})') + rc = RadiaCode(bluetooth_uuid=args.bluetooth_uuid) + elif args.bluetooth_serial: + print(f'Connecting to Radiacode via Bluetooth (Serial: {args.bluetooth_serial})') + rc = RadiaCode(bluetooth_serial=args.bluetooth_serial) + elif args.serial: + print(f'Connecting to Radiacode via USB (Serial: {args.serial})') + rc = RadiaCode(serial_number=args.serial) + else: + print('Connecting to Radiacode via USB') + rc = RadiaCode() + except DeviceNotFoundBT as e: + print(e) + return + except DeviceNotFoundUSB: + print('Radiacode not found, check your USB connection') + return + except ValueError as e: + print(e) + return + except Exception as e: + print(e) + return serial = rc.serial_number() diff --git a/radiacode-examples/show-spectrum.py b/radiacode-examples/show-spectrum.py old mode 100755 new mode 100644 index 1a70d33..1e7eda4 --- a/radiacode-examples/show-spectrum.py +++ b/radiacode-examples/show-spectrum.py @@ -43,7 +43,6 @@ import time import numpy as np import yaml -import asyncio import matplotlib.pyplot as plt import matplotlib.patches as patches @@ -77,7 +76,7 @@ class appColors: auxline = 'red' -async def plot_RC102Spectrum(args: argparse.Namespace): +def plot_RC102Spectrum(args: argparse.Namespace): # Helper functions for conversion of channel numbers to energies global a0, a1, a2 # calibration constants # approx. calibration, overwritten by first retrieved spectrum @@ -129,7 +128,7 @@ def on_mpl_window_closed(ax): # initialize and connect to RC10x device # ------ try: - rc = await RadiaCode.connect(bluetooth_mac=bluetooth_mac, bluetooth_uuid=bluetooth_uuid, bluetooth_serial=bluetooth_serial, serial_number=serial_number) + rc = RadiaCode(bluetooth_mac=bluetooth_mac, bluetooth_uuid=bluetooth_uuid, bluetooth_serial=bluetooth_serial, serial_number=serial_number) except DeviceNotFoundBT as e: print(e) return @@ -143,17 +142,17 @@ def on_mpl_window_closed(ax): print(e) return - serial = await rc.serial_number() - fw_version = await rc.fw_version() - status = await rc.status() + serial = rc.serial_number() + fw_version = rc.fw_version() + status = rc.status() status_flags = eval(status.split(':')[1])[0] - a0, a1, a2 = await rc.energy_calib() + a0, a1, a2 = rc.energy_calib() # get initial spectrum and meta-data if reset_device_spectrum: - await rc.spectrum_reset() + rc.spectrum_reset() - spectrum = await rc.spectrum() + spectrum = rc.spectrum() # print(f'### Spectrum: {spectrum}') counts0 = np.asarray(spectrum.counts) @@ -284,7 +283,7 @@ def on_mpl_window_closed(ax): # dt = _t - _t0 # last time interval _t0 = _t total_time = int(10 * (_t - T0)) / 10 # active time rounded to 0.1s - spectrum = await rc.spectrum() + spectrum = rc.spectrum() actual_counts = np.asarray(spectrum.counts) if not any(actual_counts): time.sleep(dt_wait) @@ -370,7 +369,7 @@ def on_mpl_window_closed(ax): input(' type to close down graphics window --> ') ### get dose info from device - # for v in await rc.data_buf(): + # for v in rc.data_buf(): # print(v.dt.isoformat(), v) @@ -398,4 +397,4 @@ def on_mpl_window_closed(ax): parser.add_argument('-H', '--history', type=int, default=500, help='Number of rate-history points to store in file') args = parser.parse_args() - asyncio.run(plot_RC102Spectrum(args)) \ No newline at end of file + plot_RC102Spectrum(args) \ No newline at end of file diff --git a/radiacode-examples/webserver.py b/radiacode-examples/webserver.py index 104989f..582b895 100644 --- a/radiacode-examples/webserver.py +++ b/radiacode-examples/webserver.py @@ -26,7 +26,7 @@ async def handle_ws(request): async def handle_spectrum(request): cn = request.app['rc_conn'] accum = request.query.get('accum') == 'true' - spectrum = await (cn.spectrum_accum() if accum else cn.spectrum()) + spectrum = await (cn.async_spectrum_accum() if accum else cn.async_spectrum()) # apexcharts can't handle 0 in logarithmic view spectrum_data = [(channel, cnt if cnt > 0 else 0.5) for channel, cnt in enumerate(spectrum.counts)] @@ -39,7 +39,7 @@ async def handle_spectrum(request): async def handle_spectrum_reset(request): cn = request.app['rc_conn'] - await cn.spectrum_reset() + await cn.async_spectrum_reset() return web.json_response({'message': 'Spectrum reset'}) async def process(app): @@ -47,7 +47,7 @@ async def process(app): history = [] while True: - databuf = await app['rc_conn'].data_buf() + databuf = await app['rc_conn'].async_data_buf() for v in databuf: if isinstance(v, RealTimeData): @@ -82,13 +82,13 @@ async def on_startup(app): async def init_connection(app): if app['args'].bluetooth_mac: print('will use Bluetooth connection via MAC address') - app['rc_conn'] = await RadiaCode.connect(bluetooth_mac=app['args'].bluetooth_mac) + app['rc_conn'] = await RadiaCode.async_init(bluetooth_mac=app['args'].bluetooth_mac) elif app['args'].bluetooth_uuid: print('will use Bluetooth connection via UUID') - app['rc_conn'] = await RadiaCode.connect(bluetooth_uuid=app['args'].bluetooth_uuid) + app['rc_conn'] = await RadiaCode.async_init(bluetooth_uuid=app['args'].bluetooth_uuid) else: print('will use USB connection') - app['rc_conn'] = await RadiaCode.connect() + app['rc_conn'] = await RadiaCode.async_init() def main(): parser = argparse.ArgumentParser() diff --git a/radiacode/radiacode.py b/radiacode/radiacode.py index b9f0bbc..876ff0b 100644 --- a/radiacode/radiacode.py +++ b/radiacode/radiacode.py @@ -1,6 +1,7 @@ import datetime import struct import platform +import asyncio from typing import List, Optional, Union from radiacode.logger import Logger @@ -18,15 +19,33 @@ def spectrum_channel_to_energy(channel_number: int, a0: float, a1: float, a2: fl class RadiaCode: _connection: Union[Bluetooth, Usb] + """ + To use this class synchronously: + rc = Radiacode() + serial = rc.serial_number() + """ def __init__( self, bluetooth_mac: Optional[str] = None, bluetooth_serial: Optional[str] = None, bluetooth_uuid: Optional[str] = None, - serial_number: Optional[str] = None - ): + serial_number: Optional[str] = None, + ignore_firmware_compatibility_check: Optional[bool] = False, + async_init: Optional[bool] = False): + self._seq = 0 self._usb = False + self._async_init = async_init + self._ignore_firmware_compatibility_check = ignore_firmware_compatibility_check + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.loop) + + if platform.system() == 'Darwin' and bluetooth_mac: + Logger.warning('You would like to establish a bluetooth connection using a MAC address, but you appear to be on a Mac.') + Logger.warning('Apple does not expose Bluetooth MAC addresses anymore, so this method will not work.') + Logger.warning('Try connecting to the device using another option (UUID or Serial).') + + raise Exception('Exception: The chosen connection method does not work on this platform.') if bluetooth_mac is not None: self._connection = Bluetooth(bluetooth_mac=bluetooth_mac) @@ -39,16 +58,24 @@ def __init__( # Connect over USB self._connection = Usb(serial_number=serial_number) + if self._async_init is False: + self.loop.run_until_complete(self._init_device()) + + """ + Use this method to create an asynchronous Radiacode() object: + rc = Radiacode.async_init() + serial = await rc.async_serial_number() + """ @classmethod - async def connect(cls, + async def async_init(cls, bluetooth_mac: Optional[str] = None, bluetooth_serial: Optional[str] = None, bluetooth_uuid: Optional[str] = None, serial_number: Optional[str] = None, - ignore_firmware_compatibility_check: bool = False): + ignore_firmware_compatibility_check: Optional[bool] = False): if platform.system() == 'Darwin' and bluetooth_mac: - Logger.warning('You bluetooth connection using MAC address, but you appear to be on a Mac.') + Logger.warning('You want to connect over bluetooth using a MAC address, but you appear to be on a Mac.') Logger.warning('Apple does not expose Bluetooth MAC addresses anymore, so this method will not work.') Logger.warning('Try connecting to the device using another option (UUID or Serial).') @@ -57,32 +84,34 @@ async def connect(cls, self = cls(bluetooth_mac=bluetooth_mac, bluetooth_serial=bluetooth_serial, bluetooth_uuid=bluetooth_uuid, - serial_number=serial_number) + serial_number=serial_number, + ignore_firmware_compatibility_check=ignore_firmware_compatibility_check, + async_init=True) - await self._init_device(ignore_firmware_compatibility_check) + await self._init_device() return self - async def _init_device(self, ignore_firmware_compatibility_check = False): + async def _init_device(self): if self._usb is False: # Connect over Bluetooth await self._connection.connect() # Init Logger.info('Initializing Radiacode...') - await self.execute(b'\x07\x00', b'\x01\xff\x12\xff') + await self._async_execute(b'\x07\x00', b'\x01\xff\x12\xff') self._base_time = datetime.datetime.now() - await self.set_local_time(self._base_time) - await self.device_time(0) + await self.async_set_local_time(self._base_time) + await self.async_device_time(0) - (_, (vmaj, vmin, _)) = await self.fw_version() - if ignore_firmware_compatibility_check is False and vmaj < 4 or (vmaj == 4 and vmin < 8): + (_, (vmaj, vmin, _)) = await self.async_fw_version() + if self._ignore_firmware_compatibility_check is False and vmaj < 4 or (vmaj == 4 and vmin < 8): raise Exception( f'Incompatible firmware version {vmaj}.{vmin}, >=4.8 required. Upgrade device firmware or use radiacode==0.2.2' ) self._spectrum_format_version = 0 - lines = await self.configuration() + lines = await self.async_configuration() for line in lines.split('\n'): if line.startswith('SpecFormatVersion'): @@ -93,8 +122,100 @@ async def _init_device(self, ignore_firmware_compatibility_check = False): def base_time(self) -> datetime.datetime: return self._base_time + + # def _execute(self, reqtype: bytes, args: Optional[bytes] = None) -> BytesBuffer: + # return self.loop.run_until_complete(self._async_execute(reqtype, args)) + + + def read_request(self, command_id: Union[int, VS, VSFR]) -> BytesBuffer: + return self.loop.run_until_complete(self.async_read_request(command_id)) + + def write_request(self, command_id: Union[int, VSFR], data: Optional[bytes] = None) -> None: + return self.loop.run_until_complete(self.async_write_request(command_id, data)) + + def batch_read_vsfrs(self, vsfr_ids: List[VSFR]) -> List[int]: + return self.loop.run_until_complete(self.async_batch_read_vsfrs(vsfr_ids)) + + def status(self) -> str: + return self.loop.run_until_complete(self.async_status()) + + def set_local_time(self, dt: datetime.datetime) -> None: + return self.loop.run_until_complete(self.set_local_time(dt)) + + def fw_signature(self) -> str: + return self.loop.run_until_complete(self.async_fw_signature()) + + def fw_version(self) -> tuple[tuple[int, int, str], tuple[int, int, str]]: + return self.loop.run_until_complete(self.async_fw_signature()) + + def hw_serial_number(self) -> str: + return self.loop.run_until_complete(self.async_hw_serial_number()) + + def configuration(self) -> str: + return self.loop.run_until_complete(self.async_configuration()) + + def text_message(self) -> str: + return self.loop.run_until_complete(self.async_text_message()) + + def serial_number(self) -> str: + return self.loop.run_until_complete(self.async_serial_number()) + #return self.loop.run_until_complete(self.async_serial_number()) + + def commands(self) -> str: + return self.loop.run_until_complete(self.async_commands()) + + def device_time(self, v: int) -> None: + return self.loop.run_until_complete(self.async_device_time(v)) + + def data_buf(self) -> List[Union[DoseRateDB, RareData, RealTimeData, RawData, Event]]: + return self.loop.run_until_complete(self.async_data_buf()) + + def spectrum(self) -> Spectrum: + return self.loop.run_until_complete(self.async_spectrum()) + + def spectrum_accum(self) -> Spectrum: + return self.loop.run_until_complete(self.async_spectrum_accum()) + + def dose_reset(self) -> None: + return self.loop.run_until_complete(self.async_dose_reset()) + + def spectrum_reset(self) -> None: + return self.loop.run_until_complete(self.async_spectrum_reset()) + + def energy_calib(self) -> List[float]: + return self.loop.run_until_complete(self.async_energy_calib()) + + def set_energy_calib(self, coef: List[float]) -> None: + return self.loop.run_until_complete(self.async_set_energy_calib(coef)) - async def execute(self, reqtype: bytes, args: Optional[bytes] = None) -> BytesBuffer: + def set_language(self, lang='en') -> None: + return self.loop.run_until_complete(self.async_set_language(lang)) + + def set_device_on(self, on: bool): + return self.loop.run_until_complete(self.async_set_device_on(on)) + + def set_sound_on(self, on: bool) -> None: + return self.loop.run_until_complete(self.async_set_sound_on(on)) + + def set_vibro_on(self, on: bool) -> None: + return self.loop.run_until_complete(self.async_set_vibro_on(on)) + + def set_sound_ctrl(self, ctrls: List[CTRL]) -> None: + return self.loop.run_until_complete(self.async_set_sound_ctrl(ctrls)) + + def set_display_off_time(self, seconds: int) -> None: + return self.loop.run_until_complete(self.async_set_display_off_time(seconds)) + + def set_display_brightness(self, brightness: int) -> None: + return self.loop.run_until_complete(self.async_set_display_brightness(brightness)) + + def set_display_direction(self, direction: DisplayDirection) -> None: + return self.loop.run_until_complete(self.async_set_display_direction(direction)) + + def set_vibro_ctrl(self, ctrls: List[CTRL]) -> None: + return self.loop.run_until_complete(self.async_set_vibro_ctrl(ctrls)) + + async def _async_execute(self, reqtype: bytes, args: Optional[bytes] = None) -> BytesBuffer: assert len(reqtype) == 2 req_seq_no = 0x80 + self._seq self._seq = (self._seq + 1) % 32 @@ -108,8 +229,8 @@ async def execute(self, reqtype: bytes, args: Optional[bytes] = None) -> BytesBu assert req_header == resp_header, f'req={req_header.hex()} resp={resp_header.hex()}' return response - async def read_request(self, command_id: Union[int, VS, VSFR]) -> BytesBuffer: - r = await self.execute(b'\x26\x08', struct.pack(' BytesBuffer: + r = await self._async_execute(b'\x26\x08', struct.pack(' BytesBuffer: assert r.size() == flen, f'{command_id}: got size {r.size()}, expect {flen}' return r - async def write_request(self, command_id: Union[int, VSFR], data: Optional[bytes] = None) -> None: - r = await self.execute(b'\x25\x08', struct.pack(' None: + r = await self._async_execute(b'\x25\x08', struct.pack(' List[int]: + async def async_batch_read_vsfrs(self, vsfr_ids: List[VSFR]) -> List[int]: assert len(vsfr_ids) - r = await self.execute(b'\x2a\x08', b''.join(struct.pack(' str: - r = await self.execute(b'\x05\x00') + async def async_status(self) -> str: + r = await self._async_execute(b'\x05\x00') flags = r.unpack(' None: + async def async_set_local_time(self, dt: datetime.datetime) -> None: d = struct.pack(' str: - r = await self.execute(b'\x01\x01') + async def async_fw_signature(self) -> str: + r = await self._async_execute(b'\x01\x01') signature = r.unpack(' tuple[tuple[int, int, str], tuple[int, int, str]]: - r = await self.execute(b'\x0a\x00') + async def async_fw_version(self) -> tuple[tuple[int, int, str], tuple[int, int, str]]: + r = await self._async_execute(b'\x0a\x00') boot_minor, boot_major = r.unpack(' tuple[tuple[int, int, str], tuple[int, int, str]]: assert r.size() == 0 return ((boot_major, boot_minor, boot_date), (target_major, target_minor, target_date.strip('\x00'))) - async def hw_serial_number(self) -> str: - r = await self.execute(b'\x0b\x00') + async def async_hw_serial_number(self) -> str: + r = await self._async_execute(b'\x0b\x00') serial_len = r.unpack(' str: - r = await self.read_request(VS.CONFIGURATION) + async def async_configuration(self) -> str: + r = await self.async_read_request(VS.CONFIGURATION) return r.data().decode('cp1251') - async def text_message(self) -> str: - r = await self.read_request(VS.TEXT_MESSAGE) + async def async_text_message(self) -> str: + r = await self.async_read_request(VS.TEXT_MESSAGE) return r.data().decode('ascii') - - async def serial_number(self) -> str: - r = await self.read_request(8) + + async def async_serial_number(self) -> str: + r = await self.async_read_request(8) return r.data().decode('ascii') - async def commands(self) -> str: - br = await self.read_request(257) + async def async_commands(self) -> str: + br = await self.async_read_request(257) return br.data().decode('ascii') # called with 0 after init! - async def device_time(self, v: int) -> None: - await self.write_request(VSFR.DEVICE_TIME, struct.pack(' None: + await self.async_write_request(VSFR.DEVICE_TIME, struct.pack(' List[Union[DoseRateDB, RareData, RealTimeData, RawData, Event]]: - r = await self.read_request(VS.DATA_BUF) + async def async_data_buf(self) -> List[Union[DoseRateDB, RareData, RealTimeData, RawData, Event]]: + r = await self.async_read_request(VS.DATA_BUF) return decode_VS_DATA_BUF(r, self._base_time) - async def spectrum(self) -> Spectrum: - r = await self.read_request(VS.SPECTRUM) + async def async_spectrum(self) -> Spectrum: + r = await self.async_read_request(VS.SPECTRUM) return decode_RC_VS_SPECTRUM(r, self._spectrum_format_version) - async def spectrum_accum(self) -> Spectrum: - r = await self.read_request(VS.SPEC_ACCUM) + async def async_spectrum_accum(self) -> Spectrum: + r = await self.async_read_request(VS.SPEC_ACCUM) return decode_RC_VS_SPECTRUM(r, self._spectrum_format_version) - async def dose_reset(self) -> None: - await self.write_request(VSFR.DOSE_RESET) + async def async_dose_reset(self) -> None: + await self.async_write_request(VSFR.DOSE_RESET) - async def spectrum_reset(self) -> None: - r = await self.execute(b'\x27\x08', struct.pack(' None: + r = await self._async_execute(b'\x27\x08', struct.pack(' List[float]: - r = await self.read_request(VS.ENERGY_CALIB) + async def async_energy_calib(self) -> List[float]: + r = await self.async_read_request(VS.ENERGY_CALIB) return list(r.unpack(' None: + async def async_set_energy_calib(self, coef: List[float]) -> None: assert len(coef) == 3 pc = struct.pack(' None: + async def async_set_language(self, lang='en') -> None: assert lang in {'ru', 'en'}, 'unsupported lang value - use "ru" or "en"' - await self.write_request(VSFR.DEVICE_LANG, struct.pack(' None: - await self.write_request(VSFR.SOUND_ON, struct.pack(' None: + await self.async_write_request(VSFR.SOUND_ON, struct.pack(' None: - await self.write_request(VSFR.SOUND_ON, struct.pack(' None: + await self.async_write_request(VSFR.SOUND_ON, struct.pack(' None: + async def async_set_sound_ctrl(self, ctrls: List[CTRL]) -> None: flags = 0 + for c in ctrls: flags |= int(c) - await self.write_request(VSFR.SOUND_CTRL, struct.pack(' None: + async def async_set_display_off_time(self, seconds: int) -> None: assert seconds in {5, 10, 15, 30} v = 3 if seconds == 30 else (seconds // 5) - 1 - await self.write_request(VSFR.DISP_OFF_TIME, struct.pack(' None: + async def async_set_display_brightness(self, brightness: int) -> None: assert 0 <= brightness and brightness <= 9 - await self.write_request(VSFR.DISP_BRT, struct.pack(' None: + async def async_set_display_direction(self, direction: DisplayDirection) -> None: assert isinstance(direction, DisplayDirection) - await self.write_request(VSFR.DISP_DIR, struct.pack(' None: + async def async_set_vibro_ctrl(self, ctrls: List[CTRL]) -> None: flags = 0 for c in ctrls: assert c != CTRL.CLICKS, 'CTRL.CLICKS not supported for vibro' flags |= int(c) - await self.write_request(VSFR.VIBRO_CTRL, struct.pack(' None: if len(self.bluetooth_serial) < 6: Logger.warning('To improve reliability, try to provide at least 6 digits of your Radiacode serial number') - bt_devices = await self._scan() + bt_devices = await self._async_scan() if len(bt_devices) == 0: raise DeviceNotFound('No Radiacodes found. Check that bluetooth is enabled and that the Radiacode is not connected to another device.') @@ -83,7 +83,10 @@ async def connect(self) -> None: Logger.notify('Notifications started') - async def _scan(self) -> List[Tuple[BLEDevice, AdvertisementData]]: + def _scan(self) -> List[Tuple[BLEDevice, AdvertisementData]]: + return asyncio.run(self._async_scan()) + + async def _async_scan(self) -> List[Tuple[BLEDevice, AdvertisementData]]: """ Returns a list of Tuples of valid Radiacodes """ radiacodes = [] From 0a62fc0308046a6e305d75582afdbf5ae9b0e328 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Sat, 11 May 2024 15:24:49 +0800 Subject: [PATCH 12/20] Format fixes --- radiacode-examples/basic.py | 27 +++++- radiacode-examples/find-radiacode.py | 8 +- radiacode-examples/narodmon.py | 31 +++++-- radiacode-examples/radiacode-exporter.py | 26 +++++- radiacode-examples/show-spectrum.py | 50 ++++++++--- radiacode-examples/webserver.py | 44 +++++---- radiacode/logger.py | 4 +- radiacode/radiacode.py | 110 ++++++++++++----------- radiacode/transports/bluetooth.py | 56 ++++++------ radiacode/transports/usb.py | 5 +- 10 files changed, 240 insertions(+), 121 deletions(-) diff --git a/radiacode-examples/basic.py b/radiacode-examples/basic.py index 48829d2..8ffa169 100644 --- a/radiacode-examples/basic.py +++ b/radiacode-examples/basic.py @@ -5,6 +5,7 @@ from radiacode.transports.usb import DeviceNotFound as DeviceNotFoundUSB from radiacode.transports.bluetooth import DeviceNotFound as DeviceNotFoundBT + def main(args: argparse.Namespace): try: if args.bluetooth_mac: @@ -53,13 +54,31 @@ def main(args: argparse.Namespace): print(v.dt.isoformat(), v) time.sleep(2) + if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument('--bluetooth-mac', type=str, required=False, help='Radiacode Bluetooth MAC address (e.g. 00:11:22:33:44:55). MacOS does not support BT MACs, use Serial Number or UUID instead.') - parser.add_argument('--bluetooth-serial', type=str, required=False, help='Connect via Bluetooth using Radiacode Serial (e.g. "RC-10x-xxxxxx").') - parser.add_argument('--bluetooth-uuid', type=str, required=False, help='Connect via Bluetooth using Radiacode UUID (e.g. "11111111-2222-3333-4444-56789ABCDEF").') - parser.add_argument('--serial', type=str, required=False, help='Connect via USB using Radiacode Serial (e.g. "RC-10x-xxxxxx").') + parser.add_argument( + '--bluetooth-mac', + type=str, + required=False, + help='Radiacode Bluetooth MAC address (e.g. 00:11:22:33:44:55). MacOS does not support BT MACs, use Serial Number or UUID instead.', + ) + parser.add_argument( + '--bluetooth-serial', + type=str, + required=False, + help='Connect via Bluetooth using Radiacode Serial (e.g. "RC-10x-xxxxxx").', + ) + parser.add_argument( + '--bluetooth-uuid', + type=str, + required=False, + help='Connect via Bluetooth using Radiacode UUID (e.g. "11111111-2222-3333-4444-56789ABCDEF").', + ) + parser.add_argument( + '--serial', type=str, required=False, help='Connect via USB using Radiacode Serial (e.g. "RC-10x-xxxxxx").' + ) parser.add_argument('--usb', type=str, required=False, help='(default) Connect via USB to the first Radiacode available.') args = parser.parse_args() diff --git a/radiacode-examples/find-radiacode.py b/radiacode-examples/find-radiacode.py index 5ae8dc9..2596667 100644 --- a/radiacode-examples/find-radiacode.py +++ b/radiacode-examples/find-radiacode.py @@ -6,14 +6,18 @@ from radiacode.transports.bluetooth import Bluetooth from radiacode.logger import Logger + def main(): Logger.info('Looking for Radiacodes over Bluetooth') radiacodes = Bluetooth()._scan() if len(radiacodes) == 0: - Logger.error('No Radiacodes found, make sure Bluetooth is active on both your device and the Radiacode. Make sure the Radiacode is not connected to other devices.') + Logger.error( + 'No Radiacodes found, make sure Bluetooth is active on both your device and the Radiacode. Make sure the Radiacode is not connected to other devices.' + ) else: Logger.notify(f'{len(radiacodes)} Radiacode(s) found') + if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/radiacode-examples/narodmon.py b/radiacode-examples/narodmon.py index d9b4326..05e5cfa 100644 --- a/radiacode-examples/narodmon.py +++ b/radiacode-examples/narodmon.py @@ -7,6 +7,7 @@ from radiacode.transports.usb import DeviceNotFound as DeviceNotFoundUSB from radiacode.transports.bluetooth import DeviceNotFound as DeviceNotFoundBT + def sensors_data(rc_conn): databuf = rc_conn.data_buf() @@ -44,12 +45,30 @@ async def send_data(d): async with session.post('https://narodmon.ru/json', json=d) as resp: return await resp.text() + def main(): parser = argparse.ArgumentParser() - parser.add_argument('--bluetooth-mac', type=str, required=False, help='Radiacode Bluetooth MAC address (e.g. 00:11:22:33:44:55). MacOS does not support BT MACs, use Serial Number or UUID instead.') - parser.add_argument('--bluetooth-serial', type=str, required=False, help='Connect via Bluetooth using Radiacode Serial (e.g. "RC-10x-xxxxxx").') - parser.add_argument('--bluetooth-uuid', type=str, required=False, help='Connect via Bluetooth using Radiacode UUID (e.g. "11111111-2222-3333-4444-56789ABCDEF").') - parser.add_argument('--serial', type=str, required=False, help='Connect via USB using Radiacode Serial (e.g. "RC-10x-xxxxxx").') + parser.add_argument( + '--bluetooth-mac', + type=str, + required=False, + help='Radiacode Bluetooth MAC address (e.g. 00:11:22:33:44:55). MacOS does not support BT MACs, use Serial Number or UUID instead.', + ) + parser.add_argument( + '--bluetooth-serial', + type=str, + required=False, + help='Connect via Bluetooth using Radiacode Serial (e.g. "RC-10x-xxxxxx").', + ) + parser.add_argument( + '--bluetooth-uuid', + type=str, + required=False, + help='Connect via Bluetooth using Radiacode UUID (e.g. "11111111-2222-3333-4444-56789ABCDEF").', + ) + parser.add_argument( + '--serial', type=str, required=False, help='Connect via USB using Radiacode Serial (e.g. "RC-10x-xxxxxx").' + ) parser.add_argument('--usb', type=str, required=False, help='(default) Connect via USB to the first Radiacode available.') parser.add_argument('--interval', type=int, required=False, default=600, help='Send interval, seconds') args = parser.parse_args() @@ -84,9 +103,9 @@ def main(): return mac = args.bluetooth_mac.replace(':', '-') if args.bluetooth_mac else '00-00-00-00-00-00' - + device_data = { - 'mac': mac, + 'mac': mac, 'name': 'RadiaCode-101', } diff --git a/radiacode-examples/radiacode-exporter.py b/radiacode-examples/radiacode-exporter.py index b5e7d74..5dcfad2 100644 --- a/radiacode-examples/radiacode-exporter.py +++ b/radiacode-examples/radiacode-exporter.py @@ -7,12 +7,30 @@ from radiacode.transports.usb import DeviceNotFound as DeviceNotFoundUSB from radiacode.transports.bluetooth import DeviceNotFound as DeviceNotFoundBT + def main(): parser = argparse.ArgumentParser() - parser.add_argument('--bluetooth-mac', type=str, required=False, help='Radiacode Bluetooth MAC address (e.g. 00:11:22:33:44:55). MacOS does not support BT MACs, use Serial Number or UUID instead.') - parser.add_argument('--bluetooth-serial', type=str, required=False, help='Connect via Bluetooth using Radiacode Serial (e.g. "RC-10x-xxxxxx").') - parser.add_argument('--bluetooth-uuid', type=str, required=False, help='Connect via Bluetooth using Radiacode UUID (e.g. "11111111-2222-3333-4444-56789ABCDEF").') - parser.add_argument('--serial', type=str, required=False, help='Connect via USB using Radiacode Serial (e.g. "RC-10x-xxxxxx").') + parser.add_argument( + '--bluetooth-mac', + type=str, + required=False, + help='Radiacode Bluetooth MAC address (e.g. 00:11:22:33:44:55). MacOS does not support BT MACs, use Serial Number or UUID instead.', + ) + parser.add_argument( + '--bluetooth-serial', + type=str, + required=False, + help='Connect via Bluetooth using Radiacode Serial (e.g. "RC-10x-xxxxxx").', + ) + parser.add_argument( + '--bluetooth-uuid', + type=str, + required=False, + help='Connect via Bluetooth using Radiacode UUID (e.g. "11111111-2222-3333-4444-56789ABCDEF").', + ) + parser.add_argument( + '--serial', type=str, required=False, help='Connect via USB using Radiacode Serial (e.g. "RC-10x-xxxxxx").' + ) parser.add_argument('--update-interval', type=int, default=3, required=False, help='update interval (seconds)') parser.add_argument('--port', type=int, default=5432, required=False, help='prometheus http port') diff --git a/radiacode-examples/show-spectrum.py b/radiacode-examples/show-spectrum.py index 1e7eda4..e19f692 100644 --- a/radiacode-examples/show-spectrum.py +++ b/radiacode-examples/show-spectrum.py @@ -51,7 +51,7 @@ from radiacode.transports.bluetooth import DeviceNotFound as DeviceNotFoundBT # set backend and matplotlib style -#mpl.use('Qt5Agg') +# mpl.use('Qt5Agg') plt.style.use('dark_background') # some constants @@ -106,7 +106,6 @@ def on_mpl_window_closed(ax): # end helpers --------------------------------------- - bluetooth_mac = args.bluetooth_mac bluetooth_uuid = args.bluetooth_uuid bluetooth_serial = args.bluetooth_serial @@ -128,7 +127,12 @@ def on_mpl_window_closed(ax): # initialize and connect to RC10x device # ------ try: - rc = RadiaCode(bluetooth_mac=bluetooth_mac, bluetooth_uuid=bluetooth_uuid, bluetooth_serial=bluetooth_serial, serial_number=serial_number) + rc = RadiaCode( + bluetooth_mac=bluetooth_mac, + bluetooth_uuid=bluetooth_uuid, + bluetooth_serial=bluetooth_serial, + serial_number=serial_number, + ) except DeviceNotFoundBT as e: print(e) return @@ -150,7 +154,7 @@ def on_mpl_window_closed(ax): # get initial spectrum and meta-data if reset_device_spectrum: - rc.spectrum_reset() + rc.spectrum_reset() spectrum = rc.spectrum() @@ -384,17 +388,43 @@ def on_mpl_window_closed(ax): + 'show differential and updated cumulative spectrum, ' + 'optionally store data to file in yaml format.' ) - parser.add_argument('-b', '--bluetooth-mac', type=str, required=False, help='Radiacode Bluetooth MAC address (e.g. 00:11:22:33:44:55). MacOS does not support BT MACs, use Serial Number or UUID instead.') - parser.add_argument('-u', '--bluetooth-uuid', type=str, required=False, help='Connect via Bluetooth using Radiacode UUID (e.g. "11111111-2222-3333-4444-56789ABCDEF").') - parser.add_argument('-e', '--bluetooth-serial', type=str, required=False, help='Connect via Bluetooth using Radiacode Serial (e.g. "RC-10x-xxxxxx").') - parser.add_argument('-s', '--serial-number', type=str, required=False, help='Connect via USB using Radiacode Serial (e.g. "RC-10x-xxxxxx").') + parser.add_argument( + '-b', + '--bluetooth-mac', + type=str, + required=False, + help='Radiacode Bluetooth MAC address (e.g. 00:11:22:33:44:55). MacOS does not support BT MACs, use Serial Number or UUID instead.', + ) + parser.add_argument( + '-u', + '--bluetooth-uuid', + type=str, + required=False, + help='Connect via Bluetooth using Radiacode UUID (e.g. "11111111-2222-3333-4444-56789ABCDEF").', + ) + parser.add_argument( + '-e', + '--bluetooth-serial', + type=str, + required=False, + help='Connect via Bluetooth using Radiacode Serial (e.g. "RC-10x-xxxxxx").', + ) + parser.add_argument( + '-s', '--serial-number', type=str, required=False, help='Connect via USB using Radiacode Serial (e.g. "RC-10x-xxxxxx").' + ) parser.add_argument('-r', '--restart', action='store_true', help='Restart spectrum accumulation') parser.add_argument('-R', '--Reset', action='store_true', help='Reset spectrum stored in device') parser.add_argument('-q', '--quiet', action='store_true', help='No status output to terminal') parser.add_argument('-i', '--interval', type=float, default=1.0, help='Update interval (s)') - parser.add_argument('-f', '--file', type=str, default='', help='Filename to store results (.yaml extension will be automatically added to the name)') + parser.add_argument( + '-f', + '--file', + type=str, + default='', + help='Filename to store results (.yaml extension will be automatically added to the name)', + ) parser.add_argument('-t', '--time', type=int, default=36000, help='Run time in seconds') parser.add_argument('-H', '--history', type=int, default=500, help='Number of rate-history points to store in file') args = parser.parse_args() - plot_RC102Spectrum(args) \ No newline at end of file + plot_RC102Spectrum(args) diff --git a/radiacode-examples/webserver.py b/radiacode-examples/webserver.py index 582b895..a12ebbf 100644 --- a/radiacode-examples/webserver.py +++ b/radiacode-examples/webserver.py @@ -7,9 +7,11 @@ from radiacode import RadiaCode, RealTimeData + async def handle_index(request): return web.FileResponse(pathlib.Path(__file__).parent.absolute() / 'webserver.html') + async def handle_ws(request): ws = web.WebSocketResponse() await ws.prepare(request) @@ -23,25 +25,30 @@ async def handle_ws(request): return ws + async def handle_spectrum(request): cn = request.app['rc_conn'] accum = request.query.get('accum') == 'true' spectrum = await (cn.async_spectrum_accum() if accum else cn.async_spectrum()) - + # apexcharts can't handle 0 in logarithmic view spectrum_data = [(channel, cnt if cnt > 0 else 0.5) for channel, cnt in enumerate(spectrum.counts)] - - return web.json_response({ - 'coef': [spectrum.a0, spectrum.a1, spectrum.a2], - 'duration': spectrum.duration.total_seconds(), - 'series': [{'name': 'spectrum', 'data': spectrum_data}], - }) + + return web.json_response( + { + 'coef': [spectrum.a0, spectrum.a1, spectrum.a2], + 'duration': spectrum.duration.total_seconds(), + 'series': [{'name': 'spectrum', 'data': spectrum_data}], + } + ) + async def handle_spectrum_reset(request): cn = request.app['rc_conn'] await cn.async_spectrum_reset() return web.json_response({'message': 'Spectrum reset'}) + async def process(app): max_history_size = 128 history = [] @@ -55,7 +62,7 @@ async def process(app): history.sort(key=lambda x: x.dt) history = history[-max_history_size:] - + jdata = json.dumps( { 'series': [ @@ -75,10 +82,12 @@ async def process(app): await asyncio.gather(*(ws.send_str(jdata) for ws in app['ws_clients'])) await asyncio.sleep(1.0) + async def on_startup(app): app['process_task'] = asyncio.create_task(process(app)) app['ws_clients'] = [] + async def init_connection(app): if app['args'].bluetooth_mac: print('will use Bluetooth connection via MAC address') @@ -90,6 +99,7 @@ async def init_connection(app): print('will use USB connection') app['rc_conn'] = await RadiaCode.async_init() + def main(): parser = argparse.ArgumentParser() parser.add_argument('--bluetooth-mac', type=str, required=False, help='Bluetooth MAC address of radiascan device') @@ -102,16 +112,18 @@ def main(): app['args'] = args app.on_startup.append(init_connection) app.on_startup.append(on_startup) - - app.add_routes([ - web.get('/', handle_index), - web.get('/spectrum', handle_spectrum), - web.post('/spectrum/reset', handle_spectrum_reset), - web.get('/ws', handle_ws), - ]) + + app.add_routes( + [ + web.get('/', handle_index), + web.get('/spectrum', handle_spectrum), + web.post('/spectrum/reset', handle_spectrum_reset), + web.get('/ws', handle_ws), + ] + ) web.run_app(app, host=args.listen_host, port=args.listen_port) + if __name__ == '__main__': main() - diff --git a/radiacode/logger.py b/radiacode/logger.py index 762d533..7e02e1f 100644 --- a/radiacode/logger.py +++ b/radiacode/logger.py @@ -1,11 +1,13 @@ from enum import Enum + class LogLevel(Enum): Notification = ('notification', '[\033[1;32m\N{check mark}\033[0m]') Error = ('error', '[\033[1;31m\N{aegean check mark}\033[0m]') Info = ('info', '[\033[1;34m\N{information source}\033[0m]') Warning = ('warning', '[\033[1;35m\N{warning sign}\033[0m]') + class Logger: @staticmethod def log(message): @@ -30,4 +32,4 @@ def warning(message): @staticmethod def _log_level(message, level): prefix = level.value[1] - print(f'{prefix} {message}') \ No newline at end of file + print(f'{prefix} {message}') diff --git a/radiacode/radiacode.py b/radiacode/radiacode.py index 876ff0b..fb25036 100644 --- a/radiacode/radiacode.py +++ b/radiacode/radiacode.py @@ -12,10 +12,12 @@ from radiacode.transports.usb import Usb from radiacode.types import CTRL, VS, VSFR, DisplayDirection, DoseRateDB, Event, RareData, RawData, RealTimeData, Spectrum + # channel number -> kEv def spectrum_channel_to_energy(channel_number: int, a0: float, a1: float, a2: float) -> float: return a0 + a1 * channel_number + a2 * channel_number * channel_number + class RadiaCode: _connection: Union[Bluetooth, Usb] @@ -24,6 +26,7 @@ class RadiaCode: rc = Radiacode() serial = rc.serial_number() """ + def __init__( self, bluetooth_mac: Optional[str] = None, @@ -31,8 +34,8 @@ def __init__( bluetooth_uuid: Optional[str] = None, serial_number: Optional[str] = None, ignore_firmware_compatibility_check: Optional[bool] = False, - async_init: Optional[bool] = False): - + async_init: Optional[bool] = False, + ): self._seq = 0 self._usb = False self._async_init = async_init @@ -41,7 +44,9 @@ def __init__( asyncio.set_event_loop(self.loop) if platform.system() == 'Darwin' and bluetooth_mac: - Logger.warning('You would like to establish a bluetooth connection using a MAC address, but you appear to be on a Mac.') + Logger.warning( + 'You would like to establish a bluetooth connection using a MAC address, but you appear to be on a Mac.' + ) Logger.warning('Apple does not expose Bluetooth MAC addresses anymore, so this method will not work.') Logger.warning('Try connecting to the device using another option (UUID or Serial).') @@ -66,14 +71,16 @@ def __init__( rc = Radiacode.async_init() serial = await rc.async_serial_number() """ + @classmethod - async def async_init(cls, - bluetooth_mac: Optional[str] = None, - bluetooth_serial: Optional[str] = None, - bluetooth_uuid: Optional[str] = None, - serial_number: Optional[str] = None, - ignore_firmware_compatibility_check: Optional[bool] = False): - + async def async_init( + cls, + bluetooth_mac: Optional[str] = None, + bluetooth_serial: Optional[str] = None, + bluetooth_uuid: Optional[str] = None, + serial_number: Optional[str] = None, + ignore_firmware_compatibility_check: Optional[bool] = False, + ): if platform.system() == 'Darwin' and bluetooth_mac: Logger.warning('You want to connect over bluetooth using a MAC address, but you appear to be on a Mac.') Logger.warning('Apple does not expose Bluetooth MAC addresses anymore, so this method will not work.') @@ -81,16 +88,18 @@ async def async_init(cls, raise Exception('Exception: The chosen connection method does not work on this platform.') - self = cls(bluetooth_mac=bluetooth_mac, - bluetooth_serial=bluetooth_serial, - bluetooth_uuid=bluetooth_uuid, - serial_number=serial_number, - ignore_firmware_compatibility_check=ignore_firmware_compatibility_check, - async_init=True) - + self = cls( + bluetooth_mac=bluetooth_mac, + bluetooth_serial=bluetooth_serial, + bluetooth_uuid=bluetooth_uuid, + serial_number=serial_number, + ignore_firmware_compatibility_check=ignore_firmware_compatibility_check, + async_init=True, + ) + await self._init_device() return self - + async def _init_device(self): if self._usb is False: # Connect over Bluetooth @@ -112,7 +121,7 @@ async def _init_device(self): self._spectrum_format_version = 0 lines = await self.async_configuration() - + for line in lines.split('\n'): if line.startswith('SpecFormatVersion'): self._spectrum_format_version = int(line.split('=')[1]) @@ -122,69 +131,68 @@ async def _init_device(self): def base_time(self) -> datetime.datetime: return self._base_time - + # def _execute(self, reqtype: bytes, args: Optional[bytes] = None) -> BytesBuffer: # return self.loop.run_until_complete(self._async_execute(reqtype, args)) - def read_request(self, command_id: Union[int, VS, VSFR]) -> BytesBuffer: return self.loop.run_until_complete(self.async_read_request(command_id)) - + def write_request(self, command_id: Union[int, VSFR], data: Optional[bytes] = None) -> None: return self.loop.run_until_complete(self.async_write_request(command_id, data)) - + def batch_read_vsfrs(self, vsfr_ids: List[VSFR]) -> List[int]: return self.loop.run_until_complete(self.async_batch_read_vsfrs(vsfr_ids)) - + def status(self) -> str: return self.loop.run_until_complete(self.async_status()) - + def set_local_time(self, dt: datetime.datetime) -> None: return self.loop.run_until_complete(self.set_local_time(dt)) - + def fw_signature(self) -> str: return self.loop.run_until_complete(self.async_fw_signature()) - + def fw_version(self) -> tuple[tuple[int, int, str], tuple[int, int, str]]: return self.loop.run_until_complete(self.async_fw_signature()) - + def hw_serial_number(self) -> str: return self.loop.run_until_complete(self.async_hw_serial_number()) - + def configuration(self) -> str: return self.loop.run_until_complete(self.async_configuration()) - + def text_message(self) -> str: return self.loop.run_until_complete(self.async_text_message()) - + def serial_number(self) -> str: return self.loop.run_until_complete(self.async_serial_number()) - #return self.loop.run_until_complete(self.async_serial_number()) - + # return self.loop.run_until_complete(self.async_serial_number()) + def commands(self) -> str: return self.loop.run_until_complete(self.async_commands()) - + def device_time(self, v: int) -> None: return self.loop.run_until_complete(self.async_device_time(v)) - + def data_buf(self) -> List[Union[DoseRateDB, RareData, RealTimeData, RawData, Event]]: return self.loop.run_until_complete(self.async_data_buf()) - + def spectrum(self) -> Spectrum: return self.loop.run_until_complete(self.async_spectrum()) - + def spectrum_accum(self) -> Spectrum: return self.loop.run_until_complete(self.async_spectrum_accum()) - + def dose_reset(self) -> None: return self.loop.run_until_complete(self.async_dose_reset()) - + def spectrum_reset(self) -> None: return self.loop.run_until_complete(self.async_spectrum_reset()) - + def energy_calib(self) -> List[float]: return self.loop.run_until_complete(self.async_energy_calib()) - + def set_energy_calib(self, coef: List[float]) -> None: return self.loop.run_until_complete(self.async_set_energy_calib(coef)) @@ -193,28 +201,28 @@ def set_language(self, lang='en') -> None: def set_device_on(self, on: bool): return self.loop.run_until_complete(self.async_set_device_on(on)) - + def set_sound_on(self, on: bool) -> None: return self.loop.run_until_complete(self.async_set_sound_on(on)) - + def set_vibro_on(self, on: bool) -> None: return self.loop.run_until_complete(self.async_set_vibro_on(on)) - + def set_sound_ctrl(self, ctrls: List[CTRL]) -> None: return self.loop.run_until_complete(self.async_set_sound_ctrl(ctrls)) - + def set_display_off_time(self, seconds: int) -> None: return self.loop.run_until_complete(self.async_set_display_off_time(seconds)) - + def set_display_brightness(self, brightness: int) -> None: return self.loop.run_until_complete(self.async_set_display_brightness(brightness)) - + def set_display_direction(self, direction: DisplayDirection) -> None: return self.loop.run_until_complete(self.async_set_display_direction(direction)) - + def set_vibro_ctrl(self, ctrls: List[CTRL]) -> None: return self.loop.run_until_complete(self.async_set_vibro_ctrl(ctrls)) - + async def _async_execute(self, reqtype: bytes, args: Optional[bytes] = None) -> BytesBuffer: assert len(reqtype) == 2 req_seq_no = 0x80 + self._seq @@ -233,7 +241,7 @@ async def async_read_request(self, command_id: Union[int, VS, VSFR]) -> BytesBuf r = await self._async_execute(b'\x26\x08', struct.pack(' str: async def async_text_message(self) -> str: r = await self.async_read_request(VS.TEXT_MESSAGE) return r.data().decode('ascii') - + async def async_serial_number(self) -> str: r = await self.async_read_request(8) return r.data().decode('ascii') diff --git a/radiacode/transports/bluetooth.py b/radiacode/transports/bluetooth.py index a682f10..7b9d355 100644 --- a/radiacode/transports/bluetooth.py +++ b/radiacode/transports/bluetooth.py @@ -8,25 +8,27 @@ from bleak.backends.scanner import AdvertisementData, BLEDevice RADIACODE_SERVICE_UUID = 'e63215e5-7003-49d8-96b0-b024798fb901' # Handle: 12 -RADIACODE_WRITEFD_UUID = 'e63215e6-7003-49d8-96b0-b024798fb901' # Handle: 13, (write-without-response, write), Max write w/o rsp size: 217 -RADIACODE_NOTIFYFD_UUID = 'e63215e7-7003-49d8-96b0-b024798fb901' # Handle: 15, notify +RADIACODE_WRITEFD_UUID = ( + 'e63215e6-7003-49d8-96b0-b024798fb901' # Handle: 13, (write-without-response, write), Max write w/o rsp size: 217 +) +RADIACODE_NOTIFYFD_UUID = 'e63215e7-7003-49d8-96b0-b024798fb901' # Handle: 15, notify + class DeviceNotFound(Exception): pass -class Bluetooth(): - def __init__(self, - bluetooth_mac: Optional[str] = None, - bluetooth_serial: Optional[str] = None, - bluetooth_uuid: Optional[str] = None + +class Bluetooth: + def __init__( + self, bluetooth_mac: Optional[str] = None, bluetooth_serial: Optional[str] = None, bluetooth_uuid: Optional[str] = None ): self._resp_buffer = b'' self._resp_size = 0 self._response = None self.client = None - #self._response_event = asyncio.Event() + # self._response_event = asyncio.Event() - self.bluetooth_mac = bluetooth_mac # Only for Windows and Linux + self.bluetooth_mac = bluetooth_mac # Only for Windows and Linux self.bluetooth_serial = bluetooth_serial self.bluetooth_uuid = bluetooth_uuid @@ -45,8 +47,10 @@ async def connect(self) -> None: bt_devices = await self._async_scan() if len(bt_devices) == 0: - raise DeviceNotFound('No Radiacodes found. Check that bluetooth is enabled and that the Radiacode is not connected to another device.') - + raise DeviceNotFound( + 'No Radiacodes found. Check that bluetooth is enabled and that the Radiacode is not connected to another device.' + ) + ble, _ = (None, None) # Find the requested device in the list @@ -69,12 +73,12 @@ async def connect(self) -> None: # Attempt connection await self.client.connect() - + if self.client.is_connected: Logger.notify(f'Connected to Radiacode via bluetooth to: {self.client.address}') else: raise DeviceNotFound('Cannot connect to the requested Radiacode') - + # Start notifications self.notiffd = self.client.services.get_characteristic(RADIACODE_NOTIFYFD_UUID) await self.client.start_notify(self.notiffd, self.handleNotification) @@ -82,12 +86,12 @@ async def connect(self) -> None: self.writefd = self.client.services.get_characteristic(RADIACODE_WRITEFD_UUID) Logger.notify('Notifications started') - + def _scan(self) -> List[Tuple[BLEDevice, AdvertisementData]]: return asyncio.run(self._async_scan()) async def _async_scan(self) -> List[Tuple[BLEDevice, AdvertisementData]]: - """ Returns a list of Tuples of valid Radiacodes """ + """Returns a list of Tuples of valid Radiacodes""" radiacodes = [] Logger.info('Scan started...') @@ -99,7 +103,7 @@ async def _async_scan(self) -> List[Tuple[BLEDevice, AdvertisementData]]: if len(radiacodes) == 0: return [] - + bt_devices = [] for r in radiacodes: @@ -112,7 +116,7 @@ async def _async_scan(self) -> List[Tuple[BLEDevice, AdvertisementData]]: Logger.notify(f'Active service found for device ID: {adv.local_name} - UUID: {ble.address}') bt_devices.append(r) - + return bt_devices def handleNotification(self, characteristic, data) -> None: @@ -125,15 +129,15 @@ def handleNotification(self, characteristic, data) -> None: self._resp_size -= len(data) assert self._resp_size >= 0 - + if self._resp_size == 0: self._response = self._resp_buffer self._resp_buffer = b'' - - #self._response_event.set() - #print(f'{tok} Notification: {characteristic.description}: {self._resp_buffer}') - + # self._response_event.set() + + # print(f'{tok} Notification: {characteristic.description}: {self._resp_buffer}') + async def execute(self, req) -> BytesBuffer: if self.client is None or self.client.is_connected is False: await self.client.connect() @@ -145,10 +149,10 @@ async def execute(self, req) -> BytesBuffer: self._response = [] await self.client.write_gatt_char(self.writefd, req, response=False) await asyncio.sleep(1.5) - #await self._response_event.wait() - - #await self.client.stop_notify(notif) + # await self._response_event.wait() + + # await self.client.stop_notify(notif) br = BytesBuffer(self._response) self._response = None - return br \ No newline at end of file + return br diff --git a/radiacode/transports/usb.py b/radiacode/transports/usb.py index 48c4a32..c05d727 100644 --- a/radiacode/transports/usb.py +++ b/radiacode/transports/usb.py @@ -3,9 +3,11 @@ from radiacode.bytes_buffer import BytesBuffer + class DeviceNotFound(Exception): pass + class MultipleUSBReadFailure(Exception): """Raised when max. number of USB read failues reached""" @@ -13,6 +15,7 @@ def __init__(self, message=None): self.message = 'Multiple USB Read Failures' if message is None else message super().__init__(self.message) + class Usb: def __init__(self, serial_number=None, timeout_ms=3000): _vid = 0x0483 @@ -48,7 +51,7 @@ async def execute(self, request: bytes) -> BytesBuffer: break else: trials += 1 - + if trials >= max_trials: raise MultipleUSBReadFailure(str(trials) + ' USB Read Failures in sequence') From 810082c89dc08c438033d98c4d0b3ef81d600905 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Sun, 12 May 2024 13:36:33 +0800 Subject: [PATCH 13/20] Cosmetics --- poetry.lock | 371 +++--------------------------- radiacode-examples/basic.py | 1 - radiacode-examples/webserver.py | 3 - radiacode/transports/bluetooth.py | 6 +- 4 files changed, 39 insertions(+), 342 deletions(-) diff --git a/poetry.lock b/poetry.lock index a0cc699..af0ca46 100644 --- a/poetry.lock +++ b/poetry.lock @@ -268,45 +268,45 @@ tests = ["pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "dbus-fast" -version = "2.21.1" +version = "2.21.2" description = "A faster version of dbus-next" optional = false -python-versions = ">=3.7,<4.0" +python-versions = "<4.0,>=3.7" files = [ - {file = "dbus_fast-2.21.1-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:b04b88be594dad81b33f6770283eed2125763632515c5112f8aa30f259cd334c"}, - {file = "dbus_fast-2.21.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7333896544a4d0a3d708bd092f8c05eb3599dc2b34ae6e4c4b44d04d5514b0ec"}, - {file = "dbus_fast-2.21.1-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:4591e0962c272d42d305ab3fb8889f13d47255e412fd3b9839620836662c91fe"}, - {file = "dbus_fast-2.21.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:52641305461660c8969c6bb12364206a108c5c9e014c9220c70b99c4f48b6750"}, - {file = "dbus_fast-2.21.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:237db4ab0b90e5284ea7659264630d693273cdbda323a40368f320869bf6470f"}, - {file = "dbus_fast-2.21.1-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:999fed45cb391126107b804be0e344e75556fceaee4cc30a0ca06d77309bdf3c"}, - {file = "dbus_fast-2.21.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2309b9cafba799e9d343fdfdd5ae46276adf3929fef60f296f23b97ed1aa2f6"}, - {file = "dbus_fast-2.21.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b7d1f35218549762e52a782c0b548e0681332beee773d3dfffe2efc38b2ee960"}, - {file = "dbus_fast-2.21.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:47aa28520fe274414b655c74cbe2e91d8b76e22f40cd41a758bb6975e526827b"}, - {file = "dbus_fast-2.21.1-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:0ff6c72bcd6539d798015bda33c7ce35c7de76276b9bd45e48db13672713521a"}, - {file = "dbus_fast-2.21.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36d8cd43b3799e766158f1bb0b27cc4eef685fd892417b0382b7fdfdd94f1e6c"}, - {file = "dbus_fast-2.21.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d4da8d58064f0a3dd07bfc283ba912b9d5a4cb38f1c0fcd9ecb2b9d43111243c"}, - {file = "dbus_fast-2.21.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:66e160f496ac79248feb09a0acf4aab5d139d823330cbd9377f6e19ae007330a"}, - {file = "dbus_fast-2.21.1-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:670b5c4d78c9c2d25e7ba650d212d98bf24d40292f91fe4e2f3ad4f80dc6d7e5"}, - {file = "dbus_fast-2.21.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15d62adfab7c6f4a491085f53f9634d24745ca5a2772549945b7e2de27c0d534"}, - {file = "dbus_fast-2.21.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:54e8771e31ee1deb01feef2475c12123cab770c371ecc97af98eb6ca10a2858e"}, - {file = "dbus_fast-2.21.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2db4d0d60a891a8b20a4c6de68a088efe73b29ab4a5949fe6aad2713c131e174"}, - {file = "dbus_fast-2.21.1-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:65e76b20099c33352d5e7734a219982858873cf66fe510951d9bd27cb690190f"}, - {file = "dbus_fast-2.21.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:927f294b1dc7cea9372ef8c7c46ebeb5c7e6c1c7345358f952e7499bdbdf7eb4"}, - {file = "dbus_fast-2.21.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9e9a43ea42b8a9f2c62ca50ce05582de7b4f1f7eb27091f904578c29124af246"}, - {file = "dbus_fast-2.21.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:78c84ecf19459571784fd6a8ad8b3e9006cf96c3282e8220bc49098866ef4cc7"}, - {file = "dbus_fast-2.21.1-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:a5b3895ea12c4e636dfaacf75fa5bd1e8450b2ffb97507520991eaf1989d102e"}, - {file = "dbus_fast-2.21.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85be33bb04e918833ac6f28f68f83a1e83425eb6e08b9c482cc3318820dfd55f"}, - {file = "dbus_fast-2.21.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:13ab6a0f64d345cb42c489239962261f724bd441458bef245b39828ed94ea6f4"}, - {file = "dbus_fast-2.21.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c585e7a94bb723a70b4966677b882be8bda324cc41bd129765e3ceab428889bb"}, - {file = "dbus_fast-2.21.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:62331ee3871f6881f517ca65ae185fb2462a0bf2fe78acc4a4d621fc4da08396"}, - {file = "dbus_fast-2.21.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbfd6892fa092cbd6f52edcb24797af62fba8baa50995db856b0a342184c850d"}, - {file = "dbus_fast-2.21.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:a999e35628988ad4f81af36192cd592b8fd1e72e1bbc76a64d80808e6f4b9540"}, - {file = "dbus_fast-2.21.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9cae9a6b9bb54f3f89424fdd960b60ac53239b9e5d4a5d9a598d222fbf8d3173"}, - {file = "dbus_fast-2.21.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:39a3f3662391b49553bf9d9d2e9a6cb31e0d7d337557ee0c0be5c558a3c7d230"}, - {file = "dbus_fast-2.21.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffc2b6beb212d0d231816dcb7bd8bcdafccd04750ba8f5e915f40ad312f5adf2"}, - {file = "dbus_fast-2.21.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:c938eb7130067ca3b74b248ee376228776d8f013a206ae78e6fc644c9db0f4f5"}, - {file = "dbus_fast-2.21.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fae9609d972f0c2b72017796a8140b8a6fb842426f0aed4f43f0fa7d780a16f"}, - {file = "dbus_fast-2.21.1.tar.gz", hash = "sha256:87b852d2005f1d59399ca51c5f3538f28a4742d739d7abe82b7ae8d01d8a5d02"}, + {file = "dbus_fast-2.21.2-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:b5f79edcb0dd48e98b1a1e3e4a655fd0ecc2ba72275f9e8379e8655b4411edcc"}, + {file = "dbus_fast-2.21.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40aa9068759bbf7e062f074c965b391b95f18f897cc9be6eb906ee48a6f77724"}, + {file = "dbus_fast-2.21.2-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:d2406b838ccbda9bd49dda4a7620ce228da306cd8f9a3f8c9f42b2d792a491fb"}, + {file = "dbus_fast-2.21.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ed431895630135da9cec736326304f0833ac31919043efdbecf8f6c7bed40d05"}, + {file = "dbus_fast-2.21.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:90f09498ac91f0e6ddc7fa569e851a2b258a70917cd07ae8412ad5725ef1d411"}, + {file = "dbus_fast-2.21.2-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:b17f1eafeaa825e8933a5394157db9e0a24e65eac188a244dbbbc01dc23fde7a"}, + {file = "dbus_fast-2.21.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9f4191f7108f9433e5c017915e60ec57231aaf58c82fde6e20bd497998ebc97"}, + {file = "dbus_fast-2.21.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3b96a645cbd035f47f3b934130cd0ae977c043480ad7fe9838f78fdcb480c189"}, + {file = "dbus_fast-2.21.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bc696304ce0f5da374ddfb3e83273e9d89602a8f20e7fab57b079378f2cb5789"}, + {file = "dbus_fast-2.21.2-cp312-cp312-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:b5e2015a385f0b364eff1827b151313429d3148d2718d679bec8a9c67b78721a"}, + {file = "dbus_fast-2.21.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32efcbe276a4fdf6946450c512355e7ae22836cf3595d48c59330687cda52117"}, + {file = "dbus_fast-2.21.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:601c3c8796e7edd23bce0432e44ca8f0b85c48a17ab5258f57cd8fe815f9c07a"}, + {file = "dbus_fast-2.21.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:194899057b8382c1902c32e1a565a2d47bcc99e06aafe9d660348394532a4bf6"}, + {file = "dbus_fast-2.21.2-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:81ac390d4e26711b3ac46b3dd81a29bcbc1eddd4a408b336c67f0c94eb6d7ff0"}, + {file = "dbus_fast-2.21.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f056f2bfee24e87a4184202d3b108a56176344303bb1278988f13f5e90777da"}, + {file = "dbus_fast-2.21.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9ba884d102e069e105f22986fccf1d21776e6ced11f4b75aeddcc37e728a80fd"}, + {file = "dbus_fast-2.21.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:60d989030403cc1611105bec6a90df22967e523ae28486dee5f9bd644e37f797"}, + {file = "dbus_fast-2.21.2-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:aabe539f0e9961a1beb6e8c0078112a1a60de18958335678edb3f26021951ff9"}, + {file = "dbus_fast-2.21.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6edec4f92d32b9a288b38457a114086a0d5f5fdec9c3e9b7ff6052fd45963c1d"}, + {file = "dbus_fast-2.21.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:37e6f717dedc299fc15ab8f5ec5b180725d2b896ba1aaef07c1921df0b7113a0"}, + {file = "dbus_fast-2.21.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eade5ed18327bf306b75e525ded98c08921e1b21d42e715b7f0a1371a7669168"}, + {file = "dbus_fast-2.21.2-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:2fd1be6967a92957f517dbd3755ee7cddc128ec840af2ef4ad6fb023a0dac74d"}, + {file = "dbus_fast-2.21.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5db0737471e60228c1a6aabecbf883c972f0b9e50bf7fc0878a8b35ebdf1d1e"}, + {file = "dbus_fast-2.21.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6c6f1fda6f318061a023d6da96ee50ad2d30c04557012a60a0f1abd39c2a8704"}, + {file = "dbus_fast-2.21.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0b78f2116fb745a7623c8e18d9c435bfe4732e4f9284a923c4b9a44ef68ae2d4"}, + {file = "dbus_fast-2.21.2-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:886ce5750d4e64636bd933f22513e9ba06b7ee9650f28699c553c162b52db666"}, + {file = "dbus_fast-2.21.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3159f1cecd4b86f565c01da787ad6eaa57e8ba210d355836fa849e4c0b1ee57"}, + {file = "dbus_fast-2.21.2-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:51279b69ac6b872208f3aa1b00b910dd9ef9c3d625b79eb378405dbd72a29cab"}, + {file = "dbus_fast-2.21.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29f07ef89e35b93afa87dea86abec2aff68802572944485250f50def15dc5ef8"}, + {file = "dbus_fast-2.21.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:38138fc5a24797cc443c6894d25497271ccf3399c8aa8cdba228a7bdda2d2921"}, + {file = "dbus_fast-2.21.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afde99d085a330e8aed59535d808636f1f563cb08d12900d0e415508e6270a1d"}, + {file = "dbus_fast-2.21.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:c2bb0fd813bf3cafc6796d86d42cc8a9d37c2633d973dd963c3ad4c080d7061d"}, + {file = "dbus_fast-2.21.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:044eec5d0668d3229480094f5b2aefafb336afa6976d686bd0cd8770eee1bb2c"}, + {file = "dbus_fast-2.21.2.tar.gz", hash = "sha256:8645187b2e86c5141217adcb462d6dbecd37fb2ab8705f66b3773a66206ef83d"}, ] [[package]] @@ -362,11 +362,9 @@ files = [ [package.extras] all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] graphite = ["lz4 (>=1.7.4.2)"] interpolatable = ["munkres", "pycairo", "scipy"] lxml = ["lxml (>=4.0)"] -lxml = ["lxml (>=4.0)"] pathops = ["skia-pathops (>=0.5.0)"] plot = ["matplotlib"] repacker = ["uharfbuzz (>=0.23.0)"] @@ -465,29 +463,23 @@ files = [ [[package]] name = "idna" version = "3.7" -version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = true python-versions = ">=3.5" files = [ {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] name = "importlib-resources" version = "6.4.0" -version = "6.4.0" description = "Read resources from Python packages" optional = true python-versions = ">=3.8" files = [ {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, - {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, - {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, ] [package.dependencies] @@ -496,7 +488,6 @@ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] -testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] [[package]] name = "kiwisolver" @@ -614,7 +605,6 @@ files = [ [[package]] name = "matplotlib" version = "3.8.4" -version = "3.8.4" description = "Python plotting package" optional = true python-versions = ">=3.9" @@ -647,34 +637,6 @@ files = [ {file = "matplotlib-3.8.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0e47eda4eb2614300fc7bb4657fced3e83d6334d03da2173b09e447418d499f"}, {file = "matplotlib-3.8.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:493e9f6aa5819156b58fce42b296ea31969f2aab71c5b680b4ea7a3cb5c07d94"}, {file = "matplotlib-3.8.4.tar.gz", hash = "sha256:8aac397d5e9ec158960e31c381c5ffc52ddd52bd9a47717e2a694038167dffea"}, - {file = "matplotlib-3.8.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:abc9d838f93583650c35eca41cfcec65b2e7cb50fd486da6f0c49b5e1ed23014"}, - {file = "matplotlib-3.8.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f65c9f002d281a6e904976007b2d46a1ee2bcea3a68a8c12dda24709ddc9106"}, - {file = "matplotlib-3.8.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce1edd9f5383b504dbc26eeea404ed0a00656c526638129028b758fd43fc5f10"}, - {file = "matplotlib-3.8.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecd79298550cba13a43c340581a3ec9c707bd895a6a061a78fa2524660482fc0"}, - {file = "matplotlib-3.8.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:90df07db7b599fe7035d2f74ab7e438b656528c68ba6bb59b7dc46af39ee48ef"}, - {file = "matplotlib-3.8.4-cp310-cp310-win_amd64.whl", hash = "sha256:ac24233e8f2939ac4fd2919eed1e9c0871eac8057666070e94cbf0b33dd9c338"}, - {file = "matplotlib-3.8.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:72f9322712e4562e792b2961971891b9fbbb0e525011e09ea0d1f416c4645661"}, - {file = "matplotlib-3.8.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:232ce322bfd020a434caaffbd9a95333f7c2491e59cfc014041d95e38ab90d1c"}, - {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6addbd5b488aedb7f9bc19f91cd87ea476206f45d7116fcfe3d31416702a82fa"}, - {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc4ccdc64e3039fc303defd119658148f2349239871db72cd74e2eeaa9b80b71"}, - {file = "matplotlib-3.8.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b7a2a253d3b36d90c8993b4620183b55665a429da8357a4f621e78cd48b2b30b"}, - {file = "matplotlib-3.8.4-cp311-cp311-win_amd64.whl", hash = "sha256:8080d5081a86e690d7688ffa542532e87f224c38a6ed71f8fbed34dd1d9fedae"}, - {file = "matplotlib-3.8.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6485ac1f2e84676cff22e693eaa4fbed50ef5dc37173ce1f023daef4687df616"}, - {file = "matplotlib-3.8.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c89ee9314ef48c72fe92ce55c4e95f2f39d70208f9f1d9db4e64079420d8d732"}, - {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50bac6e4d77e4262c4340d7a985c30912054745ec99756ce213bfbc3cb3808eb"}, - {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f51c4c869d4b60d769f7b4406eec39596648d9d70246428745a681c327a8ad30"}, - {file = "matplotlib-3.8.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b12ba985837e4899b762b81f5b2845bd1a28f4fdd1a126d9ace64e9c4eb2fb25"}, - {file = "matplotlib-3.8.4-cp312-cp312-win_amd64.whl", hash = "sha256:7a6769f58ce51791b4cb8b4d7642489df347697cd3e23d88266aaaee93b41d9a"}, - {file = "matplotlib-3.8.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:843cbde2f0946dadd8c5c11c6d91847abd18ec76859dc319362a0964493f0ba6"}, - {file = "matplotlib-3.8.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c13f041a7178f9780fb61cc3a2b10423d5e125480e4be51beaf62b172413b67"}, - {file = "matplotlib-3.8.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb44f53af0a62dc80bba4443d9b27f2fde6acfdac281d95bc872dc148a6509cc"}, - {file = "matplotlib-3.8.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:606e3b90897554c989b1e38a258c626d46c873523de432b1462f295db13de6f9"}, - {file = "matplotlib-3.8.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9bb0189011785ea794ee827b68777db3ca3f93f3e339ea4d920315a0e5a78d54"}, - {file = "matplotlib-3.8.4-cp39-cp39-win_amd64.whl", hash = "sha256:6209e5c9aaccc056e63b547a8152661324404dd92340a6e479b3a7f24b42a5d0"}, - {file = "matplotlib-3.8.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c7064120a59ce6f64103c9cefba8ffe6fba87f2c61d67c401186423c9a20fd35"}, - {file = "matplotlib-3.8.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0e47eda4eb2614300fc7bb4657fced3e83d6334d03da2173b09e447418d499f"}, - {file = "matplotlib-3.8.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:493e9f6aa5819156b58fce42b296ea31969f2aab71c5b680b4ea7a3cb5c07d94"}, - {file = "matplotlib-3.8.4.tar.gz", hash = "sha256:8aac397d5e9ec158960e31c381c5ffc52ddd52bd9a47717e2a694038167dffea"}, ] [package.dependencies] @@ -684,7 +646,6 @@ fonttools = ">=4.22.0" importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} kiwisolver = ">=1.3.1" numpy = ">=1.21" -numpy = ">=1.21" packaging = ">=20.0" pillow = ">=8" pyparsing = ">=2.3.1" @@ -693,7 +654,6 @@ python-dateutil = ">=2.7" [[package]] name = "multidict" version = "6.0.5" -version = "6.0.5" description = "multidict implementation" optional = true python-versions = ">=3.7" @@ -788,102 +748,11 @@ files = [ {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, - {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, - {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, - {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, - {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, - {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, - {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, - {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, - {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, - {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, - {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, - {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, - {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, - {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, - {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, - {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, ] [[package]] name = "mypy" version = "1.10.0" -version = "1.10.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" @@ -915,33 +784,6 @@ files = [ {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"}, {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, - {file = "mypy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2"}, - {file = "mypy-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99"}, - {file = "mypy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2"}, - {file = "mypy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9"}, - {file = "mypy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051"}, - {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, - {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, - {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, - {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, - {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, - {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, - {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, - {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, - {file = "mypy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9fd50226364cd2737351c79807775136b0abe084433b55b2e29181a4c3c878c0"}, - {file = "mypy-1.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f90cff89eea89273727d8783fef5d4a934be2fdca11b47def50cf5d311aff727"}, - {file = "mypy-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcfc70599efde5c67862a07a1aaf50e55bce629ace26bb19dc17cece5dd31ca4"}, - {file = "mypy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:075cbf81f3e134eadaf247de187bd604748171d6b79736fa9b6c9685b4083061"}, - {file = "mypy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:3f298531bca95ff615b6e9f2fc0333aae27fa48052903a0ac90215021cdcfa4f"}, - {file = "mypy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976"}, - {file = "mypy-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec"}, - {file = "mypy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821"}, - {file = "mypy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746"}, - {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"}, - {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, - {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, ] [package.dependencies] @@ -969,7 +811,6 @@ files = [ [[package]] name = "numpy" version = "1.26.4" -version = "1.26.4" description = "Fundamental package for array computing in Python" optional = true python-versions = ">=3.9" @@ -1010,62 +851,22 @@ files = [ {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, - {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, - {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, - {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, - {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, - {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, - {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, - {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, - {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, - {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, - {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, - {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, - {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, - {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, - {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, - {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, - {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, - {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] name = "packaging" version = "24.0" -version = "24.0" description = "Core utilities for Python packages" optional = true python-versions = ">=3.7" files = [ {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, ] [[package]] name = "pillow" version = "10.3.0" -version = "10.3.0" description = "Python Imaging Library (Fork)" optional = true python-versions = ">=3.8" @@ -1139,75 +940,6 @@ files = [ {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"}, {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"}, {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, - {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"}, - {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"}, - {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"}, - {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"}, - {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"}, - {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"}, - {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"}, - {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"}, - {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"}, - {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"}, - {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"}, - {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"}, - {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"}, - {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"}, - {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"}, - {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"}, - {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"}, - {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"}, - {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"}, - {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"}, - {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"}, - {file = "pillow-10.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b"}, - {file = "pillow-10.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd"}, - {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d"}, - {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3"}, - {file = "pillow-10.3.0-cp38-cp38-win32.whl", hash = "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b"}, - {file = "pillow-10.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999"}, - {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"}, - {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"}, - {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"}, - {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"}, - {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"}, - {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"}, - {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"}, - {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, ] [package.extras] @@ -1307,15 +1039,12 @@ pyobjc-framework-Cocoa = ">=10.2" [[package]] name = "pyparsing" version = "3.1.2" -version = "3.1.2" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = true python-versions = ">=3.6.8" files = [ {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, - {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, - {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, ] [package.extras] @@ -1324,15 +1053,12 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "python-dateutil" version = "2.9.0.post0" -version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, - {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, - {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -1375,7 +1101,6 @@ files = [ {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -1413,7 +1138,6 @@ files = [ [[package]] name = "ruff" version = "0.1.15" -version = "0.1.15" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" @@ -1435,23 +1159,6 @@ files = [ {file = "ruff-0.1.15-py3-none-win_amd64.whl", hash = "sha256:3837ac73d869efc4182d9036b1405ef4c73d9b1f88da2413875e34e0d6919587"}, {file = "ruff-0.1.15-py3-none-win_arm64.whl", hash = "sha256:9a933dfb1c14ec7a33cceb1e49ec4a16b51ce3c20fd42663198746efc0427360"}, {file = "ruff-0.1.15.tar.gz", hash = "sha256:f6dfa8c1b21c913c326919056c390966648b680966febcb796cc9d1aaab8564e"}, - {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5fe8d54df166ecc24106db7dd6a68d44852d14eb0729ea4672bb4d96c320b7df"}, - {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6f0bfbb53c4b4de117ac4d6ddfd33aa5fc31beeaa21d23c45c6dd249faf9126f"}, - {file = "ruff-0.1.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0d432aec35bfc0d800d4f70eba26e23a352386be3a6cf157083d18f6f5881c8"}, - {file = "ruff-0.1.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9405fa9ac0e97f35aaddf185a1be194a589424b8713e3b97b762336ec79ff807"}, - {file = "ruff-0.1.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66ec24fe36841636e814b8f90f572a8c0cb0e54d8b5c2d0e300d28a0d7bffec"}, - {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6f8ad828f01e8dd32cc58bc28375150171d198491fc901f6f98d2a39ba8e3ff5"}, - {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86811954eec63e9ea162af0ffa9f8d09088bab51b7438e8b6488b9401863c25e"}, - {file = "ruff-0.1.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd4025ac5e87d9b80e1f300207eb2fd099ff8200fa2320d7dc066a3f4622dc6b"}, - {file = "ruff-0.1.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b17b93c02cdb6aeb696effecea1095ac93f3884a49a554a9afa76bb125c114c1"}, - {file = "ruff-0.1.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ddb87643be40f034e97e97f5bc2ef7ce39de20e34608f3f829db727a93fb82c5"}, - {file = "ruff-0.1.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:abf4822129ed3a5ce54383d5f0e964e7fef74a41e48eb1dfad404151efc130a2"}, - {file = "ruff-0.1.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6c629cf64bacfd136c07c78ac10a54578ec9d1bd2a9d395efbee0935868bf852"}, - {file = "ruff-0.1.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1bab866aafb53da39c2cadfb8e1c4550ac5340bb40300083eb8967ba25481447"}, - {file = "ruff-0.1.15-py3-none-win32.whl", hash = "sha256:2417e1cb6e2068389b07e6fa74c306b2810fe3ee3476d5b8a96616633f40d14f"}, - {file = "ruff-0.1.15-py3-none-win_amd64.whl", hash = "sha256:3837ac73d869efc4182d9036b1405ef4c73d9b1f88da2413875e34e0d6919587"}, - {file = "ruff-0.1.15-py3-none-win_arm64.whl", hash = "sha256:9a933dfb1c14ec7a33cceb1e49ec4a16b51ce3c20fd42663198746efc0427360"}, - {file = "ruff-0.1.15.tar.gz", hash = "sha256:f6dfa8c1b21c913c326919056c390966648b680966febcb796cc9d1aaab8564e"}, ] [[package]] @@ -1479,7 +1186,6 @@ files = [ [[package]] name = "typing-extensions" version = "4.11.0" -version = "4.11.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" @@ -1812,22 +1518,17 @@ multidict = ">=4.0" [[package]] name = "zipp" version = "3.18.1" -version = "3.18.1" description = "Backport of pathlib-compatible object wrapper for zip files" optional = true python-versions = ">=3.8" files = [ {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, - {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, - {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [extras] examples = ["aiohttp", "matplotlib", "numpy", "prometheus-client", "pyyaml"] diff --git a/radiacode-examples/basic.py b/radiacode-examples/basic.py index f536d81..8ffa169 100644 --- a/radiacode-examples/basic.py +++ b/radiacode-examples/basic.py @@ -1,6 +1,5 @@ import argparse import time -import platform from radiacode import RadiaCode from radiacode.transports.usb import DeviceNotFound as DeviceNotFoundUSB diff --git a/radiacode-examples/webserver.py b/radiacode-examples/webserver.py index a12ebbf..faa2b2d 100644 --- a/radiacode-examples/webserver.py +++ b/radiacode-examples/webserver.py @@ -4,14 +4,11 @@ import pathlib from aiohttp import web - from radiacode import RadiaCode, RealTimeData - async def handle_index(request): return web.FileResponse(pathlib.Path(__file__).parent.absolute() / 'webserver.html') - async def handle_ws(request): ws = web.WebSocketResponse() await ws.prepare(request) diff --git a/radiacode/transports/bluetooth.py b/radiacode/transports/bluetooth.py index 5d925b5..7b9d355 100644 --- a/radiacode/transports/bluetooth.py +++ b/radiacode/transports/bluetooth.py @@ -153,6 +153,6 @@ async def execute(self, req) -> BytesBuffer: # await self.client.stop_notify(notif) - br = BytesBuffer(self._response) - self._response = None - return br + br = BytesBuffer(self._response) + self._response = None + return br From e5fccc52f7ba9d550249f40774c6dc12b471af52 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Sun, 12 May 2024 13:59:51 +0800 Subject: [PATCH 14/20] Fixed a wrong function that was calling itself rather than its async-self and added a separate event loop in Bluetooth() to avoid the use of an asyncio.run() --- radiacode/radiacode.py | 3 +-- radiacode/transports/bluetooth.py | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/radiacode/radiacode.py b/radiacode/radiacode.py index fb25036..f94f7fd 100644 --- a/radiacode/radiacode.py +++ b/radiacode/radiacode.py @@ -148,7 +148,7 @@ def status(self) -> str: return self.loop.run_until_complete(self.async_status()) def set_local_time(self, dt: datetime.datetime) -> None: - return self.loop.run_until_complete(self.set_local_time(dt)) + return self.loop.run_until_complete(self.async_set_local_time(dt)) def fw_signature(self) -> str: return self.loop.run_until_complete(self.async_fw_signature()) @@ -167,7 +167,6 @@ def text_message(self) -> str: def serial_number(self) -> str: return self.loop.run_until_complete(self.async_serial_number()) - # return self.loop.run_until_complete(self.async_serial_number()) def commands(self) -> str: return self.loop.run_until_complete(self.async_commands()) diff --git a/radiacode/transports/bluetooth.py b/radiacode/transports/bluetooth.py index 7b9d355..04ea75c 100644 --- a/radiacode/transports/bluetooth.py +++ b/radiacode/transports/bluetooth.py @@ -26,6 +26,8 @@ def __init__( self._resp_size = 0 self._response = None self.client = None + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.loop) # self._response_event = asyncio.Event() self.bluetooth_mac = bluetooth_mac # Only for Windows and Linux @@ -88,7 +90,7 @@ async def connect(self) -> None: Logger.notify('Notifications started') def _scan(self) -> List[Tuple[BLEDevice, AdvertisementData]]: - return asyncio.run(self._async_scan()) + return self.loop.run_until_complete(self._async_scan()) async def _async_scan(self) -> List[Tuple[BLEDevice, AdvertisementData]]: """Returns a list of Tuples of valid Radiacodes""" From 4ecb6197c3d4d722ed13381efcf2b9b0675249ed Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Sun, 12 May 2024 15:27:46 +0800 Subject: [PATCH 15/20] Added simple error display to webserver app and added handling of exceptions in the backend --- radiacode-examples/webserver.html | 316 +++++++++++++++++------------- radiacode-examples/webserver.py | 9 +- radiacode/transports/bluetooth.py | 7 +- 3 files changed, 193 insertions(+), 139 deletions(-) diff --git a/radiacode-examples/webserver.html b/radiacode-examples/webserver.html index 2d64394..8977f08 100644 --- a/radiacode-examples/webserver.html +++ b/radiacode-examples/webserver.html @@ -1,151 +1,197 @@ - + - -RadiaCode demo - - - + + RadiaCode demo + + + + -
-
- -
-
- - -
-
- - - - - -
-
- - - - -
-
-
- - -
-
-
- -
- +
Fetching data from Radiacode, please wait (it might take up to 1 minute over bluetooth)...
+
Error reading data, try restarting the application...
+
+
+ +
+
+ + +
+
+ + + + +
+
+ + + + +
+
+
+ + +
+
+
+ +
+ +
+
-
- diff --git a/radiacode-examples/webserver.py b/radiacode-examples/webserver.py index faa2b2d..0a16ebb 100644 --- a/radiacode-examples/webserver.py +++ b/radiacode-examples/webserver.py @@ -17,6 +17,8 @@ async def handle_ws(request): try: async for _ in ws: pass + except Exception as e: + print(f'Unexpected error in websocket: {str(e)}') finally: request.app['ws_clients'].remove(ws) @@ -26,7 +28,12 @@ async def handle_ws(request): async def handle_spectrum(request): cn = request.app['rc_conn'] accum = request.query.get('accum') == 'true' - spectrum = await (cn.async_spectrum_accum() if accum else cn.async_spectrum()) + + try: + spectrum = await (cn.async_spectrum_accum() if accum else cn.async_spectrum()) + except Exception as e: + print(f'Unexpected error while fetching data: {str(e)}') + return web.json_response({'error': str(e)}, status=500) # apexcharts can't handle 0 in logarithmic view spectrum_data = [(channel, cnt if cnt > 0 else 0.5) for channel, cnt in enumerate(spectrum.counts)] diff --git a/radiacode/transports/bluetooth.py b/radiacode/transports/bluetooth.py index 04ea75c..cd6f324 100644 --- a/radiacode/transports/bluetooth.py +++ b/radiacode/transports/bluetooth.py @@ -137,8 +137,7 @@ def handleNotification(self, characteristic, data) -> None: self._resp_buffer = b'' # self._response_event.set() - - # print(f'{tok} Notification: {characteristic.description}: {self._resp_buffer}') + # Logger.notify(f'Notification: {characteristic.description}: {self._resp_buffer}') async def execute(self, req) -> BytesBuffer: if self.client is None or self.client.is_connected is False: @@ -151,8 +150,10 @@ async def execute(self, req) -> BytesBuffer: self._response = [] await self.client.write_gatt_char(self.writefd, req, response=False) await asyncio.sleep(1.5) - # await self._response_event.wait() + # If we knew how much data to expect from every request, we could monitor + # for that in handleNotification(), rather than sleeping + # await self._response_event.wait() # await self.client.stop_notify(notif) br = BytesBuffer(self._response) From 8b2af550dde01122b3a283ef301368e679842788 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Sun, 12 May 2024 15:28:37 +0800 Subject: [PATCH 16/20] Added an async version of the basic.py script to show how to use the library in both synchronous and asynchronous way --- radiacode-examples/basic_async.py | 87 +++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 radiacode-examples/basic_async.py diff --git a/radiacode-examples/basic_async.py b/radiacode-examples/basic_async.py new file mode 100644 index 0000000..c0e4c70 --- /dev/null +++ b/radiacode-examples/basic_async.py @@ -0,0 +1,87 @@ +import argparse +import time +import asyncio + +from radiacode import RadiaCode +from radiacode.transports.usb import DeviceNotFound as DeviceNotFoundUSB +from radiacode.transports.bluetooth import DeviceNotFound as DeviceNotFoundBT + + +async def main(args: argparse.Namespace): + try: + if args.bluetooth_mac: + print(f'Connecting to Radiacode via Bluetooth (MAC address: {args.bluetooth_mac})') + rc = await RadiaCode.async_init(bluetooth_mac=args.bluetooth_mac) + elif args.bluetooth_uuid: + print(f'Connecting to Radiacode via Bluetooth (UUID: {args.bluetooth_uuid})') + rc = await RadiaCode.async_init(bluetooth_uuid=args.bluetooth_uuid) + elif args.bluetooth_serial: + print(f'Connecting to Radiacode via Bluetooth (Serial: {args.bluetooth_serial})') + rc = await RadiaCode.async_init(bluetooth_serial=args.bluetooth_serial) + elif args.serial: + print(f'Connecting to Radiacode via USB (Serial: {args.serial})') + rc = await RadiaCode.async_init(serial_number=args.serial) + else: + print('Connecting to Radiacode via USB') + rc = await RadiaCode.async_init() + except DeviceNotFoundBT as e: + print(e) + return + except DeviceNotFoundUSB: + print('Radiacode not found, check your USB connection') + return + except ValueError as e: + print(e) + return + except Exception as e: + print(e) + return + + serial = await rc.async_serial_number() + print(f'### Serial number: {serial}') + print('--------') + + fw_version = await rc.async_fw_version() + print(f'### Firmware: {fw_version}') + print('--------') + + spectrum = await rc.async_spectrum() + print(f'### Spectrum: {spectrum}') + print('--------') + + print('### DataBuf:') + while True: + for v in await rc.async_data_buf(): + print(v.dt.isoformat(), v) + time.sleep(2) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + + parser.add_argument( + '--bluetooth-mac', + type=str, + required=False, + help='Radiacode Bluetooth MAC address (e.g. 00:11:22:33:44:55). MacOS does not support BT MACs, use Serial Number or UUID instead.', + ) + parser.add_argument( + '--bluetooth-serial', + type=str, + required=False, + help='Connect via Bluetooth using Radiacode Serial (e.g. "RC-10x-xxxxxx").', + ) + parser.add_argument( + '--bluetooth-uuid', + type=str, + required=False, + help='Connect via Bluetooth using Radiacode UUID (e.g. "11111111-2222-3333-4444-56789ABCDEF").', + ) + parser.add_argument( + '--serial', type=str, required=False, help='Connect via USB using Radiacode Serial (e.g. "RC-10x-xxxxxx").' + ) + parser.add_argument('--usb', type=str, required=False, help='(default) Connect via USB to the first Radiacode available.') + + args = parser.parse_args() + + asyncio.run(main(args)) From 6815f8915b193c47d8476958cb496f36fb312d64 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Sun, 12 May 2024 15:50:23 +0800 Subject: [PATCH 17/20] Reformatted with Ruff --- radiacode-examples/webserver.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/radiacode-examples/webserver.py b/radiacode-examples/webserver.py index 0a16ebb..2930128 100644 --- a/radiacode-examples/webserver.py +++ b/radiacode-examples/webserver.py @@ -6,9 +6,11 @@ from aiohttp import web from radiacode import RadiaCode, RealTimeData + async def handle_index(request): return web.FileResponse(pathlib.Path(__file__).parent.absolute() / 'webserver.html') + async def handle_ws(request): ws = web.WebSocketResponse() await ws.prepare(request) From 4ed0e05e46cdf956343890ace070ae7fefa0dba4 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Tue, 14 May 2024 22:47:46 +0800 Subject: [PATCH 18/20] Fixed a library function that was calling the wrong async version of itself. Added non-destructive integration tests --- radiacode/radiacode.py | 2 +- tests/test_radiacode.py | 96 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 tests/test_radiacode.py diff --git a/radiacode/radiacode.py b/radiacode/radiacode.py index f94f7fd..e1746c9 100644 --- a/radiacode/radiacode.py +++ b/radiacode/radiacode.py @@ -154,7 +154,7 @@ def fw_signature(self) -> str: return self.loop.run_until_complete(self.async_fw_signature()) def fw_version(self) -> tuple[tuple[int, int, str], tuple[int, int, str]]: - return self.loop.run_until_complete(self.async_fw_signature()) + return self.loop.run_until_complete(self.async_fw_version()) def hw_serial_number(self) -> str: return self.loop.run_until_complete(self.async_hw_serial_number()) diff --git a/tests/test_radiacode.py b/tests/test_radiacode.py new file mode 100644 index 0000000..78053dd --- /dev/null +++ b/tests/test_radiacode.py @@ -0,0 +1,96 @@ +import unittest +import datetime +from radiacode.radiacode import RadiaCode +from radiacode.types import CTRL, VS, VSFR, DisplayDirection, DoseRateDB, Event, RareData, RawData, RealTimeData, Spectrum + +class TestRadiaCodeIntegration(unittest.TestCase): + """ + This test class requires a real and available Radiacode + """ + @classmethod + def setUpClass(cls): + # Connect to the device only once + #cls.rc = RadiaCode(bluetooth_serial='RadiaCode-10') + cls.rc = RadiaCode(bluetooth_uuid='C646AE3C-A4A6-AF97-CC85-56BCDABBE730') + + def test_serial_number_integration(self): + serial_number = self.rc.serial_number() + + self.assertIsInstance(serial_number, str) + self.assertIn('RC-10', serial_number) + + def test_fw_version_integration(self): + fw_version = self.rc.fw_version() + + self.assertIsInstance(fw_version, tuple) + self.assertEqual(len(fw_version), 2) + + # tuple[tuple[int, int, str], tuple[int, int, str]]: + for ver in fw_version: + self.assertIsInstance(ver, tuple) + self.assertEqual(len(ver), 3) + self.assertIsInstance(ver[0], int) + self.assertIsInstance(ver[1], int) + self.assertIsInstance(ver[2], str) + + def test_spectrum_integration(self): + spectrum = self.rc.spectrum() + + self.assertIsInstance(spectrum, Spectrum) + self.assertIsInstance(spectrum.duration, datetime.timedelta) + self.assertIsInstance(spectrum.a0, float) + self.assertIsInstance(spectrum.a1, float) + self.assertIsInstance(spectrum.a2, float) + self.assertIsInstance(spectrum.counts, list) + self.assertTrue(all(isinstance(count, int) for count in spectrum.counts)) + + def test_data_buf_integration(self): + data_buf = self.rc.data_buf() + + self.assertIsInstance(data_buf, list) + for item in data_buf: + self.assertTrue(isinstance(item, (DoseRateDB, RareData, RealTimeData, RawData, Event))) + self.assertIsInstance(item.dt, datetime.datetime) + + def test_spectrum_accum_integration(self): + spectrum_accum = self.rc.spectrum_accum() + + self.assertIsInstance(spectrum_accum, Spectrum) + self.assertIsInstance(spectrum_accum.duration, datetime.timedelta) + self.assertIsInstance(spectrum_accum.a0, float) + self.assertIsInstance(spectrum_accum.a1, float) + self.assertIsInstance(spectrum_accum.a2, float) + self.assertIsInstance(spectrum_accum.counts, list) + self.assertTrue(all(isinstance(count, int) for count in spectrum_accum.counts)) + + def test_configuration_integration(self): + configuration = self.rc.configuration() + + self.assertIsInstance(configuration, str) + self.assertIn('DeviceParams', configuration) + self.assertIn('CHN_ChargeLevel', configuration) + + def test_hw_serial_number_integration(self): + hw_serial_number = self.rc.hw_serial_number() + + # Format is: XXXXXXXX-XXXXXXXX-XXXXXXXX (hex) + self.assertIsInstance(hw_serial_number, str) + self.assertIn('-', hw_serial_number) + + def test_status_integration(self): + status = self.rc.status() + + self.assertIsInstance(status, str) + self.assertIn('flags: ', status) + + def test_commands_integration(self): + # Act + commands = self.rc.commands() + + # Assert + self.assertIsInstance(commands, str) + self.assertIn('VSFR_DEVICE_CTRL', commands) + self.assertIn('VSFR_SYS_MCU_TEMP', commands) + +if __name__ == '__main__': + unittest.main() From e5bdec5d829f644e1ac8391a64dca344ad96a6e2 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Tue, 14 May 2024 22:49:45 +0800 Subject: [PATCH 19/20] Removed unused imports --- tests/test_radiacode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_radiacode.py b/tests/test_radiacode.py index 78053dd..06d289f 100644 --- a/tests/test_radiacode.py +++ b/tests/test_radiacode.py @@ -1,7 +1,7 @@ import unittest import datetime from radiacode.radiacode import RadiaCode -from radiacode.types import CTRL, VS, VSFR, DisplayDirection, DoseRateDB, Event, RareData, RawData, RealTimeData, Spectrum +from radiacode.types import DoseRateDB, Event, RareData, RawData, RealTimeData, Spectrum class TestRadiaCodeIntegration(unittest.TestCase): """ From be227fff38c0ab2a2a0eb06eba714ecabd001af1 Mon Sep 17 00:00:00 2001 From: RamonBeast Date: Tue, 14 May 2024 22:52:58 +0800 Subject: [PATCH 20/20] Defaulted tests to USB rathern than Bluetooth --- tests/test_radiacode.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/test_radiacode.py b/tests/test_radiacode.py index 06d289f..b698edc 100644 --- a/tests/test_radiacode.py +++ b/tests/test_radiacode.py @@ -10,8 +10,7 @@ class TestRadiaCodeIntegration(unittest.TestCase): @classmethod def setUpClass(cls): # Connect to the device only once - #cls.rc = RadiaCode(bluetooth_serial='RadiaCode-10') - cls.rc = RadiaCode(bluetooth_uuid='C646AE3C-A4A6-AF97-CC85-56BCDABBE730') + cls.rc = RadiaCode(bluetooth_serial='RadiaCode-10') def test_serial_number_integration(self): serial_number = self.rc.serial_number() @@ -84,10 +83,8 @@ def test_status_integration(self): self.assertIn('flags: ', status) def test_commands_integration(self): - # Act commands = self.rc.commands() - - # Assert + self.assertIsInstance(commands, str) self.assertIn('VSFR_DEVICE_CTRL', commands) self.assertIn('VSFR_SYS_MCU_TEMP', commands)