From 9a8f9af3fb69d519e3c87d0a957dbe14ae376aba Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Wed, 28 Aug 2024 18:14:51 -0700 Subject: [PATCH 01/31] add api pickers --- poetry.lock | 899 ++++++++++++++++++- pyproject.toml | 1 + src/faebryk/libs/picker/api/api.py | 115 +++ src/faebryk/libs/picker/api/picker_lib.py | 289 ++++++ src/faebryk/libs/picker/api/pickers.py | 85 ++ src/faebryk/libs/picker/jlcpcb/jlcpcb.py | 48 +- src/faebryk/libs/picker/jlcpcb/picker_lib.py | 376 ++++---- src/faebryk/libs/picker/util.py | 36 + test/libs/picker/test_api.py | 388 ++++++++ 9 files changed, 2024 insertions(+), 213 deletions(-) create mode 100644 src/faebryk/libs/picker/api/api.py create mode 100644 src/faebryk/libs/picker/api/picker_lib.py create mode 100644 src/faebryk/libs/picker/api/pickers.py create mode 100644 src/faebryk/libs/picker/util.py create mode 100644 test/libs/picker/test_api.py diff --git a/poetry.lock b/poetry.lock index e21497d4..0c874c9f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,140 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "aiohappyeyeballs" +version = "2.4.3" +description = "Happy Eyeballs for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiohappyeyeballs-2.4.3-py3-none-any.whl", hash = "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572"}, + {file = "aiohappyeyeballs-2.4.3.tar.gz", hash = "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586"}, +] + +[[package]] +name = "aiohttp" +version = "3.10.10" +description = "Async http client/server framework (asyncio)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiohttp-3.10.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:be7443669ae9c016b71f402e43208e13ddf00912f47f623ee5994e12fc7d4b3f"}, + {file = "aiohttp-3.10.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7b06b7843929e41a94ea09eb1ce3927865387e3e23ebe108e0d0d09b08d25be9"}, + {file = "aiohttp-3.10.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:333cf6cf8e65f6a1e06e9eb3e643a0c515bb850d470902274239fea02033e9a8"}, + {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:274cfa632350225ce3fdeb318c23b4a10ec25c0e2c880eff951a3842cf358ac1"}, + {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9e5e4a85bdb56d224f412d9c98ae4cbd032cc4f3161818f692cd81766eee65a"}, + {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b606353da03edcc71130b52388d25f9a30a126e04caef1fd637e31683033abd"}, + {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab5a5a0c7a7991d90446a198689c0535be89bbd6b410a1f9a66688f0880ec026"}, + {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:578a4b875af3e0daaf1ac6fa983d93e0bbfec3ead753b6d6f33d467100cdc67b"}, + {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8105fd8a890df77b76dd3054cddf01a879fc13e8af576805d667e0fa0224c35d"}, + {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3bcd391d083f636c06a68715e69467963d1f9600f85ef556ea82e9ef25f043f7"}, + {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fbc6264158392bad9df19537e872d476f7c57adf718944cc1e4495cbabf38e2a"}, + {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e48d5021a84d341bcaf95c8460b152cfbad770d28e5fe14a768988c461b821bc"}, + {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2609e9ab08474702cc67b7702dbb8a80e392c54613ebe80db7e8dbdb79837c68"}, + {file = "aiohttp-3.10.10-cp310-cp310-win32.whl", hash = "sha256:84afcdea18eda514c25bc68b9af2a2b1adea7c08899175a51fe7c4fb6d551257"}, + {file = "aiohttp-3.10.10-cp310-cp310-win_amd64.whl", hash = "sha256:9c72109213eb9d3874f7ac8c0c5fa90e072d678e117d9061c06e30c85b4cf0e6"}, + {file = "aiohttp-3.10.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f"}, + {file = "aiohttp-3.10.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb"}, + {file = "aiohttp-3.10.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871"}, + {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c"}, + {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38"}, + {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb"}, + {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7"}, + {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911"}, + {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092"}, + {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142"}, + {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9"}, + {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1"}, + {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a"}, + {file = "aiohttp-3.10.10-cp311-cp311-win32.whl", hash = "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94"}, + {file = "aiohttp-3.10.10-cp311-cp311-win_amd64.whl", hash = "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959"}, + {file = "aiohttp-3.10.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c"}, + {file = "aiohttp-3.10.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28"}, + {file = "aiohttp-3.10.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f"}, + {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138"}, + {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742"}, + {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7"}, + {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16"}, + {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8"}, + {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6"}, + {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a"}, + {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9"}, + {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a"}, + {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205"}, + {file = "aiohttp-3.10.10-cp312-cp312-win32.whl", hash = "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628"}, + {file = "aiohttp-3.10.10-cp312-cp312-win_amd64.whl", hash = "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf"}, + {file = "aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28"}, + {file = "aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d"}, + {file = "aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79"}, + {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e"}, + {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6"}, + {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42"}, + {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e"}, + {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc"}, + {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a"}, + {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414"}, + {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3"}, + {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67"}, + {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b"}, + {file = "aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8"}, + {file = "aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151"}, + {file = "aiohttp-3.10.10-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1b66ccafef7336a1e1f0e389901f60c1d920102315a56df85e49552308fc0486"}, + {file = "aiohttp-3.10.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:acd48d5b80ee80f9432a165c0ac8cbf9253eaddb6113269a5e18699b33958dbb"}, + {file = "aiohttp-3.10.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3455522392fb15ff549d92fbf4b73b559d5e43dc522588f7eb3e54c3f38beee7"}, + {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45c3b868724137f713a38376fef8120c166d1eadd50da1855c112fe97954aed8"}, + {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:da1dee8948d2137bb51fbb8a53cce6b1bcc86003c6b42565f008438b806cccd8"}, + {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5ce2ce7c997e1971b7184ee37deb6ea9922ef5163c6ee5aa3c274b05f9e12fa"}, + {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28529e08fde6f12eba8677f5a8608500ed33c086f974de68cc65ab218713a59d"}, + {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7db54c7914cc99d901d93a34704833568d86c20925b2762f9fa779f9cd2e70f"}, + {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:03a42ac7895406220124c88911ebee31ba8b2d24c98507f4a8bf826b2937c7f2"}, + {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:7e338c0523d024fad378b376a79faff37fafb3c001872a618cde1d322400a572"}, + {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:038f514fe39e235e9fef6717fbf944057bfa24f9b3db9ee551a7ecf584b5b480"}, + {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:64f6c17757251e2b8d885d728b6433d9d970573586a78b78ba8929b0f41d045a"}, + {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:93429602396f3383a797a2a70e5f1de5df8e35535d7806c9f91df06f297e109b"}, + {file = "aiohttp-3.10.10-cp38-cp38-win32.whl", hash = "sha256:c823bc3971c44ab93e611ab1a46b1eafeae474c0c844aff4b7474287b75fe49c"}, + {file = "aiohttp-3.10.10-cp38-cp38-win_amd64.whl", hash = "sha256:54ca74df1be3c7ca1cf7f4c971c79c2daf48d9aa65dea1a662ae18926f5bc8ce"}, + {file = "aiohttp-3.10.10-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:01948b1d570f83ee7bbf5a60ea2375a89dfb09fd419170e7f5af029510033d24"}, + {file = "aiohttp-3.10.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9fc1500fd2a952c5c8e3b29aaf7e3cc6e27e9cfc0a8819b3bce48cc1b849e4cc"}, + {file = "aiohttp-3.10.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f614ab0c76397661b90b6851a030004dac502e48260ea10f2441abd2207fbcc7"}, + {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00819de9e45d42584bed046314c40ea7e9aea95411b38971082cad449392b08c"}, + {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05646ebe6b94cc93407b3bf34b9eb26c20722384d068eb7339de802154d61bc5"}, + {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:998f3bd3cfc95e9424a6acd7840cbdd39e45bc09ef87533c006f94ac47296090"}, + {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9010c31cd6fa59438da4e58a7f19e4753f7f264300cd152e7f90d4602449762"}, + {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ea7ffc6d6d6f8a11e6f40091a1040995cdff02cfc9ba4c2f30a516cb2633554"}, + {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ef9c33cc5cbca35808f6c74be11eb7f5f6b14d2311be84a15b594bd3e58b5527"}, + {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ce0cdc074d540265bfeb31336e678b4e37316849d13b308607efa527e981f5c2"}, + {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:597a079284b7ee65ee102bc3a6ea226a37d2b96d0418cc9047490f231dc09fe8"}, + {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:7789050d9e5d0c309c706953e5e8876e38662d57d45f936902e176d19f1c58ab"}, + {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e7f8b04d83483577fd9200461b057c9f14ced334dcb053090cea1da9c8321a91"}, + {file = "aiohttp-3.10.10-cp39-cp39-win32.whl", hash = "sha256:c02a30b904282777d872266b87b20ed8cc0d1501855e27f831320f471d54d983"}, + {file = "aiohttp-3.10.10-cp39-cp39-win_amd64.whl", hash = "sha256:edfe3341033a6b53a5c522c802deb2079eee5cbfbb0af032a55064bd65c73a23"}, + {file = "aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a"}, +] + +[package.dependencies] +aiohappyeyeballs = ">=2.3.0" +aiosignal = ">=1.1.2" +attrs = ">=17.3.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +yarl = ">=1.12.0,<2.0" + +[package.extras] +speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] + +[[package]] +name = "aiosignal" +version = "1.3.1" +description = "aiosignal: a list of registered asynchronous callbacks" +optional = false +python-versions = ">=3.7" +files = [ + {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, + {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, +] + +[package.dependencies] +frozenlist = ">=1.1.0" [[package]] name = "aiosqlite" @@ -25,6 +161,26 @@ files = [ {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, ] +[[package]] +name = "anyio" +version = "4.6.2.post1" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.9" +files = [ + {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, + {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, +] + +[package.dependencies] +idna = ">=2.8" +sniffio = ">=1.1" + +[package.extras] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] +trio = ["trio (>=0.26.1)"] + [[package]] name = "appdirs" version = "1.4.4" @@ -36,6 +192,25 @@ files = [ {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] +[[package]] +name = "attrs" +version = "24.2.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, +] + +[package.extras] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] + [[package]] name = "black" version = "24.8.0" @@ -357,6 +532,20 @@ wrapt = ">=1.10,<2" [package.extras] dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] +[[package]] +name = "deprecation" +version = "2.1.0" +description = "A library to handle automated deprecations" +optional = false +python-versions = "*" +files = [ + {file = "deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a"}, + {file = "deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff"}, +] + +[package.dependencies] +packaging = "*" + [[package]] name = "distlib" version = "0.3.8" @@ -531,6 +720,107 @@ files = [ {file = "freetype_py-2.5.1-py3-none-win_amd64.whl", hash = "sha256:0b7f8e0342779f65ca13ef8bc103938366fecade23e6bb37cb671c2b8ad7f124"}, ] +[[package]] +name = "frozenlist" +version = "1.4.1" +description = "A list-like structure which implements collections.abc.MutableSequence" +optional = false +python-versions = ">=3.8" +files = [ + {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, + {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, + {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"}, + {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"}, + {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, + {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, + {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, + {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, + {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"}, + {file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"}, + {file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"}, + {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"}, + {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"}, + {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, + {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, +] + +[[package]] +name = "gotrue" +version = "2.9.2" +description = "Python Client Library for Supabase Auth" +optional = false +python-versions = "<4.0,>=3.8" +files = [ + {file = "gotrue-2.9.2-py3-none-any.whl", hash = "sha256:fcd5279e8f1cc630f3ac35af5485fe39f8030b23906776920d2c32a4e308cff4"}, + {file = "gotrue-2.9.2.tar.gz", hash = "sha256:57b3245e916c5efbf19a21b1181011a903c1276bb1df2d847558f2f24f29abb2"}, +] + +[package.dependencies] +httpx = {version = ">=0.26,<0.28", extras = ["http2"]} +pydantic = ">=1.10,<3" + [[package]] name = "gprof2dot" version = "2024.6.6" @@ -542,6 +832,101 @@ files = [ {file = "gprof2dot-2024.6.6.tar.gz", hash = "sha256:fa1420c60025a9eb7734f65225b4da02a10fc6dd741b37fa129bc6b41951e5ab"}, ] +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "h2" +version = "4.1.0" +description = "HTTP/2 State-Machine based protocol implementation" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, + {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"}, +] + +[package.dependencies] +hpack = ">=4.0,<5" +hyperframe = ">=6.0,<7" + +[[package]] +name = "hpack" +version = "4.0.0" +description = "Pure-Python HPACK header compression" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, + {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, +] + +[[package]] +name = "httpcore" +version = "1.0.6" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f"}, + {file = "httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.13,<0.15" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] + +[[package]] +name = "httpx" +version = "0.27.2" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"}, + {file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +h2 = {version = ">=3,<5", optional = true, markers = "extra == \"http2\""} +httpcore = "==1.*" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "hyperframe" +version = "6.0.1" +description = "HTTP/2 framing layer for Python" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, + {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, +] + [[package]] name = "identify" version = "2.6.1" @@ -872,6 +1257,107 @@ files = [ {file = "more_itertools-10.5.0-py3-none-any.whl", hash = "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef"}, ] +[[package]] +name = "multidict" +version = "6.1.0" +description = "multidict implementation" +optional = false +python-versions = ">=3.8" +files = [ + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, + {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, + {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, + {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, + {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, + {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, + {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, + {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, + {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, + {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, + {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, + {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, + {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, + {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, + {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, +] + [[package]] name = "mypy-extensions" version = "1.0.0" @@ -1175,6 +1661,23 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "postgrest" +version = "0.17.1" +description = "PostgREST client for Python. This library provides an ORM interface to PostgREST." +optional = false +python-versions = "<4.0,>=3.8" +files = [ + {file = "postgrest-0.17.1-py3-none-any.whl", hash = "sha256:ec1d00dc8532fe5ffb342cfc7c4e610a1e0e2272eb14f78f9b2b61094f9be510"}, + {file = "postgrest-0.17.1.tar.gz", hash = "sha256:e31d9977dbb80dc5f9fdd4d444014686606692dc4ddb9adc85639e56c6d54c92"}, +] + +[package.dependencies] +deprecation = ">=2.1.0,<3.0.0" +httpx = {version = ">=0.26,<0.28", extras = ["http2"]} +pydantic = ">=1.9,<3.0" +strenum = ">=0.4.9,<0.5.0" + [[package]] name = "pre-commit" version = "3.8.0" @@ -1193,6 +1696,113 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" +[[package]] +name = "propcache" +version = "0.2.0" +description = "Accelerated property cache" +optional = false +python-versions = ">=3.8" +files = [ + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336"}, + {file = "propcache-0.2.0-cp310-cp310-win32.whl", hash = "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad"}, + {file = "propcache-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b"}, + {file = "propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1"}, + {file = "propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348"}, + {file = "propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5"}, + {file = "propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544"}, + {file = "propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032"}, + {file = "propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed"}, + {file = "propcache-0.2.0-cp38-cp38-win32.whl", hash = "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d"}, + {file = "propcache-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798"}, + {file = "propcache-0.2.0-cp39-cp39-win32.whl", hash = "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9"}, + {file = "propcache-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df"}, + {file = "propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036"}, + {file = "propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70"}, +] + [[package]] name = "psutil" version = "6.0.0" @@ -1586,6 +2196,23 @@ files = [ {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] +[[package]] +name = "realtime" +version = "2.0.5" +description = "" +optional = false +python-versions = "<4.0,>=3.9" +files = [ + {file = "realtime-2.0.5-py3-none-any.whl", hash = "sha256:f9ec2d762794709e37a8e2745c8dfd86eac4870678808f09676c8f2b7bfa6bbc"}, + {file = "realtime-2.0.5.tar.gz", hash = "sha256:133828fbc2cc2325fb015fe071c6da9fb488819cac96d85ed297045c715b35f5"}, +] + +[package.dependencies] +aiohttp = ">=3.10.6,<4.0.0" +python-dateutil = ">=2.8.1,<3.0.0" +typing-extensions = ">=4.12.2,<5.0.0" +websockets = ">=11,<14" + [[package]] name = "requests" version = "2.32.3" @@ -1785,6 +2412,83 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + +[[package]] +name = "storage3" +version = "0.8.1" +description = "Supabase Storage client for Python." +optional = false +python-versions = "<4.0,>=3.8" +files = [ + {file = "storage3-0.8.1-py3-none-any.whl", hash = "sha256:0b21205f43eaf0d1dd33bde6c6d0612f88524b7865f017d2ae9827e3f63d9cdc"}, + {file = "storage3-0.8.1.tar.gz", hash = "sha256:ea60b68b2221b3868ccc1a7f1294d57d0d9c51642cdc639d8115fe5d0adc8892"}, +] + +[package.dependencies] +httpx = {version = ">=0.26,<0.28", extras = ["http2"]} +python-dateutil = ">=2.8.2,<3.0.0" +typing-extensions = ">=4.2.0,<5.0.0" + +[[package]] +name = "strenum" +version = "0.4.15" +description = "An Enum that inherits from str." +optional = false +python-versions = "*" +files = [ + {file = "StrEnum-0.4.15-py3-none-any.whl", hash = "sha256:a30cda4af7cc6b5bf52c8055bc4bf4b2b6b14a93b574626da33df53cf7740659"}, + {file = "StrEnum-0.4.15.tar.gz", hash = "sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff"}, +] + +[package.extras] +docs = ["myst-parser[linkify]", "sphinx", "sphinx-rtd-theme"] +release = ["twine"] +test = ["pylint", "pytest", "pytest-black", "pytest-cov", "pytest-pylint"] + +[[package]] +name = "supabase" +version = "2.9.0" +description = "Supabase client for Python." +optional = false +python-versions = "<4.0,>=3.9" +files = [ + {file = "supabase-2.9.0-py3-none-any.whl", hash = "sha256:04b794dd737f7b50a8de4fcba0507983e27c9eea29577eb0af7fe06e9fe69757"}, + {file = "supabase-2.9.0.tar.gz", hash = "sha256:d94c0ee491fe0d137387bd860071fee97cb01f32a1c1485266804783b14c1c32"}, +] + +[package.dependencies] +gotrue = ">=2.7.0,<3.0.0" +httpx = ">=0.26,<0.28" +postgrest = ">=0.17.0,<0.18.0" +realtime = ">=2.0.0,<3.0.0" +storage3 = ">=0.8.0,<0.9.0" +supafunc = ">=0.6.0,<0.7.0" +typing-extensions = ">=4.12.2,<5.0.0" + +[[package]] +name = "supafunc" +version = "0.6.1" +description = "Library for Supabase Functions" +optional = false +python-versions = "<4.0,>=3.8" +files = [ + {file = "supafunc-0.6.1-py3-none-any.whl", hash = "sha256:01aeeeb4bf429977664454a32c86418345140faf6d2e6eb0636d52e4547c5fbb"}, + {file = "supafunc-0.6.1.tar.gz", hash = "sha256:3c8761e3999336ccdb7550498a395fd08afc8469382f55ea56f7f640e5a909aa"}, +] + +[package.dependencies] +httpx = {version = ">=0.26,<0.28", extras = ["http2"]} + [[package]] name = "tortoise-orm" version = "0.21.6" @@ -1940,6 +2644,101 @@ objprint = ">0.1.3" [package.extras] full = ["orjson"] +[[package]] +name = "websockets" +version = "13.1" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"}, + {file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"}, + {file = "websockets-13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6"}, + {file = "websockets-13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b"}, + {file = "websockets-13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa"}, + {file = "websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700"}, + {file = "websockets-13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c"}, + {file = "websockets-13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0"}, + {file = "websockets-13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f"}, + {file = "websockets-13.1-cp310-cp310-win32.whl", hash = "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe"}, + {file = "websockets-13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a"}, + {file = "websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19"}, + {file = "websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5"}, + {file = "websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd"}, + {file = "websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02"}, + {file = "websockets-13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7"}, + {file = "websockets-13.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096"}, + {file = "websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084"}, + {file = "websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3"}, + {file = "websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9"}, + {file = "websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f"}, + {file = "websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557"}, + {file = "websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc"}, + {file = "websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49"}, + {file = "websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd"}, + {file = "websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0"}, + {file = "websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6"}, + {file = "websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9"}, + {file = "websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68"}, + {file = "websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14"}, + {file = "websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf"}, + {file = "websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c"}, + {file = "websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3"}, + {file = "websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6"}, + {file = "websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708"}, + {file = "websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418"}, + {file = "websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a"}, + {file = "websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f"}, + {file = "websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5"}, + {file = "websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135"}, + {file = "websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2"}, + {file = "websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6"}, + {file = "websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d"}, + {file = "websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2"}, + {file = "websockets-13.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c7934fd0e920e70468e676fe7f1b7261c1efa0d6c037c6722278ca0228ad9d0d"}, + {file = "websockets-13.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:149e622dc48c10ccc3d2760e5f36753db9cacf3ad7bc7bbbfd7d9c819e286f23"}, + {file = "websockets-13.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a569eb1b05d72f9bce2ebd28a1ce2054311b66677fcd46cf36204ad23acead8c"}, + {file = "websockets-13.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95df24ca1e1bd93bbca51d94dd049a984609687cb2fb08a7f2c56ac84e9816ea"}, + {file = "websockets-13.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8dbb1bf0c0a4ae8b40bdc9be7f644e2f3fb4e8a9aca7145bfa510d4a374eeb7"}, + {file = "websockets-13.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:035233b7531fb92a76beefcbf479504db8c72eb3bff41da55aecce3a0f729e54"}, + {file = "websockets-13.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e4450fc83a3df53dec45922b576e91e94f5578d06436871dce3a6be38e40f5db"}, + {file = "websockets-13.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:463e1c6ec853202dd3657f156123d6b4dad0c546ea2e2e38be2b3f7c5b8e7295"}, + {file = "websockets-13.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6d6855bbe70119872c05107e38fbc7f96b1d8cb047d95c2c50869a46c65a8e96"}, + {file = "websockets-13.1-cp38-cp38-win32.whl", hash = "sha256:204e5107f43095012b00f1451374693267adbb832d29966a01ecc4ce1db26faf"}, + {file = "websockets-13.1-cp38-cp38-win_amd64.whl", hash = "sha256:485307243237328c022bc908b90e4457d0daa8b5cf4b3723fd3c4a8012fce4c6"}, + {file = "websockets-13.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9b37c184f8b976f0c0a231a5f3d6efe10807d41ccbe4488df8c74174805eea7d"}, + {file = "websockets-13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:163e7277e1a0bd9fb3c8842a71661ad19c6aa7bb3d6678dc7f89b17fbcc4aeb7"}, + {file = "websockets-13.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b889dbd1342820cc210ba44307cf75ae5f2f96226c0038094455a96e64fb07a"}, + {file = "websockets-13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:586a356928692c1fed0eca68b4d1c2cbbd1ca2acf2ac7e7ebd3b9052582deefa"}, + {file = "websockets-13.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7bd6abf1e070a6b72bfeb71049d6ad286852e285f146682bf30d0296f5fbadfa"}, + {file = "websockets-13.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2aad13a200e5934f5a6767492fb07151e1de1d6079c003ab31e1823733ae79"}, + {file = "websockets-13.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:df01aea34b6e9e33572c35cd16bae5a47785e7d5c8cb2b54b2acdb9678315a17"}, + {file = "websockets-13.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e54affdeb21026329fb0744ad187cf812f7d3c2aa702a5edb562b325191fcab6"}, + {file = "websockets-13.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9ef8aa8bdbac47f4968a5d66462a2a0935d044bf35c0e5a8af152d58516dbeb5"}, + {file = "websockets-13.1-cp39-cp39-win32.whl", hash = "sha256:deeb929efe52bed518f6eb2ddc00cc496366a14c726005726ad62c2dd9017a3c"}, + {file = "websockets-13.1-cp39-cp39-win_amd64.whl", hash = "sha256:7c65ffa900e7cc958cd088b9a9157a8141c991f8c53d11087e6fb7277a03f81d"}, + {file = "websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238"}, + {file = "websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5"}, + {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9"}, + {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6"}, + {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a"}, + {file = "websockets-13.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23"}, + {file = "websockets-13.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9156c45750b37337f7b0b00e6248991a047be4aa44554c9886fe6bdd605aab3b"}, + {file = "websockets-13.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80c421e07973a89fbdd93e6f2003c17d20b69010458d3a8e37fb47874bd67d51"}, + {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82d0ba76371769d6a4e56f7e83bb8e81846d17a6190971e38b5de108bde9b0d7"}, + {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9875a0143f07d74dc5e1ded1c4581f0d9f7ab86c78994e2ed9e95050073c94d"}, + {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11e38ad8922c7961447f35c7b17bffa15de4d17c70abd07bfbe12d6faa3e027"}, + {file = "websockets-13.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4059f790b6ae8768471cddb65d3c4fe4792b0ab48e154c9f0a04cefaabcd5978"}, + {file = "websockets-13.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25c35bf84bf7c7369d247f0b8cfa157f989862c49104c5cf85cb5436a641d93e"}, + {file = "websockets-13.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:83f91d8a9bb404b8c2c41a707ac7f7f75b9442a0a876df295de27251a856ad09"}, + {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a43cfdcddd07f4ca2b1afb459824dd3c6d53a51410636a2c7fc97b9a8cf4842"}, + {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a2ef1381632a2f0cb4efeff34efa97901c9fbc118e01951ad7cfc10601a9bb"}, + {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459bf774c754c35dbb487360b12c5727adab887f1622b8aed5755880a21c4a20"}, + {file = "websockets-13.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:95858ca14a9f6fa8413d29e0a585b31b278388aa775b8a81fa24830123874678"}, + {file = "websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f"}, + {file = "websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878"}, +] + [[package]] name = "wrapt" version = "1.16.0" @@ -2019,7 +2818,103 @@ files = [ {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, ] +[[package]] +name = "yarl" +version = "1.15.4" +description = "Yet another URL library" +optional = false +python-versions = ">=3.9" +files = [ + {file = "yarl-1.15.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:551205388d1da18a9975302c9a274ba24788f53bb9bb86187496ebf9e938916e"}, + {file = "yarl-1.15.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eee724176b5bc50ee64905f559345448119b860a30b9489bd7a073f61baf925f"}, + {file = "yarl-1.15.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db818e33599f7b2e4c6507f2b2c24f45ff539a1b6e4e09163bb6f3cfb4616ca7"}, + {file = "yarl-1.15.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07019a9de859c5a29916defd1e8c7557de6491a10bf50c49ff5284e6aedf5313"}, + {file = "yarl-1.15.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db64a20e78969fc66665d2e5fc96cb4f4dc80f2137d8fed4b5a650ad569bb60f"}, + {file = "yarl-1.15.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4076bfd8f1621449b19b9826848ed51bf0f2d1d38e82647c312c0730d8778903"}, + {file = "yarl-1.15.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c23a442973dba3646811c284fce3dddd7fe5c2bd674ac73a122198e8218d6115"}, + {file = "yarl-1.15.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2bdb038b3f5c284e3919218c580dedc95f592c417a358361450b9519b22f7a8"}, + {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:59db8e6888d5302b8dbca0c1026ddabe99d81d67cdc101941519e13ffc9050fe"}, + {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f3294ce265011547630a59c20085fcb6af8cc5fa1fa44a203251f7d86cd5d913"}, + {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4851618679ca70b863ba2e7109be5f09f8fd7715ec505bd42e5a947dcfde3a45"}, + {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:dce1c56beef74d9c799a6ed94001693232a1402138292353a8ce302b64f457d9"}, + {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1e7468f31de61a82817f918743e5229fce774f73fad58487cdf88eef4f06d864"}, + {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:527c68f48a91d953691291d3bce0209293aa5ad13ff05286ddb506791c331818"}, + {file = "yarl-1.15.4-cp310-cp310-win32.whl", hash = "sha256:c30115cecaf25fdcb67cc71c669d08425207f62d7a2f6d5416057c1460529216"}, + {file = "yarl-1.15.4-cp310-cp310-win_amd64.whl", hash = "sha256:df09c80f4bc2bc2efde309af383c3fe8fd8c51fe0519edb350b9c9e0af43ffa4"}, + {file = "yarl-1.15.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:76259901cf1ac3db65e7e6dff04775b626d0715f9b51d92b447351144c756a82"}, + {file = "yarl-1.15.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:98d8dc1e8133f86d916125deca9780d791b22645f0d62bafe1452d1cd5eac631"}, + {file = "yarl-1.15.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0d0f16c87c62b7a94b389ddf6a8c9d081265d788875c39f3a80108c4856eea7b"}, + {file = "yarl-1.15.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8de5328d91859b461899497980d4cc8269e84e2d18640f6ac643886fda9000bf"}, + {file = "yarl-1.15.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84937d00e2ea03616c40977de20189fa13a9213e5744a3c6afa0e7dd9141d69c"}, + {file = "yarl-1.15.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:691a3b498fdebef63308e8967bb598cfd326c56d628da82b799dd181bace4503"}, + {file = "yarl-1.15.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a706db0c3b7e4578ff34ed2b1d2507b08fd491346ffc64468786fdf1151d938"}, + {file = "yarl-1.15.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:adb6b5d07d17c32f9d34c9dd4a693637a72323cfcb1f8a52d57033ab2dd21e99"}, + {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e100c6c7d9e9d469009fd55cc4d7ad168d67d40758865c50da713f7ada491e5"}, + {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:df6b254e55c8ac2362afaa651e3e53453aa19a095570792346245773b434176e"}, + {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8721f8bedaa722c3c483cc06a1399cbfdb280eadf443aa5d324b0203cef2a75f"}, + {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1005921b30f4f39bf893946df6173567ff650307babb5ec04bbf64342a1f62c1"}, + {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ab79cc13307065a0b3ef087f09f0509996fc605d35d6642bb28e5d85b2648e1e"}, + {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f337486742c700b102d640830aab3faf2848bed966b479a39e6783edd4ab1c6c"}, + {file = "yarl-1.15.4-cp311-cp311-win32.whl", hash = "sha256:20acf84bd1ce530065f8e957e4a5878fda4bc5f18cb02659828210e1519de54e"}, + {file = "yarl-1.15.4-cp311-cp311-win_amd64.whl", hash = "sha256:ab9ccf26cb3fa32747ba2a637a189d2d42386a2fc4afc10dbc7f85922dd23b0f"}, + {file = "yarl-1.15.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f923e94e93a37fd990e8336e0b9bedea533e7cbed14e0c572bf9357ef2a70681"}, + {file = "yarl-1.15.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3198da7d7c34e29fc8c823e0c3ce6c7274aac35760de557c2017489c7d98fc5a"}, + {file = "yarl-1.15.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d886de2ea81f513ba2d6820451d33b767a97c37867ba688d42e164b2dbca1362"}, + {file = "yarl-1.15.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ac85e760543129a1912a82438fc8075223e35eaa2d457d61cd83c27d00d17be"}, + {file = "yarl-1.15.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e58c5d07b1f78dd4cb180c5b3b82465cd281aaeee8aafea0e5d72a4b97922cb1"}, + {file = "yarl-1.15.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9060589d0acad1fca048861fa9ee3e8ed060f67894fa885969648ab6e9e99a54"}, + {file = "yarl-1.15.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccd6774aa7bebdf9ca608bb0839318757a71b8e0d2cf7b10c002bc8790bd343e"}, + {file = "yarl-1.15.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7694f109867ee428c21b85ae19fd31d164c691eb45cc95c561cfdeba237a12e3"}, + {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:83e7154aa0d17f5c93d27ac01088fd9ab6673e7bab1acbd07cd7a865b980c045"}, + {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f16d1940c0cbc342f1d29d6212a006d172be616d2942c5c41966e8a3ce4c3be1"}, + {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7d5226c70af3ad9569ccc4ccc04ab65be79eeb22c87d7ae789c89e62ef76bbd6"}, + {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f25906e4a72d9833e81717c39a39dee7297ff5cb44957d06d177a2ab8ef2ef7f"}, + {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e07e4b17b648c880e8e42bf1ac0a730bde114961646ae1c2ec4433f0c11ca94"}, + {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f8136bde8dfa4477c6a85c79a366581b4a505b51a52b669318fb631d3f4f638"}, + {file = "yarl-1.15.4-cp312-cp312-win32.whl", hash = "sha256:ccbeaf5b18b173b9d78e332e017b30ba8bedcf03cdce1d13490b82a3f421bc98"}, + {file = "yarl-1.15.4-cp312-cp312-win_amd64.whl", hash = "sha256:f74f6ffdc633aefecbc80282242a5395058db9d1247fa7dd2f070ef84dc82583"}, + {file = "yarl-1.15.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:4f66a0eda48844508736e47ed476d8fdd7cdbf16a4053b5d439509a25f708504"}, + {file = "yarl-1.15.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fd2bb86f40962d53a91def15a2f7684c62e081a7b96ec74ed0259c34b15973b9"}, + {file = "yarl-1.15.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f864b412557e69a6b953d62c01a0ed0ee342666298aa7f2a29af526bfa80f6e9"}, + {file = "yarl-1.15.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a79c0a8bbb046add85663af85e9993b691bf20c2a109518bd35e0ce77edfe42"}, + {file = "yarl-1.15.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de479e30abd2dfd49fdad3bd6953f2d930a45380be5143c0c9f7a1215cffc8cc"}, + {file = "yarl-1.15.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21fabe58042f3e567b4edc75b2cf44cea02f228e41ac09d73de126bf685fe883"}, + {file = "yarl-1.15.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77390496f2f32437a721c854897f889abefae0f3009daf90a2f703508d96c920"}, + {file = "yarl-1.15.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3896bf15284dd23acab1f2e7fceb350d8da6f6f2436b922f7ec6b3de685d34ca"}, + {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:590e2d733a82ecf004c5c531cbef0d6be328e93adec960024eb213f10cb9503e"}, + {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:1ceb677fb583971351627eac70eec6763fbc889761828da7a276681b5e39742d"}, + {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:69f628d2da1489b27959f4d63fdb326781fe484944dce94abbf919e416c54abe"}, + {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:35a6b69cc44bda002705d6138346bf0a0234cbb7c26c3bf192513eb946aee6f9"}, + {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:49f886e8dcf591275c6e20915b516fd81647857566b0c0158c52df1e468849c9"}, + {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:49190eb2ece70313742b0ea51520340288a059674da1f39eefb589d598d9453e"}, + {file = "yarl-1.15.4-cp313-cp313-win32.whl", hash = "sha256:48334a6c8afee93097eb17c0a094234dac2d88da076c8cf372e09e2a5dcc4b66"}, + {file = "yarl-1.15.4-cp313-cp313-win_amd64.whl", hash = "sha256:f68025d6ba1816428b7de615c80f61cb03d5b7061158d4ced7696657a64aa59c"}, + {file = "yarl-1.15.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8b569f4f511b59518ba6719feb5b8bf0a5d4115e6ac903c89e10a8a9ac656017"}, + {file = "yarl-1.15.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9fe17744d60fc404ac61f824118e1e15ce3c2e92eced9b8e22f3c7847acafbf2"}, + {file = "yarl-1.15.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:115346433fad2084ee3a1a925ccc0659990aa42e208ca54c278830a150a3caf3"}, + {file = "yarl-1.15.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60165b8bc260f453321004b193770a66cc1b1a5c57c07d4b8dcc96839e7ad578"}, + {file = "yarl-1.15.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65a0168691373e08d869d48b62c8bed0af0cdaef19c76e11ad73b43901bbdb5a"}, + {file = "yarl-1.15.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:787532f00543a21b8f4ec3050b4e01b8fe437797903c0156a0b03dfca5e1ba6c"}, + {file = "yarl-1.15.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f51c9d173e5fa4b12d06ddca09a41cabbdeb660471dbe55432423eec095709ab"}, + {file = "yarl-1.15.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c96eaa30030e1cfafe533f3da8983812281235b7c50ef2a6c78ceca7aea1a0b"}, + {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4feab2dcb725eb5b4835207ecf3d370ff7ce930b253cba5e681646cb80d64c2c"}, + {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:de38b0b5b86e57efb129d179854e78b65cb8e294a8c75560877869c43aa2415a"}, + {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:65e0467f90f2acf3bc83bbfeedece8f1fd84df8add1a54e9600ed7b7b5debdb0"}, + {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:40c18f96696549e73b92dc12619f07019cbf5faefc1612608f967c144816e493"}, + {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:46491b3e058de7b484e1c9fb20aa8441f06d6c9a18395d711c1c2a9ad6707d6a"}, + {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:faa3dd7f4620ab5e5da7a0789d0aac78a9ad0376f102409d442ec5a4179e200a"}, + {file = "yarl-1.15.4-cp39-cp39-win32.whl", hash = "sha256:c33ea7c55a73be343f02361795caf52a187357ea07708fb1cae6661ee1d689c8"}, + {file = "yarl-1.15.4-cp39-cp39-win_amd64.whl", hash = "sha256:11b207061f28b4b6d980239b22ab0ecfadc47846b5a3b8e79f27fcc019d02cf9"}, + {file = "yarl-1.15.4-py3-none-any.whl", hash = "sha256:e5cc288111c450c0a54a74475591b206d3b1cb47dc71bb6200f6be8b1337184c"}, + {file = "yarl-1.15.4.tar.gz", hash = "sha256:a0c5e271058d148d730219ca4f33c5d841c6bd46e05b0da60fea7b516906ccd3"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" +propcache = ">=0.2.0" + [metadata] lock-version = "2.0" python-versions = "^3.12,<3.13" -content-hash = "86c6b9a700cf392c5c6fbafcc24f293dc8c5a913a8aaab1c01d3957e197784eb" +content-hash = "b41054ca397c02b759979adb8ef11ec38b0fa2e2c0d0d2bc043f02b93c0eddba" diff --git a/pyproject.toml b/pyproject.toml index 8e053b6c..c21d6d35 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ pint = "^0.24.3" deprecated = "^1.2.14" more-itertools = "^10.4.0" psutil = "^6.0.0" +supabase = "^2.9.0" [tool.poetry.group.dev.dependencies] pre-commit = ">=2.20,<4.0" diff --git a/src/faebryk/libs/picker/api/api.py b/src/faebryk/libs/picker/api/api.py new file mode 100644 index 00000000..40b20481 --- /dev/null +++ b/src/faebryk/libs/picker/api/api.py @@ -0,0 +1,115 @@ +import logging +import os +import textwrap +from dataclasses import dataclass + +from supabase import Client, create_client +from supabase.client import ClientOptions + +import faebryk.library._F as F +from faebryk.core.core import Module + +# TODO: replace with API-specific data model +from faebryk.libs.picker.jlcpcb.jlcpcb import Component, MappingParameterDB +from faebryk.libs.picker.lcsc import LCSC_NoDataException, LCSC_PinmapException +from faebryk.libs.picker.picker import PickError + +logger = logging.getLogger(__name__) + + +class ApiError(Exception): ... + + +def get_footprint_candidates(module: Module) -> list[dict] | None: + if module.has_trait(F.has_footprint_requirement): + return [ + {"footprint": footprint, "pin_count": pin_count} + for footprint, pin_count in module.get_trait( + F.has_footprint_requirement + ).get_footprint_requirement() + ] + return None + + +def check_compatible_parameters( + module: Module, component: Component, mapping: list[MappingParameterDB] +) -> bool: + """ + Check if the parameters of a component are compatible with the module + """ + # TODO: serialize the module and check compatibility in the backend + + params = component.get_params(mapping) + param_matches = [ + p.is_subset_of(getattr(module.PARAMs, m.param_name)) + for p, m in zip(params, mapping) + ] + + if not (is_compatible := all(param_matches)): + logger.debug( + f"Component {component.lcsc} doesn't match: " + f"{[p for p, v in zip(params, param_matches) if not v]}" + ) + + return is_compatible + + +def try_attach( + cmp: Module, parts: list[Component], mapping: list[MappingParameterDB], qty: int +) -> bool: + failures = [] + for part in parts: + if not check_compatible_parameters(cmp, part, mapping): + continue + + try: + part.attach(cmp, mapping, qty, allow_TBD=False) + return True + except (ValueError, Component.ParseError) as e: + failures.append((part, e)) + except LCSC_NoDataException as e: + failures.append((part, e)) + except LCSC_PinmapException as e: + failures.append((part, e)) + + if failures: + fail_str = textwrap.indent( + "\n" + f"{'\n'.join(f'{c}: {e}' for c, e in failures)}", " " * 4 + ) + + raise PickError( + f"Failed to attach any components to module {cmp}: {len(failures)}" + f" {fail_str}", + cmp, + ) + + +class ApiClient: + @dataclass + class Config: + # TODO: add defaults + enable: str = os.getenv("FBRK_PICKER", "").lower() == "api" + api_url: str = os.getenv("FBRK_API_URL") + api_key: str = os.getenv("FBRK_API_KEY") + + config = Config() + _client: Client | None = None + + def __init__(self): + if self.config.enable: + if self.config.api_url and self.config.api_key: + self._client = create_client( + self.config.api_url, + self.config.api_key, + options=ClientOptions( + postgrest_client_timeout=10, + storage_client_timeout=10, + schema="public", + ), + ) + else: + raise ApiError("API URL and API key must be set") + + def fetch_parts(self, method: str, params: dict) -> list[Component]: + response = self._client.rpc(method, params).execute() + return [Component(**part) for part in response.data] diff --git a/src/faebryk/libs/picker/api/picker_lib.py b/src/faebryk/libs/picker/api/picker_lib.py new file mode 100644 index 00000000..6994d105 --- /dev/null +++ b/src/faebryk/libs/picker/api/picker_lib.py @@ -0,0 +1,289 @@ +import logging +import re +from typing import Type + +import faebryk.library._F as F +from faebryk.core.core import Module +from faebryk.libs.e_series import E_SERIES_VALUES +from faebryk.libs.picker.api.api import ( + ApiClient, + check_compatible_parameters, + get_footprint_candidates, + try_attach, +) + +# re-use the existing model for components from the jlcparts dataset, but as the data +# schema diverges over time we'll migrate this to separate models +from faebryk.libs.picker.jlcpcb.jlcpcb import Component +from faebryk.libs.picker.jlcpcb.picker_lib import _MAPPINGS_BY_TYPE +from faebryk.libs.picker.picker import DescriptiveProperties, PickError +from faebryk.libs.picker.util import generate_si_values + +logger = logging.getLogger(__name__) +client = ApiClient() + + +# TODO add trait to module that specifies the quantity of the part +qty: int = 1 + + +def find_lcsc_part(module: Module): + """ + Find a part by LCSC part number + """ + if not module.has_trait(F.has_descriptive_properties): + raise PickError("Module does not have any descriptive properties", module) + if "LCSC" not in module.get_trait(F.has_descriptive_properties).get_properties(): + raise PickError("Module does not have an LCSC part number", module) + + def get_lcsc_pn(module: Module) -> int: + pn = module.get_trait(F.has_descriptive_properties).get_properties()["LCSC"] + match = re.match(r"C(\d+)", pn) + if match is None: + raise PickError(f"Invalid LCSC part number {pn}", module) + return int(match[1]) + + lcsc_pn = get_lcsc_pn(module) + parts = client.fetch_parts("find_by_lcsc", {"lcsc": lcsc_pn}) + + # TODO: pass through errors from API + match parts: + case []: + raise PickError( + f"Could not find part with LCSC part number {lcsc_pn}", module + ) + case [part]: + if part.stock < qty: + raise PickError( + f"Part with LCSC part number {lcsc_pn} has insufficient stock", + module, + ) + part.attach(module, []) + case _: + raise PickError( + f"Found no exact match for LCSC part number {lcsc_pn}", module + ) + + +def find_manufacturer_part(module: Module): + """ + Find a part by manufacturer and manufacturer part number + """ + if not module.has_trait(F.has_descriptive_properties): + raise PickError("Module does not have any descriptive properties", module) + + properties = module.get_trait(F.has_descriptive_properties).get_properties() + + if DescriptiveProperties.manufacturer not in properties: + raise PickError("Module does not have a manufacturer", module) + + if DescriptiveProperties.partno not in properties: + raise PickError("Module does not have a manufacturer part number", module) + + manufacturer = properties[DescriptiveProperties.manufacturer] + partno = properties[DescriptiveProperties.partno] + + parts = client.fetch_parts( + "find_by_manufacturer_part", + {"manufacturer_name": manufacturer, "mfr": partno, "qty": qty}, + ) + + if not parts: + raise PickError( + f"Could not find part with manufacturer part number {partno}", module + ) + + for part in parts: + try: + part.attach(module, []) + return + except ValueError as e: + logger.warning(f"Failed to attach component: {e}") + continue + + return PickError( + f"Could not attach any part with manufacturer part number {partno}", module + ) + + +def _filter_by_module_params_and_attach( + cmp: Module, component_type: Type[Module], parts: list[Component] +): + """ + Find a component with matching parameters + """ + mapping = _MAPPINGS_BY_TYPE[component_type] + parts = [part for part in parts if check_compatible_parameters(cmp, part, mapping)] + + if not try_attach(cmp, parts, mapping, qty): + raise PickError( + "No components found that match the parameters and that can be attached", + cmp, + ) + + +def find_resistor(cmp: Module): + """ + Find a resistor with matching parameters + """ + if not isinstance(cmp, F.Resistor): + raise PickError("Module is not a resistor", cmp) + + parts = client.fetch_parts( + "find_resistors", + { + "resistances": generate_si_values( + cmp.PARAMs.resistance, "Ω", E_SERIES_VALUES.E96 + ), + "footprint_candidates": get_footprint_candidates(cmp), + "qty": qty, + }, + ) + + _filter_by_module_params_and_attach(cmp, F.Resistor, parts) + + +def find_capacitor(cmp: Module): + """ + Find a capacitor with matching parameters + """ + if not isinstance(cmp, F.Capacitor): + raise PickError("Module is not a capacitor", cmp) + + parts = client.fetch_parts( + "find_capacitors", + { + "capacitances": generate_si_values( + cmp.PARAMs.capacitance, "F", E_SERIES_VALUES.E6 + ), + "footprint_candidates": get_footprint_candidates(cmp), + "qty": qty, + }, + ) + + _filter_by_module_params_and_attach(cmp, F.Capacitor, parts) + + +def find_inductor(cmp: Module): + """ + Find an inductor with matching parameters + """ + if not isinstance(cmp, F.Inductor): + raise PickError("Module is not an inductor", cmp) + + parts = client.fetch_parts( + "find_inductors", + { + "inductances": generate_si_values( + cmp.PARAMs.inductance, "H", E_SERIES_VALUES.E24 + ), + "footprint_candidates": get_footprint_candidates(cmp), + "qty": qty, + }, + ) + + _filter_by_module_params_and_attach(cmp, F.Inductor, parts) + + +def find_tvs(cmp: Module): + """ + Find a TVS diode with matching parameters + """ + if not isinstance(cmp, F.TVS): + raise PickError("Module is not a TVS diode", cmp) + + parts = client.fetch_parts( + "find_tvs", + { + "footprint_candidates": get_footprint_candidates(cmp), + "qty": qty, + }, + ) + + _filter_by_module_params_and_attach(cmp, F.TVS, parts) + + +def find_diode(cmp: Module): + """ + Find a diode with matching parameters + """ + if not isinstance(cmp, F.Diode): + raise PickError("Module is not a diode", cmp) + + parts = client.fetch_parts( + "find_diodes", + { + "footprint_candidates": get_footprint_candidates(cmp), + "qty": qty, + }, + ) + + _filter_by_module_params_and_attach(cmp, F.Diode, parts) + + +def find_led(cmp: Module): + """ + Find an LED with matching parameters + """ + if not isinstance(cmp, F.LED): + raise PickError("Module is not an LED", cmp) + + parts = client.fetch_parts( + "find_leds", + { + "footprint_candidates": get_footprint_candidates(cmp), + "qty": qty, + }, + ) + + _filter_by_module_params_and_attach(cmp, F.LED, parts) + + +def find_mosfet(cmp: Module): + """ + Find a MOSFET with matching parameters + """ + + if not isinstance(cmp, F.MOSFET): + raise PickError("Module is not a MOSFET", cmp) + + parts = client.fetch_parts( + "find_mosfets", + { + "footprint_candidates": get_footprint_candidates(cmp), + "qty": qty, + }, + ) + + _filter_by_module_params_and_attach(cmp, F.MOSFET, parts) + + +def find_ldo(cmp: Module): + """ + Find an LDO with matching parameters + """ + + if not isinstance(cmp, F.LDO): + raise PickError("Module is not a LDO", cmp) + + parts = client.fetch_parts( + "find_ldos", + { + "footprint_candidates": get_footprint_candidates(cmp), + "qty": qty, + }, + ) + + _filter_by_module_params_and_attach(cmp, F.LDO, parts) + + +TYPE_SPECIFIC_LOOKUP = { + F.Resistor: find_resistor, + F.Capacitor: find_capacitor, + F.Inductor: find_inductor, + F.TVS: find_tvs, + F.LED: find_led, + F.Diode: find_diode, + F.MOSFET: find_mosfet, + F.LDO: find_ldo, +} diff --git a/src/faebryk/libs/picker/api/pickers.py b/src/faebryk/libs/picker/api/pickers.py new file mode 100644 index 00000000..95b011cd --- /dev/null +++ b/src/faebryk/libs/picker/api/pickers.py @@ -0,0 +1,85 @@ +from typing import Any + +import faebryk.library._F as F +import faebryk.libs.picker.api.picker_lib as P +from faebryk.core.core import Module +from faebryk.libs.picker.picker import PickError + + +class ApiPicker(F.has_multi_picker.FunctionPicker): ... + + +class StaticApiPartPicker(F.has_multi_picker.Picker): + """ + Picks a specific part by ID or manufacturer / part number + """ + + # subject to change as the API evolves + def __init__( + self, + *, + mfr: str | None = None, + mfr_pn: str | None = None, + lcsc_pn: str | None = None, + ) -> None: + super().__init__() + self.mfr = mfr + self.mfr_pn = mfr_pn + self.lcsc_pn = lcsc_pn + + def _friendly_description(self) -> str: + desc = "" + if self.mfr: + desc += f"mfr={self.mfr}" + if self.mfr_pn: + desc += f"mfr_pn={self.mfr_pn}" + if self.lcsc_pn: + desc += f"lcsc_pn={self.lcsc_pn}" + + return desc or "" + + def pick(self, module: Module): + match self.mfr, self.mfr_pn, self.lcsc_pn: + case Any(mfr), Any(mfr_pn), None: + parts = P.find_manufacturer_part(module, mfr, mfr_pn) + case None, None, Any(lcsc_pn): + parts = P.find_lcsc_part(module, lcsc_pn) + case None, None, None: + raise PickError("No parameters provided", module) + + if len(parts) > 1: + raise PickError( + f"Multiple parts found for {self._friendly_description()}", module + ) + + if len(parts) < 1: + raise PickError( + f"Could not find part for {self._friendly_description()}", module + ) + + (part,) = parts + try: + part.attach(module, []) + except ValueError as e: + raise PickError( + f"Could not attach part for {self._friendly_description()}", module + ) from e + + +def add_api_pickers(module: Module, base_prio: int = 0) -> None: + # Generic pickers + F.has_multi_picker.add_to_module( + module, + base_prio, + ApiPicker(P.find_lcsc_part), + ) + F.has_multi_picker.add_to_module( + module, + base_prio, + ApiPicker(P.find_manufacturer_part), + ) + + # Type-specific pickers + F.has_multi_picker.add_pickers_by_type( + module, P.TYPE_SPECIFIC_LOOKUP, ApiPicker, base_prio + 1 + ) diff --git a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py index 721754a8..3bf3f8e4 100644 --- a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py +++ b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py @@ -18,17 +18,13 @@ from rich.progress import track from tortoise import Tortoise from tortoise.expressions import Q -from tortoise.fields import CharField, IntField, JSONField +from tortoise.fields import CharField, DatetimeField, IntField, JSONField from tortoise.models import Model import faebryk.library._F as F from faebryk.core.module import Module from faebryk.core.parameter import Parameter -from faebryk.libs.e_series import ( - E_SERIES_VALUES, - ParamNotResolvedError, - e_series_intersect, -) +from faebryk.core.core import Module, Parameter from faebryk.libs.picker.lcsc import ( LCSC_NoDataException, LCSC_Part, @@ -40,8 +36,8 @@ PickError, has_part_picked_defined, ) -from faebryk.libs.units import P, Quantity, UndefinedUnitError, to_si_str -from faebryk.libs.util import at_exit, cast_assert, try_or +from faebryk.libs.units import P, UndefinedUnitError +from faebryk.libs.util import at_exit, try_or logger = logging.getLogger(__name__) @@ -140,19 +136,22 @@ async def get_from_id(self, manufacturer_id: int) -> str: class Component(Model): lcsc = IntField(primary_key=True) category_id = IntField() + category = CharField(max_length=255) + subcategory = CharField(max_length=255, optional=True) mfr = CharField(max_length=255) package = CharField(max_length=255) joints = IntField() manufacturer_id = IntField() + manufacturer_name = CharField(max_length=255, optional=True) basic = IntField() description = CharField(max_length=255) datasheet = CharField(max_length=255) stock = IntField() price = JSONField() - last_update = IntField() + last_update = DatetimeField() extra = JSONField() flag = IntField() - last_on_stock = IntField() + last_on_stock = DatetimeField() preferred = IntField() class Meta: @@ -216,6 +215,11 @@ def attribute_to_parameter( if ignore_at: value_field = value_field.split("@")[0] + # parse fields like "110mA;130mA" + # TODO: better data model so we can choose the appropriate value + if ";" in value_field: + value_field = value_field.split(";")[0] + value_field = value_field.replace("cd", "candela") # parse fields like "1.5V~2.5V" @@ -414,37 +418,19 @@ def filter_by_description(self, *keywords: str) -> Self: return self - def filter_by_value( - self, - value: Parameter[Quantity], - si_unit: str, - e_series: set[float] | None = None, - ) -> Self: + def filter_by_si_values(self, value: Parameter, si_vals: list[str]) -> Self: assert self.Q - value = value.get_most_narrow() if logger.isEnabledFor(logging.DEBUG): logger.debug( f"Filtering by value:\n{indent(value.get_tree_param().pretty(), ' '*4)}" ) + logger.debug(f"Possible values: {si_vals}") if isinstance(value, F.ANY): return self assert not self.results - try: - intersection = F.Set( - [e_series_intersect(value, e_series or E_SERIES_VALUES.E_ALL)] - ).params - except ParamNotResolvedError as e: - raise ComponentQuery.ParamError( - value, f"Could not run e_series_intersect: {e}" - ) from e - si_vals = [ - to_si_str(cast_assert(F.Constant, r).value, si_unit) - .replace("µ", "u") - .replace("inf", "∞") - for r in intersection - ] + return self.filter_by_description(*si_vals) def filter_by_category(self, category: str, subcategory: str) -> Self: diff --git a/src/faebryk/libs/picker/jlcpcb/picker_lib.py b/src/faebryk/libs/picker/jlcpcb/picker_lib.py index 49a421b4..a53a53dd 100644 --- a/src/faebryk/libs/picker/jlcpcb/picker_lib.py +++ b/src/faebryk/libs/picker/jlcpcb/picker_lib.py @@ -15,6 +15,7 @@ PickError, ) from faebryk.libs.util import KeyErrorAmbiguous, KeyErrorNotFound +from faebryk.libs.picker.util import generate_si_values logger = logging.getLogger(__name__) @@ -29,9 +30,6 @@ # - should be classes instead of functions -# Generic pickers ---------------------------------------------------------------------- - - def str_to_enum[T: Enum](enum: type[T], x: str) -> F.Constant[T]: name = x.replace(" ", "_").replace("-", "_").upper() if name not in [e.name for e in enum]: @@ -46,6 +44,181 @@ def f(x: str) -> F.Constant[T]: return f +_MAPPINGS_BY_TYPE = { + F.Resistor: [ + MappingParameterDB( + "resistance", + ["Resistance"], + "Tolerance", + ), + MappingParameterDB( + "rated_power", + ["Power(Watts)"], + ), + MappingParameterDB( + "rated_voltage", + ["Overload Voltage (Max)"], + ), + ], + F.Capacitor: [ + MappingParameterDB("capacitance", ["Capacitance"], "Tolerance"), + MappingParameterDB( + "rated_voltage", + ["Voltage Rated"], + ), + MappingParameterDB( + "temperature_coefficient", + ["Temperature Coefficient"], + transform_fn=lambda x: str_to_enum( + F.Capacitor.TemperatureCoefficient, x.replace("NP0", "C0G") + ), + ), + ], + F.Inductor: [ + MappingParameterDB( + "inductance", + ["Inductance"], + "Tolerance", + ), + MappingParameterDB( + "rated_current", + ["Rated Current"], + ), + MappingParameterDB( + "dc_resistance", + ["DC Resistance (DCR)", "DC Resistance"], + ), + MappingParameterDB( + "self_resonant_frequency", + ["Frequency - Self Resonant"], + ), + ], + F.TVS: [ + MappingParameterDB( + "forward_voltage", + ["Breakdown Voltage"], + ), + # TODO: think about the difference of meaning for max_current between Diode + # and TVS + MappingParameterDB( + "max_current", + ["Peak Pulse Current (Ipp)@10/1000us"], + ), + MappingParameterDB( + "reverse_working_voltage", + ["Reverse Voltage (Vr)", "Reverse Stand-Off Voltage (Vrwm)"], + ), + MappingParameterDB( + "reverse_leakage_current", + ["Reverse Leakage Current", "Reverse Leakage Current (Ir)"], + ), + MappingParameterDB( + "reverse_breakdown_voltage", + ["Breakdown Voltage"], + ), + ], + F.Diode: [ + MappingParameterDB( + "forward_voltage", + ["Forward Voltage", "Forward Voltage (Vf@If)"], + ), + MappingParameterDB( + "max_current", + ["Average Rectified Current (Io)"], + ), + MappingParameterDB( + "reverse_working_voltage", + ["Reverse Voltage (Vr)", "Reverse Stand-Off Voltage (Vrwm)"], + ), + MappingParameterDB( + "reverse_leakage_current", + ["Reverse Leakage Current", "Reverse Leakage Current (Ir)"], + ), + ], + F.LED: [ + MappingParameterDB( + "color", + ["Emitted Color"], + transform_fn=str_to_enum_func(F.LED.Color), + ), + MappingParameterDB( + "max_brightness", + ["Luminous Intensity"], + ), + MappingParameterDB( + "max_current", + ["Forward Current"], + ), + MappingParameterDB( + "forward_voltage", + ["Forward Voltage", "Forward Voltage (VF)"], + ), + ], + F.MOSFET: [ + MappingParameterDB( + "max_drain_source_voltage", + ["Drain Source Voltage (Vdss)"], + ), + MappingParameterDB( + "max_continuous_drain_current", + ["Continuous Drain Current (Id)"], + ), + MappingParameterDB( + "channel_type", + ["Type"], + transform_fn=str_to_enum_func(F.MOSFET.ChannelType), + ), + MappingParameterDB( + "gate_source_threshold_voltage", + ["Gate Threshold Voltage (Vgs(th)@Id)"], + ), + MappingParameterDB( + "on_resistance", + ["Drain Source On Resistance (RDS(on)@Vgs,Id)"], + ), + ], + F.LDO: [ + MappingParameterDB( + "output_polarity", + ["Output Polarity"], + transform_fn=str_to_enum_func(F.LDO.OutputPolarity), + ), + MappingParameterDB( + "max_input_voltage", + ["Maximum Input Voltage"], + ), + MappingParameterDB( + "output_type", + ["Output Type"], + transform_fn=str_to_enum_func(F.LDO.OutputType), + ), + MappingParameterDB( + "output_current", + ["Output Current"], + ), + MappingParameterDB( + "dropout_voltage", + ["Dropout Voltage"], + ), + MappingParameterDB( + "output_voltage", + ["Output Voltage"], + ), + MappingParameterDB( + "quiescent_current", + [ + "Quiescent Current", + "standby current", + "Quiescent Current (Ground Current)", + ], + ), + ], +} + + +# Generic pickers ---------------------------------------------------------------------- + + def find_component_by_lcsc_id(lcsc_id: str) -> Component: parts = ComponentQuery().filter_by_lcsc_pn(lcsc_id).get() @@ -168,28 +341,16 @@ def find_resistor(cmp: Module): provided resistor """ assert isinstance(cmp, F.Resistor) - - mapping = [ - MappingParameterDB( - "resistance", - ["Resistance"], - "Tolerance", - ), - MappingParameterDB( - "rated_power", - ["Power(Watts)"], - ), - MappingParameterDB( - "rated_voltage", - ["Overload Voltage (Max)"], - ), - ] + mapping = _MAPPINGS_BY_TYPE[F.Resistor] ( ComponentQuery() .filter_by_category("Resistors", "Chip Resistor - Surface Mount") .filter_by_stock(qty) - .filter_by_value(cmp.resistance, "Ω", E_SERIES_VALUES.E96) + .filter_by_si_values( + cmp.PARAMs.resistance, + generate_si_values(cmp.PARAMs.resistance, "Ω", E_SERIES_VALUES.E96), + ) .filter_by_traits(cmp) .sort_by_price(qty) .filter_by_module_params_and_attach(cmp, mapping, qty) @@ -203,21 +364,7 @@ def find_capacitor(cmp: Module): """ assert isinstance(cmp, F.Capacitor) - - mapping = [ - MappingParameterDB("capacitance", ["Capacitance"], "Tolerance"), - MappingParameterDB( - "rated_voltage", - ["Voltage Rated"], - ), - MappingParameterDB( - "temperature_coefficient", - ["Temperature Coefficient"], - transform_fn=lambda x: str_to_enum( - F.Capacitor.TemperatureCoefficient, x.replace("NP0", "C0G") - ), - ), - ] + mapping = _MAPPINGS_BY_TYPE[F.Capacitor] # TODO: add support for electrolytic capacitors. ( @@ -227,7 +374,10 @@ def find_capacitor(cmp: Module): ) .filter_by_stock(qty) .filter_by_traits(cmp) - .filter_by_value(cmp.capacitance, "F", E_SERIES_VALUES.E24) + .filter_by_si_values( + cmp.PARAMs.capacitance, + generate_si_values(cmp.PARAMs.capacitance, "F", E_SERIES_VALUES.E24), + ) .sort_by_price(qty) .filter_by_module_params_and_attach(cmp, mapping, qty) ) @@ -243,26 +393,7 @@ def find_inductor(cmp: Module): """ assert isinstance(cmp, F.Inductor) - - mapping = [ - MappingParameterDB( - "inductance", - ["Inductance"], - "Tolerance", - ), - MappingParameterDB( - "rated_current", - ["Rated Current"], - ), - MappingParameterDB( - "dc_resistance", - ["DC Resistance (DCR)", "DC Resistance"], - ), - MappingParameterDB( - "self_resonant_frequency", - ["Frequency - Self Resonant"], - ), - ] + mapping = _MAPPINGS_BY_TYPE[F.Inductor] ( ComponentQuery() @@ -271,7 +402,10 @@ def find_inductor(cmp: Module): .filter_by_category("Inductors", "Inductors") .filter_by_stock(qty) .filter_by_traits(cmp) - .filter_by_value(cmp.inductance, "H", E_SERIES_VALUES.E24) + .filter_by_si_values( + cmp.PARAMs.inductance, + generate_si_values(cmp.PARAMs.inductance, "H", E_SERIES_VALUES.E24), + ) .sort_by_price(qty) .filter_by_module_params_and_attach(cmp, mapping, qty) ) @@ -288,30 +422,7 @@ def find_tvs(cmp: Module): # TODO: handle bidirectional TVS diodes # "Bidirectional Channels": "1" in extra['attributes'] - mapping = [ - MappingParameterDB( - "forward_voltage", - ["Breakdown Voltage"], - ), - # TODO: think about the difference of meaning for max_current between Diode - # and TVS - MappingParameterDB( - "max_current", - ["Peak Pulse Current (Ipp)@10/1000us"], - ), - MappingParameterDB( - "reverse_working_voltage", - ["Reverse Voltage (Vr)", "Reverse Stand-Off Voltage (Vrwm)"], - ), - MappingParameterDB( - "reverse_leakage_current", - ["Reverse Leakage Current", "Reverse Leakage Current (Ir)"], - ), - MappingParameterDB( - "reverse_breakdown_voltage", - ["Breakdown Voltage"], - ), - ] + mapping = _MAPPINGS_BY_TYPE[F.TVS] ( ComponentQuery() @@ -331,24 +442,7 @@ def find_diode(cmp: Module): assert isinstance(cmp, F.Diode) - mapping = [ - MappingParameterDB( - "forward_voltage", - ["Forward Voltage", "Forward Voltage (Vf@If)"], - ), - MappingParameterDB( - "max_current", - ["Average Rectified Current (Io)"], - ), - MappingParameterDB( - "reverse_working_voltage", - ["Reverse Voltage (Vr)", "Reverse Stand-Off Voltage (Vrwm)"], - ), - MappingParameterDB( - "reverse_leakage_current", - ["Reverse Leakage Current", "Reverse Leakage Current (Ir)"], - ), - ] + mapping = _MAPPINGS_BY_TYPE[F.Diode] ( ComponentQuery() @@ -369,26 +463,7 @@ def find_led(cmp: Module): """ assert isinstance(cmp, F.LED) - - mapping = [ - MappingParameterDB( - "color", - ["Emitted Color"], - transform_fn=str_to_enum_func(F.LED.Color), - ), - MappingParameterDB( - "max_brightness", - ["Luminous Intensity"], - ), - MappingParameterDB( - "max_current", - ["Forward Current"], - ), - MappingParameterDB( - "forward_voltage", - ["Forward Voltage", "Forward Voltage (VF)"], - ), - ] + mapping = _MAPPINGS_BY_TYPE[F.LED] ( ComponentQuery() @@ -407,30 +482,7 @@ def find_mosfet(cmp: Module): """ assert isinstance(cmp, F.MOSFET) - - mapping = [ - MappingParameterDB( - "max_drain_source_voltage", - ["Drain Source Voltage (Vdss)"], - ), - MappingParameterDB( - "max_continuous_drain_current", - ["Continuous Drain Current (Id)"], - ), - MappingParameterDB( - "channel_type", - ["Type"], - transform_fn=str_to_enum_func(F.MOSFET.ChannelType), - ), - MappingParameterDB( - "gate_source_threshold_voltage", - ["Gate Threshold Voltage (Vgs(th)@Id)"], - ), - MappingParameterDB( - "on_resistance", - ["Drain Source On Resistance (RDS(on)@Vgs,Id)"], - ), - ] + mapping = _MAPPINGS_BY_TYPE[F.MOSFET] ( ComponentQuery() @@ -449,43 +501,7 @@ def find_ldo(cmp: Module): """ assert isinstance(cmp, F.LDO) - - mapping = [ - MappingParameterDB( - "output_polarity", - ["Output Polarity"], - transform_fn=str_to_enum_func(F.LDO.OutputPolarity), - ), - MappingParameterDB( - "max_input_voltage", - ["Maximum Input Voltage"], - ), - MappingParameterDB( - "output_type", - ["Output Type"], - transform_fn=str_to_enum_func(F.LDO.OutputType), - ), - MappingParameterDB( - "output_current", - ["Output Current"], - ), - MappingParameterDB( - "dropout_voltage", - ["Dropout Voltage"], - ), - MappingParameterDB( - "output_voltage", - ["Output Voltage"], - ), - MappingParameterDB( - "quiescent_current", - [ - "Quiescent Current", - "standby current", - "Quiescent Current (Ground Current)", - ], - ), - ] + mapping = _MAPPINGS_BY_TYPE[F.LDO] ( ComponentQuery() diff --git a/src/faebryk/libs/picker/util.py b/src/faebryk/libs/picker/util.py new file mode 100644 index 00000000..02343f74 --- /dev/null +++ b/src/faebryk/libs/picker/util.py @@ -0,0 +1,36 @@ +import faebryk.library._F as F +from faebryk.core.core import Parameter +from faebryk.library.Set import Set +from faebryk.libs.e_series import ( + E_SERIES_VALUES, + ParamNotResolvedError, + e_series_intersect, +) +from faebryk.libs.picker.picker import PickError +from faebryk.libs.units import Quantity, to_si_str +from faebryk.libs.util import cast_assert + + +def generate_si_values( + value: Parameter[Quantity], si_unit: str, e_series: set[float] | None = None +): + """ + Generate a list of permissible SI values for the given parameter from an + E-series + """ + + value = value.get_most_narrow() + + try: + intersection = Set( + [e_series_intersect(value, e_series or E_SERIES_VALUES.E_ALL)] + ).params + except ParamNotResolvedError as e: + raise PickError(value, f"Could not run e_series_intersect: {e}") from e + + return [ + to_si_str(cast_assert(F.Constant, r).value, si_unit) + .replace("µ", "u") + .replace("inf", "∞") + for r in intersection + ] diff --git a/test/libs/picker/test_api.py b/test/libs/picker/test_api.py new file mode 100644 index 00000000..33e04783 --- /dev/null +++ b/test/libs/picker/test_api.py @@ -0,0 +1,388 @@ +import logging +import os +import unittest + +import faebryk.library._F as F +from faebryk.core.core import Module +from faebryk.libs.logging import setup_basic_logging +from faebryk.libs.picker.api.pickers import add_api_pickers +from faebryk.libs.picker.picker import DescriptiveProperties, has_part_picked +from faebryk.libs.units import P, Quantity + +logger = logging.getLogger(__name__) + + +# TODO: abstract out commonalities with test_jlcpcb.py +@unittest.skipIf(not os.getenv("FBRK_PICKER") == "api", reason="Requires API info") +class TestPickerApi(unittest.TestCase): + class TestRequirements: + def __init__( + self, + test_case: unittest.TestCase, + requirement: Module, + footprint: list[tuple[str, int]], + ): + self.test_case = test_case + self.result = requirement + self.requirement = requirement + self.footprint = footprint + + self.req_lcsc_pn = None + if self.requirement.has_trait(F.has_descriptive_properties) and "LCSC" in ( + self.requirement.get_trait(F.has_descriptive_properties).get_properties, + ): + self.req_lcsc_pn = self.requirement.get_trait( + F.has_descriptive_properties + ).get_properties()["LCSC"] + + self.req_manufacturer_pn = None + if ( + self.requirement.has_trait(F.has_descriptive_properties) + and DescriptiveProperties.partno + in self.requirement.get_trait( + F.has_descriptive_properties + ).get_properties() + ): + self.req_manufacturer_pn = self.requirement.get_trait( + F.has_descriptive_properties + ).get_properties()[DescriptiveProperties.partno] + + requirement.add_trait(F.has_footprint_requirement_defined(footprint)) + + self.test() + + def satisfies_requirements(self): + self.test_case.assertTrue( + self.result.has_trait(F.has_descriptive_properties) + ) + if self.req_lcsc_pn is not None: + self.test_case.assertIn( + "LCSC", + self.result.get_trait( + F.has_descriptive_properties + ).get_properties(), + ) + + self.test_case.assertEqual( + self.req_lcsc_pn, + self.result.get_trait( + F.has_descriptive_properties + ).get_properties()["LCSC"], + ) + + if self.req_manufacturer_pn is not None: + self.test_case.assertIn( + DescriptiveProperties.partno, + self.result.get_trait( + F.has_descriptive_properties + ).get_properties(), + ) + self.test_case.assertEqual( + self.req_manufacturer_pn, + self.result.get_trait( + F.has_descriptive_properties + ).get_properties()[DescriptiveProperties.partno], + ) + + for req, res in zip( + self.requirement.PARAMs.get_all(), self.result.PARAMs.get_all() + ): + req = req.get_most_narrow() + res = res.get_most_narrow() + + if isinstance(req, F.Range): + self.test_case.assertTrue(res in req) + elif isinstance(req, F.Constant): + self.test_case.assertEqual(req, res) + elif isinstance(req, F.Set): + self.test_case.assertIn(res, req.params) + elif isinstance(req, F.TBD): + self.test_case.assertTrue(isinstance(res, F.ANY)) + elif isinstance(req, F.ANY): + self.test_case.assertTrue(isinstance(res, F.ANY)) + else: + raise NotImplementedError( + f"Unsupported type of parameter: {type(req)}: {req}" + ) + + def test(self): + add_api_pickers(self.result) + self.result.get_trait(F.has_picker).pick() + + self.test_case.assertTrue(self.result.has_trait(has_part_picked)) + + # check part number + self.test_case.assertTrue( + self.result.has_trait(F.has_descriptive_properties) + ) + self.test_case.assertIn( + DescriptiveProperties.partno, + self.result.get_trait(F.has_descriptive_properties).get_properties(), + ) + self.test_case.assertNotEqual( + "", + self.result.get_trait(F.has_descriptive_properties).get_properties()[ + DescriptiveProperties.partno + ], + ) + + # check footprint + self.test_case.assertTrue(self.result.has_trait(F.has_footprint)) + self.test_case.assertTrue( + self.result.get_trait(F.has_footprint) + .get_footprint() + .has_trait(F.has_kicad_footprint) + ) + # check pin count + self.test_case.assertEqual( + self.footprint[0][1], + len( + self.result.get_trait(F.has_footprint) + .get_footprint() + .get_trait(F.has_kicad_footprint) + .get_pin_names() + ), + ) + + # check requirements from module + self.satisfies_requirements() + + def test_find_manufacturer_partnumber(self): + requirement = F.OpAmp().builder( + lambda r: ( + r.PARAMs.bandwidth.merge(F.Range.upper_bound(1 * P.Mhertz)), + r.PARAMs.common_mode_rejection_ratio.merge( + F.Range.lower_bound(Quantity(50, P.dB)) + ), + r.PARAMs.input_bias_current.merge(F.Range.upper_bound(1 * P.nA)), + r.PARAMs.input_offset_voltage.merge(F.Range.upper_bound(1 * P.mV)), + r.PARAMs.gain_bandwidth_product.merge( + F.Range.upper_bound(1 * P.Mhertz) + ), + r.PARAMs.output_current.merge(F.Range.upper_bound(1 * P.mA)), + r.PARAMs.slew_rate.merge(F.Range.upper_bound(1 * P.MV / P.us)), + ) + ) + requirement.add_trait( + F.has_defined_descriptive_properties( + { + DescriptiveProperties.partno: "LMV321IDBVR", + DescriptiveProperties.manufacturer: "Texas Instruments", + } + ) + ) + self.TestRequirements( + self, + requirement=requirement, + footprint=[("SOT-23-5", 5)], + ) + + def test_find_lcsc_partnumber(self): + requirement = F.OpAmp().builder( + lambda r: ( + r.PARAMs.bandwidth.merge(F.Range.upper_bound(1 * P.Mhertz)), + r.PARAMs.common_mode_rejection_ratio.merge( + F.Range.lower_bound(Quantity(50, P.dB)) + ), + r.PARAMs.input_bias_current.merge(F.Range.upper_bound(1 * P.nA)), + r.PARAMs.input_offset_voltage.merge(F.Range.upper_bound(1 * P.mV)), + r.PARAMs.gain_bandwidth_product.merge( + F.Range.upper_bound(1 * P.Mhertz) + ), + r.PARAMs.output_current.merge(F.Range.upper_bound(1 * P.mA)), + r.PARAMs.slew_rate.merge(F.Range.upper_bound(1 * P.MV / P.us)), + ) + ) + requirement.add_trait( + F.has_defined_descriptive_properties( + { + "LCSC": "C7972", + } + ) + ) + self.TestRequirements( + self, + requirement=requirement, + footprint=[("SOT-23-5", 5)], + ) + + def test_find_resistor(self): + self.TestRequirements( + self, + requirement=F.Resistor().builder( + lambda r: ( + r.PARAMs.resistance.merge( + F.Range.from_center(10 * P.kohm, 1 * P.kohm) + ), + r.PARAMs.rated_power.merge(F.Range.lower_bound(0.05 * P.W)), + r.PARAMs.rated_voltage.merge(F.Range.lower_bound(25 * P.V)), + ) + ), + footprint=[("0402", 2)], + ) + + self.TestRequirements( + self, + requirement=F.Resistor().builder( + lambda r: ( + r.PARAMs.resistance.merge( + F.Range.from_center(69 * P.kohm, 2 * P.kohm) + ), + r.PARAMs.rated_power.merge(F.Range.lower_bound(0.1 * P.W)), + r.PARAMs.rated_voltage.merge(F.Range.lower_bound(50 * P.V)), + ) + ), + footprint=[("0603", 2)], + ) + + def test_find_capacitor(self): + self.TestRequirements( + self, + requirement=F.Capacitor().builder( + lambda c: ( + c.PARAMs.capacitance.merge( + F.Range.from_center(100 * P.nF, 10 * P.nF) + ), + c.PARAMs.rated_voltage.merge(F.Range.lower_bound(25 * P.V)), + c.PARAMs.temperature_coefficient.merge( + F.Range.lower_bound(F.Capacitor.TemperatureCoefficient.X7R) + ), + ) + ), + footprint=[("0603", 2)], + ) + + self.TestRequirements( + self, + requirement=F.Capacitor().builder( + lambda c: ( + c.PARAMs.capacitance.merge( + F.Range.from_center(47 * P.pF, 4.7 * P.pF) + ), + c.PARAMs.rated_voltage.merge(F.Range.lower_bound(50 * P.V)), + c.PARAMs.temperature_coefficient.merge( + F.Range.lower_bound(F.Capacitor.TemperatureCoefficient.C0G) + ), + ) + ), + footprint=[("0402", 2)], + ) + + def test_find_inductor(self): + self.TestRequirements( + self, + requirement=F.Inductor().builder( + lambda i: ( + i.PARAMs.inductance.merge( + F.Range.from_center(4.7 * P.nH, 0.47 * P.nH) + ), + i.PARAMs.rated_current.merge(F.Range.lower_bound(0.01 * P.A)), + i.PARAMs.dc_resistance.merge(F.Range.upper_bound(1 * P.ohm)), + i.PARAMs.self_resonant_frequency.merge( + F.Range.lower_bound(100 * P.Mhertz) + ), + ) + ), + footprint=[("0603", 2)], + ) + + def test_find_mosfet(self): + self.TestRequirements( + self, + requirement=F.MOSFET().builder( + lambda m: ( + m.PARAMs.channel_type.merge( + F.Constant(F.MOSFET.ChannelType.N_CHANNEL) + ), + m.PARAMs.saturation_type.merge( + F.Constant(F.MOSFET.SaturationType.ENHANCEMENT) + ), + m.PARAMs.gate_source_threshold_voltage.merge( + F.Range(0.4 * P.V, 3 * P.V) + ), + m.PARAMs.max_drain_source_voltage.merge( + F.Range.lower_bound(20 * P.V) + ), + m.PARAMs.max_continuous_drain_current.merge( + F.Range.lower_bound(2 * P.A) + ), + m.PARAMs.on_resistance.merge(F.Range.upper_bound(0.1 * P.ohm)), + ) + ), + footprint=[("SOT-23", 3)], + ) + + def test_find_diode(self): + self.TestRequirements( + self, + requirement=F.Diode().builder( + lambda d: ( + d.PARAMs.current.merge(F.Range.lower_bound(1 * P.A)), + d.PARAMs.forward_voltage.merge(F.Range.upper_bound(1.7 * P.V)), + d.PARAMs.reverse_working_voltage.merge( + F.Range.lower_bound(20 * P.V) + ), + d.PARAMs.reverse_leakage_current.merge( + F.Range.upper_bound(100 * P.uA) + ), + d.PARAMs.max_current.merge(F.Range.lower_bound(1 * P.A)), + ) + ), + footprint=[("SOD-123", 2)], + ) + + def test_find_tvs(self): + self.TestRequirements( + self, + requirement=F.TVS().builder( + lambda t: ( + # TODO: There is no current specified for TVS diodes, only peak + # current + t.PARAMs.current.merge(F.ANY()), + t.PARAMs.forward_voltage.merge(F.ANY()), + t.PARAMs.reverse_working_voltage.merge( + F.Range.lower_bound(5 * P.V) + ), + t.PARAMs.reverse_leakage_current.merge(F.ANY()), + t.PARAMs.max_current.merge(F.Range.lower_bound(10 * P.A)), + t.PARAMs.reverse_breakdown_voltage.merge( + F.Range.upper_bound(8 * P.V) + ), + ) + ), + footprint=[("SMB(DO-214AA)", 2)], + ) + + def test_find_ldo(self): + self.TestRequirements( + self, + F.LDO().builder( + lambda u: ( + u.PARAMs.output_voltage.merge( + F.Range.from_center(3.3 * P.V, 0.1 * P.V) + ), + u.PARAMs.output_current.merge(F.Range.lower_bound(0.1 * P.A)), + u.PARAMs.max_input_voltage.merge(F.Range.lower_bound(5 * P.V)), + u.PARAMs.dropout_voltage.merge(F.Range.upper_bound(1 * P.V)), + u.PARAMs.output_polarity.merge( + F.Constant(F.LDO.OutputPolarity.POSITIVE) + ), + u.PARAMs.output_type.merge(F.Constant(F.LDO.OutputType.FIXED)), + u.PARAMs.psrr.merge(F.ANY()), + u.PARAMs.quiescent_current.merge(F.ANY()), + ) + ), + footprint=[ + ("SOT-23", 3), + ("SOT23", 3), + ("SOT-23-3", 3), + ("SOT-23-3L", 3), + ], + ) + + +if __name__ == "__main__": + setup_basic_logging() + logger.setLevel(logging.DEBUG) + + unittest.main() From c0cbecaa511673ba0e5c825892d5ffb41920490a Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Fri, 30 Aug 2024 11:00:04 -0700 Subject: [PATCH 02/31] add LED test case --- test/libs/picker/test_api.py | 27 +++++++++++++++++++++++++-- test/libs/picker/test_jlcpcb.py | 28 ++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/test/libs/picker/test_api.py b/test/libs/picker/test_api.py index 33e04783..9d52ae92 100644 --- a/test/libs/picker/test_api.py +++ b/test/libs/picker/test_api.py @@ -4,6 +4,7 @@ import faebryk.library._F as F from faebryk.core.core import Module +from faebryk.libs.brightness import TypicalLuminousIntensity from faebryk.libs.logging import setup_basic_logging from faebryk.libs.picker.api.pickers import add_api_pickers from faebryk.libs.picker.picker import DescriptiveProperties, has_part_picked @@ -97,9 +98,9 @@ def satisfies_requirements(self): elif isinstance(req, F.Set): self.test_case.assertIn(res, req.params) elif isinstance(req, F.TBD): - self.test_case.assertTrue(isinstance(res, F.ANY)) + self.test_case.assertIsInstance(res, F.ANY) elif isinstance(req, F.ANY): - self.test_case.assertTrue(isinstance(res, F.ANY)) + self.test_case.assertIsInstance(res, F.ANY) else: raise NotImplementedError( f"Unsupported type of parameter: {type(req)}: {req}" @@ -331,6 +332,28 @@ def test_find_diode(self): footprint=[("SOD-123", 2)], ) + def test_find_led(self): + self.TestRequirements( + self, + requirement=F.LED().builder( + lambda led: ( + led.PARAMs.color.merge(F.LED.Color.RED), + led.PARAMs.brightness.merge( + TypicalLuminousIntensity.APPLICATION_LED_INDICATOR_INSIDE.value.value + ), + # TODO: check semantics of F.ANY vs F.TBD + led.PARAMs.reverse_leakage_current.merge(F.ANY()), + led.PARAMs.reverse_working_voltage.merge(F.ANY()), + led.PARAMs.max_brightness.merge( + F.Range.lower_bound(100 * P.millicandela) + ), + led.PARAMs.forward_voltage.merge(F.Range.upper_bound(2.5 * P.V)), + led.PARAMs.max_current.merge(F.Range.upper_bound(20 * P.mA)), + ) + ), + footprint=[("0805", 2)], + ) + def test_find_tvs(self): self.TestRequirements( self, diff --git a/test/libs/picker/test_jlcpcb.py b/test/libs/picker/test_jlcpcb.py index 7997221b..11847344 100644 --- a/test/libs/picker/test_jlcpcb.py +++ b/test/libs/picker/test_jlcpcb.py @@ -9,6 +9,8 @@ import faebryk.libs.picker.lcsc as lcsc from faebryk.core.module import Module from faebryk.core.parameter import Parameter +from faebryk.core.core import Module +from faebryk.libs.brightness import TypicalLuminousIntensity from faebryk.libs.logging import setup_basic_logging from faebryk.libs.picker.jlcpcb.jlcpcb import JLCPCB_DB from faebryk.libs.picker.jlcpcb.pickers import add_jlcpcb_pickers @@ -107,9 +109,9 @@ def satisfies_requirements(self): elif isinstance(req, F.Set): self.test_case.assertIn(res, req.params) elif isinstance(req, F.TBD): - self.test_case.assertTrue(isinstance(res, F.ANY)) + self.test_case.assertIsInstance(res, F.ANY) elif isinstance(req, F.ANY): - self.test_case.assertTrue(isinstance(res, F.ANY)) + self.test_case.assertIsInstance(res, F.ANY) else: raise NotImplementedError( f"Unsupported type of parameter: {type(req)}: {req}" @@ -315,6 +317,28 @@ def test_find_diode(self): footprint=[("SOD-123", 2)], ) + def test_find_led(self): + self.TestRequirements( + self, + requirement=F.LED().builder( + lambda led: ( + led.PARAMs.color.merge(F.LED.Color.RED), + led.PARAMs.brightness.merge( + TypicalLuminousIntensity.APPLICATION_LED_INDICATOR_INSIDE.value.value + ), + # TODO: check semantics of F.ANY vs F.TBD + led.PARAMs.reverse_leakage_current.merge(F.ANY()), + led.PARAMs.reverse_working_voltage.merge(F.ANY()), + led.PARAMs.max_brightness.merge( + F.Range.lower_bound(100 * P.millicandela) + ), + led.PARAMs.forward_voltage.merge(F.Range.upper_bound(2.5 * P.V)), + led.PARAMs.max_current.merge(F.Range.upper_bound(20 * P.mA)), + ) + ), + footprint=[("0805", 2)], + ) + def test_find_tvs(self): self.TestRequirements( self, From add6c83bd9b94f9d7971a15da50888af15b3f7ee Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Wed, 16 Oct 2024 14:45:53 -0700 Subject: [PATCH 03/31] add file license headers --- src/faebryk/libs/picker/api/api.py | 3 +++ src/faebryk/libs/picker/api/picker_lib.py | 3 +++ src/faebryk/libs/picker/api/pickers.py | 3 +++ src/faebryk/libs/picker/util.py | 3 +++ test/libs/picker/test_api.py | 3 +++ 5 files changed, 15 insertions(+) diff --git a/src/faebryk/libs/picker/api/api.py b/src/faebryk/libs/picker/api/api.py index 40b20481..ef269656 100644 --- a/src/faebryk/libs/picker/api/api.py +++ b/src/faebryk/libs/picker/api/api.py @@ -1,3 +1,6 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + import logging import os import textwrap diff --git a/src/faebryk/libs/picker/api/picker_lib.py b/src/faebryk/libs/picker/api/picker_lib.py index 6994d105..38239439 100644 --- a/src/faebryk/libs/picker/api/picker_lib.py +++ b/src/faebryk/libs/picker/api/picker_lib.py @@ -1,3 +1,6 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + import logging import re from typing import Type diff --git a/src/faebryk/libs/picker/api/pickers.py b/src/faebryk/libs/picker/api/pickers.py index 95b011cd..fa619bb7 100644 --- a/src/faebryk/libs/picker/api/pickers.py +++ b/src/faebryk/libs/picker/api/pickers.py @@ -1,3 +1,6 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + from typing import Any import faebryk.library._F as F diff --git a/src/faebryk/libs/picker/util.py b/src/faebryk/libs/picker/util.py index 02343f74..0a5614d1 100644 --- a/src/faebryk/libs/picker/util.py +++ b/src/faebryk/libs/picker/util.py @@ -1,3 +1,6 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + import faebryk.library._F as F from faebryk.core.core import Parameter from faebryk.library.Set import Set diff --git a/test/libs/picker/test_api.py b/test/libs/picker/test_api.py index 9d52ae92..c754acc9 100644 --- a/test/libs/picker/test_api.py +++ b/test/libs/picker/test_api.py @@ -1,3 +1,6 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + import logging import os import unittest From 86797357b37698994bd395509d1c605c4bc16217 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Wed, 16 Oct 2024 14:50:17 -0700 Subject: [PATCH 04/31] fix imports --- src/faebryk/libs/picker/api/api.py | 2 +- src/faebryk/libs/picker/api/picker_lib.py | 2 +- src/faebryk/libs/picker/api/pickers.py | 2 +- src/faebryk/libs/picker/jlcpcb/jlcpcb.py | 1 - src/faebryk/libs/picker/util.py | 2 +- test/libs/picker/test_api.py | 2 +- test/libs/picker/test_jlcpcb.py | 1 - 7 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/faebryk/libs/picker/api/api.py b/src/faebryk/libs/picker/api/api.py index ef269656..84c76628 100644 --- a/src/faebryk/libs/picker/api/api.py +++ b/src/faebryk/libs/picker/api/api.py @@ -10,7 +10,7 @@ from supabase.client import ClientOptions import faebryk.library._F as F -from faebryk.core.core import Module +from faebryk.core.module import Module # TODO: replace with API-specific data model from faebryk.libs.picker.jlcpcb.jlcpcb import Component, MappingParameterDB diff --git a/src/faebryk/libs/picker/api/picker_lib.py b/src/faebryk/libs/picker/api/picker_lib.py index 38239439..08c489fe 100644 --- a/src/faebryk/libs/picker/api/picker_lib.py +++ b/src/faebryk/libs/picker/api/picker_lib.py @@ -6,7 +6,7 @@ from typing import Type import faebryk.library._F as F -from faebryk.core.core import Module +from faebryk.core.module import Module from faebryk.libs.e_series import E_SERIES_VALUES from faebryk.libs.picker.api.api import ( ApiClient, diff --git a/src/faebryk/libs/picker/api/pickers.py b/src/faebryk/libs/picker/api/pickers.py index fa619bb7..66be729c 100644 --- a/src/faebryk/libs/picker/api/pickers.py +++ b/src/faebryk/libs/picker/api/pickers.py @@ -5,7 +5,7 @@ import faebryk.library._F as F import faebryk.libs.picker.api.picker_lib as P -from faebryk.core.core import Module +from faebryk.core.module import Module from faebryk.libs.picker.picker import PickError diff --git a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py index 3bf3f8e4..12246634 100644 --- a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py +++ b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py @@ -24,7 +24,6 @@ import faebryk.library._F as F from faebryk.core.module import Module from faebryk.core.parameter import Parameter -from faebryk.core.core import Module, Parameter from faebryk.libs.picker.lcsc import ( LCSC_NoDataException, LCSC_Part, diff --git a/src/faebryk/libs/picker/util.py b/src/faebryk/libs/picker/util.py index 0a5614d1..1ca8e3fb 100644 --- a/src/faebryk/libs/picker/util.py +++ b/src/faebryk/libs/picker/util.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT import faebryk.library._F as F -from faebryk.core.core import Parameter +from faebryk.core.parameter import Parameter from faebryk.library.Set import Set from faebryk.libs.e_series import ( E_SERIES_VALUES, diff --git a/test/libs/picker/test_api.py b/test/libs/picker/test_api.py index c754acc9..4717a764 100644 --- a/test/libs/picker/test_api.py +++ b/test/libs/picker/test_api.py @@ -6,7 +6,7 @@ import unittest import faebryk.library._F as F -from faebryk.core.core import Module +from faebryk.core.module import Module from faebryk.libs.brightness import TypicalLuminousIntensity from faebryk.libs.logging import setup_basic_logging from faebryk.libs.picker.api.pickers import add_api_pickers diff --git a/test/libs/picker/test_jlcpcb.py b/test/libs/picker/test_jlcpcb.py index 11847344..eb098e0c 100644 --- a/test/libs/picker/test_jlcpcb.py +++ b/test/libs/picker/test_jlcpcb.py @@ -9,7 +9,6 @@ import faebryk.libs.picker.lcsc as lcsc from faebryk.core.module import Module from faebryk.core.parameter import Parameter -from faebryk.core.core import Module from faebryk.libs.brightness import TypicalLuminousIntensity from faebryk.libs.logging import setup_basic_logging from faebryk.libs.picker.jlcpcb.jlcpcb import JLCPCB_DB From 36e5a4925094a3a237a610c33150c61ae9e196c9 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Wed, 16 Oct 2024 15:17:19 -0700 Subject: [PATCH 05/31] add missing find by lcsc_id/mfr methods to api picker lib --- src/faebryk/libs/picker/api/picker_lib.py | 108 ++++++++++++------- src/faebryk/libs/picker/jlcpcb/picker_lib.py | 8 +- 2 files changed, 75 insertions(+), 41 deletions(-) diff --git a/src/faebryk/libs/picker/api/picker_lib.py b/src/faebryk/libs/picker/api/picker_lib.py index 08c489fe..ab4db6b3 100644 --- a/src/faebryk/libs/picker/api/picker_lib.py +++ b/src/faebryk/libs/picker/api/picker_lib.py @@ -21,6 +21,7 @@ from faebryk.libs.picker.jlcpcb.picker_lib import _MAPPINGS_BY_TYPE from faebryk.libs.picker.picker import DescriptiveProperties, PickError from faebryk.libs.picker.util import generate_si_values +from faebryk.libs.util import KeyErrorAmbiguous, KeyErrorNotFound logger = logging.getLogger(__name__) client = ApiClient() @@ -30,7 +31,27 @@ qty: int = 1 -def find_lcsc_part(module: Module): +def find_component_by_lcsc_id(lcsc_id: str) -> Component: + def extract_numeric_id(lcsc_id: str) -> int: + match = re.match(r"C(\d+)", lcsc_id) + if match is None: + raise PickError(f"Invalid LCSC part number {lcsc_id}") + return int(match[1]) + + parts = client.fetch_parts("find_by_lcsc", {"lcsc": extract_numeric_id(lcsc_id)}) + + if len(parts) < 1: + raise KeyErrorNotFound(f"Could not find part with LCSC part number {lcsc_id}") + + if len(parts) > 1: + raise KeyErrorAmbiguous( + parts, f"Found multiple parts with LCSC part number {lcsc_id}" + ) + + return next(iter(parts)) + + +def find_and_attach_by_lcsc_id(module: Module): """ Find a part by LCSC part number """ @@ -39,36 +60,48 @@ def find_lcsc_part(module: Module): if "LCSC" not in module.get_trait(F.has_descriptive_properties).get_properties(): raise PickError("Module does not have an LCSC part number", module) - def get_lcsc_pn(module: Module) -> int: - pn = module.get_trait(F.has_descriptive_properties).get_properties()["LCSC"] - match = re.match(r"C(\d+)", pn) - if match is None: - raise PickError(f"Invalid LCSC part number {pn}", module) - return int(match[1]) - - lcsc_pn = get_lcsc_pn(module) - parts = client.fetch_parts("find_by_lcsc", {"lcsc": lcsc_pn}) + lcsc_pn = module.get_trait(F.has_descriptive_properties).get_properties()["LCSC"] # TODO: pass through errors from API - match parts: - case []: - raise PickError( - f"Could not find part with LCSC part number {lcsc_pn}", module - ) - case [part]: - if part.stock < qty: - raise PickError( - f"Part with LCSC part number {lcsc_pn} has insufficient stock", - module, - ) - part.attach(module, []) - case _: - raise PickError( - f"Found no exact match for LCSC part number {lcsc_pn}", module - ) + try: + part = find_component_by_lcsc_id(lcsc_pn) + except KeyErrorNotFound as e: + raise PickError( + f"Could not find part with LCSC part number {lcsc_pn}", module + ) from e + except KeyErrorAmbiguous as e: + raise PickError( + f"Found no exact match for LCSC part number {lcsc_pn}", module + ) from e + if part.stock < qty: + raise PickError( + f"Part with LCSC part number {lcsc_pn} has insufficient stock", + module, + ) + part.attach(module, []) -def find_manufacturer_part(module: Module): + +def find_component_by_mfr(mfr: str, mfr_pn: str) -> Component: + parts = client.fetch_parts( + "find_by_manufacturer_part", + {"manufacturer_name": mfr, "mfr": mfr_pn, "qty": qty}, + ) + + if len(parts) < 1: + raise KeyErrorNotFound( + f"Could not find part with manufacturer part number {mfr_pn}" + ) + + if len(parts) > 1: + raise KeyErrorAmbiguous( + parts, f"Found multiple parts with manufacturer part number {mfr_pn}" + ) + + return next(iter(parts)) + + +def find_and_attach_by_mfr(module: Module): """ Find a part by manufacturer and manufacturer part number """ @@ -83,18 +116,17 @@ def find_manufacturer_part(module: Module): if DescriptiveProperties.partno not in properties: raise PickError("Module does not have a manufacturer part number", module) - manufacturer = properties[DescriptiveProperties.manufacturer] - partno = properties[DescriptiveProperties.partno] - - parts = client.fetch_parts( - "find_by_manufacturer_part", - {"manufacturer_name": manufacturer, "mfr": partno, "qty": qty}, - ) + mfr = properties[DescriptiveProperties.manufacturer] + mfr_pn = properties[DescriptiveProperties.partno] - if not parts: + try: + parts = [find_component_by_mfr(mfr, mfr_pn)] + except KeyErrorNotFound as e: raise PickError( - f"Could not find part with manufacturer part number {partno}", module - ) + f"Could not find part with manufacturer part number {mfr_pn}", module + ) from e + except KeyErrorAmbiguous as e: + parts = e.duplicates for part in parts: try: @@ -105,7 +137,7 @@ def find_manufacturer_part(module: Module): continue return PickError( - f"Could not attach any part with manufacturer part number {partno}", module + f"Could not attach any part with manufacturer part number {mfr_pn}", module ) diff --git a/src/faebryk/libs/picker/jlcpcb/picker_lib.py b/src/faebryk/libs/picker/jlcpcb/picker_lib.py index a53a53dd..30e7fac8 100644 --- a/src/faebryk/libs/picker/jlcpcb/picker_lib.py +++ b/src/faebryk/libs/picker/jlcpcb/picker_lib.py @@ -14,8 +14,8 @@ DescriptiveProperties, PickError, ) -from faebryk.libs.util import KeyErrorAmbiguous, KeyErrorNotFound from faebryk.libs.picker.util import generate_si_values +from faebryk.libs.util import KeyErrorAmbiguous, KeyErrorNotFound logger = logging.getLogger(__name__) @@ -251,8 +251,10 @@ def find_and_attach_by_lcsc_id(module: Module): raise PickError( f"Could not find part with LCSC part number {lcsc_pn}", module ) from e - except KeyErrorAmbiguous: - raise PickError(f"Found no exact match for LCSC part number {lcsc_pn}", module) + except KeyErrorAmbiguous as e: + raise PickError( + f"Found no exact match for LCSC part number {lcsc_pn}", module + ) from e if part.stock < qty: raise PickError( From afbc2df88b5fbcf386512a47d3dce42edf014dbb Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Wed, 16 Oct 2024 15:17:35 -0700 Subject: [PATCH 06/31] fix for Component.PARAMs removal --- src/faebryk/libs/picker/api/picker_lib.py | 10 +++------- src/faebryk/libs/picker/jlcpcb/picker_lib.py | 12 ++++++------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/faebryk/libs/picker/api/picker_lib.py b/src/faebryk/libs/picker/api/picker_lib.py index ab4db6b3..d8b74018 100644 --- a/src/faebryk/libs/picker/api/picker_lib.py +++ b/src/faebryk/libs/picker/api/picker_lib.py @@ -167,9 +167,7 @@ def find_resistor(cmp: Module): parts = client.fetch_parts( "find_resistors", { - "resistances": generate_si_values( - cmp.PARAMs.resistance, "Ω", E_SERIES_VALUES.E96 - ), + "resistances": generate_si_values(cmp.resistance, "Ω", E_SERIES_VALUES.E96), "footprint_candidates": get_footprint_candidates(cmp), "qty": qty, }, @@ -189,7 +187,7 @@ def find_capacitor(cmp: Module): "find_capacitors", { "capacitances": generate_si_values( - cmp.PARAMs.capacitance, "F", E_SERIES_VALUES.E6 + cmp.capacitance, "F", E_SERIES_VALUES.E6 ), "footprint_candidates": get_footprint_candidates(cmp), "qty": qty, @@ -209,9 +207,7 @@ def find_inductor(cmp: Module): parts = client.fetch_parts( "find_inductors", { - "inductances": generate_si_values( - cmp.PARAMs.inductance, "H", E_SERIES_VALUES.E24 - ), + "inductances": generate_si_values(cmp.inductance, "H", E_SERIES_VALUES.E24), "footprint_candidates": get_footprint_candidates(cmp), "qty": qty, }, diff --git a/src/faebryk/libs/picker/jlcpcb/picker_lib.py b/src/faebryk/libs/picker/jlcpcb/picker_lib.py index 30e7fac8..a7dd988c 100644 --- a/src/faebryk/libs/picker/jlcpcb/picker_lib.py +++ b/src/faebryk/libs/picker/jlcpcb/picker_lib.py @@ -350,8 +350,8 @@ def find_resistor(cmp: Module): .filter_by_category("Resistors", "Chip Resistor - Surface Mount") .filter_by_stock(qty) .filter_by_si_values( - cmp.PARAMs.resistance, - generate_si_values(cmp.PARAMs.resistance, "Ω", E_SERIES_VALUES.E96), + cmp.resistance, + generate_si_values(cmp.resistance, "Ω", E_SERIES_VALUES.E96), ) .filter_by_traits(cmp) .sort_by_price(qty) @@ -377,8 +377,8 @@ def find_capacitor(cmp: Module): .filter_by_stock(qty) .filter_by_traits(cmp) .filter_by_si_values( - cmp.PARAMs.capacitance, - generate_si_values(cmp.PARAMs.capacitance, "F", E_SERIES_VALUES.E24), + cmp.capacitance, + generate_si_values(cmp.capacitance, "F", E_SERIES_VALUES.E24), ) .sort_by_price(qty) .filter_by_module_params_and_attach(cmp, mapping, qty) @@ -405,8 +405,8 @@ def find_inductor(cmp: Module): .filter_by_stock(qty) .filter_by_traits(cmp) .filter_by_si_values( - cmp.PARAMs.inductance, - generate_si_values(cmp.PARAMs.inductance, "H", E_SERIES_VALUES.E24), + cmp.inductance, + generate_si_values(cmp.inductance, "H", E_SERIES_VALUES.E24), ) .sort_by_price(qty) .filter_by_module_params_and_attach(cmp, mapping, qty) From 2fc6ad9a3aa6186138c41c61342a316f035b3a51 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Wed, 16 Oct 2024 15:41:37 -0700 Subject: [PATCH 07/31] fix for extra diode filters --- src/faebryk/libs/picker/api/picker_lib.py | 6 ++++++ src/faebryk/libs/picker/jlcpcb/picker_lib.py | 10 ++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/faebryk/libs/picker/api/picker_lib.py b/src/faebryk/libs/picker/api/picker_lib.py index d8b74018..7fde8c21 100644 --- a/src/faebryk/libs/picker/api/picker_lib.py +++ b/src/faebryk/libs/picker/api/picker_lib.py @@ -244,6 +244,12 @@ def find_diode(cmp: Module): parts = client.fetch_parts( "find_diodes", { + "max_currents": generate_si_values( + cmp.max_current, "A", E_SERIES_VALUES.E3 + ), + "reverse_working_voltages": generate_si_values( + cmp.reverse_working_voltage, "V", E_SERIES_VALUES.E3 + ), "footprint_candidates": get_footprint_candidates(cmp), "qty": qty, }, diff --git a/src/faebryk/libs/picker/jlcpcb/picker_lib.py b/src/faebryk/libs/picker/jlcpcb/picker_lib.py index a7dd988c..b1ea9b43 100644 --- a/src/faebryk/libs/picker/jlcpcb/picker_lib.py +++ b/src/faebryk/libs/picker/jlcpcb/picker_lib.py @@ -450,8 +450,14 @@ def find_diode(cmp: Module): ComponentQuery() .filter_by_category("Diodes", "") .filter_by_stock(qty) - .filter_by_value(cmp.max_current, "A", E_SERIES_VALUES.E3) - .filter_by_value(cmp.reverse_working_voltage, "V", E_SERIES_VALUES.E3) + .filter_by_si_values( + cmp.max_current, + generate_si_values(cmp.max_current, "A", E_SERIES_VALUES.E3), + ) + .filter_by_si_values( + cmp.reverse_working_voltage, + generate_si_values(cmp.reverse_working_voltage, "V", E_SERIES_VALUES.E3), + ) .filter_by_traits(cmp) .sort_by_price(qty) .filter_by_module_params_and_attach(cmp, mapping, qty) From 4877603e43fb7fa078baa434447893fa95f389b5 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Wed, 16 Oct 2024 15:41:54 -0700 Subject: [PATCH 08/31] more Component.PARAMs --- test/libs/picker/test_api.py | 164 ++++++++++++-------------------- test/libs/picker/test_jlcpcb.py | 16 ++-- 2 files changed, 70 insertions(+), 110 deletions(-) diff --git a/test/libs/picker/test_api.py b/test/libs/picker/test_api.py index 4717a764..de00db45 100644 --- a/test/libs/picker/test_api.py +++ b/test/libs/picker/test_api.py @@ -88,9 +88,7 @@ def satisfies_requirements(self): ).get_properties()[DescriptiveProperties.partno], ) - for req, res in zip( - self.requirement.PARAMs.get_all(), self.result.PARAMs.get_all() - ): + for req, res in zip(self.requirement.get_all(), self.result.get_all()): req = req.get_most_narrow() res = res.get_most_narrow() @@ -154,17 +152,15 @@ def test(self): def test_find_manufacturer_partnumber(self): requirement = F.OpAmp().builder( lambda r: ( - r.PARAMs.bandwidth.merge(F.Range.upper_bound(1 * P.Mhertz)), - r.PARAMs.common_mode_rejection_ratio.merge( + r.bandwidth.merge(F.Range.upper_bound(1 * P.Mhertz)), + r.common_mode_rejection_ratio.merge( F.Range.lower_bound(Quantity(50, P.dB)) ), - r.PARAMs.input_bias_current.merge(F.Range.upper_bound(1 * P.nA)), - r.PARAMs.input_offset_voltage.merge(F.Range.upper_bound(1 * P.mV)), - r.PARAMs.gain_bandwidth_product.merge( - F.Range.upper_bound(1 * P.Mhertz) - ), - r.PARAMs.output_current.merge(F.Range.upper_bound(1 * P.mA)), - r.PARAMs.slew_rate.merge(F.Range.upper_bound(1 * P.MV / P.us)), + r.input_bias_current.merge(F.Range.upper_bound(1 * P.nA)), + r.input_offset_voltage.merge(F.Range.upper_bound(1 * P.mV)), + r.gain_bandwidth_product.merge(F.Range.upper_bound(1 * P.Mhertz)), + r.output_current.merge(F.Range.upper_bound(1 * P.mA)), + r.slew_rate.merge(F.Range.upper_bound(1 * P.MV / P.us)), ) ) requirement.add_trait( @@ -184,17 +180,15 @@ def test_find_manufacturer_partnumber(self): def test_find_lcsc_partnumber(self): requirement = F.OpAmp().builder( lambda r: ( - r.PARAMs.bandwidth.merge(F.Range.upper_bound(1 * P.Mhertz)), - r.PARAMs.common_mode_rejection_ratio.merge( + r.bandwidth.merge(F.Range.upper_bound(1 * P.Mhertz)), + r.common_mode_rejection_ratio.merge( F.Range.lower_bound(Quantity(50, P.dB)) ), - r.PARAMs.input_bias_current.merge(F.Range.upper_bound(1 * P.nA)), - r.PARAMs.input_offset_voltage.merge(F.Range.upper_bound(1 * P.mV)), - r.PARAMs.gain_bandwidth_product.merge( - F.Range.upper_bound(1 * P.Mhertz) - ), - r.PARAMs.output_current.merge(F.Range.upper_bound(1 * P.mA)), - r.PARAMs.slew_rate.merge(F.Range.upper_bound(1 * P.MV / P.us)), + r.input_bias_current.merge(F.Range.upper_bound(1 * P.nA)), + r.input_offset_voltage.merge(F.Range.upper_bound(1 * P.mV)), + r.gain_bandwidth_product.merge(F.Range.upper_bound(1 * P.Mhertz)), + r.output_current.merge(F.Range.upper_bound(1 * P.mA)), + r.slew_rate.merge(F.Range.upper_bound(1 * P.MV / P.us)), ) ) requirement.add_trait( @@ -215,11 +209,9 @@ def test_find_resistor(self): self, requirement=F.Resistor().builder( lambda r: ( - r.PARAMs.resistance.merge( - F.Range.from_center(10 * P.kohm, 1 * P.kohm) - ), - r.PARAMs.rated_power.merge(F.Range.lower_bound(0.05 * P.W)), - r.PARAMs.rated_voltage.merge(F.Range.lower_bound(25 * P.V)), + r.resistance.merge(F.Range.from_center(10 * P.kohm, 1 * P.kohm)), + r.rated_power.merge(F.Range.lower_bound(0.05 * P.W)), + r.rated_voltage.merge(F.Range.lower_bound(25 * P.V)), ) ), footprint=[("0402", 2)], @@ -229,11 +221,9 @@ def test_find_resistor(self): self, requirement=F.Resistor().builder( lambda r: ( - r.PARAMs.resistance.merge( - F.Range.from_center(69 * P.kohm, 2 * P.kohm) - ), - r.PARAMs.rated_power.merge(F.Range.lower_bound(0.1 * P.W)), - r.PARAMs.rated_voltage.merge(F.Range.lower_bound(50 * P.V)), + r.resistance.merge(F.Range.from_center(69 * P.kohm, 2 * P.kohm)), + r.rated_power.merge(F.Range.lower_bound(0.1 * P.W)), + r.rated_voltage.merge(F.Range.lower_bound(50 * P.V)), ) ), footprint=[("0603", 2)], @@ -244,11 +234,9 @@ def test_find_capacitor(self): self, requirement=F.Capacitor().builder( lambda c: ( - c.PARAMs.capacitance.merge( - F.Range.from_center(100 * P.nF, 10 * P.nF) - ), - c.PARAMs.rated_voltage.merge(F.Range.lower_bound(25 * P.V)), - c.PARAMs.temperature_coefficient.merge( + c.capacitance.merge(F.Range.from_center(100 * P.nF, 10 * P.nF)), + c.rated_voltage.merge(F.Range.lower_bound(25 * P.V)), + c.temperature_coefficient.merge( F.Range.lower_bound(F.Capacitor.TemperatureCoefficient.X7R) ), ) @@ -260,11 +248,9 @@ def test_find_capacitor(self): self, requirement=F.Capacitor().builder( lambda c: ( - c.PARAMs.capacitance.merge( - F.Range.from_center(47 * P.pF, 4.7 * P.pF) - ), - c.PARAMs.rated_voltage.merge(F.Range.lower_bound(50 * P.V)), - c.PARAMs.temperature_coefficient.merge( + c.capacitance.merge(F.Range.from_center(47 * P.pF, 4.7 * P.pF)), + c.rated_voltage.merge(F.Range.lower_bound(50 * P.V)), + c.temperature_coefficient.merge( F.Range.lower_bound(F.Capacitor.TemperatureCoefficient.C0G) ), ) @@ -277,12 +263,10 @@ def test_find_inductor(self): self, requirement=F.Inductor().builder( lambda i: ( - i.PARAMs.inductance.merge( - F.Range.from_center(4.7 * P.nH, 0.47 * P.nH) - ), - i.PARAMs.rated_current.merge(F.Range.lower_bound(0.01 * P.A)), - i.PARAMs.dc_resistance.merge(F.Range.upper_bound(1 * P.ohm)), - i.PARAMs.self_resonant_frequency.merge( + i.inductance.merge(F.Range.from_center(4.7 * P.nH, 0.47 * P.nH)), + i.rated_current.merge(F.Range.lower_bound(0.01 * P.A)), + i.dc_resistance.merge(F.Range.upper_bound(1 * P.ohm)), + i.self_resonant_frequency.merge( F.Range.lower_bound(100 * P.Mhertz) ), ) @@ -295,22 +279,14 @@ def test_find_mosfet(self): self, requirement=F.MOSFET().builder( lambda m: ( - m.PARAMs.channel_type.merge( - F.Constant(F.MOSFET.ChannelType.N_CHANNEL) - ), - m.PARAMs.saturation_type.merge( + m.channel_type.merge(F.Constant(F.MOSFET.ChannelType.N_CHANNEL)), + m.saturation_type.merge( F.Constant(F.MOSFET.SaturationType.ENHANCEMENT) ), - m.PARAMs.gate_source_threshold_voltage.merge( - F.Range(0.4 * P.V, 3 * P.V) - ), - m.PARAMs.max_drain_source_voltage.merge( - F.Range.lower_bound(20 * P.V) - ), - m.PARAMs.max_continuous_drain_current.merge( - F.Range.lower_bound(2 * P.A) - ), - m.PARAMs.on_resistance.merge(F.Range.upper_bound(0.1 * P.ohm)), + m.gate_source_threshold_voltage.merge(F.Range(0.4 * P.V, 3 * P.V)), + m.max_drain_source_voltage.merge(F.Range.lower_bound(20 * P.V)), + m.max_continuous_drain_current.merge(F.Range.lower_bound(2 * P.A)), + m.on_resistance.merge(F.Range.upper_bound(0.1 * P.ohm)), ) ), footprint=[("SOT-23", 3)], @@ -321,15 +297,11 @@ def test_find_diode(self): self, requirement=F.Diode().builder( lambda d: ( - d.PARAMs.current.merge(F.Range.lower_bound(1 * P.A)), - d.PARAMs.forward_voltage.merge(F.Range.upper_bound(1.7 * P.V)), - d.PARAMs.reverse_working_voltage.merge( - F.Range.lower_bound(20 * P.V) - ), - d.PARAMs.reverse_leakage_current.merge( - F.Range.upper_bound(100 * P.uA) - ), - d.PARAMs.max_current.merge(F.Range.lower_bound(1 * P.A)), + d.current.merge(F.Range.lower_bound(1 * P.A)), + d.forward_voltage.merge(F.Range.upper_bound(1.7 * P.V)), + d.reverse_working_voltage.merge(F.Range.lower_bound(20 * P.V)), + d.reverse_leakage_current.merge(F.Range.upper_bound(100 * P.uA)), + d.max_current.merge(F.Range.lower_bound(1 * P.A)), ) ), footprint=[("SOD-123", 2)], @@ -340,18 +312,16 @@ def test_find_led(self): self, requirement=F.LED().builder( lambda led: ( - led.PARAMs.color.merge(F.LED.Color.RED), - led.PARAMs.brightness.merge( + led.color.merge(F.LED.Color.RED), + led.brightness.merge( TypicalLuminousIntensity.APPLICATION_LED_INDICATOR_INSIDE.value.value ), # TODO: check semantics of F.ANY vs F.TBD - led.PARAMs.reverse_leakage_current.merge(F.ANY()), - led.PARAMs.reverse_working_voltage.merge(F.ANY()), - led.PARAMs.max_brightness.merge( - F.Range.lower_bound(100 * P.millicandela) - ), - led.PARAMs.forward_voltage.merge(F.Range.upper_bound(2.5 * P.V)), - led.PARAMs.max_current.merge(F.Range.upper_bound(20 * P.mA)), + led.reverse_leakage_current.merge(F.ANY()), + led.reverse_working_voltage.merge(F.ANY()), + led.max_brightness.merge(F.Range.lower_bound(100 * P.millicandela)), + led.forward_voltage.merge(F.Range.upper_bound(2.5 * P.V)), + led.max_current.merge(F.Range.upper_bound(20 * P.mA)), ) ), footprint=[("0805", 2)], @@ -364,16 +334,12 @@ def test_find_tvs(self): lambda t: ( # TODO: There is no current specified for TVS diodes, only peak # current - t.PARAMs.current.merge(F.ANY()), - t.PARAMs.forward_voltage.merge(F.ANY()), - t.PARAMs.reverse_working_voltage.merge( - F.Range.lower_bound(5 * P.V) - ), - t.PARAMs.reverse_leakage_current.merge(F.ANY()), - t.PARAMs.max_current.merge(F.Range.lower_bound(10 * P.A)), - t.PARAMs.reverse_breakdown_voltage.merge( - F.Range.upper_bound(8 * P.V) - ), + t.current.merge(F.ANY()), + t.forward_voltage.merge(F.ANY()), + t.reverse_working_voltage.merge(F.Range.lower_bound(5 * P.V)), + t.reverse_leakage_current.merge(F.ANY()), + t.max_current.merge(F.Range.lower_bound(10 * P.A)), + t.reverse_breakdown_voltage.merge(F.Range.upper_bound(8 * P.V)), ) ), footprint=[("SMB(DO-214AA)", 2)], @@ -384,18 +350,14 @@ def test_find_ldo(self): self, F.LDO().builder( lambda u: ( - u.PARAMs.output_voltage.merge( - F.Range.from_center(3.3 * P.V, 0.1 * P.V) - ), - u.PARAMs.output_current.merge(F.Range.lower_bound(0.1 * P.A)), - u.PARAMs.max_input_voltage.merge(F.Range.lower_bound(5 * P.V)), - u.PARAMs.dropout_voltage.merge(F.Range.upper_bound(1 * P.V)), - u.PARAMs.output_polarity.merge( - F.Constant(F.LDO.OutputPolarity.POSITIVE) - ), - u.PARAMs.output_type.merge(F.Constant(F.LDO.OutputType.FIXED)), - u.PARAMs.psrr.merge(F.ANY()), - u.PARAMs.quiescent_current.merge(F.ANY()), + u.output_voltage.merge(F.Range.from_center(3.3 * P.V, 0.1 * P.V)), + u.output_current.merge(F.Range.lower_bound(0.1 * P.A)), + u.max_input_voltage.merge(F.Range.lower_bound(5 * P.V)), + u.dropout_voltage.merge(F.Range.upper_bound(1 * P.V)), + u.output_polarity.merge(F.Constant(F.LDO.OutputPolarity.POSITIVE)), + u.output_type.merge(F.Constant(F.LDO.OutputType.FIXED)), + u.psrr.merge(F.ANY()), + u.quiescent_current.merge(F.ANY()), ) ), footprint=[ diff --git a/test/libs/picker/test_jlcpcb.py b/test/libs/picker/test_jlcpcb.py index eb098e0c..c03a82aa 100644 --- a/test/libs/picker/test_jlcpcb.py +++ b/test/libs/picker/test_jlcpcb.py @@ -321,18 +321,16 @@ def test_find_led(self): self, requirement=F.LED().builder( lambda led: ( - led.PARAMs.color.merge(F.LED.Color.RED), - led.PARAMs.brightness.merge( + led.color.merge(F.LED.Color.RED), + led.brightness.merge( TypicalLuminousIntensity.APPLICATION_LED_INDICATOR_INSIDE.value.value ), # TODO: check semantics of F.ANY vs F.TBD - led.PARAMs.reverse_leakage_current.merge(F.ANY()), - led.PARAMs.reverse_working_voltage.merge(F.ANY()), - led.PARAMs.max_brightness.merge( - F.Range.lower_bound(100 * P.millicandela) - ), - led.PARAMs.forward_voltage.merge(F.Range.upper_bound(2.5 * P.V)), - led.PARAMs.max_current.merge(F.Range.upper_bound(20 * P.mA)), + led.reverse_leakage_current.merge(F.ANY()), + led.reverse_working_voltage.merge(F.ANY()), + led.max_brightness.merge(F.Range.lower_bound(100 * P.millicandela)), + led.forward_voltage.merge(F.Range.upper_bound(2.5 * P.V)), + led.max_current.merge(F.Range.upper_bound(20 * P.mA)), ) ), footprint=[("0805", 2)], From 202a45526d4dc5cf5981266d92ee6b8db4e3ad11 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Wed, 16 Oct 2024 15:55:28 -0700 Subject: [PATCH 09/31] update api tests to match jlcpcb test changes --- test/libs/picker/test_api.py | 22 ++++++++++------------ test/libs/picker/test_jlcpcb.py | 8 +------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/test/libs/picker/test_api.py b/test/libs/picker/test_api.py index de00db45..295bc815 100644 --- a/test/libs/picker/test_api.py +++ b/test/libs/picker/test_api.py @@ -7,6 +7,7 @@ import faebryk.library._F as F from faebryk.core.module import Module +from faebryk.core.parameter import Parameter from faebryk.libs.brightness import TypicalLuminousIntensity from faebryk.libs.logging import setup_basic_logging from faebryk.libs.picker.api.pickers import add_api_pickers @@ -51,7 +52,7 @@ def __init__( F.has_descriptive_properties ).get_properties()[DescriptiveProperties.partno] - requirement.add_trait(F.has_footprint_requirement_defined(footprint)) + requirement.add(F.has_footprint_requirement_defined(footprint)) self.test() @@ -88,7 +89,10 @@ def satisfies_requirements(self): ).get_properties()[DescriptiveProperties.partno], ) - for req, res in zip(self.requirement.get_all(), self.result.get_all()): + for req, res in zip( + self.requirement.get_children(direct_only=True, types=Parameter), + self.result.get_children(direct_only=True, types=Parameter), + ): req = req.get_most_narrow() res = res.get_most_narrow() @@ -163,8 +167,8 @@ def test_find_manufacturer_partnumber(self): r.slew_rate.merge(F.Range.upper_bound(1 * P.MV / P.us)), ) ) - requirement.add_trait( - F.has_defined_descriptive_properties( + requirement.add( + F.has_descriptive_properties_defined( { DescriptiveProperties.partno: "LMV321IDBVR", DescriptiveProperties.manufacturer: "Texas Instruments", @@ -191,13 +195,7 @@ def test_find_lcsc_partnumber(self): r.slew_rate.merge(F.Range.upper_bound(1 * P.MV / P.us)), ) ) - requirement.add_trait( - F.has_defined_descriptive_properties( - { - "LCSC": "C7972", - } - ) - ) + requirement.add(F.has_descriptive_properties_defined({"LCSC": "C7972"})) self.TestRequirements( self, requirement=requirement, @@ -352,7 +350,7 @@ def test_find_ldo(self): lambda u: ( u.output_voltage.merge(F.Range.from_center(3.3 * P.V, 0.1 * P.V)), u.output_current.merge(F.Range.lower_bound(0.1 * P.A)), - u.max_input_voltage.merge(F.Range.lower_bound(5 * P.V)), + u.power_in.voltage.merge(5 * P.V), u.dropout_voltage.merge(F.Range.upper_bound(1 * P.V)), u.output_polarity.merge(F.Constant(F.LDO.OutputPolarity.POSITIVE)), u.output_type.merge(F.Constant(F.LDO.OutputType.FIXED)), diff --git a/test/libs/picker/test_jlcpcb.py b/test/libs/picker/test_jlcpcb.py index c03a82aa..ed6f4f32 100644 --- a/test/libs/picker/test_jlcpcb.py +++ b/test/libs/picker/test_jlcpcb.py @@ -200,13 +200,7 @@ def test_find_lcsc_partnumber(self): r.slew_rate.merge(F.Range.upper_bound(1 * P.MV / P.us)), ) ) - requirement.add( - F.has_descriptive_properties_defined( - { - "LCSC": "C7972", - } - ) - ) + requirement.add(F.has_descriptive_properties_defined({"LCSC": "C7972"})) self.TestRequirements( self, requirement=requirement, From 75a1df5f7c58f006de0b77f551ef6a638d8780a6 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Wed, 16 Oct 2024 16:23:12 -0700 Subject: [PATCH 10/31] fix for recent changes --- src/faebryk/libs/picker/api/api.py | 8 +++++++- src/faebryk/libs/picker/api/pickers.py | 12 ++---------- src/faebryk/libs/picker/jlcpcb/jlcpcb.py | 5 ++--- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/faebryk/libs/picker/api/api.py b/src/faebryk/libs/picker/api/api.py index 84c76628..419f21e8 100644 --- a/src/faebryk/libs/picker/api/api.py +++ b/src/faebryk/libs/picker/api/api.py @@ -6,6 +6,7 @@ import textwrap from dataclasses import dataclass +from pint import DimensionalityError from supabase import Client, create_client from supabase.client import ClientOptions @@ -16,6 +17,7 @@ from faebryk.libs.picker.jlcpcb.jlcpcb import Component, MappingParameterDB from faebryk.libs.picker.lcsc import LCSC_NoDataException, LCSC_PinmapException from faebryk.libs.picker.picker import PickError +from faebryk.libs.util import try_or logger = logging.getLogger(__name__) @@ -44,7 +46,11 @@ def check_compatible_parameters( params = component.get_params(mapping) param_matches = [ - p.is_subset_of(getattr(module.PARAMs, m.param_name)) + try_or( + lambda: p.is_subset_of(getattr(module, m.param_name)), + default=False, + catch=DimensionalityError, + ) for p, m in zip(params, mapping) ] diff --git a/src/faebryk/libs/picker/api/pickers.py b/src/faebryk/libs/picker/api/pickers.py index 66be729c..a4a7ab34 100644 --- a/src/faebryk/libs/picker/api/pickers.py +++ b/src/faebryk/libs/picker/api/pickers.py @@ -71,16 +71,8 @@ def pick(self, module: Module): def add_api_pickers(module: Module, base_prio: int = 0) -> None: # Generic pickers - F.has_multi_picker.add_to_module( - module, - base_prio, - ApiPicker(P.find_lcsc_part), - ) - F.has_multi_picker.add_to_module( - module, - base_prio, - ApiPicker(P.find_manufacturer_part), - ) + module.add(F.has_multi_picker(base_prio, ApiPicker(P.find_and_attach_by_lcsc_id))) + module.add(F.has_multi_picker(base_prio, ApiPicker(P.find_and_attach_by_mfr))) # Type-specific pickers F.has_multi_picker.add_pickers_by_type( diff --git a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py index 12246634..b2068ee4 100644 --- a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py +++ b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py @@ -346,9 +346,8 @@ def attach( F.has_descriptive_properties_defined( { DescriptiveProperties.partno: self.mfr, - DescriptiveProperties.manufacturer: asyncio.run( - Manufacturers().get_from_id(self.manufacturer_id) - ), + DescriptiveProperties.manufacturer: self.manufacturer_name + or asyncio.run(Manufacturers().get_from_id(self.manufacturer_id)), DescriptiveProperties.datasheet: self.datasheet, "JLCPCB stock": str(self.stock), "JLCPCB price": f"{self.get_price(qty):.4f}", From f7e77665337c126ac1039b254028153ee5681dd0 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Wed, 16 Oct 2024 16:41:22 -0700 Subject: [PATCH 11/31] fix capacitor e-series --- src/faebryk/libs/picker/api/picker_lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/faebryk/libs/picker/api/picker_lib.py b/src/faebryk/libs/picker/api/picker_lib.py index 7fde8c21..88f9b2a1 100644 --- a/src/faebryk/libs/picker/api/picker_lib.py +++ b/src/faebryk/libs/picker/api/picker_lib.py @@ -187,7 +187,7 @@ def find_capacitor(cmp: Module): "find_capacitors", { "capacitances": generate_si_values( - cmp.capacitance, "F", E_SERIES_VALUES.E6 + cmp.capacitance, "F", E_SERIES_VALUES.E24 ), "footprint_candidates": get_footprint_candidates(cmp), "qty": qty, From 51b055041c0bbebe1983e00b5f457834b00e1ae8 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Wed, 16 Oct 2024 16:41:39 -0700 Subject: [PATCH 12/31] add api picker perf test --- test/libs/picker/test_api.py | 81 ++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/test/libs/picker/test_api.py b/test/libs/picker/test_api.py index 295bc815..3d58c0b4 100644 --- a/test/libs/picker/test_api.py +++ b/test/libs/picker/test_api.py @@ -12,6 +12,7 @@ from faebryk.libs.logging import setup_basic_logging from faebryk.libs.picker.api.pickers import add_api_pickers from faebryk.libs.picker.picker import DescriptiveProperties, has_part_picked +from faebryk.libs.test.times import Times from faebryk.libs.units import P, Quantity logger = logging.getLogger(__name__) @@ -367,6 +368,86 @@ def test_find_ldo(self): ) +@unittest.skipIf(not os.getenv("FBRK_PICKER") == "api", reason="Requires API info") +class TestPickerPerformanceApi(unittest.TestCase): + def test_simple_full(self): + # conclusions + # - first pick overall is slow, need to load sqlite into buffer cache + # - first pick of component type is slower than subsequent picks + # (even with different parameters) + # - component type order has no influence + # - component type speed differs a lot (res = 500ms, cap = 100ms) + # (even though both value based) + # e-series speed (query or count), if resistor with E24, 200ms + # still 2x though, maybe total count? + # - e-series intersect 20% execution time + # => optimized with cache + + timings = Times() + + def r_builder(resistance_kohm: float): + return F.Resistor().builder( + lambda r: ( + r.resistance.merge( + F.Range.from_center_rel(resistance_kohm * P.kohm, 0.1) + ), + r.rated_power.merge(F.ANY()), + r.rated_voltage.merge(F.ANY()), + ) + ) + + def c_builder(capacitance_pf: float): + return F.Capacitor().builder( + lambda c: ( + c.capacitance.merge( + F.Range.from_center_rel(capacitance_pf * P.pF, 0.1) + ), + c.rated_voltage.merge(F.ANY()), + c.temperature_coefficient.merge(F.ANY()), + ) + ) + + resistors = [r_builder(5 * (i + 1)) for i in range(5)] + [ + r_builder(5 * (i + 1)) for i in reversed(range(5)) + ] + caps = [c_builder(10 * (i + 1)) for i in range(5)] + [ + c_builder(10 * (i + 1)) for i in reversed(range(5)) + ] + resistors_10k = [r_builder(10) for _ in range(10)] + + mods = resistors + caps + resistors_10k + + for mod in mods: + add_api_pickers(mod) + + with timings.context("resistors"): + for i, r in enumerate(resistors): + r.get_trait(F.has_picker).pick() + timings.add( + f"full pick value pick (resistor {i}:" + f" {r.resistance.as_unit_with_tolerance('ohm')})" + ) + + # cache is warm now, but also for non resistors? + with timings.context("capacitors"): + for i, c in enumerate(caps): + c.get_trait(F.has_picker).pick() + timings.add( + f"full pick value pick (capacitor {i}:" + f" {c.capacitance.as_unit_with_tolerance('F')})" + ) + + with timings.context("resistors_10k"): + for i, r in enumerate(resistors_10k): + r.get_trait(F.has_picker).pick() + timings.add( + f"full pick value pick (resistor {i}:" + f" {r.resistance.as_unit_with_tolerance('ohm')})" + ) + + print(timings) + + if __name__ == "__main__": setup_basic_logging() logger.setLevel(logging.DEBUG) From dfed1ef336a51517dfa0adb5f2af54f7b20b0834 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Wed, 16 Oct 2024 18:17:06 -0700 Subject: [PATCH 13/31] fix manufacturer_name sometimes available --- src/faebryk/libs/picker/jlcpcb/jlcpcb.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py index b2068ee4..80325be0 100644 --- a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py +++ b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py @@ -346,8 +346,7 @@ def attach( F.has_descriptive_properties_defined( { DescriptiveProperties.partno: self.mfr, - DescriptiveProperties.manufacturer: self.manufacturer_name - or asyncio.run(Manufacturers().get_from_id(self.manufacturer_id)), + DescriptiveProperties.manufacturer: self.mfr_name, DescriptiveProperties.datasheet: self.datasheet, "JLCPCB stock": str(self.stock), "JLCPCB price": f"{self.get_price(qty):.4f}", @@ -368,8 +367,11 @@ def attach( ) @property - def mfr_name(self) -> str: - return asyncio.run(Manufacturers().get_from_id(self.manufacturer_id)) + def mfr_name(self): + try: + return self.manufacturer_name + except AttributeError: + return asyncio.run(Manufacturers().get_from_id(self.manufacturer_id)) class ComponentQuery: From c8d38aa4bcb1e4b1af5a91603fa7a365a05a2efc Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Mon, 21 Oct 2024 12:41:12 -0700 Subject: [PATCH 14/31] dedup picker tests --- test/libs/picker/test_api.py | 455 ------------------ .../{test_jlcpcb.py => test_pickers.py} | 82 +++- 2 files changed, 68 insertions(+), 469 deletions(-) delete mode 100644 test/libs/picker/test_api.py rename test/libs/picker/{test_jlcpcb.py => test_pickers.py} (90%) diff --git a/test/libs/picker/test_api.py b/test/libs/picker/test_api.py deleted file mode 100644 index 3d58c0b4..00000000 --- a/test/libs/picker/test_api.py +++ /dev/null @@ -1,455 +0,0 @@ -# This file is part of the faebryk project -# SPDX-License-Identifier: MIT - -import logging -import os -import unittest - -import faebryk.library._F as F -from faebryk.core.module import Module -from faebryk.core.parameter import Parameter -from faebryk.libs.brightness import TypicalLuminousIntensity -from faebryk.libs.logging import setup_basic_logging -from faebryk.libs.picker.api.pickers import add_api_pickers -from faebryk.libs.picker.picker import DescriptiveProperties, has_part_picked -from faebryk.libs.test.times import Times -from faebryk.libs.units import P, Quantity - -logger = logging.getLogger(__name__) - - -# TODO: abstract out commonalities with test_jlcpcb.py -@unittest.skipIf(not os.getenv("FBRK_PICKER") == "api", reason="Requires API info") -class TestPickerApi(unittest.TestCase): - class TestRequirements: - def __init__( - self, - test_case: unittest.TestCase, - requirement: Module, - footprint: list[tuple[str, int]], - ): - self.test_case = test_case - self.result = requirement - self.requirement = requirement - self.footprint = footprint - - self.req_lcsc_pn = None - if self.requirement.has_trait(F.has_descriptive_properties) and "LCSC" in ( - self.requirement.get_trait(F.has_descriptive_properties).get_properties, - ): - self.req_lcsc_pn = self.requirement.get_trait( - F.has_descriptive_properties - ).get_properties()["LCSC"] - - self.req_manufacturer_pn = None - if ( - self.requirement.has_trait(F.has_descriptive_properties) - and DescriptiveProperties.partno - in self.requirement.get_trait( - F.has_descriptive_properties - ).get_properties() - ): - self.req_manufacturer_pn = self.requirement.get_trait( - F.has_descriptive_properties - ).get_properties()[DescriptiveProperties.partno] - - requirement.add(F.has_footprint_requirement_defined(footprint)) - - self.test() - - def satisfies_requirements(self): - self.test_case.assertTrue( - self.result.has_trait(F.has_descriptive_properties) - ) - if self.req_lcsc_pn is not None: - self.test_case.assertIn( - "LCSC", - self.result.get_trait( - F.has_descriptive_properties - ).get_properties(), - ) - - self.test_case.assertEqual( - self.req_lcsc_pn, - self.result.get_trait( - F.has_descriptive_properties - ).get_properties()["LCSC"], - ) - - if self.req_manufacturer_pn is not None: - self.test_case.assertIn( - DescriptiveProperties.partno, - self.result.get_trait( - F.has_descriptive_properties - ).get_properties(), - ) - self.test_case.assertEqual( - self.req_manufacturer_pn, - self.result.get_trait( - F.has_descriptive_properties - ).get_properties()[DescriptiveProperties.partno], - ) - - for req, res in zip( - self.requirement.get_children(direct_only=True, types=Parameter), - self.result.get_children(direct_only=True, types=Parameter), - ): - req = req.get_most_narrow() - res = res.get_most_narrow() - - if isinstance(req, F.Range): - self.test_case.assertTrue(res in req) - elif isinstance(req, F.Constant): - self.test_case.assertEqual(req, res) - elif isinstance(req, F.Set): - self.test_case.assertIn(res, req.params) - elif isinstance(req, F.TBD): - self.test_case.assertIsInstance(res, F.ANY) - elif isinstance(req, F.ANY): - self.test_case.assertIsInstance(res, F.ANY) - else: - raise NotImplementedError( - f"Unsupported type of parameter: {type(req)}: {req}" - ) - - def test(self): - add_api_pickers(self.result) - self.result.get_trait(F.has_picker).pick() - - self.test_case.assertTrue(self.result.has_trait(has_part_picked)) - - # check part number - self.test_case.assertTrue( - self.result.has_trait(F.has_descriptive_properties) - ) - self.test_case.assertIn( - DescriptiveProperties.partno, - self.result.get_trait(F.has_descriptive_properties).get_properties(), - ) - self.test_case.assertNotEqual( - "", - self.result.get_trait(F.has_descriptive_properties).get_properties()[ - DescriptiveProperties.partno - ], - ) - - # check footprint - self.test_case.assertTrue(self.result.has_trait(F.has_footprint)) - self.test_case.assertTrue( - self.result.get_trait(F.has_footprint) - .get_footprint() - .has_trait(F.has_kicad_footprint) - ) - # check pin count - self.test_case.assertEqual( - self.footprint[0][1], - len( - self.result.get_trait(F.has_footprint) - .get_footprint() - .get_trait(F.has_kicad_footprint) - .get_pin_names() - ), - ) - - # check requirements from module - self.satisfies_requirements() - - def test_find_manufacturer_partnumber(self): - requirement = F.OpAmp().builder( - lambda r: ( - r.bandwidth.merge(F.Range.upper_bound(1 * P.Mhertz)), - r.common_mode_rejection_ratio.merge( - F.Range.lower_bound(Quantity(50, P.dB)) - ), - r.input_bias_current.merge(F.Range.upper_bound(1 * P.nA)), - r.input_offset_voltage.merge(F.Range.upper_bound(1 * P.mV)), - r.gain_bandwidth_product.merge(F.Range.upper_bound(1 * P.Mhertz)), - r.output_current.merge(F.Range.upper_bound(1 * P.mA)), - r.slew_rate.merge(F.Range.upper_bound(1 * P.MV / P.us)), - ) - ) - requirement.add( - F.has_descriptive_properties_defined( - { - DescriptiveProperties.partno: "LMV321IDBVR", - DescriptiveProperties.manufacturer: "Texas Instruments", - } - ) - ) - self.TestRequirements( - self, - requirement=requirement, - footprint=[("SOT-23-5", 5)], - ) - - def test_find_lcsc_partnumber(self): - requirement = F.OpAmp().builder( - lambda r: ( - r.bandwidth.merge(F.Range.upper_bound(1 * P.Mhertz)), - r.common_mode_rejection_ratio.merge( - F.Range.lower_bound(Quantity(50, P.dB)) - ), - r.input_bias_current.merge(F.Range.upper_bound(1 * P.nA)), - r.input_offset_voltage.merge(F.Range.upper_bound(1 * P.mV)), - r.gain_bandwidth_product.merge(F.Range.upper_bound(1 * P.Mhertz)), - r.output_current.merge(F.Range.upper_bound(1 * P.mA)), - r.slew_rate.merge(F.Range.upper_bound(1 * P.MV / P.us)), - ) - ) - requirement.add(F.has_descriptive_properties_defined({"LCSC": "C7972"})) - self.TestRequirements( - self, - requirement=requirement, - footprint=[("SOT-23-5", 5)], - ) - - def test_find_resistor(self): - self.TestRequirements( - self, - requirement=F.Resistor().builder( - lambda r: ( - r.resistance.merge(F.Range.from_center(10 * P.kohm, 1 * P.kohm)), - r.rated_power.merge(F.Range.lower_bound(0.05 * P.W)), - r.rated_voltage.merge(F.Range.lower_bound(25 * P.V)), - ) - ), - footprint=[("0402", 2)], - ) - - self.TestRequirements( - self, - requirement=F.Resistor().builder( - lambda r: ( - r.resistance.merge(F.Range.from_center(69 * P.kohm, 2 * P.kohm)), - r.rated_power.merge(F.Range.lower_bound(0.1 * P.W)), - r.rated_voltage.merge(F.Range.lower_bound(50 * P.V)), - ) - ), - footprint=[("0603", 2)], - ) - - def test_find_capacitor(self): - self.TestRequirements( - self, - requirement=F.Capacitor().builder( - lambda c: ( - c.capacitance.merge(F.Range.from_center(100 * P.nF, 10 * P.nF)), - c.rated_voltage.merge(F.Range.lower_bound(25 * P.V)), - c.temperature_coefficient.merge( - F.Range.lower_bound(F.Capacitor.TemperatureCoefficient.X7R) - ), - ) - ), - footprint=[("0603", 2)], - ) - - self.TestRequirements( - self, - requirement=F.Capacitor().builder( - lambda c: ( - c.capacitance.merge(F.Range.from_center(47 * P.pF, 4.7 * P.pF)), - c.rated_voltage.merge(F.Range.lower_bound(50 * P.V)), - c.temperature_coefficient.merge( - F.Range.lower_bound(F.Capacitor.TemperatureCoefficient.C0G) - ), - ) - ), - footprint=[("0402", 2)], - ) - - def test_find_inductor(self): - self.TestRequirements( - self, - requirement=F.Inductor().builder( - lambda i: ( - i.inductance.merge(F.Range.from_center(4.7 * P.nH, 0.47 * P.nH)), - i.rated_current.merge(F.Range.lower_bound(0.01 * P.A)), - i.dc_resistance.merge(F.Range.upper_bound(1 * P.ohm)), - i.self_resonant_frequency.merge( - F.Range.lower_bound(100 * P.Mhertz) - ), - ) - ), - footprint=[("0603", 2)], - ) - - def test_find_mosfet(self): - self.TestRequirements( - self, - requirement=F.MOSFET().builder( - lambda m: ( - m.channel_type.merge(F.Constant(F.MOSFET.ChannelType.N_CHANNEL)), - m.saturation_type.merge( - F.Constant(F.MOSFET.SaturationType.ENHANCEMENT) - ), - m.gate_source_threshold_voltage.merge(F.Range(0.4 * P.V, 3 * P.V)), - m.max_drain_source_voltage.merge(F.Range.lower_bound(20 * P.V)), - m.max_continuous_drain_current.merge(F.Range.lower_bound(2 * P.A)), - m.on_resistance.merge(F.Range.upper_bound(0.1 * P.ohm)), - ) - ), - footprint=[("SOT-23", 3)], - ) - - def test_find_diode(self): - self.TestRequirements( - self, - requirement=F.Diode().builder( - lambda d: ( - d.current.merge(F.Range.lower_bound(1 * P.A)), - d.forward_voltage.merge(F.Range.upper_bound(1.7 * P.V)), - d.reverse_working_voltage.merge(F.Range.lower_bound(20 * P.V)), - d.reverse_leakage_current.merge(F.Range.upper_bound(100 * P.uA)), - d.max_current.merge(F.Range.lower_bound(1 * P.A)), - ) - ), - footprint=[("SOD-123", 2)], - ) - - def test_find_led(self): - self.TestRequirements( - self, - requirement=F.LED().builder( - lambda led: ( - led.color.merge(F.LED.Color.RED), - led.brightness.merge( - TypicalLuminousIntensity.APPLICATION_LED_INDICATOR_INSIDE.value.value - ), - # TODO: check semantics of F.ANY vs F.TBD - led.reverse_leakage_current.merge(F.ANY()), - led.reverse_working_voltage.merge(F.ANY()), - led.max_brightness.merge(F.Range.lower_bound(100 * P.millicandela)), - led.forward_voltage.merge(F.Range.upper_bound(2.5 * P.V)), - led.max_current.merge(F.Range.upper_bound(20 * P.mA)), - ) - ), - footprint=[("0805", 2)], - ) - - def test_find_tvs(self): - self.TestRequirements( - self, - requirement=F.TVS().builder( - lambda t: ( - # TODO: There is no current specified for TVS diodes, only peak - # current - t.current.merge(F.ANY()), - t.forward_voltage.merge(F.ANY()), - t.reverse_working_voltage.merge(F.Range.lower_bound(5 * P.V)), - t.reverse_leakage_current.merge(F.ANY()), - t.max_current.merge(F.Range.lower_bound(10 * P.A)), - t.reverse_breakdown_voltage.merge(F.Range.upper_bound(8 * P.V)), - ) - ), - footprint=[("SMB(DO-214AA)", 2)], - ) - - def test_find_ldo(self): - self.TestRequirements( - self, - F.LDO().builder( - lambda u: ( - u.output_voltage.merge(F.Range.from_center(3.3 * P.V, 0.1 * P.V)), - u.output_current.merge(F.Range.lower_bound(0.1 * P.A)), - u.power_in.voltage.merge(5 * P.V), - u.dropout_voltage.merge(F.Range.upper_bound(1 * P.V)), - u.output_polarity.merge(F.Constant(F.LDO.OutputPolarity.POSITIVE)), - u.output_type.merge(F.Constant(F.LDO.OutputType.FIXED)), - u.psrr.merge(F.ANY()), - u.quiescent_current.merge(F.ANY()), - ) - ), - footprint=[ - ("SOT-23", 3), - ("SOT23", 3), - ("SOT-23-3", 3), - ("SOT-23-3L", 3), - ], - ) - - -@unittest.skipIf(not os.getenv("FBRK_PICKER") == "api", reason="Requires API info") -class TestPickerPerformanceApi(unittest.TestCase): - def test_simple_full(self): - # conclusions - # - first pick overall is slow, need to load sqlite into buffer cache - # - first pick of component type is slower than subsequent picks - # (even with different parameters) - # - component type order has no influence - # - component type speed differs a lot (res = 500ms, cap = 100ms) - # (even though both value based) - # e-series speed (query or count), if resistor with E24, 200ms - # still 2x though, maybe total count? - # - e-series intersect 20% execution time - # => optimized with cache - - timings = Times() - - def r_builder(resistance_kohm: float): - return F.Resistor().builder( - lambda r: ( - r.resistance.merge( - F.Range.from_center_rel(resistance_kohm * P.kohm, 0.1) - ), - r.rated_power.merge(F.ANY()), - r.rated_voltage.merge(F.ANY()), - ) - ) - - def c_builder(capacitance_pf: float): - return F.Capacitor().builder( - lambda c: ( - c.capacitance.merge( - F.Range.from_center_rel(capacitance_pf * P.pF, 0.1) - ), - c.rated_voltage.merge(F.ANY()), - c.temperature_coefficient.merge(F.ANY()), - ) - ) - - resistors = [r_builder(5 * (i + 1)) for i in range(5)] + [ - r_builder(5 * (i + 1)) for i in reversed(range(5)) - ] - caps = [c_builder(10 * (i + 1)) for i in range(5)] + [ - c_builder(10 * (i + 1)) for i in reversed(range(5)) - ] - resistors_10k = [r_builder(10) for _ in range(10)] - - mods = resistors + caps + resistors_10k - - for mod in mods: - add_api_pickers(mod) - - with timings.context("resistors"): - for i, r in enumerate(resistors): - r.get_trait(F.has_picker).pick() - timings.add( - f"full pick value pick (resistor {i}:" - f" {r.resistance.as_unit_with_tolerance('ohm')})" - ) - - # cache is warm now, but also for non resistors? - with timings.context("capacitors"): - for i, c in enumerate(caps): - c.get_trait(F.has_picker).pick() - timings.add( - f"full pick value pick (capacitor {i}:" - f" {c.capacitance.as_unit_with_tolerance('F')})" - ) - - with timings.context("resistors_10k"): - for i, r in enumerate(resistors_10k): - r.get_trait(F.has_picker).pick() - timings.add( - f"full pick value pick (resistor {i}:" - f" {r.resistance.as_unit_with_tolerance('ohm')})" - ) - - print(timings) - - -if __name__ == "__main__": - setup_basic_logging() - logger.setLevel(logging.DEBUG) - - unittest.main() diff --git a/test/libs/picker/test_jlcpcb.py b/test/libs/picker/test_pickers.py similarity index 90% rename from test/libs/picker/test_jlcpcb.py rename to test/libs/picker/test_pickers.py index ed6f4f32..8e11f91d 100644 --- a/test/libs/picker/test_jlcpcb.py +++ b/test/libs/picker/test_pickers.py @@ -1,7 +1,10 @@ # This file is part of the faebryk project # SPDX-License-Identifier: MIT + import logging +import os import unittest +from abc import ABC, abstractmethod from pathlib import Path from tempfile import mkdtemp @@ -11,6 +14,7 @@ from faebryk.core.parameter import Parameter from faebryk.libs.brightness import TypicalLuminousIntensity from faebryk.libs.logging import setup_basic_logging +from faebryk.libs.picker.api.pickers import add_api_pickers from faebryk.libs.picker.jlcpcb.jlcpcb import JLCPCB_DB from faebryk.libs.picker.jlcpcb.pickers import add_jlcpcb_pickers from faebryk.libs.picker.picker import DescriptiveProperties, has_part_picked @@ -19,23 +23,27 @@ logger = logging.getLogger(__name__) - lcsc.LIB_FOLDER = Path(mkdtemp()) -@unittest.skipIf(not JLCPCB_DB.config.db_path.exists(), reason="Requires large db") -class TestPickerJlcpcb(unittest.TestCase): +class TestPickerBase(unittest.TestCase, ABC): + @abstractmethod + def add_pickers(self, module: Module): + pass + class TestRequirements: def __init__( self, test_case: unittest.TestCase, requirement: Module, footprint: list[tuple[str, int]], + add_pickers_func, ): self.test_case = test_case self.result = requirement self.requirement = requirement self.footprint = footprint + self.add_pickers_func = add_pickers_func self.req_lcsc_pn = None if self.requirement.has_trait(F.has_descriptive_properties) and "LCSC" in ( @@ -117,7 +125,7 @@ def satisfies_requirements(self): ) def test(self): - add_jlcpcb_pickers(self.result) + self.add_pickers_func(self.result) self.result.get_trait(F.has_picker).pick() self.test_case.assertTrue(self.result.has_trait(has_part_picked)) @@ -184,6 +192,7 @@ def test_find_manufacturer_partnumber(self): self, requirement=requirement, footprint=[("SOT-23-5", 5)], + add_pickers_func=self.add_pickers, ) def test_find_lcsc_partnumber(self): @@ -205,6 +214,7 @@ def test_find_lcsc_partnumber(self): self, requirement=requirement, footprint=[("SOT-23-5", 5)], + add_pickers_func=self.add_pickers, ) def test_find_resistor(self): @@ -218,6 +228,7 @@ def test_find_resistor(self): ) ), footprint=[("0402", 2)], + add_pickers_func=self.add_pickers, ) self.TestRequirements( @@ -230,6 +241,7 @@ def test_find_resistor(self): ) ), footprint=[("0603", 2)], + add_pickers_func=self.add_pickers, ) def test_find_capacitor(self): @@ -245,6 +257,7 @@ def test_find_capacitor(self): ) ), footprint=[("0603", 2)], + add_pickers_func=self.add_pickers, ) self.TestRequirements( @@ -259,6 +272,7 @@ def test_find_capacitor(self): ) ), footprint=[("0402", 2)], + add_pickers_func=self.add_pickers, ) def test_find_inductor(self): @@ -275,6 +289,7 @@ def test_find_inductor(self): ) ), footprint=[("0603", 2)], + add_pickers_func=self.add_pickers, ) def test_find_mosfet(self): @@ -293,6 +308,7 @@ def test_find_mosfet(self): ) ), footprint=[("SOT-23", 3)], + add_pickers_func=self.add_pickers, ) def test_find_diode(self): @@ -308,6 +324,7 @@ def test_find_diode(self): ) ), footprint=[("SOD-123", 2)], + add_pickers_func=self.add_pickers, ) def test_find_led(self): @@ -328,6 +345,7 @@ def test_find_led(self): ) ), footprint=[("0805", 2)], + add_pickers_func=self.add_pickers, ) def test_find_tvs(self): @@ -346,6 +364,7 @@ def test_find_tvs(self): ) ), footprint=[("SMB(DO-214AA)", 2)], + add_pickers_func=self.add_pickers, ) def test_find_ldo(self): @@ -369,19 +388,15 @@ def test_find_ldo(self): ("SOT-23-3", 3), ("SOT-23-3L", 3), ], + add_pickers_func=self.add_pickers, ) - def tearDown(self): - # in test atexit not triggered, thus need to close DB manually - JLCPCB_DB.get().close() - -def is_db_available(): - return JLCPCB_DB.config.db_path.exists() +class TestPickerPerformanceBase(unittest.TestCase, ABC): + @abstractmethod + def add_pickers(self, module: Module): + pass - -@unittest.skipIf(not is_db_available(), reason="Requires large db") -class TestPickerPerformanceJLCPCB(unittest.TestCase): def test_simple_full(self): # conclusions # - first pick overall is slow, need to load sqlite into buffer cache @@ -430,7 +445,7 @@ def c_builder(capacitance_pf: float): mods = resistors + caps + resistors_10k for mod in mods: - add_jlcpcb_pickers(mod) + self.add_pickers(mod) with timings.context("resistors"): for i, r in enumerate(resistors): @@ -460,6 +475,45 @@ def c_builder(capacitance_pf: float): print(timings) +def is_db_available(): + return JLCPCB_DB.config.db_path.exists() + + +def is_api_available(): + return os.getenv("FBRK_PICKER") == "api" + + +@unittest.skipIf(not is_db_available(), reason="Requires large db") +class TestPickerJlcpcb(TestPickerBase): + def add_pickers(self, module): + add_jlcpcb_pickers(module) + + def tearDown(self): + # in test atexit not triggered, thus need to close DB manually + JLCPCB_DB.get().close() + + +@unittest.skipIf(not is_db_available(), reason="Requires large db") +class TestPickerPerformanceJLCPCB(TestPickerPerformanceBase): + def add_pickers(self, module): + add_jlcpcb_pickers(module) + + def tearDown(self): + JLCPCB_DB.get().close() + + +@unittest.skipIf(not is_api_available(), reason="Requires API info") +class TestPickerApi(TestPickerBase): + def add_pickers(self, module): + add_api_pickers(module) + + +@unittest.skipIf(not is_api_available(), reason="Requires API info") +class TestPickerPerformanceApi(TestPickerPerformanceBase): + def add_pickers(self, module): + add_api_pickers(module) + + if __name__ == "__main__": setup_basic_logging() logger.setLevel(logging.DEBUG) From f6a27bc0f7411e8ac814e2e9d3f63ad01654f3b3 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Mon, 21 Oct 2024 12:49:33 -0700 Subject: [PATCH 15/31] run gen_F.py --- src/faebryk/library/_F.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/faebryk/library/_F.py b/src/faebryk/library/_F.py index 12340c67..e420a1a1 100644 --- a/src/faebryk/library/_F.py +++ b/src/faebryk/library/_F.py @@ -32,13 +32,13 @@ from faebryk.library.Operation import Operation from faebryk.library.has_linked_pad import has_linked_pad from faebryk.library.has_reference import has_reference +from faebryk.library.has_footprint_requirement import has_footprint_requirement from faebryk.library.can_bridge import can_bridge from faebryk.library.has_designator import has_designator from faebryk.library.has_descriptive_properties import has_descriptive_properties from faebryk.library.has_simple_value_representation import has_simple_value_representation from faebryk.library.has_capacitance import has_capacitance from faebryk.library.has_datasheet import has_datasheet -from faebryk.library.has_footprint_requirement import has_footprint_requirement from faebryk.library.has_kicad_ref import has_kicad_ref from faebryk.library.has_picker import has_picker from faebryk.library.has_pcb_layout import has_pcb_layout @@ -61,13 +61,13 @@ from faebryk.library.Footprint import Footprint from faebryk.library.has_overriden_name_defined import has_overriden_name_defined from faebryk.library.has_linked_pad_defined import has_linked_pad_defined +from faebryk.library.has_footprint_requirement_defined import has_footprint_requirement_defined from faebryk.library.can_bridge_defined import can_bridge_defined from faebryk.library.has_designator_defined import has_designator_defined from faebryk.library.has_descriptive_properties_defined import has_descriptive_properties_defined from faebryk.library.has_simple_value_representation_based_on_params import has_simple_value_representation_based_on_params from faebryk.library.has_simple_value_representation_defined import has_simple_value_representation_defined from faebryk.library.has_datasheet_defined import has_datasheet_defined -from faebryk.library.has_footprint_requirement_defined import has_footprint_requirement_defined from faebryk.library.has_multi_picker import has_multi_picker from faebryk.library.has_pcb_layout_defined import has_pcb_layout_defined from faebryk.library.has_single_connection_impl import has_single_connection_impl From a856ce1171c77d48a2f4d8c877060334a57697d9 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Mon, 21 Oct 2024 14:35:03 -0700 Subject: [PATCH 16/31] add lru cache on api queries --- src/faebryk/libs/picker/api/api.py | 139 +++++++++++++++++++--- src/faebryk/libs/picker/api/picker_lib.py | 119 +++++++++--------- 2 files changed, 184 insertions(+), 74 deletions(-) diff --git a/src/faebryk/libs/picker/api/api.py b/src/faebryk/libs/picker/api/api.py index 419f21e8..3db5a7af 100644 --- a/src/faebryk/libs/picker/api/api.py +++ b/src/faebryk/libs/picker/api/api.py @@ -1,16 +1,18 @@ # This file is part of the faebryk project # SPDX-License-Identifier: MIT +import functools +import json import logging import os import textwrap from dataclasses import dataclass +from typing import List from pint import DimensionalityError from supabase import Client, create_client from supabase.client import ClientOptions -import faebryk.library._F as F from faebryk.core.module import Module # TODO: replace with API-specific data model @@ -25,17 +27,6 @@ class ApiError(Exception): ... -def get_footprint_candidates(module: Module) -> list[dict] | None: - if module.has_trait(F.has_footprint_requirement): - return [ - {"footprint": footprint, "pin_count": pin_count} - for footprint, pin_count in module.get_trait( - F.has_footprint_requirement - ).get_footprint_requirement() - ] - return None - - def check_compatible_parameters( module: Module, component: Component, mapping: list[MappingParameterDB] ) -> bool: @@ -93,6 +84,101 @@ def try_attach( ) +@dataclass(frozen=True, eq=True) +class FootprintCandidate: + footprint: str + pin_count: int + + +@dataclass(frozen=True, eq=True) +class BaseParams: + footprint_candidates: List[FootprintCandidate] + qty: int + + def __hash__(self): + return hash( + ( + json.dumps(self.footprint_candidates, default=lambda o: o.__dict__), + self.qty, + ) + ) + + +@dataclass(frozen=True, eq=True) +class ResistorParams(BaseParams): + resistances: List[float] + + def __hash__(self): + return hash((super().__hash__(), json.dumps(self.resistances))) + + +@dataclass(frozen=True, eq=True) +class CapacitorParams(BaseParams): + capacitances: List[float] + + def __hash__(self): + return hash((super().__hash__(), json.dumps(self.capacitances))) + + +@dataclass(frozen=True, eq=True) +class InductorParams(BaseParams): + inductances: List[float] + + def __hash__(self): + return hash((super().__hash__(), json.dumps(self.inductances))) + + +@dataclass(frozen=True, eq=True) +class TVSParams(BaseParams): + def __hash__(self): + return super().__hash__() + + +@dataclass(frozen=True, eq=True) +class DiodeParams(BaseParams): + max_currents: List[float] + reverse_working_voltages: List[float] + + def __hash__(self): + return hash( + ( + super().__hash__(), + json.dumps(self.max_currents), + json.dumps(self.reverse_working_voltages), + ) + ) + + +@dataclass(frozen=True, eq=True) +class LEDParams(BaseParams): + def __hash__(self): + return super().__hash__() + + +@dataclass(frozen=True, eq=True) +class MOSFETParams(BaseParams): + def __hash__(self): + return super().__hash__() + + +@dataclass(frozen=True, eq=True) +class LDOParams(BaseParams): + def __hash__(self): + return super().__hash__() + + +@dataclass(frozen=True, eq=True) +class LCSCParams: + lcsc: int + + +@dataclass(frozen=True, eq=True) +class ManufacturerPartParams: + manufacturer_name: str + mfr: str + qty: int + + class ApiClient: @dataclass class Config: @@ -119,6 +205,31 @@ def __init__(self): else: raise ApiError("API URL and API key must be set") - def fetch_parts(self, method: str, params: dict) -> list[Component]: - response = self._client.rpc(method, params).execute() + @functools.lru_cache(maxsize=None) + def fetch_parts(self, method: str, params: BaseParams) -> list[Component]: + response = self._client.rpc(method, params.__dict__).execute() return [Component(**part) for part in response.data] + + def fetch_resistors(self, params: ResistorParams) -> list[Component]: + return self.fetch_parts("find_resistors", params) + + def fetch_capacitors(self, params: CapacitorParams) -> list[Component]: + return self.fetch_parts("find_capacitors", params) + + def fetch_inductors(self, params: InductorParams) -> list[Component]: + return self.fetch_parts("find_inductors", params) + + def fetch_tvs(self, params: TVSParams) -> list[Component]: + return self.fetch_parts("find_tvs", params) + + def fetch_diodes(self, params: DiodeParams) -> list[Component]: + return self.fetch_parts("find_diodes", params) + + def fetch_leds(self, params: LEDParams) -> list[Component]: + return self.fetch_parts("find_leds", params) + + def fetch_mosfets(self, params: MOSFETParams) -> list[Component]: + return self.fetch_parts("find_mosfets", params) + + def fetch_ldos(self, params: LDOParams) -> list[Component]: + return self.fetch_parts("find_ldos", params) diff --git a/src/faebryk/libs/picker/api/picker_lib.py b/src/faebryk/libs/picker/api/picker_lib.py index 88f9b2a1..eeacbdb2 100644 --- a/src/faebryk/libs/picker/api/picker_lib.py +++ b/src/faebryk/libs/picker/api/picker_lib.py @@ -10,8 +10,18 @@ from faebryk.libs.e_series import E_SERIES_VALUES from faebryk.libs.picker.api.api import ( ApiClient, + CapacitorParams, + DiodeParams, + FootprintCandidate, + InductorParams, + LCSCParams, + LDOParams, + LEDParams, + ManufacturerPartParams, + MOSFETParams, + ResistorParams, + TVSParams, check_compatible_parameters, - get_footprint_candidates, try_attach, ) @@ -38,7 +48,9 @@ def extract_numeric_id(lcsc_id: str) -> int: raise PickError(f"Invalid LCSC part number {lcsc_id}") return int(match[1]) - parts = client.fetch_parts("find_by_lcsc", {"lcsc": extract_numeric_id(lcsc_id)}) + parts = client.fetch_parts( + "find_by_lcsc", LCSCParams(lcsc=extract_numeric_id(lcsc_id)) + ) if len(parts) < 1: raise KeyErrorNotFound(f"Could not find part with LCSC part number {lcsc_id}") @@ -85,7 +97,7 @@ def find_and_attach_by_lcsc_id(module: Module): def find_component_by_mfr(mfr: str, mfr_pn: str) -> Component: parts = client.fetch_parts( "find_by_manufacturer_part", - {"manufacturer_name": mfr, "mfr": mfr_pn, "qty": qty}, + ManufacturerPartParams(manufacturer_name=mfr, mfr=mfr_pn, qty=qty), ) if len(parts) < 1: @@ -157,6 +169,17 @@ def _filter_by_module_params_and_attach( ) +def _get_footprint_candidates(module: Module) -> list[FootprintCandidate] | None: + if module.has_trait(F.has_footprint_requirement): + return [ + {"footprint": footprint, "pin_count": pin_count} + for footprint, pin_count in module.get_trait( + F.has_footprint_requirement + ).get_footprint_requirement() + ] + return None + + def find_resistor(cmp: Module): """ Find a resistor with matching parameters @@ -164,13 +187,12 @@ def find_resistor(cmp: Module): if not isinstance(cmp, F.Resistor): raise PickError("Module is not a resistor", cmp) - parts = client.fetch_parts( - "find_resistors", - { - "resistances": generate_si_values(cmp.resistance, "Ω", E_SERIES_VALUES.E96), - "footprint_candidates": get_footprint_candidates(cmp), - "qty": qty, - }, + parts = client.fetch_resistors( + ResistorParams( + resistances=generate_si_values(cmp.resistance, "Ω", E_SERIES_VALUES.E96), + footprint_candidates=_get_footprint_candidates(cmp), + qty=qty, + ), ) _filter_by_module_params_and_attach(cmp, F.Resistor, parts) @@ -183,15 +205,12 @@ def find_capacitor(cmp: Module): if not isinstance(cmp, F.Capacitor): raise PickError("Module is not a capacitor", cmp) - parts = client.fetch_parts( - "find_capacitors", - { - "capacitances": generate_si_values( - cmp.capacitance, "F", E_SERIES_VALUES.E24 - ), - "footprint_candidates": get_footprint_candidates(cmp), - "qty": qty, - }, + parts = client.fetch_capacitors( + CapacitorParams( + capacitances=generate_si_values(cmp.capacitance, "F", E_SERIES_VALUES.E24), + footprint_candidates=_get_footprint_candidates(cmp), + qty=qty, + ), ) _filter_by_module_params_and_attach(cmp, F.Capacitor, parts) @@ -204,13 +223,12 @@ def find_inductor(cmp: Module): if not isinstance(cmp, F.Inductor): raise PickError("Module is not an inductor", cmp) - parts = client.fetch_parts( - "find_inductors", - { - "inductances": generate_si_values(cmp.inductance, "H", E_SERIES_VALUES.E24), - "footprint_candidates": get_footprint_candidates(cmp), - "qty": qty, - }, + parts = client.fetch_inductors( + InductorParams( + inductances=generate_si_values(cmp.inductance, "H", E_SERIES_VALUES.E24), + footprint_candidates=_get_footprint_candidates(cmp), + qty=qty, + ), ) _filter_by_module_params_and_attach(cmp, F.Inductor, parts) @@ -223,12 +241,8 @@ def find_tvs(cmp: Module): if not isinstance(cmp, F.TVS): raise PickError("Module is not a TVS diode", cmp) - parts = client.fetch_parts( - "find_tvs", - { - "footprint_candidates": get_footprint_candidates(cmp), - "qty": qty, - }, + parts = client.fetch_tvs( + TVSParams(footprint_candidates=_get_footprint_candidates(cmp), qty=qty), ) _filter_by_module_params_and_attach(cmp, F.TVS, parts) @@ -241,18 +255,15 @@ def find_diode(cmp: Module): if not isinstance(cmp, F.Diode): raise PickError("Module is not a diode", cmp) - parts = client.fetch_parts( - "find_diodes", - { - "max_currents": generate_si_values( - cmp.max_current, "A", E_SERIES_VALUES.E3 - ), - "reverse_working_voltages": generate_si_values( + parts = client.fetch_diodes( + DiodeParams( + max_currents=generate_si_values(cmp.max_current, "A", E_SERIES_VALUES.E3), + reverse_working_voltages=generate_si_values( cmp.reverse_working_voltage, "V", E_SERIES_VALUES.E3 ), - "footprint_candidates": get_footprint_candidates(cmp), - "qty": qty, - }, + footprint_candidates=_get_footprint_candidates(cmp), + qty=qty, + ), ) _filter_by_module_params_and_attach(cmp, F.Diode, parts) @@ -265,12 +276,8 @@ def find_led(cmp: Module): if not isinstance(cmp, F.LED): raise PickError("Module is not an LED", cmp) - parts = client.fetch_parts( - "find_leds", - { - "footprint_candidates": get_footprint_candidates(cmp), - "qty": qty, - }, + parts = client.fetch_leds( + LEDParams(footprint_candidates=_get_footprint_candidates(cmp), qty=qty) ) _filter_by_module_params_and_attach(cmp, F.LED, parts) @@ -284,12 +291,8 @@ def find_mosfet(cmp: Module): if not isinstance(cmp, F.MOSFET): raise PickError("Module is not a MOSFET", cmp) - parts = client.fetch_parts( - "find_mosfets", - { - "footprint_candidates": get_footprint_candidates(cmp), - "qty": qty, - }, + parts = client.fetch_mosfets( + MOSFETParams(footprint_candidates=_get_footprint_candidates(cmp), qty=qty) ) _filter_by_module_params_and_attach(cmp, F.MOSFET, parts) @@ -303,12 +306,8 @@ def find_ldo(cmp: Module): if not isinstance(cmp, F.LDO): raise PickError("Module is not a LDO", cmp) - parts = client.fetch_parts( - "find_ldos", - { - "footprint_candidates": get_footprint_candidates(cmp), - "qty": qty, - }, + parts = client.fetch_ldos( + LDOParams(footprint_candidates=_get_footprint_candidates(cmp), qty=qty) ) _filter_by_module_params_and_attach(cmp, F.LDO, parts) From a678cb861c8765ff58d0c565a774f201bfa525c9 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Mon, 21 Oct 2024 14:58:54 -0700 Subject: [PATCH 17/31] surface in examples/buildutil --- src/faebryk/libs/examples/buildutil.py | 35 ++++++++++++++++++++------ src/faebryk/libs/picker/api/api.py | 5 +++- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/faebryk/libs/examples/buildutil.py b/src/faebryk/libs/examples/buildutil.py index c9fd6ab2..75c1394e 100644 --- a/src/faebryk/libs/examples/buildutil.py +++ b/src/faebryk/libs/examples/buildutil.py @@ -3,6 +3,7 @@ import logging import shutil +from enum import StrEnum from pathlib import Path from typing import Callable @@ -13,10 +14,11 @@ from faebryk.libs.app.parameters import replace_tbd_with_any from faebryk.libs.app.pcb import apply_design from faebryk.libs.examples.pickers import add_example_pickers +from faebryk.libs.picker.api.api import ApiNotConfiguredError, add_api_pickers from faebryk.libs.picker.jlcpcb.jlcpcb import JLCPCB_DB from faebryk.libs.picker.jlcpcb.pickers import add_jlcpcb_pickers from faebryk.libs.picker.picker import pick_part_recursively -from faebryk.libs.util import ConfigFlag +from faebryk.libs.util import ConfigFlag, ConfigFlagEnum BUILD_DIR = Path("./build") GRAPH_OUT = BUILD_DIR / Path("faebryk/graph.png") @@ -34,6 +36,16 @@ logger = logging.getLogger(__name__) +class PickerType(StrEnum): + JLCPCB = "jlcpcb" + API = "api" + + +PICKER = ConfigFlagEnum( + PickerType, "PICKER", PickerType.JLCPCB, "Picker backend to use" +) + + def apply_design_to_pcb( m: Module, transform: Callable[[PCB_Transformer], None] | None = None ): @@ -59,12 +71,21 @@ def apply_design_to_pcb( # TODO this can be prettier # picking ---------------------------------------------------------------- modules = m.get_children_modules(types=Module) - try: - JLCPCB_DB() - for n in modules: - add_jlcpcb_pickers(n, base_prio=-10) - except FileNotFoundError: - logger.warning("JLCPCB database not found. Skipping JLCPCB pickers.") + + match PICKER.get(): + case PickerType.JLCPCB: + try: + JLCPCB_DB() + for n in modules: + add_jlcpcb_pickers(n, base_prio=-10) + except FileNotFoundError: + logger.warning("JLCPCB database not found. Skipping JLCPCB pickers.") + case PickerType.API: + try: + for n in modules: + add_api_pickers(n) + except ApiNotConfiguredError: + logger.warning("API not configured. Skipping API pickers.") for n in modules: add_example_pickers(n) diff --git a/src/faebryk/libs/picker/api/api.py b/src/faebryk/libs/picker/api/api.py index 3db5a7af..e871035f 100644 --- a/src/faebryk/libs/picker/api/api.py +++ b/src/faebryk/libs/picker/api/api.py @@ -27,6 +27,9 @@ class ApiError(Exception): ... +class ApiNotConfiguredError(ApiError): ... + + def check_compatible_parameters( module: Module, component: Component, mapping: list[MappingParameterDB] ) -> bool: @@ -203,7 +206,7 @@ def __init__(self): ), ) else: - raise ApiError("API URL and API key must be set") + raise ApiNotConfiguredError("API URL and API key must be set") @functools.lru_cache(maxsize=None) def fetch_parts(self, method: str, params: BaseParams) -> list[Component]: From 85c3e12ab253dc63a61334d95d9ae4fd885cc606 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Mon, 21 Oct 2024 15:07:39 -0700 Subject: [PATCH 18/31] fix typing issues --- src/faebryk/libs/picker/api/api.py | 11 ++++++++--- src/faebryk/libs/picker/api/pickers.py | 12 +++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/faebryk/libs/picker/api/api.py b/src/faebryk/libs/picker/api/api.py index e871035f..7bad2ecd 100644 --- a/src/faebryk/libs/picker/api/api.py +++ b/src/faebryk/libs/picker/api/api.py @@ -86,6 +86,8 @@ def try_attach( cmp, ) + return False + @dataclass(frozen=True, eq=True) class FootprintCandidate: @@ -186,9 +188,9 @@ class ApiClient: @dataclass class Config: # TODO: add defaults - enable: str = os.getenv("FBRK_PICKER", "").lower() == "api" - api_url: str = os.getenv("FBRK_API_URL") - api_key: str = os.getenv("FBRK_API_KEY") + enable: bool = os.getenv("FBRK_PICKER", "").lower() == "api" + api_url: str | None = os.getenv("FBRK_API_URL") + api_key: str | None = os.getenv("FBRK_API_KEY") config = Config() _client: Client | None = None @@ -210,6 +212,9 @@ def __init__(self): @functools.lru_cache(maxsize=None) def fetch_parts(self, method: str, params: BaseParams) -> list[Component]: + if self._client is None: + raise ApiNotConfiguredError("API client is not initialized") + response = self._client.rpc(method, params.__dict__).execute() return [Component(**part) for part in response.data] diff --git a/src/faebryk/libs/picker/api/pickers.py b/src/faebryk/libs/picker/api/pickers.py index a4a7ab34..31de05a9 100644 --- a/src/faebryk/libs/picker/api/pickers.py +++ b/src/faebryk/libs/picker/api/pickers.py @@ -1,8 +1,6 @@ # This file is part of the faebryk project # SPDX-License-Identifier: MIT -from typing import Any - import faebryk.library._F as F import faebryk.libs.picker.api.picker_lib as P from faebryk.core.module import Module @@ -43,11 +41,11 @@ def _friendly_description(self) -> str: def pick(self, module: Module): match self.mfr, self.mfr_pn, self.lcsc_pn: - case Any(mfr), Any(mfr_pn), None: - parts = P.find_manufacturer_part(module, mfr, mfr_pn) - case None, None, Any(lcsc_pn): - parts = P.find_lcsc_part(module, lcsc_pn) - case None, None, None: + case (mfr, mfr_pn, None) if mfr is not None and mfr_pn is not None: + parts = P.find_component_by_mfr(module, mfr, mfr_pn) + case (None, None, lcsc_pn) if lcsc_pn is not None: + parts = P.find_component_by_lcsc(module, lcsc_pn) + case (None, None, None): raise PickError("No parameters provided", module) if len(parts) > 1: From 8dd700737a02e8a2e42d01a76a4a205f9bf47066 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Mon, 21 Oct 2024 15:15:01 -0700 Subject: [PATCH 19/31] run gen_F.py --- src/faebryk/library/_F.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/faebryk/library/_F.py b/src/faebryk/library/_F.py index e420a1a1..12340c67 100644 --- a/src/faebryk/library/_F.py +++ b/src/faebryk/library/_F.py @@ -32,13 +32,13 @@ from faebryk.library.Operation import Operation from faebryk.library.has_linked_pad import has_linked_pad from faebryk.library.has_reference import has_reference -from faebryk.library.has_footprint_requirement import has_footprint_requirement from faebryk.library.can_bridge import can_bridge from faebryk.library.has_designator import has_designator from faebryk.library.has_descriptive_properties import has_descriptive_properties from faebryk.library.has_simple_value_representation import has_simple_value_representation from faebryk.library.has_capacitance import has_capacitance from faebryk.library.has_datasheet import has_datasheet +from faebryk.library.has_footprint_requirement import has_footprint_requirement from faebryk.library.has_kicad_ref import has_kicad_ref from faebryk.library.has_picker import has_picker from faebryk.library.has_pcb_layout import has_pcb_layout @@ -61,13 +61,13 @@ from faebryk.library.Footprint import Footprint from faebryk.library.has_overriden_name_defined import has_overriden_name_defined from faebryk.library.has_linked_pad_defined import has_linked_pad_defined -from faebryk.library.has_footprint_requirement_defined import has_footprint_requirement_defined from faebryk.library.can_bridge_defined import can_bridge_defined from faebryk.library.has_designator_defined import has_designator_defined from faebryk.library.has_descriptive_properties_defined import has_descriptive_properties_defined from faebryk.library.has_simple_value_representation_based_on_params import has_simple_value_representation_based_on_params from faebryk.library.has_simple_value_representation_defined import has_simple_value_representation_defined from faebryk.library.has_datasheet_defined import has_datasheet_defined +from faebryk.library.has_footprint_requirement_defined import has_footprint_requirement_defined from faebryk.library.has_multi_picker import has_multi_picker from faebryk.library.has_pcb_layout_defined import has_pcb_layout_defined from faebryk.library.has_single_connection_impl import has_single_connection_impl From 023dc64990228151d0bf81e379e67f50beee6e9c Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Mon, 21 Oct 2024 15:27:49 -0700 Subject: [PATCH 20/31] refactor */pickers.py --- src/faebryk/libs/picker/api/pickers.py | 59 +++++------------------ src/faebryk/libs/picker/common.py | 57 ++++++++++++++++++++++ src/faebryk/libs/picker/jlcpcb/pickers.py | 49 ++----------------- 3 files changed, 73 insertions(+), 92 deletions(-) create mode 100644 src/faebryk/libs/picker/common.py diff --git a/src/faebryk/libs/picker/api/pickers.py b/src/faebryk/libs/picker/api/pickers.py index 31de05a9..22604074 100644 --- a/src/faebryk/libs/picker/api/pickers.py +++ b/src/faebryk/libs/picker/api/pickers.py @@ -4,68 +4,33 @@ import faebryk.library._F as F import faebryk.libs.picker.api.picker_lib as P from faebryk.core.module import Module +from faebryk.libs.picker.api.api import ApiError +from faebryk.libs.picker.common import StaticPartPicker from faebryk.libs.picker.picker import PickError -class ApiPicker(F.has_multi_picker.FunctionPicker): ... +class ApiPicker(F.has_multi_picker.FunctionPicker): + def pick(self, module: Module): + try: + super().pick(module) + except ApiError as e: + raise PickError(e.args[0], module) from e -class StaticApiPartPicker(F.has_multi_picker.Picker): +class StaticApiPartPicker(StaticPartPicker): """ Picks a specific part by ID or manufacturer / part number """ - # subject to change as the API evolves - def __init__( - self, - *, - mfr: str | None = None, - mfr_pn: str | None = None, - lcsc_pn: str | None = None, - ) -> None: - super().__init__() - self.mfr = mfr - self.mfr_pn = mfr_pn - self.lcsc_pn = lcsc_pn - - def _friendly_description(self) -> str: - desc = "" - if self.mfr: - desc += f"mfr={self.mfr}" - if self.mfr_pn: - desc += f"mfr_pn={self.mfr_pn}" - if self.lcsc_pn: - desc += f"lcsc_pn={self.lcsc_pn}" - - return desc or "" - - def pick(self, module: Module): + def _find_parts(self, module: Module): match self.mfr, self.mfr_pn, self.lcsc_pn: case (mfr, mfr_pn, None) if mfr is not None and mfr_pn is not None: - parts = P.find_component_by_mfr(module, mfr, mfr_pn) + return P.find_component_by_mfr(module, mfr, mfr_pn) case (None, None, lcsc_pn) if lcsc_pn is not None: - parts = P.find_component_by_lcsc(module, lcsc_pn) + return P.find_component_by_lcsc(module, lcsc_pn) case (None, None, None): raise PickError("No parameters provided", module) - if len(parts) > 1: - raise PickError( - f"Multiple parts found for {self._friendly_description()}", module - ) - - if len(parts) < 1: - raise PickError( - f"Could not find part for {self._friendly_description()}", module - ) - - (part,) = parts - try: - part.attach(module, []) - except ValueError as e: - raise PickError( - f"Could not attach part for {self._friendly_description()}", module - ) from e - def add_api_pickers(module: Module, base_prio: int = 0) -> None: # Generic pickers diff --git a/src/faebryk/libs/picker/common.py b/src/faebryk/libs/picker/common.py new file mode 100644 index 00000000..634636e9 --- /dev/null +++ b/src/faebryk/libs/picker/common.py @@ -0,0 +1,57 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +from abc import ABC, abstractmethod + +import faebryk.library._F as F +from faebryk.core.module import Module +from faebryk.libs.picker.picker import PickError + + +class StaticPartPicker(F.has_multi_picker.Picker, ABC): + def __init__( + self, + *, + mfr: str | None = None, + mfr_pn: str | None = None, + lcsc_pn: str | None = None, + ) -> None: + super().__init__() + self.mfr = mfr + self.mfr_pn = mfr_pn + self.lcsc_pn = lcsc_pn + + def _friendly_description(self) -> str: + desc = "" + if self.mfr: + desc += f"mfr={self.mfr}" + if self.mfr_pn: + desc += f"mfr_pn={self.mfr_pn}" + if self.lcsc_pn: + desc += f"lcsc_pn={self.lcsc_pn}" + return desc or "" + + @abstractmethod + def _find_parts(self, module: Module): + pass + + def pick(self, module: Module): + parts = self._find_parts(module) + + if len(parts) > 1: + raise PickError( + f"Multiple parts found for {self._friendly_description()}", module + ) + + if len(parts) < 1: + raise PickError( + f"Could not find part for {self._friendly_description()}", module + ) + + (part,) = parts + try: + part.attach(module, []) + except ValueError as e: + raise PickError( + f"Could not attach part for {self._friendly_description()}", module + ) from e diff --git a/src/faebryk/libs/picker/jlcpcb/pickers.py b/src/faebryk/libs/picker/jlcpcb/pickers.py index 376f4d3c..86a5a9c7 100644 --- a/src/faebryk/libs/picker/jlcpcb/pickers.py +++ b/src/faebryk/libs/picker/jlcpcb/pickers.py @@ -3,6 +3,7 @@ import faebryk.library._F as F import faebryk.libs.picker.jlcpcb.picker_lib as P from faebryk.core.module import Module +from faebryk.libs.picker.common import StaticPartPicker from faebryk.libs.picker.jlcpcb.jlcpcb import JLCPCB_DB, ComponentQuery from faebryk.libs.picker.picker import PickError @@ -19,37 +20,13 @@ def pick(self, module: Module): raise PickError(e.args[0], module) from e -class StaticJLCPCBPartPicker(F.has_multi_picker.Picker): +class StaticJLCPCBPartPicker(StaticPartPicker): """ Use this if you want to specify a specific part to the multi-picker eg. a default switch """ - def __init__( - self, - *, - mfr: str | None = None, - mfr_pn: str | None = None, - lcsc_pn: str | None = None, - ) -> None: - super().__init__() - self.mfr = mfr - self.mfr_pn = mfr_pn - self.lcsc_pn = lcsc_pn - - def _friendly_description(self) -> str: - desc = "" - if self.mfr: - desc += f"mfr={self.mfr}" - if self.mfr_pn: - desc += f"mfr_pn={self.mfr_pn}" - if self.lcsc_pn: - desc += f"lcsc_pn={self.lcsc_pn}" - if not desc: - return "" - return desc - - def pick(self, module: Module): + def _find_parts(self, module: Module): q = ComponentQuery() if self.mfr: @@ -59,25 +36,7 @@ def pick(self, module: Module): if self.lcsc_pn: q.filter_by_lcsc_pn(self.lcsc_pn) - parts = q.get() - - if len(parts) > 1: - raise PickError( - f"Multiple parts found for {self._friendly_description()}", module - ) - - if len(parts) < 1: - raise PickError( - f"Could not find part for {self._friendly_description()}", module - ) - - try: - parts[0].attach(module, []) - return - except ValueError as e: - raise PickError( - f"Could not attach part for {self._friendly_description()}", module - ) from e + return q.get() def add_jlcpcb_pickers(module: Module, base_prio: int = 0) -> None: From 7694d09b8f03be3157aaea57823148526d529457 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Mon, 21 Oct 2024 17:59:24 -0700 Subject: [PATCH 21/31] switch to fastapi backend --- poetry.lock | 899 +--------------------- pyproject.toml | 1 - src/faebryk/libs/picker/api/api.py | 79 +- src/faebryk/libs/picker/api/picker_lib.py | 11 +- 4 files changed, 57 insertions(+), 933 deletions(-) diff --git a/poetry.lock b/poetry.lock index 0c874c9f..e21497d4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,140 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. - -[[package]] -name = "aiohappyeyeballs" -version = "2.4.3" -description = "Happy Eyeballs for asyncio" -optional = false -python-versions = ">=3.8" -files = [ - {file = "aiohappyeyeballs-2.4.3-py3-none-any.whl", hash = "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572"}, - {file = "aiohappyeyeballs-2.4.3.tar.gz", hash = "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586"}, -] - -[[package]] -name = "aiohttp" -version = "3.10.10" -description = "Async http client/server framework (asyncio)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "aiohttp-3.10.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:be7443669ae9c016b71f402e43208e13ddf00912f47f623ee5994e12fc7d4b3f"}, - {file = "aiohttp-3.10.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7b06b7843929e41a94ea09eb1ce3927865387e3e23ebe108e0d0d09b08d25be9"}, - {file = "aiohttp-3.10.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:333cf6cf8e65f6a1e06e9eb3e643a0c515bb850d470902274239fea02033e9a8"}, - {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:274cfa632350225ce3fdeb318c23b4a10ec25c0e2c880eff951a3842cf358ac1"}, - {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9e5e4a85bdb56d224f412d9c98ae4cbd032cc4f3161818f692cd81766eee65a"}, - {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b606353da03edcc71130b52388d25f9a30a126e04caef1fd637e31683033abd"}, - {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab5a5a0c7a7991d90446a198689c0535be89bbd6b410a1f9a66688f0880ec026"}, - {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:578a4b875af3e0daaf1ac6fa983d93e0bbfec3ead753b6d6f33d467100cdc67b"}, - {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8105fd8a890df77b76dd3054cddf01a879fc13e8af576805d667e0fa0224c35d"}, - {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3bcd391d083f636c06a68715e69467963d1f9600f85ef556ea82e9ef25f043f7"}, - {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fbc6264158392bad9df19537e872d476f7c57adf718944cc1e4495cbabf38e2a"}, - {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e48d5021a84d341bcaf95c8460b152cfbad770d28e5fe14a768988c461b821bc"}, - {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2609e9ab08474702cc67b7702dbb8a80e392c54613ebe80db7e8dbdb79837c68"}, - {file = "aiohttp-3.10.10-cp310-cp310-win32.whl", hash = "sha256:84afcdea18eda514c25bc68b9af2a2b1adea7c08899175a51fe7c4fb6d551257"}, - {file = "aiohttp-3.10.10-cp310-cp310-win_amd64.whl", hash = "sha256:9c72109213eb9d3874f7ac8c0c5fa90e072d678e117d9061c06e30c85b4cf0e6"}, - {file = "aiohttp-3.10.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f"}, - {file = "aiohttp-3.10.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb"}, - {file = "aiohttp-3.10.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871"}, - {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c"}, - {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38"}, - {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb"}, - {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7"}, - {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911"}, - {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092"}, - {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142"}, - {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9"}, - {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1"}, - {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a"}, - {file = "aiohttp-3.10.10-cp311-cp311-win32.whl", hash = "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94"}, - {file = "aiohttp-3.10.10-cp311-cp311-win_amd64.whl", hash = "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959"}, - {file = "aiohttp-3.10.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c"}, - {file = "aiohttp-3.10.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28"}, - {file = "aiohttp-3.10.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f"}, - {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138"}, - {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742"}, - {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7"}, - {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16"}, - {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8"}, - {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6"}, - {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a"}, - {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9"}, - {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a"}, - {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205"}, - {file = "aiohttp-3.10.10-cp312-cp312-win32.whl", hash = "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628"}, - {file = "aiohttp-3.10.10-cp312-cp312-win_amd64.whl", hash = "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf"}, - {file = "aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28"}, - {file = "aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d"}, - {file = "aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79"}, - {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e"}, - {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6"}, - {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42"}, - {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e"}, - {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc"}, - {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a"}, - {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414"}, - {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3"}, - {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67"}, - {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b"}, - {file = "aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8"}, - {file = "aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151"}, - {file = "aiohttp-3.10.10-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1b66ccafef7336a1e1f0e389901f60c1d920102315a56df85e49552308fc0486"}, - {file = "aiohttp-3.10.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:acd48d5b80ee80f9432a165c0ac8cbf9253eaddb6113269a5e18699b33958dbb"}, - {file = "aiohttp-3.10.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3455522392fb15ff549d92fbf4b73b559d5e43dc522588f7eb3e54c3f38beee7"}, - {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45c3b868724137f713a38376fef8120c166d1eadd50da1855c112fe97954aed8"}, - {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:da1dee8948d2137bb51fbb8a53cce6b1bcc86003c6b42565f008438b806cccd8"}, - {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5ce2ce7c997e1971b7184ee37deb6ea9922ef5163c6ee5aa3c274b05f9e12fa"}, - {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28529e08fde6f12eba8677f5a8608500ed33c086f974de68cc65ab218713a59d"}, - {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7db54c7914cc99d901d93a34704833568d86c20925b2762f9fa779f9cd2e70f"}, - {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:03a42ac7895406220124c88911ebee31ba8b2d24c98507f4a8bf826b2937c7f2"}, - {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:7e338c0523d024fad378b376a79faff37fafb3c001872a618cde1d322400a572"}, - {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:038f514fe39e235e9fef6717fbf944057bfa24f9b3db9ee551a7ecf584b5b480"}, - {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:64f6c17757251e2b8d885d728b6433d9d970573586a78b78ba8929b0f41d045a"}, - {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:93429602396f3383a797a2a70e5f1de5df8e35535d7806c9f91df06f297e109b"}, - {file = "aiohttp-3.10.10-cp38-cp38-win32.whl", hash = "sha256:c823bc3971c44ab93e611ab1a46b1eafeae474c0c844aff4b7474287b75fe49c"}, - {file = "aiohttp-3.10.10-cp38-cp38-win_amd64.whl", hash = "sha256:54ca74df1be3c7ca1cf7f4c971c79c2daf48d9aa65dea1a662ae18926f5bc8ce"}, - {file = "aiohttp-3.10.10-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:01948b1d570f83ee7bbf5a60ea2375a89dfb09fd419170e7f5af029510033d24"}, - {file = "aiohttp-3.10.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9fc1500fd2a952c5c8e3b29aaf7e3cc6e27e9cfc0a8819b3bce48cc1b849e4cc"}, - {file = "aiohttp-3.10.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f614ab0c76397661b90b6851a030004dac502e48260ea10f2441abd2207fbcc7"}, - {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00819de9e45d42584bed046314c40ea7e9aea95411b38971082cad449392b08c"}, - {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05646ebe6b94cc93407b3bf34b9eb26c20722384d068eb7339de802154d61bc5"}, - {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:998f3bd3cfc95e9424a6acd7840cbdd39e45bc09ef87533c006f94ac47296090"}, - {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9010c31cd6fa59438da4e58a7f19e4753f7f264300cd152e7f90d4602449762"}, - {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ea7ffc6d6d6f8a11e6f40091a1040995cdff02cfc9ba4c2f30a516cb2633554"}, - {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ef9c33cc5cbca35808f6c74be11eb7f5f6b14d2311be84a15b594bd3e58b5527"}, - {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ce0cdc074d540265bfeb31336e678b4e37316849d13b308607efa527e981f5c2"}, - {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:597a079284b7ee65ee102bc3a6ea226a37d2b96d0418cc9047490f231dc09fe8"}, - {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:7789050d9e5d0c309c706953e5e8876e38662d57d45f936902e176d19f1c58ab"}, - {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e7f8b04d83483577fd9200461b057c9f14ced334dcb053090cea1da9c8321a91"}, - {file = "aiohttp-3.10.10-cp39-cp39-win32.whl", hash = "sha256:c02a30b904282777d872266b87b20ed8cc0d1501855e27f831320f471d54d983"}, - {file = "aiohttp-3.10.10-cp39-cp39-win_amd64.whl", hash = "sha256:edfe3341033a6b53a5c522c802deb2079eee5cbfbb0af032a55064bd65c73a23"}, - {file = "aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a"}, -] - -[package.dependencies] -aiohappyeyeballs = ">=2.3.0" -aiosignal = ">=1.1.2" -attrs = ">=17.3.0" -frozenlist = ">=1.1.1" -multidict = ">=4.5,<7.0" -yarl = ">=1.12.0,<2.0" - -[package.extras] -speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] - -[[package]] -name = "aiosignal" -version = "1.3.1" -description = "aiosignal: a list of registered asynchronous callbacks" -optional = false -python-versions = ">=3.7" -files = [ - {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, - {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, -] - -[package.dependencies] -frozenlist = ">=1.1.0" +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiosqlite" @@ -161,26 +25,6 @@ files = [ {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, ] -[[package]] -name = "anyio" -version = "4.6.2.post1" -description = "High level compatibility layer for multiple asynchronous event loop implementations" -optional = false -python-versions = ">=3.9" -files = [ - {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, - {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, -] - -[package.dependencies] -idna = ">=2.8" -sniffio = ">=1.1" - -[package.extras] -doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] -trio = ["trio (>=0.26.1)"] - [[package]] name = "appdirs" version = "1.4.4" @@ -192,25 +36,6 @@ files = [ {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] -[[package]] -name = "attrs" -version = "24.2.0" -description = "Classes Without Boilerplate" -optional = false -python-versions = ">=3.7" -files = [ - {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, - {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, -] - -[package.extras] -benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] - [[package]] name = "black" version = "24.8.0" @@ -532,20 +357,6 @@ wrapt = ">=1.10,<2" [package.extras] dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] -[[package]] -name = "deprecation" -version = "2.1.0" -description = "A library to handle automated deprecations" -optional = false -python-versions = "*" -files = [ - {file = "deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a"}, - {file = "deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff"}, -] - -[package.dependencies] -packaging = "*" - [[package]] name = "distlib" version = "0.3.8" @@ -720,107 +531,6 @@ files = [ {file = "freetype_py-2.5.1-py3-none-win_amd64.whl", hash = "sha256:0b7f8e0342779f65ca13ef8bc103938366fecade23e6bb37cb671c2b8ad7f124"}, ] -[[package]] -name = "frozenlist" -version = "1.4.1" -description = "A list-like structure which implements collections.abc.MutableSequence" -optional = false -python-versions = ">=3.8" -files = [ - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"}, - {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"}, - {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, - {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, - {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, - {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, - {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"}, - {file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"}, - {file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"}, - {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"}, - {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"}, - {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, - {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, -] - -[[package]] -name = "gotrue" -version = "2.9.2" -description = "Python Client Library for Supabase Auth" -optional = false -python-versions = "<4.0,>=3.8" -files = [ - {file = "gotrue-2.9.2-py3-none-any.whl", hash = "sha256:fcd5279e8f1cc630f3ac35af5485fe39f8030b23906776920d2c32a4e308cff4"}, - {file = "gotrue-2.9.2.tar.gz", hash = "sha256:57b3245e916c5efbf19a21b1181011a903c1276bb1df2d847558f2f24f29abb2"}, -] - -[package.dependencies] -httpx = {version = ">=0.26,<0.28", extras = ["http2"]} -pydantic = ">=1.10,<3" - [[package]] name = "gprof2dot" version = "2024.6.6" @@ -832,101 +542,6 @@ files = [ {file = "gprof2dot-2024.6.6.tar.gz", hash = "sha256:fa1420c60025a9eb7734f65225b4da02a10fc6dd741b37fa129bc6b41951e5ab"}, ] -[[package]] -name = "h11" -version = "0.14.0" -description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -optional = false -python-versions = ">=3.7" -files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, -] - -[[package]] -name = "h2" -version = "4.1.0" -description = "HTTP/2 State-Machine based protocol implementation" -optional = false -python-versions = ">=3.6.1" -files = [ - {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, - {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"}, -] - -[package.dependencies] -hpack = ">=4.0,<5" -hyperframe = ">=6.0,<7" - -[[package]] -name = "hpack" -version = "4.0.0" -description = "Pure-Python HPACK header compression" -optional = false -python-versions = ">=3.6.1" -files = [ - {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, - {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, -] - -[[package]] -name = "httpcore" -version = "1.0.6" -description = "A minimal low-level HTTP client." -optional = false -python-versions = ">=3.8" -files = [ - {file = "httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f"}, - {file = "httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f"}, -] - -[package.dependencies] -certifi = "*" -h11 = ">=0.13,<0.15" - -[package.extras] -asyncio = ["anyio (>=4.0,<5.0)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<1.0)"] - -[[package]] -name = "httpx" -version = "0.27.2" -description = "The next generation HTTP client." -optional = false -python-versions = ">=3.8" -files = [ - {file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"}, - {file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"}, -] - -[package.dependencies] -anyio = "*" -certifi = "*" -h2 = {version = ">=3,<5", optional = true, markers = "extra == \"http2\""} -httpcore = "==1.*" -idna = "*" -sniffio = "*" - -[package.extras] -brotli = ["brotli", "brotlicffi"] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -zstd = ["zstandard (>=0.18.0)"] - -[[package]] -name = "hyperframe" -version = "6.0.1" -description = "HTTP/2 framing layer for Python" -optional = false -python-versions = ">=3.6.1" -files = [ - {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, - {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, -] - [[package]] name = "identify" version = "2.6.1" @@ -1257,107 +872,6 @@ files = [ {file = "more_itertools-10.5.0-py3-none-any.whl", hash = "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef"}, ] -[[package]] -name = "multidict" -version = "6.1.0" -description = "multidict implementation" -optional = false -python-versions = ">=3.8" -files = [ - {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, - {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, - {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, - {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, - {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, - {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, - {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, - {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, - {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, - {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, - {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, - {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, - {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, - {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, - {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, - {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, - {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, -] - [[package]] name = "mypy-extensions" version = "1.0.0" @@ -1661,23 +1175,6 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] -[[package]] -name = "postgrest" -version = "0.17.1" -description = "PostgREST client for Python. This library provides an ORM interface to PostgREST." -optional = false -python-versions = "<4.0,>=3.8" -files = [ - {file = "postgrest-0.17.1-py3-none-any.whl", hash = "sha256:ec1d00dc8532fe5ffb342cfc7c4e610a1e0e2272eb14f78f9b2b61094f9be510"}, - {file = "postgrest-0.17.1.tar.gz", hash = "sha256:e31d9977dbb80dc5f9fdd4d444014686606692dc4ddb9adc85639e56c6d54c92"}, -] - -[package.dependencies] -deprecation = ">=2.1.0,<3.0.0" -httpx = {version = ">=0.26,<0.28", extras = ["http2"]} -pydantic = ">=1.9,<3.0" -strenum = ">=0.4.9,<0.5.0" - [[package]] name = "pre-commit" version = "3.8.0" @@ -1696,113 +1193,6 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" -[[package]] -name = "propcache" -version = "0.2.0" -description = "Accelerated property cache" -optional = false -python-versions = ">=3.8" -files = [ - {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58"}, - {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b"}, - {file = "propcache-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110"}, - {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2"}, - {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a"}, - {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577"}, - {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850"}, - {file = "propcache-0.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b"}, - {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336"}, - {file = "propcache-0.2.0-cp310-cp310-win32.whl", hash = "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad"}, - {file = "propcache-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99"}, - {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354"}, - {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de"}, - {file = "propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87"}, - {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016"}, - {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb"}, - {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2"}, - {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4"}, - {file = "propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b"}, - {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b"}, - {file = "propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1"}, - {file = "propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71"}, - {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2"}, - {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7"}, - {file = "propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8"}, - {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793"}, - {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09"}, - {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89"}, - {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e"}, - {file = "propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23"}, - {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348"}, - {file = "propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5"}, - {file = "propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3"}, - {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7"}, - {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763"}, - {file = "propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d"}, - {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a"}, - {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b"}, - {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb"}, - {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf"}, - {file = "propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83"}, - {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544"}, - {file = "propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032"}, - {file = "propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e"}, - {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861"}, - {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6"}, - {file = "propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063"}, - {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f"}, - {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90"}, - {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68"}, - {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9"}, - {file = "propcache-0.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7"}, - {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed"}, - {file = "propcache-0.2.0-cp38-cp38-win32.whl", hash = "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d"}, - {file = "propcache-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5"}, - {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6"}, - {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638"}, - {file = "propcache-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957"}, - {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1"}, - {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562"}, - {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d"}, - {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12"}, - {file = "propcache-0.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d"}, - {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798"}, - {file = "propcache-0.2.0-cp39-cp39-win32.whl", hash = "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9"}, - {file = "propcache-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df"}, - {file = "propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036"}, - {file = "propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70"}, -] - [[package]] name = "psutil" version = "6.0.0" @@ -2196,23 +1586,6 @@ files = [ {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] -[[package]] -name = "realtime" -version = "2.0.5" -description = "" -optional = false -python-versions = "<4.0,>=3.9" -files = [ - {file = "realtime-2.0.5-py3-none-any.whl", hash = "sha256:f9ec2d762794709e37a8e2745c8dfd86eac4870678808f09676c8f2b7bfa6bbc"}, - {file = "realtime-2.0.5.tar.gz", hash = "sha256:133828fbc2cc2325fb015fe071c6da9fb488819cac96d85ed297045c715b35f5"}, -] - -[package.dependencies] -aiohttp = ">=3.10.6,<4.0.0" -python-dateutil = ">=2.8.1,<3.0.0" -typing-extensions = ">=4.12.2,<5.0.0" -websockets = ">=11,<14" - [[package]] name = "requests" version = "2.32.3" @@ -2412,83 +1785,6 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] -[[package]] -name = "sniffio" -version = "1.3.1" -description = "Sniff out which async library your code is running under" -optional = false -python-versions = ">=3.7" -files = [ - {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, - {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, -] - -[[package]] -name = "storage3" -version = "0.8.1" -description = "Supabase Storage client for Python." -optional = false -python-versions = "<4.0,>=3.8" -files = [ - {file = "storage3-0.8.1-py3-none-any.whl", hash = "sha256:0b21205f43eaf0d1dd33bde6c6d0612f88524b7865f017d2ae9827e3f63d9cdc"}, - {file = "storage3-0.8.1.tar.gz", hash = "sha256:ea60b68b2221b3868ccc1a7f1294d57d0d9c51642cdc639d8115fe5d0adc8892"}, -] - -[package.dependencies] -httpx = {version = ">=0.26,<0.28", extras = ["http2"]} -python-dateutil = ">=2.8.2,<3.0.0" -typing-extensions = ">=4.2.0,<5.0.0" - -[[package]] -name = "strenum" -version = "0.4.15" -description = "An Enum that inherits from str." -optional = false -python-versions = "*" -files = [ - {file = "StrEnum-0.4.15-py3-none-any.whl", hash = "sha256:a30cda4af7cc6b5bf52c8055bc4bf4b2b6b14a93b574626da33df53cf7740659"}, - {file = "StrEnum-0.4.15.tar.gz", hash = "sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff"}, -] - -[package.extras] -docs = ["myst-parser[linkify]", "sphinx", "sphinx-rtd-theme"] -release = ["twine"] -test = ["pylint", "pytest", "pytest-black", "pytest-cov", "pytest-pylint"] - -[[package]] -name = "supabase" -version = "2.9.0" -description = "Supabase client for Python." -optional = false -python-versions = "<4.0,>=3.9" -files = [ - {file = "supabase-2.9.0-py3-none-any.whl", hash = "sha256:04b794dd737f7b50a8de4fcba0507983e27c9eea29577eb0af7fe06e9fe69757"}, - {file = "supabase-2.9.0.tar.gz", hash = "sha256:d94c0ee491fe0d137387bd860071fee97cb01f32a1c1485266804783b14c1c32"}, -] - -[package.dependencies] -gotrue = ">=2.7.0,<3.0.0" -httpx = ">=0.26,<0.28" -postgrest = ">=0.17.0,<0.18.0" -realtime = ">=2.0.0,<3.0.0" -storage3 = ">=0.8.0,<0.9.0" -supafunc = ">=0.6.0,<0.7.0" -typing-extensions = ">=4.12.2,<5.0.0" - -[[package]] -name = "supafunc" -version = "0.6.1" -description = "Library for Supabase Functions" -optional = false -python-versions = "<4.0,>=3.8" -files = [ - {file = "supafunc-0.6.1-py3-none-any.whl", hash = "sha256:01aeeeb4bf429977664454a32c86418345140faf6d2e6eb0636d52e4547c5fbb"}, - {file = "supafunc-0.6.1.tar.gz", hash = "sha256:3c8761e3999336ccdb7550498a395fd08afc8469382f55ea56f7f640e5a909aa"}, -] - -[package.dependencies] -httpx = {version = ">=0.26,<0.28", extras = ["http2"]} - [[package]] name = "tortoise-orm" version = "0.21.6" @@ -2644,101 +1940,6 @@ objprint = ">0.1.3" [package.extras] full = ["orjson"] -[[package]] -name = "websockets" -version = "13.1" -description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"}, - {file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"}, - {file = "websockets-13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f"}, - {file = "websockets-13.1-cp310-cp310-win32.whl", hash = "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe"}, - {file = "websockets-13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a"}, - {file = "websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19"}, - {file = "websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5"}, - {file = "websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9"}, - {file = "websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f"}, - {file = "websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557"}, - {file = "websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc"}, - {file = "websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49"}, - {file = "websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf"}, - {file = "websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c"}, - {file = "websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3"}, - {file = "websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6"}, - {file = "websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708"}, - {file = "websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6"}, - {file = "websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d"}, - {file = "websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2"}, - {file = "websockets-13.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c7934fd0e920e70468e676fe7f1b7261c1efa0d6c037c6722278ca0228ad9d0d"}, - {file = "websockets-13.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:149e622dc48c10ccc3d2760e5f36753db9cacf3ad7bc7bbbfd7d9c819e286f23"}, - {file = "websockets-13.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a569eb1b05d72f9bce2ebd28a1ce2054311b66677fcd46cf36204ad23acead8c"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95df24ca1e1bd93bbca51d94dd049a984609687cb2fb08a7f2c56ac84e9816ea"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8dbb1bf0c0a4ae8b40bdc9be7f644e2f3fb4e8a9aca7145bfa510d4a374eeb7"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:035233b7531fb92a76beefcbf479504db8c72eb3bff41da55aecce3a0f729e54"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e4450fc83a3df53dec45922b576e91e94f5578d06436871dce3a6be38e40f5db"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:463e1c6ec853202dd3657f156123d6b4dad0c546ea2e2e38be2b3f7c5b8e7295"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6d6855bbe70119872c05107e38fbc7f96b1d8cb047d95c2c50869a46c65a8e96"}, - {file = "websockets-13.1-cp38-cp38-win32.whl", hash = "sha256:204e5107f43095012b00f1451374693267adbb832d29966a01ecc4ce1db26faf"}, - {file = "websockets-13.1-cp38-cp38-win_amd64.whl", hash = "sha256:485307243237328c022bc908b90e4457d0daa8b5cf4b3723fd3c4a8012fce4c6"}, - {file = "websockets-13.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9b37c184f8b976f0c0a231a5f3d6efe10807d41ccbe4488df8c74174805eea7d"}, - {file = "websockets-13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:163e7277e1a0bd9fb3c8842a71661ad19c6aa7bb3d6678dc7f89b17fbcc4aeb7"}, - {file = "websockets-13.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b889dbd1342820cc210ba44307cf75ae5f2f96226c0038094455a96e64fb07a"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:586a356928692c1fed0eca68b4d1c2cbbd1ca2acf2ac7e7ebd3b9052582deefa"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7bd6abf1e070a6b72bfeb71049d6ad286852e285f146682bf30d0296f5fbadfa"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2aad13a200e5934f5a6767492fb07151e1de1d6079c003ab31e1823733ae79"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:df01aea34b6e9e33572c35cd16bae5a47785e7d5c8cb2b54b2acdb9678315a17"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e54affdeb21026329fb0744ad187cf812f7d3c2aa702a5edb562b325191fcab6"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9ef8aa8bdbac47f4968a5d66462a2a0935d044bf35c0e5a8af152d58516dbeb5"}, - {file = "websockets-13.1-cp39-cp39-win32.whl", hash = "sha256:deeb929efe52bed518f6eb2ddc00cc496366a14c726005726ad62c2dd9017a3c"}, - {file = "websockets-13.1-cp39-cp39-win_amd64.whl", hash = "sha256:7c65ffa900e7cc958cd088b9a9157a8141c991f8c53d11087e6fb7277a03f81d"}, - {file = "websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238"}, - {file = "websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a"}, - {file = "websockets-13.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23"}, - {file = "websockets-13.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9156c45750b37337f7b0b00e6248991a047be4aa44554c9886fe6bdd605aab3b"}, - {file = "websockets-13.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80c421e07973a89fbdd93e6f2003c17d20b69010458d3a8e37fb47874bd67d51"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82d0ba76371769d6a4e56f7e83bb8e81846d17a6190971e38b5de108bde9b0d7"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9875a0143f07d74dc5e1ded1c4581f0d9f7ab86c78994e2ed9e95050073c94d"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11e38ad8922c7961447f35c7b17bffa15de4d17c70abd07bfbe12d6faa3e027"}, - {file = "websockets-13.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4059f790b6ae8768471cddb65d3c4fe4792b0ab48e154c9f0a04cefaabcd5978"}, - {file = "websockets-13.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25c35bf84bf7c7369d247f0b8cfa157f989862c49104c5cf85cb5436a641d93e"}, - {file = "websockets-13.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:83f91d8a9bb404b8c2c41a707ac7f7f75b9442a0a876df295de27251a856ad09"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a43cfdcddd07f4ca2b1afb459824dd3c6d53a51410636a2c7fc97b9a8cf4842"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a2ef1381632a2f0cb4efeff34efa97901c9fbc118e01951ad7cfc10601a9bb"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459bf774c754c35dbb487360b12c5727adab887f1622b8aed5755880a21c4a20"}, - {file = "websockets-13.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:95858ca14a9f6fa8413d29e0a585b31b278388aa775b8a81fa24830123874678"}, - {file = "websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f"}, - {file = "websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878"}, -] - [[package]] name = "wrapt" version = "1.16.0" @@ -2818,103 +2019,7 @@ files = [ {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, ] -[[package]] -name = "yarl" -version = "1.15.4" -description = "Yet another URL library" -optional = false -python-versions = ">=3.9" -files = [ - {file = "yarl-1.15.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:551205388d1da18a9975302c9a274ba24788f53bb9bb86187496ebf9e938916e"}, - {file = "yarl-1.15.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eee724176b5bc50ee64905f559345448119b860a30b9489bd7a073f61baf925f"}, - {file = "yarl-1.15.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db818e33599f7b2e4c6507f2b2c24f45ff539a1b6e4e09163bb6f3cfb4616ca7"}, - {file = "yarl-1.15.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07019a9de859c5a29916defd1e8c7557de6491a10bf50c49ff5284e6aedf5313"}, - {file = "yarl-1.15.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db64a20e78969fc66665d2e5fc96cb4f4dc80f2137d8fed4b5a650ad569bb60f"}, - {file = "yarl-1.15.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4076bfd8f1621449b19b9826848ed51bf0f2d1d38e82647c312c0730d8778903"}, - {file = "yarl-1.15.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c23a442973dba3646811c284fce3dddd7fe5c2bd674ac73a122198e8218d6115"}, - {file = "yarl-1.15.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2bdb038b3f5c284e3919218c580dedc95f592c417a358361450b9519b22f7a8"}, - {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:59db8e6888d5302b8dbca0c1026ddabe99d81d67cdc101941519e13ffc9050fe"}, - {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f3294ce265011547630a59c20085fcb6af8cc5fa1fa44a203251f7d86cd5d913"}, - {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4851618679ca70b863ba2e7109be5f09f8fd7715ec505bd42e5a947dcfde3a45"}, - {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:dce1c56beef74d9c799a6ed94001693232a1402138292353a8ce302b64f457d9"}, - {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1e7468f31de61a82817f918743e5229fce774f73fad58487cdf88eef4f06d864"}, - {file = "yarl-1.15.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:527c68f48a91d953691291d3bce0209293aa5ad13ff05286ddb506791c331818"}, - {file = "yarl-1.15.4-cp310-cp310-win32.whl", hash = "sha256:c30115cecaf25fdcb67cc71c669d08425207f62d7a2f6d5416057c1460529216"}, - {file = "yarl-1.15.4-cp310-cp310-win_amd64.whl", hash = "sha256:df09c80f4bc2bc2efde309af383c3fe8fd8c51fe0519edb350b9c9e0af43ffa4"}, - {file = "yarl-1.15.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:76259901cf1ac3db65e7e6dff04775b626d0715f9b51d92b447351144c756a82"}, - {file = "yarl-1.15.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:98d8dc1e8133f86d916125deca9780d791b22645f0d62bafe1452d1cd5eac631"}, - {file = "yarl-1.15.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0d0f16c87c62b7a94b389ddf6a8c9d081265d788875c39f3a80108c4856eea7b"}, - {file = "yarl-1.15.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8de5328d91859b461899497980d4cc8269e84e2d18640f6ac643886fda9000bf"}, - {file = "yarl-1.15.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84937d00e2ea03616c40977de20189fa13a9213e5744a3c6afa0e7dd9141d69c"}, - {file = "yarl-1.15.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:691a3b498fdebef63308e8967bb598cfd326c56d628da82b799dd181bace4503"}, - {file = "yarl-1.15.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a706db0c3b7e4578ff34ed2b1d2507b08fd491346ffc64468786fdf1151d938"}, - {file = "yarl-1.15.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:adb6b5d07d17c32f9d34c9dd4a693637a72323cfcb1f8a52d57033ab2dd21e99"}, - {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e100c6c7d9e9d469009fd55cc4d7ad168d67d40758865c50da713f7ada491e5"}, - {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:df6b254e55c8ac2362afaa651e3e53453aa19a095570792346245773b434176e"}, - {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8721f8bedaa722c3c483cc06a1399cbfdb280eadf443aa5d324b0203cef2a75f"}, - {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1005921b30f4f39bf893946df6173567ff650307babb5ec04bbf64342a1f62c1"}, - {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ab79cc13307065a0b3ef087f09f0509996fc605d35d6642bb28e5d85b2648e1e"}, - {file = "yarl-1.15.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f337486742c700b102d640830aab3faf2848bed966b479a39e6783edd4ab1c6c"}, - {file = "yarl-1.15.4-cp311-cp311-win32.whl", hash = "sha256:20acf84bd1ce530065f8e957e4a5878fda4bc5f18cb02659828210e1519de54e"}, - {file = "yarl-1.15.4-cp311-cp311-win_amd64.whl", hash = "sha256:ab9ccf26cb3fa32747ba2a637a189d2d42386a2fc4afc10dbc7f85922dd23b0f"}, - {file = "yarl-1.15.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f923e94e93a37fd990e8336e0b9bedea533e7cbed14e0c572bf9357ef2a70681"}, - {file = "yarl-1.15.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3198da7d7c34e29fc8c823e0c3ce6c7274aac35760de557c2017489c7d98fc5a"}, - {file = "yarl-1.15.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d886de2ea81f513ba2d6820451d33b767a97c37867ba688d42e164b2dbca1362"}, - {file = "yarl-1.15.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ac85e760543129a1912a82438fc8075223e35eaa2d457d61cd83c27d00d17be"}, - {file = "yarl-1.15.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e58c5d07b1f78dd4cb180c5b3b82465cd281aaeee8aafea0e5d72a4b97922cb1"}, - {file = "yarl-1.15.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9060589d0acad1fca048861fa9ee3e8ed060f67894fa885969648ab6e9e99a54"}, - {file = "yarl-1.15.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccd6774aa7bebdf9ca608bb0839318757a71b8e0d2cf7b10c002bc8790bd343e"}, - {file = "yarl-1.15.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7694f109867ee428c21b85ae19fd31d164c691eb45cc95c561cfdeba237a12e3"}, - {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:83e7154aa0d17f5c93d27ac01088fd9ab6673e7bab1acbd07cd7a865b980c045"}, - {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f16d1940c0cbc342f1d29d6212a006d172be616d2942c5c41966e8a3ce4c3be1"}, - {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7d5226c70af3ad9569ccc4ccc04ab65be79eeb22c87d7ae789c89e62ef76bbd6"}, - {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f25906e4a72d9833e81717c39a39dee7297ff5cb44957d06d177a2ab8ef2ef7f"}, - {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e07e4b17b648c880e8e42bf1ac0a730bde114961646ae1c2ec4433f0c11ca94"}, - {file = "yarl-1.15.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f8136bde8dfa4477c6a85c79a366581b4a505b51a52b669318fb631d3f4f638"}, - {file = "yarl-1.15.4-cp312-cp312-win32.whl", hash = "sha256:ccbeaf5b18b173b9d78e332e017b30ba8bedcf03cdce1d13490b82a3f421bc98"}, - {file = "yarl-1.15.4-cp312-cp312-win_amd64.whl", hash = "sha256:f74f6ffdc633aefecbc80282242a5395058db9d1247fa7dd2f070ef84dc82583"}, - {file = "yarl-1.15.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:4f66a0eda48844508736e47ed476d8fdd7cdbf16a4053b5d439509a25f708504"}, - {file = "yarl-1.15.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fd2bb86f40962d53a91def15a2f7684c62e081a7b96ec74ed0259c34b15973b9"}, - {file = "yarl-1.15.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f864b412557e69a6b953d62c01a0ed0ee342666298aa7f2a29af526bfa80f6e9"}, - {file = "yarl-1.15.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a79c0a8bbb046add85663af85e9993b691bf20c2a109518bd35e0ce77edfe42"}, - {file = "yarl-1.15.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de479e30abd2dfd49fdad3bd6953f2d930a45380be5143c0c9f7a1215cffc8cc"}, - {file = "yarl-1.15.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21fabe58042f3e567b4edc75b2cf44cea02f228e41ac09d73de126bf685fe883"}, - {file = "yarl-1.15.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77390496f2f32437a721c854897f889abefae0f3009daf90a2f703508d96c920"}, - {file = "yarl-1.15.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3896bf15284dd23acab1f2e7fceb350d8da6f6f2436b922f7ec6b3de685d34ca"}, - {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:590e2d733a82ecf004c5c531cbef0d6be328e93adec960024eb213f10cb9503e"}, - {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:1ceb677fb583971351627eac70eec6763fbc889761828da7a276681b5e39742d"}, - {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:69f628d2da1489b27959f4d63fdb326781fe484944dce94abbf919e416c54abe"}, - {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:35a6b69cc44bda002705d6138346bf0a0234cbb7c26c3bf192513eb946aee6f9"}, - {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:49f886e8dcf591275c6e20915b516fd81647857566b0c0158c52df1e468849c9"}, - {file = "yarl-1.15.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:49190eb2ece70313742b0ea51520340288a059674da1f39eefb589d598d9453e"}, - {file = "yarl-1.15.4-cp313-cp313-win32.whl", hash = "sha256:48334a6c8afee93097eb17c0a094234dac2d88da076c8cf372e09e2a5dcc4b66"}, - {file = "yarl-1.15.4-cp313-cp313-win_amd64.whl", hash = "sha256:f68025d6ba1816428b7de615c80f61cb03d5b7061158d4ced7696657a64aa59c"}, - {file = "yarl-1.15.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8b569f4f511b59518ba6719feb5b8bf0a5d4115e6ac903c89e10a8a9ac656017"}, - {file = "yarl-1.15.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9fe17744d60fc404ac61f824118e1e15ce3c2e92eced9b8e22f3c7847acafbf2"}, - {file = "yarl-1.15.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:115346433fad2084ee3a1a925ccc0659990aa42e208ca54c278830a150a3caf3"}, - {file = "yarl-1.15.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60165b8bc260f453321004b193770a66cc1b1a5c57c07d4b8dcc96839e7ad578"}, - {file = "yarl-1.15.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65a0168691373e08d869d48b62c8bed0af0cdaef19c76e11ad73b43901bbdb5a"}, - {file = "yarl-1.15.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:787532f00543a21b8f4ec3050b4e01b8fe437797903c0156a0b03dfca5e1ba6c"}, - {file = "yarl-1.15.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f51c9d173e5fa4b12d06ddca09a41cabbdeb660471dbe55432423eec095709ab"}, - {file = "yarl-1.15.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c96eaa30030e1cfafe533f3da8983812281235b7c50ef2a6c78ceca7aea1a0b"}, - {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4feab2dcb725eb5b4835207ecf3d370ff7ce930b253cba5e681646cb80d64c2c"}, - {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:de38b0b5b86e57efb129d179854e78b65cb8e294a8c75560877869c43aa2415a"}, - {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:65e0467f90f2acf3bc83bbfeedece8f1fd84df8add1a54e9600ed7b7b5debdb0"}, - {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:40c18f96696549e73b92dc12619f07019cbf5faefc1612608f967c144816e493"}, - {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:46491b3e058de7b484e1c9fb20aa8441f06d6c9a18395d711c1c2a9ad6707d6a"}, - {file = "yarl-1.15.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:faa3dd7f4620ab5e5da7a0789d0aac78a9ad0376f102409d442ec5a4179e200a"}, - {file = "yarl-1.15.4-cp39-cp39-win32.whl", hash = "sha256:c33ea7c55a73be343f02361795caf52a187357ea07708fb1cae6661ee1d689c8"}, - {file = "yarl-1.15.4-cp39-cp39-win_amd64.whl", hash = "sha256:11b207061f28b4b6d980239b22ab0ecfadc47846b5a3b8e79f27fcc019d02cf9"}, - {file = "yarl-1.15.4-py3-none-any.whl", hash = "sha256:e5cc288111c450c0a54a74475591b206d3b1cb47dc71bb6200f6be8b1337184c"}, - {file = "yarl-1.15.4.tar.gz", hash = "sha256:a0c5e271058d148d730219ca4f33c5d841c6bd46e05b0da60fea7b516906ccd3"}, -] - -[package.dependencies] -idna = ">=2.0" -multidict = ">=4.0" -propcache = ">=0.2.0" - [metadata] lock-version = "2.0" python-versions = "^3.12,<3.13" -content-hash = "b41054ca397c02b759979adb8ef11ec38b0fa2e2c0d0d2bc043f02b93c0eddba" +content-hash = "86c6b9a700cf392c5c6fbafcc24f293dc8c5a913a8aaab1c01d3957e197784eb" diff --git a/pyproject.toml b/pyproject.toml index c21d6d35..8e053b6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,6 @@ pint = "^0.24.3" deprecated = "^1.2.14" more-itertools = "^10.4.0" psutil = "^6.0.0" -supabase = "^2.9.0" [tool.poetry.group.dev.dependencies] pre-commit = ">=2.20,<4.0" diff --git a/src/faebryk/libs/picker/api/api.py b/src/faebryk/libs/picker/api/api.py index 7bad2ecd..2b70f9a9 100644 --- a/src/faebryk/libs/picker/api/api.py +++ b/src/faebryk/libs/picker/api/api.py @@ -9,9 +9,8 @@ from dataclasses import dataclass from typing import List +import requests from pint import DimensionalityError -from supabase import Client, create_client -from supabase.client import ClientOptions from faebryk.core.module import Module @@ -193,51 +192,79 @@ class Config: api_key: str | None = os.getenv("FBRK_API_KEY") config = Config() - _client: Client | None = None + _client: requests.Session | None = None def __init__(self): if self.config.enable: - if self.config.api_url and self.config.api_key: - self._client = create_client( - self.config.api_url, - self.config.api_key, - options=ClientOptions( - postgrest_client_timeout=10, - storage_client_timeout=10, - schema="public", - ), - ) + if self.config.api_url: + self._client = requests.Session() + self._client.headers["Authorization"] = f"Bearer {self.config.api_key}" + self._client.base_url = self.config.api_url else: - raise ApiNotConfiguredError("API URL and API key must be set") + raise ApiNotConfiguredError("API URL must be set") - @functools.lru_cache(maxsize=None) - def fetch_parts(self, method: str, params: BaseParams) -> list[Component]: + def _get(self, url: str, timeout: float = 10) -> requests.Response: + if self._client is None: + raise ApiNotConfiguredError("API client is not initialized") + + try: + response = self._client.get( + f"{self._client.base_url}{url}", timeout=timeout + ) + response.raise_for_status() + except requests.exceptions.HTTPError as e: + raise ApiError(f"Failed to fetch {url}: {e}") from e + + return response + + def _post(self, url: str, data: dict, timeout: float = 10) -> requests.Response: if self._client is None: raise ApiNotConfiguredError("API client is not initialized") - response = self._client.rpc(method, params.__dict__).execute() - return [Component(**part) for part in response.data] + try: + response = self._client.post( + f"{self._client.base_url}{url}", json=data, timeout=timeout + ) + response.raise_for_status() + except requests.exceptions.HTTPError as e: + raise ApiError(f"Failed to fetch {url}: {e}") from e + + return response + + @functools.lru_cache(maxsize=None) + def fetch_part_by_lcsc(self, lcsc: int) -> list[Component]: + response = self._get(f"/v0/component/lcsc/{lcsc}") + return [Component(**part) for part in response.json()["components"]] + + @functools.lru_cache(maxsize=None) + def fetch_part_by_mfr(self, mfr: str, mfr_pn: str) -> list[Component]: + response = self._get(f"/v0/component/mfr/{mfr}/{mfr_pn}") + return [Component(**part) for part in response.json()["components"]] + + def query_parts(self, method: str, params: BaseParams) -> list[Component]: + response = self._post(f"/v0/query/{method}", params.__dict__) + return [Component(**part) for part in response.json()["components"]] def fetch_resistors(self, params: ResistorParams) -> list[Component]: - return self.fetch_parts("find_resistors", params) + return self.query_parts("resistors", params) def fetch_capacitors(self, params: CapacitorParams) -> list[Component]: - return self.fetch_parts("find_capacitors", params) + return self.query_parts("capacitors", params) def fetch_inductors(self, params: InductorParams) -> list[Component]: - return self.fetch_parts("find_inductors", params) + return self.query_parts("inductors", params) def fetch_tvs(self, params: TVSParams) -> list[Component]: - return self.fetch_parts("find_tvs", params) + return self.query_parts("tvs", params) def fetch_diodes(self, params: DiodeParams) -> list[Component]: - return self.fetch_parts("find_diodes", params) + return self.query_parts("diodes", params) def fetch_leds(self, params: LEDParams) -> list[Component]: - return self.fetch_parts("find_leds", params) + return self.query_parts("leds", params) def fetch_mosfets(self, params: MOSFETParams) -> list[Component]: - return self.fetch_parts("find_mosfets", params) + return self.query_parts("mosfets", params) def fetch_ldos(self, params: LDOParams) -> list[Component]: - return self.fetch_parts("find_ldos", params) + return self.query_parts("ldos", params) diff --git a/src/faebryk/libs/picker/api/picker_lib.py b/src/faebryk/libs/picker/api/picker_lib.py index eeacbdb2..ff12dc5f 100644 --- a/src/faebryk/libs/picker/api/picker_lib.py +++ b/src/faebryk/libs/picker/api/picker_lib.py @@ -14,10 +14,8 @@ DiodeParams, FootprintCandidate, InductorParams, - LCSCParams, LDOParams, LEDParams, - ManufacturerPartParams, MOSFETParams, ResistorParams, TVSParams, @@ -48,9 +46,7 @@ def extract_numeric_id(lcsc_id: str) -> int: raise PickError(f"Invalid LCSC part number {lcsc_id}") return int(match[1]) - parts = client.fetch_parts( - "find_by_lcsc", LCSCParams(lcsc=extract_numeric_id(lcsc_id)) - ) + parts = client.fetch_part_by_lcsc(extract_numeric_id(lcsc_id)) if len(parts) < 1: raise KeyErrorNotFound(f"Could not find part with LCSC part number {lcsc_id}") @@ -95,10 +91,7 @@ def find_and_attach_by_lcsc_id(module: Module): def find_component_by_mfr(mfr: str, mfr_pn: str) -> Component: - parts = client.fetch_parts( - "find_by_manufacturer_part", - ManufacturerPartParams(manufacturer_name=mfr, mfr=mfr_pn, qty=qty), - ) + parts = client.fetch_part_by_mfr(mfr, mfr_pn) if len(parts) < 1: raise KeyErrorNotFound( From a35863f4e9e3b61b1d22b94dc0097ed64dcd6b28 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Mon, 21 Oct 2024 19:00:16 -0700 Subject: [PATCH 22/31] embed default API url --- src/faebryk/libs/picker/api/api.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/faebryk/libs/picker/api/api.py b/src/faebryk/libs/picker/api/api.py index 2b70f9a9..4954c094 100644 --- a/src/faebryk/libs/picker/api/api.py +++ b/src/faebryk/libs/picker/api/api.py @@ -22,6 +22,8 @@ logger = logging.getLogger(__name__) +DEFAULT_API_URL = "https://api-6121-5335559d-q87t043v.onporter.run/" + class ApiError(Exception): ... @@ -186,9 +188,8 @@ class ManufacturerPartParams: class ApiClient: @dataclass class Config: - # TODO: add defaults enable: bool = os.getenv("FBRK_PICKER", "").lower() == "api" - api_url: str | None = os.getenv("FBRK_API_URL") + api_url: str | None = os.getenv("FBRK_API_URL", DEFAULT_API_URL) api_key: str | None = os.getenv("FBRK_API_KEY") config = Config() From bf9cca1fe929249716a028be2543a10b6ced8a5c Mon Sep 17 00:00:00 2001 From: iopapamanoglou Date: Tue, 22 Oct 2024 10:44:40 +0200 Subject: [PATCH 23/31] Minor improvements - Fix types - Improve ConfigFlags - Change Exceptions --- .../has_descriptive_properties_defined.py | 11 +- src/faebryk/libs/examples/buildutil.py | 19 +- src/faebryk/libs/picker/api/api.py | 97 ++++------ src/faebryk/libs/picker/api/picker_lib.py | 14 +- src/faebryk/libs/picker/api/pickers.py | 29 ++- src/faebryk/libs/picker/common.py | 25 ++- src/faebryk/libs/picker/jlcpcb/picker_lib.py | 2 +- src/faebryk/libs/util.py | 176 +++++++++--------- test/libs/picker/test_pickers.py | 5 +- 9 files changed, 190 insertions(+), 188 deletions(-) diff --git a/src/faebryk/library/has_descriptive_properties_defined.py b/src/faebryk/library/has_descriptive_properties_defined.py index 794c0fc2..3f4ffbfc 100644 --- a/src/faebryk/library/has_descriptive_properties_defined.py +++ b/src/faebryk/library/has_descriptive_properties_defined.py @@ -7,18 +7,25 @@ import faebryk.library._F as F from faebryk.core.node import Node from faebryk.core.trait import TraitImpl +from faebryk.libs.picker.picker import DescriptiveProperties class has_descriptive_properties_defined(F.has_descriptive_properties.impl()): - def __init__(self, properties: Mapping[str, str]) -> None: + def __init__( + self, + properties: Mapping[str, str] + | Mapping[DescriptiveProperties, str] + | Mapping[str | DescriptiveProperties, str], + ) -> None: super().__init__() - self.properties = dict(properties) + self.properties: dict[str, str] = dict(properties) def get_properties(self) -> dict[str, str]: return self.properties def handle_duplicate(self, other: TraitImpl, node: Node) -> bool: if not isinstance(other, has_descriptive_properties_defined): + assert isinstance(other, F.has_descriptive_properties) self.properties.update(other.get_properties()) return super().handle_duplicate(other, node) diff --git a/src/faebryk/libs/examples/buildutil.py b/src/faebryk/libs/examples/buildutil.py index 75c1394e..20a28d56 100644 --- a/src/faebryk/libs/examples/buildutil.py +++ b/src/faebryk/libs/examples/buildutil.py @@ -3,7 +3,6 @@ import logging import shutil -from enum import StrEnum from pathlib import Path from typing import Callable @@ -14,11 +13,13 @@ from faebryk.libs.app.parameters import replace_tbd_with_any from faebryk.libs.app.pcb import apply_design from faebryk.libs.examples.pickers import add_example_pickers -from faebryk.libs.picker.api.api import ApiNotConfiguredError, add_api_pickers +from faebryk.libs.picker.api.api import ApiNotConfiguredError +from faebryk.libs.picker.api.pickers import add_api_pickers +from faebryk.libs.picker.common import DB_PICKER_BACKEND, PickerType from faebryk.libs.picker.jlcpcb.jlcpcb import JLCPCB_DB from faebryk.libs.picker.jlcpcb.pickers import add_jlcpcb_pickers from faebryk.libs.picker.picker import pick_part_recursively -from faebryk.libs.util import ConfigFlag, ConfigFlagEnum +from faebryk.libs.util import ConfigFlag BUILD_DIR = Path("./build") GRAPH_OUT = BUILD_DIR / Path("faebryk/graph.png") @@ -36,16 +37,6 @@ logger = logging.getLogger(__name__) -class PickerType(StrEnum): - JLCPCB = "jlcpcb" - API = "api" - - -PICKER = ConfigFlagEnum( - PickerType, "PICKER", PickerType.JLCPCB, "Picker backend to use" -) - - def apply_design_to_pcb( m: Module, transform: Callable[[PCB_Transformer], None] | None = None ): @@ -72,7 +63,7 @@ def apply_design_to_pcb( # picking ---------------------------------------------------------------- modules = m.get_children_modules(types=Module) - match PICKER.get(): + match DB_PICKER_BACKEND: case PickerType.JLCPCB: try: JLCPCB_DB() diff --git a/src/faebryk/libs/picker/api/api.py b/src/faebryk/libs/picker/api/api.py index 4954c094..6bb3b6e3 100644 --- a/src/faebryk/libs/picker/api/api.py +++ b/src/faebryk/libs/picker/api/api.py @@ -2,14 +2,12 @@ # SPDX-License-Identifier: MIT import functools -import json import logging -import os import textwrap from dataclasses import dataclass -from typing import List import requests +from dataclasses_json import dataclass_json from pint import DimensionalityError from faebryk.core.module import Module @@ -18,11 +16,13 @@ from faebryk.libs.picker.jlcpcb.jlcpcb import Component, MappingParameterDB from faebryk.libs.picker.lcsc import LCSC_NoDataException, LCSC_PinmapException from faebryk.libs.picker.picker import PickError -from faebryk.libs.util import try_or +from faebryk.libs.util import ConfigFlagString, try_or logger = logging.getLogger(__name__) DEFAULT_API_URL = "https://api-6121-5335559d-q87t043v.onporter.run/" +API_URL = ConfigFlagString("PICKER_API_URL", DEFAULT_API_URL, "API URL") +API_KEY = ConfigFlagString("PICKER_API_KEY", "", "API key") class ApiError(Exception): ... @@ -90,87 +90,63 @@ def try_attach( return False +type SIvalue = str + + +@dataclass_json @dataclass(frozen=True, eq=True) class FootprintCandidate: footprint: str pin_count: int +# dataclass json decorator only needed in base class +@dataclass_json @dataclass(frozen=True, eq=True) class BaseParams: - footprint_candidates: List[FootprintCandidate] + footprint_candidates: list[FootprintCandidate] qty: int - def __hash__(self): - return hash( - ( - json.dumps(self.footprint_candidates, default=lambda o: o.__dict__), - self.qty, - ) - ) + def convert_to_dict(self): + # comes from dataclass_json + return self.to_dict() # type: ignore @dataclass(frozen=True, eq=True) class ResistorParams(BaseParams): - resistances: List[float] - - def __hash__(self): - return hash((super().__hash__(), json.dumps(self.resistances))) + resistances: list[SIvalue] @dataclass(frozen=True, eq=True) class CapacitorParams(BaseParams): - capacitances: List[float] - - def __hash__(self): - return hash((super().__hash__(), json.dumps(self.capacitances))) + capacitances: list[SIvalue] @dataclass(frozen=True, eq=True) class InductorParams(BaseParams): - inductances: List[float] - - def __hash__(self): - return hash((super().__hash__(), json.dumps(self.inductances))) + inductances: list[SIvalue] @dataclass(frozen=True, eq=True) -class TVSParams(BaseParams): - def __hash__(self): - return super().__hash__() +class TVSParams(BaseParams): ... @dataclass(frozen=True, eq=True) class DiodeParams(BaseParams): - max_currents: List[float] - reverse_working_voltages: List[float] - - def __hash__(self): - return hash( - ( - super().__hash__(), - json.dumps(self.max_currents), - json.dumps(self.reverse_working_voltages), - ) - ) + max_currents: list[SIvalue] + reverse_working_voltages: list[SIvalue] @dataclass(frozen=True, eq=True) -class LEDParams(BaseParams): - def __hash__(self): - return super().__hash__() +class LEDParams(BaseParams): ... @dataclass(frozen=True, eq=True) -class MOSFETParams(BaseParams): - def __hash__(self): - return super().__hash__() +class MOSFETParams(BaseParams): ... @dataclass(frozen=True, eq=True) -class LDOParams(BaseParams): - def __hash__(self): - return super().__hash__() +class LDOParams(BaseParams): ... @dataclass(frozen=True, eq=True) @@ -188,30 +164,27 @@ class ManufacturerPartParams: class ApiClient: @dataclass class Config: - enable: bool = os.getenv("FBRK_PICKER", "").lower() == "api" - api_url: str | None = os.getenv("FBRK_API_URL", DEFAULT_API_URL) - api_key: str | None = os.getenv("FBRK_API_KEY") + api_url: str = API_URL.get() + api_key: str = API_KEY.get() config = Config() _client: requests.Session | None = None + # TODO make __new__ that creates singleton + def __init__(self): - if self.config.enable: - if self.config.api_url: - self._client = requests.Session() - self._client.headers["Authorization"] = f"Bearer {self.config.api_key}" - self._client.base_url = self.config.api_url - else: - raise ApiNotConfiguredError("API URL must be set") + if self.config.api_url: + self._client = requests.Session() + self._client.headers["Authorization"] = f"Bearer {self.config.api_key}" + else: + raise ApiNotConfiguredError("API URL must be set") def _get(self, url: str, timeout: float = 10) -> requests.Response: if self._client is None: raise ApiNotConfiguredError("API client is not initialized") try: - response = self._client.get( - f"{self._client.base_url}{url}", timeout=timeout - ) + response = self._client.get(f"{self.config.api_url}{url}", timeout=timeout) response.raise_for_status() except requests.exceptions.HTTPError as e: raise ApiError(f"Failed to fetch {url}: {e}") from e @@ -224,7 +197,7 @@ def _post(self, url: str, data: dict, timeout: float = 10) -> requests.Response: try: response = self._client.post( - f"{self._client.base_url}{url}", json=data, timeout=timeout + f"{self.config.api_url}{url}", json=data, timeout=timeout ) response.raise_for_status() except requests.exceptions.HTTPError as e: @@ -243,7 +216,7 @@ def fetch_part_by_mfr(self, mfr: str, mfr_pn: str) -> list[Component]: return [Component(**part) for part in response.json()["components"]] def query_parts(self, method: str, params: BaseParams) -> list[Component]: - response = self._post(f"/v0/query/{method}", params.__dict__) + response = self._post(f"/v0/query/{method}", params.convert_to_dict()) return [Component(**part) for part in response.json()["components"]] def fetch_resistors(self, params: ResistorParams) -> list[Component]: diff --git a/src/faebryk/libs/picker/api/picker_lib.py b/src/faebryk/libs/picker/api/picker_lib.py index ff12dc5f..8c55700f 100644 --- a/src/faebryk/libs/picker/api/picker_lib.py +++ b/src/faebryk/libs/picker/api/picker_lib.py @@ -3,7 +3,7 @@ import logging import re -from typing import Type +from typing import Callable, Type import faebryk.library._F as F from faebryk.core.module import Module @@ -43,7 +43,7 @@ def find_component_by_lcsc_id(lcsc_id: str) -> Component: def extract_numeric_id(lcsc_id: str) -> int: match = re.match(r"C(\d+)", lcsc_id) if match is None: - raise PickError(f"Invalid LCSC part number {lcsc_id}") + raise ValueError(f"Invalid LCSC part number {lcsc_id}") return int(match[1]) parts = client.fetch_part_by_lcsc(extract_numeric_id(lcsc_id)) @@ -141,7 +141,7 @@ def find_and_attach_by_mfr(module: Module): logger.warning(f"Failed to attach component: {e}") continue - return PickError( + raise PickError( f"Could not attach any part with manufacturer part number {mfr_pn}", module ) @@ -162,15 +162,15 @@ def _filter_by_module_params_and_attach( ) -def _get_footprint_candidates(module: Module) -> list[FootprintCandidate] | None: +def _get_footprint_candidates(module: Module) -> list[FootprintCandidate]: if module.has_trait(F.has_footprint_requirement): return [ - {"footprint": footprint, "pin_count": pin_count} + FootprintCandidate(footprint, pin_count) for footprint, pin_count in module.get_trait( F.has_footprint_requirement ).get_footprint_requirement() ] - return None + return [] def find_resistor(cmp: Module): @@ -306,7 +306,7 @@ def find_ldo(cmp: Module): _filter_by_module_params_and_attach(cmp, F.LDO, parts) -TYPE_SPECIFIC_LOOKUP = { +TYPE_SPECIFIC_LOOKUP: dict[type[Module], Callable[[Module], None]] = { F.Resistor: find_resistor, F.Capacitor: find_capacitor, F.Inductor: find_inductor, diff --git a/src/faebryk/libs/picker/api/pickers.py b/src/faebryk/libs/picker/api/pickers.py index 22604074..0dd9af60 100644 --- a/src/faebryk/libs/picker/api/pickers.py +++ b/src/faebryk/libs/picker/api/pickers.py @@ -2,10 +2,11 @@ # SPDX-License-Identifier: MIT import faebryk.library._F as F -import faebryk.libs.picker.api.picker_lib as P +import faebryk.libs.picker.api.picker_lib as picker_lib from faebryk.core.module import Module -from faebryk.libs.picker.api.api import ApiError +from faebryk.libs.picker.api.api import ApiNotConfiguredError from faebryk.libs.picker.common import StaticPartPicker +from faebryk.libs.picker.jlcpcb.jlcpcb import Component from faebryk.libs.picker.picker import PickError @@ -13,8 +14,11 @@ class ApiPicker(F.has_multi_picker.FunctionPicker): def pick(self, module: Module): try: super().pick(module) - except ApiError as e: - raise PickError(e.args[0], module) from e + except ApiNotConfiguredError: + raise + # TODO do we actually ever want to catch this? + # except ApiError as e: + # raise PickError(e.args[0], module) from e class StaticApiPartPicker(StaticPartPicker): @@ -22,22 +26,27 @@ class StaticApiPartPicker(StaticPartPicker): Picks a specific part by ID or manufacturer / part number """ - def _find_parts(self, module: Module): + def _find_parts(self, module: Module) -> list[Component]: match self.mfr, self.mfr_pn, self.lcsc_pn: case (mfr, mfr_pn, None) if mfr is not None and mfr_pn is not None: - return P.find_component_by_mfr(module, mfr, mfr_pn) + return [picker_lib.find_component_by_mfr(mfr, mfr_pn)] case (None, None, lcsc_pn) if lcsc_pn is not None: - return P.find_component_by_lcsc(module, lcsc_pn) + return [picker_lib.find_component_by_lcsc_id(lcsc_pn)] case (None, None, None): raise PickError("No parameters provided", module) + return [] def add_api_pickers(module: Module, base_prio: int = 0) -> None: # Generic pickers - module.add(F.has_multi_picker(base_prio, ApiPicker(P.find_and_attach_by_lcsc_id))) - module.add(F.has_multi_picker(base_prio, ApiPicker(P.find_and_attach_by_mfr))) + module.add( + F.has_multi_picker(base_prio, ApiPicker(picker_lib.find_and_attach_by_lcsc_id)) + ) + module.add( + F.has_multi_picker(base_prio, ApiPicker(picker_lib.find_and_attach_by_mfr)) + ) # Type-specific pickers F.has_multi_picker.add_pickers_by_type( - module, P.TYPE_SPECIFIC_LOOKUP, ApiPicker, base_prio + 1 + module, picker_lib.TYPE_SPECIFIC_LOOKUP, ApiPicker, base_prio + 1 ) diff --git a/src/faebryk/libs/picker/common.py b/src/faebryk/libs/picker/common.py index 634636e9..76f8aa81 100644 --- a/src/faebryk/libs/picker/common.py +++ b/src/faebryk/libs/picker/common.py @@ -2,10 +2,23 @@ # SPDX-License-Identifier: MIT from abc import ABC, abstractmethod +from enum import StrEnum import faebryk.library._F as F from faebryk.core.module import Module +from faebryk.libs.picker.jlcpcb.jlcpcb import Component from faebryk.libs.picker.picker import PickError +from faebryk.libs.util import ConfigFlagEnum + + +class PickerType(StrEnum): + JLCPCB = "jlcpcb" + API = "api" + + +DB_PICKER_BACKEND = ConfigFlagEnum( + PickerType, "PICKER", PickerType.JLCPCB, "Picker backend to use" +) class StaticPartPicker(F.has_multi_picker.Picker, ABC): @@ -22,17 +35,17 @@ def __init__( self.lcsc_pn = lcsc_pn def _friendly_description(self) -> str: - desc = "" + desc = [] if self.mfr: - desc += f"mfr={self.mfr}" + desc.append(f"mfr={self.mfr}") if self.mfr_pn: - desc += f"mfr_pn={self.mfr_pn}" + desc.append(f"mfr_pn={self.mfr_pn}") if self.lcsc_pn: - desc += f"lcsc_pn={self.lcsc_pn}" - return desc or "" + desc.append(f"lcsc_pn={self.lcsc_pn}") + return ", ".join(desc) or "" @abstractmethod - def _find_parts(self, module: Module): + def _find_parts(self, module: Module) -> list[Component]: pass def pick(self, module: Module): diff --git a/src/faebryk/libs/picker/jlcpcb/picker_lib.py b/src/faebryk/libs/picker/jlcpcb/picker_lib.py index b1ea9b43..a4b2fdcf 100644 --- a/src/faebryk/libs/picker/jlcpcb/picker_lib.py +++ b/src/faebryk/libs/picker/jlcpcb/picker_lib.py @@ -44,7 +44,7 @@ def f(x: str) -> F.Constant[T]: return f -_MAPPINGS_BY_TYPE = { +_MAPPINGS_BY_TYPE: dict[type[Module], list[MappingParameterDB]] = { F.Resistor: [ MappingParameterDB( "resistance", diff --git a/src/faebryk/libs/util.py b/src/faebryk/libs/util.py index dabb8b1f..cc10d422 100644 --- a/src/faebryk/libs/util.py +++ b/src/faebryk/libs/util.py @@ -5,13 +5,13 @@ import collections.abc import inspect import logging +import os import sys from abc import abstractmethod from collections import defaultdict from contextlib import contextmanager from dataclasses import dataclass, fields from enum import StrEnum -from functools import cache from itertools import chain from textwrap import indent from typing import ( @@ -711,68 +711,121 @@ def __init_subclass__(cls) -> None: lazy_construct(cls) -class ConfigFlag: - def __init__(self, name: str, default: bool = False, descr: str = "") -> None: - self.name = name - self.default = default - self.descr = descr +def once[T, **P](f: Callable[P, T]) -> Callable[P, T]: + def wrapper(*args: P.args, **kwargs: P.kwargs) -> Any: + lookup = (args, tuple(kwargs.items())) + if lookup in wrapper.cache: + return wrapper.cache[lookup] - @cache - def __bool__(self): - import os + result = f(*args, **kwargs) + wrapper.cache[lookup] = result + return result - key = f"FBRK_{self.name}" + wrapper.cache = {} + wrapper._is_once_wrapper = True + return wrapper - if key not in os.environ: - return self.default - matches = [ - (True, ["1", "true", "yes", "y"]), - (False, ["0", "false", "no", "n"]), - ] - val = os.environ[key].lower() +def assert_once[T, O, **P]( + f: Callable[Concatenate[O, P], T], +) -> Callable[Concatenate[O, P], T]: + def wrapper(obj: O, *args: P.args, **kwargs: P.kwargs) -> T: + if not hasattr(obj, "_assert_once_called"): + setattr(obj, "_assert_once_called", set()) - res = find(matches, lambda x: val in x[1])[0] + wrapper_set = getattr(obj, "_assert_once_called") - if res != self.default: - logger.warning(f"Config flag |{self.name}={res}|") + if wrapper not in wrapper_set: + wrapper_set.add(wrapper) + return f(obj, *args, **kwargs) + else: + raise AssertionError(f"{f.__name__} called on {obj} more than once") - return res + return wrapper -class ConfigFlagEnum[E: StrEnum]: - def __init__(self, enum: type[E], name: str, default: E, descr: str = "") -> None: - self.enum = enum +def assert_once_global[T, **P](f: Callable[P, T]) -> Callable[P, T]: + def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: + if not wrapper.called: + wrapper.called = True + return f(*args, **kwargs) + else: + raise AssertionError("Function called more than once") + + wrapper.called = False + return wrapper + + +class _ConfigFlagBase[T]: + def __init__(self, name: str, default: T, descr: str = ""): self._name = name self.default = default self.descr = descr + self._type: type[T] = type(default) - self._resolved = None - - def get(self): - if self._resolved is not None: - return self._resolved - - import os + @property + def name(self) -> str: + return f"FBRK_{self._name}" - key = f"FBRK_{self._name}" + @property + def raw_value(self) -> str | None: + return os.getenv(self.name, None) - if key not in os.environ: - return self.default + @once + def get(self) -> T: + raw_val = self.raw_value - val = os.environ[key].upper() - res = self.enum[val] + if raw_val is None: + res = self.default + else: + res = self._convert(raw_val) if res != self.default: - logger.warning(f"Config flag |{self._name}={res}|") + logger.warning(f"Config flag |{self.name}={res}|") - self._resolved = res return res - def __eq__(self, other) -> Any: + def __hash__(self) -> int: + return hash(self.name) + + @abstractmethod + def _convert(self, raw_val: str) -> T: ... + + def __eq__(self, other) -> bool: return self.get() == other +class ConfigFlag(_ConfigFlagBase[bool]): + def __init__(self, name: str, default: bool = False, descr: str = "") -> None: + super().__init__(name, default, descr) + + def _convert(self, raw_val: str) -> bool: + matches = [ + (True, ["1", "true", "yes", "y"]), + (False, ["0", "false", "no", "n"]), + ] + val = raw_val.lower() + + return find(matches, lambda x: val in x[1])[0] + + def __bool__(self): + return self.get() + + +class ConfigFlagEnum[E: StrEnum](_ConfigFlagBase[E]): + def __init__(self, enum: type[E], name: str, default: E, descr: str = "") -> None: + super().__init__(name, default, descr) + self.enum = enum + + def _convert(self, raw_val: str) -> E: + return self.enum[raw_val.upper()] + + +class ConfigFlagString(_ConfigFlagBase[str]): + def _convert(self, raw_val: str) -> str: + return raw_val + + def zip_dicts_by_key(*dicts): keys = {k for d in dicts for k in d} return {k: tuple(d.get(k) for d in dicts) for k in keys} @@ -807,51 +860,6 @@ def __() -> T: return _ -def once[T, **P](f: Callable[P, T]) -> Callable[P, T]: - def wrapper(*args: P.args, **kwargs: P.kwargs) -> Any: - lookup = (args, tuple(kwargs.items())) - if lookup in wrapper.cache: - return wrapper.cache[lookup] - - result = f(*args, **kwargs) - wrapper.cache[lookup] = result - return result - - wrapper.cache = {} - wrapper._is_once_wrapper = True - return wrapper - - -def assert_once[T, O, **P]( - f: Callable[Concatenate[O, P], T], -) -> Callable[Concatenate[O, P], T]: - def wrapper(obj: O, *args: P.args, **kwargs: P.kwargs) -> T: - if not hasattr(obj, "_assert_once_called"): - setattr(obj, "_assert_once_called", set()) - - wrapper_set = getattr(obj, "_assert_once_called") - - if wrapper not in wrapper_set: - wrapper_set.add(wrapper) - return f(obj, *args, **kwargs) - else: - raise AssertionError(f"{f.__name__} called on {obj} more than once") - - return wrapper - - -def assert_once_global[T, **P](f: Callable[P, T]) -> Callable[P, T]: - def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: - if not wrapper.called: - wrapper.called = True - return f(*args, **kwargs) - else: - raise AssertionError("Function called more than once") - - wrapper.called = False - return wrapper - - class PostInitCaller(type): def __call__(cls, *args, **kwargs): obj = type.__call__(cls, *args, **kwargs) diff --git a/test/libs/picker/test_pickers.py b/test/libs/picker/test_pickers.py index 8e11f91d..8a26fa32 100644 --- a/test/libs/picker/test_pickers.py +++ b/test/libs/picker/test_pickers.py @@ -2,7 +2,6 @@ # SPDX-License-Identifier: MIT import logging -import os import unittest from abc import ABC, abstractmethod from pathlib import Path @@ -480,7 +479,9 @@ def is_db_available(): def is_api_available(): - return os.getenv("FBRK_PICKER") == "api" + # currently API fully open, thus as long as internet access + # API access possible + return True @unittest.skipIf(not is_db_available(), reason="Requires large db") From 1d9d3201781e4d77d9ed64493545c8181ebf6bd2 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Tue, 22 Oct 2024 10:27:56 -0700 Subject: [PATCH 24/31] api client init simplification --- src/faebryk/libs/picker/api/api.py | 42 +++++++++++------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/src/faebryk/libs/picker/api/api.py b/src/faebryk/libs/picker/api/api.py index 6bb3b6e3..9a48b30d 100644 --- a/src/faebryk/libs/picker/api/api.py +++ b/src/faebryk/libs/picker/api/api.py @@ -94,67 +94,65 @@ def try_attach( @dataclass_json -@dataclass(frozen=True, eq=True) +@dataclass(frozen=True) class FootprintCandidate: footprint: str pin_count: int -# dataclass json decorator only needed in base class @dataclass_json -@dataclass(frozen=True, eq=True) +@dataclass(frozen=True) class BaseParams: footprint_candidates: list[FootprintCandidate] qty: int - def convert_to_dict(self): - # comes from dataclass_json + def convert_to_dict(self) -> dict: return self.to_dict() # type: ignore -@dataclass(frozen=True, eq=True) +@dataclass(frozen=True) class ResistorParams(BaseParams): resistances: list[SIvalue] -@dataclass(frozen=True, eq=True) +@dataclass(frozen=True) class CapacitorParams(BaseParams): capacitances: list[SIvalue] -@dataclass(frozen=True, eq=True) +@dataclass(frozen=True) class InductorParams(BaseParams): inductances: list[SIvalue] -@dataclass(frozen=True, eq=True) +@dataclass(frozen=True) class TVSParams(BaseParams): ... -@dataclass(frozen=True, eq=True) +@dataclass(frozen=True) class DiodeParams(BaseParams): max_currents: list[SIvalue] reverse_working_voltages: list[SIvalue] -@dataclass(frozen=True, eq=True) +@dataclass(frozen=True) class LEDParams(BaseParams): ... -@dataclass(frozen=True, eq=True) +@dataclass(frozen=True) class MOSFETParams(BaseParams): ... -@dataclass(frozen=True, eq=True) +@dataclass(frozen=True) class LDOParams(BaseParams): ... -@dataclass(frozen=True, eq=True) +@dataclass(frozen=True) class LCSCParams: lcsc: int -@dataclass(frozen=True, eq=True) +@dataclass(frozen=True) class ManufacturerPartParams: manufacturer_name: str mfr: str @@ -168,21 +166,14 @@ class Config: api_key: str = API_KEY.get() config = Config() - _client: requests.Session | None = None # TODO make __new__ that creates singleton def __init__(self): - if self.config.api_url: - self._client = requests.Session() - self._client.headers["Authorization"] = f"Bearer {self.config.api_key}" - else: - raise ApiNotConfiguredError("API URL must be set") + self._client = requests.Session() + self._client.headers["Authorization"] = f"Bearer {self.config.api_key}" def _get(self, url: str, timeout: float = 10) -> requests.Response: - if self._client is None: - raise ApiNotConfiguredError("API client is not initialized") - try: response = self._client.get(f"{self.config.api_url}{url}", timeout=timeout) response.raise_for_status() @@ -192,9 +183,6 @@ def _get(self, url: str, timeout: float = 10) -> requests.Response: return response def _post(self, url: str, data: dict, timeout: float = 10) -> requests.Response: - if self._client is None: - raise ApiNotConfiguredError("API client is not initialized") - try: response = self._client.post( f"{self.config.api_url}{url}", json=data, timeout=timeout From 9db79f29ff9cc626e6529faf253224d13034624b Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Tue, 22 Oct 2024 10:28:40 -0700 Subject: [PATCH 25/31] revert assertIsInstance --- test/libs/picker/test_pickers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/libs/picker/test_pickers.py b/test/libs/picker/test_pickers.py index 8a26fa32..a41124d9 100644 --- a/test/libs/picker/test_pickers.py +++ b/test/libs/picker/test_pickers.py @@ -115,9 +115,9 @@ def satisfies_requirements(self): elif isinstance(req, F.Set): self.test_case.assertIn(res, req.params) elif isinstance(req, F.TBD): - self.test_case.assertIsInstance(res, F.ANY) + self.test_case.assertTrue(isinstance(res, F.ANY)) elif isinstance(req, F.ANY): - self.test_case.assertIsInstance(res, F.ANY) + self.test_case.assertTrue(isinstance(res, F.ANY)) else: raise NotImplementedError( f"Unsupported type of parameter: {type(req)}: {req}" From 27f25ab6ab80bc36993474ef76b974c668be1b6c Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Tue, 22 Oct 2024 10:28:58 -0700 Subject: [PATCH 26/31] api picker test conditions cleanup --- test/libs/picker/test_pickers.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/test/libs/picker/test_pickers.py b/test/libs/picker/test_pickers.py index a41124d9..8c687a17 100644 --- a/test/libs/picker/test_pickers.py +++ b/test/libs/picker/test_pickers.py @@ -478,12 +478,6 @@ def is_db_available(): return JLCPCB_DB.config.db_path.exists() -def is_api_available(): - # currently API fully open, thus as long as internet access - # API access possible - return True - - @unittest.skipIf(not is_db_available(), reason="Requires large db") class TestPickerJlcpcb(TestPickerBase): def add_pickers(self, module): @@ -503,13 +497,11 @@ def tearDown(self): JLCPCB_DB.get().close() -@unittest.skipIf(not is_api_available(), reason="Requires API info") class TestPickerApi(TestPickerBase): def add_pickers(self, module): add_api_pickers(module) -@unittest.skipIf(not is_api_available(), reason="Requires API info") class TestPickerPerformanceApi(TestPickerPerformanceBase): def add_pickers(self, module): add_api_pickers(module) From 0c9aea8483ba30599d8a2a207c776cbb7b2bebcd Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Tue, 22 Oct 2024 20:03:51 -0700 Subject: [PATCH 27/31] singleton api client --- src/faebryk/libs/picker/api/api.py | 7 +++++-- src/faebryk/libs/picker/api/picker_lib.py | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/faebryk/libs/picker/api/api.py b/src/faebryk/libs/picker/api/api.py index 9a48b30d..584f92ed 100644 --- a/src/faebryk/libs/picker/api/api.py +++ b/src/faebryk/libs/picker/api/api.py @@ -167,8 +167,6 @@ class Config: config = Config() - # TODO make __new__ that creates singleton - def __init__(self): self._client = requests.Session() self._client.headers["Authorization"] = f"Bearer {self.config.api_key}" @@ -230,3 +228,8 @@ def fetch_mosfets(self, params: MOSFETParams) -> list[Component]: def fetch_ldos(self, params: LDOParams) -> list[Component]: return self.query_parts("ldos", params) + + +@functools.lru_cache +def get_api_client() -> ApiClient: + return ApiClient() diff --git a/src/faebryk/libs/picker/api/picker_lib.py b/src/faebryk/libs/picker/api/picker_lib.py index 8c55700f..27328c4e 100644 --- a/src/faebryk/libs/picker/api/picker_lib.py +++ b/src/faebryk/libs/picker/api/picker_lib.py @@ -9,7 +9,6 @@ from faebryk.core.module import Module from faebryk.libs.e_series import E_SERIES_VALUES from faebryk.libs.picker.api.api import ( - ApiClient, CapacitorParams, DiodeParams, FootprintCandidate, @@ -20,6 +19,7 @@ ResistorParams, TVSParams, check_compatible_parameters, + get_api_client, try_attach, ) @@ -32,7 +32,7 @@ from faebryk.libs.util import KeyErrorAmbiguous, KeyErrorNotFound logger = logging.getLogger(__name__) -client = ApiClient() +client = get_api_client() # TODO add trait to module that specifies the quantity of the part From 1e31929dadaca54d4c9f6cdab1c889ee059064d0 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Tue, 22 Oct 2024 20:04:02 -0700 Subject: [PATCH 28/31] fix TestPickerPerformanceJlcpcb casing --- test/libs/picker/test_pickers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/libs/picker/test_pickers.py b/test/libs/picker/test_pickers.py index 8c687a17..6b996761 100644 --- a/test/libs/picker/test_pickers.py +++ b/test/libs/picker/test_pickers.py @@ -489,7 +489,7 @@ def tearDown(self): @unittest.skipIf(not is_db_available(), reason="Requires large db") -class TestPickerPerformanceJLCPCB(TestPickerPerformanceBase): +class TestPickerPerformanceJlcpcb(TestPickerPerformanceBase): def add_pickers(self, module): add_jlcpcb_pickers(module) From 796f73e37b64a4b4dcd40ae0fd316a7a265968ca Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Tue, 22 Oct 2024 20:17:29 -0700 Subject: [PATCH 29/31] bump default api timeout 10s -> 30s --- src/faebryk/libs/picker/api/api.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/faebryk/libs/picker/api/api.py b/src/faebryk/libs/picker/api/api.py index 584f92ed..3dc353dc 100644 --- a/src/faebryk/libs/picker/api/api.py +++ b/src/faebryk/libs/picker/api/api.py @@ -21,6 +21,7 @@ logger = logging.getLogger(__name__) DEFAULT_API_URL = "https://api-6121-5335559d-q87t043v.onporter.run/" +DEFAULT_API_TIMEOUT_SECONDS = 30 API_URL = ConfigFlagString("PICKER_API_URL", DEFAULT_API_URL, "API URL") API_KEY = ConfigFlagString("PICKER_API_KEY", "", "API key") @@ -180,7 +181,9 @@ def _get(self, url: str, timeout: float = 10) -> requests.Response: return response - def _post(self, url: str, data: dict, timeout: float = 10) -> requests.Response: + def _post( + self, url: str, data: dict, timeout: float = DEFAULT_API_TIMEOUT_SECONDS + ) -> requests.Response: try: response = self._client.post( f"{self.config.api_url}{url}", json=data, timeout=timeout From 3c1f03e1e8fedf37f85baa2ddeef9e8ad3bab063 Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Wed, 23 Oct 2024 15:02:35 -0700 Subject: [PATCH 30/31] custom domain --- src/faebryk/libs/picker/api/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/faebryk/libs/picker/api/api.py b/src/faebryk/libs/picker/api/api.py index 3dc353dc..8e724e5e 100644 --- a/src/faebryk/libs/picker/api/api.py +++ b/src/faebryk/libs/picker/api/api.py @@ -20,7 +20,7 @@ logger = logging.getLogger(__name__) -DEFAULT_API_URL = "https://api-6121-5335559d-q87t043v.onporter.run/" +DEFAULT_API_URL = "https://components.atopileapi.com" DEFAULT_API_TIMEOUT_SECONDS = 30 API_URL = ConfigFlagString("PICKER_API_URL", DEFAULT_API_URL, "API URL") API_KEY = ConfigFlagString("PICKER_API_KEY", "", "API key") From 77ba5b17b3af3c7a224c6efa85df584a4c353a2e Mon Sep 17 00:00:00 2001 From: Sam Mellor Date: Thu, 24 Oct 2024 16:03:51 -0700 Subject: [PATCH 31/31] 404 -> PickError --- src/faebryk/libs/picker/api/api.py | 15 +++++++++++++-- src/faebryk/libs/picker/api/pickers.py | 12 ++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/faebryk/libs/picker/api/api.py b/src/faebryk/libs/picker/api/api.py index 8e724e5e..59f27a74 100644 --- a/src/faebryk/libs/picker/api/api.py +++ b/src/faebryk/libs/picker/api/api.py @@ -32,6 +32,17 @@ class ApiError(Exception): ... class ApiNotConfiguredError(ApiError): ... +class ApiHTTPError(ApiError): + def __init__(self, error: requests.exceptions.HTTPError): + super().__init__() + self.response = error.response + + def __str__(self) -> str: + status_code = self.response.status_code + detail = self.response.json()["detail"] + return f"{super().__str__()}: {status_code} {detail}" + + def check_compatible_parameters( module: Module, component: Component, mapping: list[MappingParameterDB] ) -> bool: @@ -177,7 +188,7 @@ def _get(self, url: str, timeout: float = 10) -> requests.Response: response = self._client.get(f"{self.config.api_url}{url}", timeout=timeout) response.raise_for_status() except requests.exceptions.HTTPError as e: - raise ApiError(f"Failed to fetch {url}: {e}") from e + raise ApiHTTPError(e) from e return response @@ -190,7 +201,7 @@ def _post( ) response.raise_for_status() except requests.exceptions.HTTPError as e: - raise ApiError(f"Failed to fetch {url}: {e}") from e + raise ApiHTTPError(e) from e return response diff --git a/src/faebryk/libs/picker/api/pickers.py b/src/faebryk/libs/picker/api/pickers.py index 0dd9af60..40506ce7 100644 --- a/src/faebryk/libs/picker/api/pickers.py +++ b/src/faebryk/libs/picker/api/pickers.py @@ -4,7 +4,7 @@ import faebryk.library._F as F import faebryk.libs.picker.api.picker_lib as picker_lib from faebryk.core.module import Module -from faebryk.libs.picker.api.api import ApiNotConfiguredError +from faebryk.libs.picker.api.api import ApiHTTPError from faebryk.libs.picker.common import StaticPartPicker from faebryk.libs.picker.jlcpcb.jlcpcb import Component from faebryk.libs.picker.picker import PickError @@ -14,11 +14,11 @@ class ApiPicker(F.has_multi_picker.FunctionPicker): def pick(self, module: Module): try: super().pick(module) - except ApiNotConfiguredError: - raise - # TODO do we actually ever want to catch this? - # except ApiError as e: - # raise PickError(e.args[0], module) from e + except ApiHTTPError as e: + if e.response.status_code == 404: + raise PickError(str(e), module) from e + else: + raise class StaticApiPartPicker(StaticPartPicker):