From d67d3529c46e09d5dfa9ece9a9eab0c9b3f1a4d0 Mon Sep 17 00:00:00 2001 From: Jonathan Haas Date: Fri, 5 Jan 2024 16:45:09 +0100 Subject: [PATCH] Merge upstream main --- .github/workflows/deploy-pypi.yml | 4 +- .github/workflows/test-pr.yml | 4 +- Pipfile.lock | 1361 +++++++++++++++----- docs/examples/plot_empty_levels.py | 18 +- docs/requirements.txt | 2 +- hiclass/HierarchicalClassifier.py | 121 +- hiclass/LocalClassifierPerLevel.py | 7 +- hiclass/LocalClassifierPerNode.py | 94 +- hiclass/LocalClassifierPerParentNode.py | 98 +- setup.cfg | 2 +- setup.py | 5 +- tests/test_HierarchicalClassifier.py | 315 +---- tests/test_LocalClassifierPerLevel.py | 62 - tests/test_LocalClassifierPerNode.py | 78 -- tests/test_LocalClassifierPerParentNode.py | 239 +--- tests/test_LocalClassifiers.py | 121 ++ tests/test_metrics.py | 184 --- 17 files changed, 1307 insertions(+), 1408 deletions(-) create mode 100644 tests/test_LocalClassifiers.py diff --git a/.github/workflows/deploy-pypi.yml b/.github/workflows/deploy-pypi.yml index a31c5522..b10cddcd 100644 --- a/.github/workflows/deploy-pypi.yml +++ b/.github/workflows/deploy-pypi.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7", "3.8", "3.9"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] os: [ubuntu-latest, macOS-latest, windows-latest] steps: - uses: actions/checkout@v2 @@ -29,7 +29,7 @@ jobs: python -m pip install pydocstyle==6.1.1 python -m pip install pytest-pydocstyle==2.3.0 python -m pip install pytest-cov==3.0.0 - python -m pip install ray==1.13.0 + python -m pip install ray python -m pip install 'importlib-metadata<4.3' python -m pip install . - name: Test with pytest diff --git a/.github/workflows/test-pr.yml b/.github/workflows/test-pr.yml index 2fbf4d43..57f15877 100644 --- a/.github/workflows/test-pr.yml +++ b/.github/workflows/test-pr.yml @@ -30,9 +30,7 @@ jobs: python -m pip install pydocstyle==6.1.1 python -m pip install pytest-pydocstyle==2.3.0 python -m pip install pytest-cov==3.0.0 - python -m pip install ray==1.13.0 - python -m pip install pandas==1.4.2 - python -m pip install numpy==1.23.4 + python -m pip install ray python -m pip install . - name: Test with pytest run: | diff --git a/Pipfile.lock b/Pipfile.lock index e41c2155..1151d408 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "9438ec9ee7d8cdc029038b6abfbed5cf900628765bd8862f830e42c63fd6a522" + "sha256": "4f36f76cfc52dc83b74cc00b92af24b8ff556ca22dc2f21401224c39659346eb" }, "pipfile-spec": 6, "requires": {}, @@ -16,238 +16,319 @@ "default": { "joblib": { "hashes": [ - "sha256:4158fcecd13733f8be669be0683b96ebdbbd38d23559f54dca7205aea1bf1e35", - "sha256:f21f109b3c7ff9d95f8387f752d0d9c34a02aa2f7060c2135f465da0e5160ff6" + "sha256:92f865e621e17784e7955080b6d042489e3b8e294949cc44c6eac304f59772b1", + "sha256:ef4331c65f239985f3f2220ecc87db222f08fd22097a3dd5698f693875f8cbb9" ], - "markers": "python_version >= '3.6'", - "version": "==1.1.0" + "markers": "python_version >= '3.7'", + "version": "==1.3.2" }, "networkx": { "hashes": [ - "sha256:15a7b81a360791c458c55a417418ea136c13378cfdc06a2dcdc12bd2f9cf09c1", - "sha256:a762f4b385692d9c3a6f2912d058d76d29a827deaedf9e63ed14d397b8030687" + "sha256:4f33f68cb2afcf86f28a45f43efc27a9386b535d567d2127f8f61d51dec58d36", + "sha256:de346335408f84de0eada6ff9fafafff9bcda11f0a0dfaa931133debb146ab61" ], "index": "pypi", - "version": "==2.8.5" + "markers": "python_version >= '3.8'", + "version": "==3.1" }, "numpy": { "hashes": [ - "sha256:1408c3527a74a0209c781ac82bde2182b0f0bf54dea6e6a363fe0cc4488a7ce7", - "sha256:173f28921b15d341afadf6c3898a34f20a0569e4ad5435297ba262ee8941e77b", - "sha256:1865fdf51446839ca3fffaab172461f2b781163f6f395f1aed256b1ddc253622", - "sha256:3119daed207e9410eaf57dcf9591fdc68045f60483d94956bee0bfdcba790953", - "sha256:35590b9c33c0f1c9732b3231bb6a72d1e4f77872390c47d50a615686ae7ed3fd", - "sha256:37e5ebebb0eb54c5b4a9b04e6f3018e16b8ef257d26c8945925ba8105008e645", - "sha256:37ece2bd095e9781a7156852e43d18044fd0d742934833335599c583618181b9", - "sha256:3ab67966c8d45d55a2bdf40701536af6443763907086c0a6d1232688e27e5447", - "sha256:47f10ab202fe4d8495ff484b5561c65dd59177949ca07975663f4494f7269e3e", - "sha256:55df0f7483b822855af67e38fb3a526e787adf189383b4934305565d71c4b148", - "sha256:5d732d17b8a9061540a10fda5bfeabca5785700ab5469a5e9b93aca5e2d3a5fb", - "sha256:68b69f52e6545af010b76516f5daaef6173e73353e3295c5cb9f96c35d755641", - "sha256:7e8229f3687cdadba2c4faef39204feb51ef7c1a9b669247d49a24f3e2e1617c", - "sha256:8002574a6b46ac3b5739a003b5233376aeac5163e5dcd43dd7ad062f3e186129", - "sha256:876f60de09734fbcb4e27a97c9a286b51284df1326b1ac5f1bf0ad3678236b22", - "sha256:9ce242162015b7e88092dccd0e854548c0926b75c7924a3495e02c6067aba1f5", - "sha256:a35c4e64dfca659fe4d0f1421fc0f05b8ed1ca8c46fb73d9e5a7f175f85696bb", - "sha256:aeba539285dcf0a1ba755945865ec61240ede5432df41d6e29fab305f4384db2", - "sha256:b15c3f1ed08df4980e02cc79ee058b788a3d0bef2fb3c9ca90bb8cbd5b8a3a04", - "sha256:c2f91f88230042a130ceb1b496932aa717dcbd665350beb821534c5c7e15881c", - "sha256:d748ef349bfef2e1194b59da37ed5a29c19ea8d7e6342019921ba2ba4fd8b624", - "sha256:e0d7447679ae9a7124385ccf0ea990bb85bb869cef217e2ea6c844b6a6855073" + "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2", + "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55", + "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf", + "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01", + "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca", + "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901", + "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d", + "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4", + "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf", + "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380", + "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044", + "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545", + "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f", + "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f", + "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3", + "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364", + "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9", + "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418", + "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f", + "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295", + "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3", + "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187", + "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926", + "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357", + "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760" ], "index": "pypi", - "version": "==1.23.1" + "markers": "python_version >= '3.9'", + "version": "==1.25.2" }, "scikit-learn": { "hashes": [ - "sha256:0403ad13f283e27d43b0ad875f187ec7f5d964903d92d1ed06c51439560ecea0", - "sha256:102f51797cd8944bf44a038d106848ddf2804f2c1edf7aea45fba81a4fdc4d80", - "sha256:22145b60fef02e597a8e7f061ebc7c51739215f11ce7fcd2ca9af22c31aa9f86", - "sha256:33cf061ed0b79d647a3e4c3f6c52c412172836718a7cd4d11c1318d083300133", - "sha256:3be10d8d325821ca366d4fe7083d87c40768f842f54371a9c908d97c45da16fc", - "sha256:3e77b71e8e644f86c8b5be7f1c285ef597de4c384961389ee3e9ca36c445b256", - "sha256:45c0f6ae523353f1d99b85469d746f9c497410adff5ba8b24423705b6956a86e", - "sha256:47464c110eaa9ed9d1fe108cb403510878c3d3a40f110618d2a19b2190a3e35c", - "sha256:542ccd2592fe7ad31f5c85fed3a3deb3e252383960a85e4b49a629353fffaba4", - "sha256:723cdb278b1fa57a55f68945bc4e501a2f12abe82f76e8d21e1806cbdbef6fc5", - "sha256:8fe80df08f5b9cee5dd008eccc672e543976198d790c07e5337f7dfb67eaac05", - "sha256:8ff56d07b9507fbe07ca0f4e5c8f3e171f74a429f998da03e308166251316b34", - "sha256:b2db720e13e697d912a87c1a51194e6fb085dc6d8323caa5ca51369ca6948f78", - "sha256:b928869072366dc138762fe0929e7dc88413f8a469aebc6a64adc10a9226180c", - "sha256:c2dad2bfc502344b869d4a3f4aa7271b2a5f4fe41f7328f404844c51612e2c58", - "sha256:e851f8874398dcd50d1e174e810e9331563d189356e945b3271c0e19ee6f4d6f", - "sha256:e9d228ced1214d67904f26fb820c8abbea12b2889cd4aa8cda20a4ca0ed781c1", - "sha256:f2d5b5d6e87d482e17696a7bfa03fe9515fdfe27e462a4ad37f3d7774a5e2fd6" + "sha256:0e8102d5036e28d08ab47166b48c8d5e5810704daecf3a476a4282d562be9a28", + "sha256:151ac2bf65ccf363664a689b8beafc9e6aae36263db114b4ca06fbbbf827444a", + "sha256:1d54fb9e6038284548072df22fd34777e434153f7ffac72c8596f2d6987110dd", + "sha256:3a11936adbc379a6061ea32fa03338d4ca7248d86dd507c81e13af428a5bc1db", + "sha256:436aaaae2c916ad16631142488e4c82f4296af2404f480e031d866863425d2a2", + "sha256:552fd1b6ee22900cf1780d7386a554bb96949e9a359999177cf30211e6b20df6", + "sha256:6a885a9edc9c0a341cab27ec4f8a6c58b35f3d449c9d2503a6fd23e06bbd4f6a", + "sha256:7617164951c422747e7c32be4afa15d75ad8044f42e7d70d3e2e0429a50e6718", + "sha256:79970a6d759eb00a62266a31e2637d07d2d28446fca8079cf9afa7c07b0427f8", + "sha256:850a00b559e636b23901aabbe79b73dc604b4e4248ba9e2d6e72f95063765603", + "sha256:8be549886f5eda46436b6e555b0e4873b4f10aa21c07df45c4bc1735afbccd7a", + "sha256:981287869e576d42c682cf7ca96af0c6ac544ed9316328fd0d9292795c742cf5", + "sha256:9877af9c6d1b15486e18a94101b742e9d0d2f343d35a634e337411ddb57783f3", + "sha256:998d38fcec96584deee1e79cd127469b3ad6fefd1ea6c2dfc54e8db367eb396b", + "sha256:9d953531f5d9f00c90c34fa3b7d7cfb43ecff4c605dac9e4255a20b114a27369", + "sha256:ae80c08834a473d08a204d966982a62e11c976228d306a2648c575e3ead12111", + "sha256:c470f53cea065ff3d588050955c492793bb50c19a92923490d18fcb637f6383a", + "sha256:c7e28d8fa47a0b30ae1bd7a079519dd852764e31708a7804da6cb6f8b36e3630", + "sha256:ded35e810438a527e17623ac6deae3b360134345b7c598175ab7741720d7ffa7", + "sha256:ee04835fb016e8062ee9fe9074aef9b82e430504e420bff51e3e5fffe72750ca", + "sha256:fd6e2d7389542eae01077a1ee0318c4fec20c66c957f45c7aac0c6eb0fe3c612" ], "index": "pypi", - "version": "==1.1.1" + "markers": "python_version >= '3.8'", + "version": "==1.3.0" }, "scipy": { "hashes": [ - "sha256:02b567e722d62bddd4ac253dafb01ce7ed8742cf8031aea030a41414b86c1125", - "sha256:1166514aa3bbf04cb5941027c6e294a000bba0cf00f5cdac6c77f2dad479b434", - "sha256:1da52b45ce1a24a4a22db6c157c38b39885a990a566748fc904ec9f03ed8c6ba", - "sha256:23b22fbeef3807966ea42d8163322366dd89da9bebdc075da7034cee3a1441ca", - "sha256:28d2cab0c6ac5aa131cc5071a3a1d8e1366dad82288d9ec2ca44df78fb50e649", - "sha256:2ef0fbc8bcf102c1998c1f16f15befe7cffba90895d6e84861cd6c6a33fb54f6", - "sha256:3b69b90c9419884efeffaac2c38376d6ef566e6e730a231e15722b0ab58f0328", - "sha256:4b93ec6f4c3c4d041b26b5f179a6aab8f5045423117ae7a45ba9710301d7e462", - "sha256:4e53a55f6a4f22de01ffe1d2f016e30adedb67a699a310cdcac312806807ca81", - "sha256:6311e3ae9cc75f77c33076cb2794fb0606f14c8f1b1c9ff8ce6005ba2c283621", - "sha256:65b77f20202599c51eb2771d11a6b899b97989159b7975e9b5259594f1d35ef4", - "sha256:6cc6b33139eb63f30725d5f7fa175763dc2df6a8f38ddf8df971f7c345b652dc", - "sha256:70de2f11bf64ca9921fda018864c78af7147025e467ce9f4a11bc877266900a6", - "sha256:70ebc84134cf0c504ce6a5f12d6db92cb2a8a53a49437a6bb4edca0bc101f11c", - "sha256:83606129247e7610b58d0e1e93d2c5133959e9cf93555d3c27e536892f1ba1f2", - "sha256:93d07494a8900d55492401917a119948ed330b8c3f1d700e0b904a578f10ead4", - "sha256:9c4e3ae8a716c8b3151e16c05edb1daf4cb4d866caa385e861556aff41300c14", - "sha256:9dd4012ac599a1e7eb63c114d1eee1bcfc6dc75a29b589ff0ad0bb3d9412034f", - "sha256:9e3fb1b0e896f14a85aa9a28d5f755daaeeb54c897b746df7a55ccb02b340f33", - "sha256:a0aa8220b89b2e3748a2836fbfa116194378910f1a6e78e4675a095bcd2c762d", - "sha256:d3b3c8924252caaffc54d4a99f1360aeec001e61267595561089f8b5900821bb", - "sha256:e013aed00ed776d790be4cb32826adb72799c61e318676172495383ba4570aa4", - "sha256:f3e7a8867f307e3359cc0ed2c63b61a1e33a19080f92fe377bc7d49f646f2ec1" - ], - "markers": "python_version < '3.11' and python_version >= '3.8'", - "version": "==1.8.1" + "sha256:0f3261f14b767b316d7137c66cc4f33a80ea05841b9c87ad83a726205b901423", + "sha256:10eb6af2f751aa3424762948e5352f707b0dece77288206f227864ddf675aca0", + "sha256:1342ca385c673208f32472830c10110a9dcd053cf0c4b7d4cd7026d0335a6c1d", + "sha256:214cdf04bbae7a54784f8431f976704ed607c4bc69ba0d5d5d6a9df84374df76", + "sha256:2b997a5369e2d30c97995dcb29d638701f8000d04df01b8e947f206e5d0ac788", + "sha256:2c91cf049ffb5575917f2a01da1da082fd24ed48120d08a6e7297dfcac771dcd", + "sha256:3aeb87661de987f8ec56fa6950863994cd427209158255a389fc5aea51fa7055", + "sha256:4447ad057d7597476f9862ecbd9285bbf13ba9d73ce25acfa4e4b11c6801b4c9", + "sha256:542a757e2a6ec409e71df3d8fd20127afbbacb1c07990cb23c5870c13953d899", + "sha256:8d9886f44ef8c9e776cb7527fb01455bf4f4a46c455c4682edc2c2cc8cd78562", + "sha256:90d3b1364e751d8214e325c371f0ee0dd38419268bf4888b2ae1040a6b266b2a", + "sha256:95763fbda1206bec41157582bea482f50eb3702c85fffcf6d24394b071c0e87a", + "sha256:ac74b1512d38718fb6a491c439aa7b3605b96b1ed3be6599c17d49d6c60fca18", + "sha256:afdb0d983f6135d50770dd979df50bf1c7f58b5b33e0eb8cf5c73c70600eae1d", + "sha256:b0620240ef445b5ddde52460e6bc3483b7c9c750275369379e5f609a1050911c", + "sha256:b133f237bd8ba73bad51bc12eb4f2d84cbec999753bf25ba58235e9fc2096d80", + "sha256:b29318a5e39bd200ca4381d80b065cdf3076c7d7281c5e36569e99273867f61d", + "sha256:b8425fa963a32936c9773ee3ce44a765d8ff67eed5f4ac81dc1e4a819a238ee9", + "sha256:d2b813bfbe8dec6a75164523de650bad41f4405d35b0fa24c2c28ae07fcefb20", + "sha256:d690e1ca993c8f7ede6d22e5637541217fc6a4d3f78b3672a6fe454dbb7eb9a7", + "sha256:e367904a0fec76433bf3fbf3e85bf60dae8e9e585ffd21898ab1085a29a04d16", + "sha256:ea932570b1c2a30edafca922345854ff2cd20d43cd9123b6dacfdecebfc1a80b", + "sha256:f28f1f6cfeb48339c192efc6275749b2a25a7e49c4d8369a28b6591da02fbc9a", + "sha256:f73102f769ee06041a3aa26b5841359b1a93cc364ce45609657751795e8f4a4a", + "sha256:fa4909c6c20c3d91480533cddbc0e7c6d849e7d9ded692918c76ce5964997898" + ], + "markers": "python_version < '3.13' and python_version >= '3.9'", + "version": "==1.11.2" }, "threadpoolctl": { "hashes": [ - "sha256:8b99adda265feb6773280df41eece7b2e6561b772d21ffd52e372f999024907b", - "sha256:a335baacfaa4400ae1f0d8e3a58d6674d2f8828e3716bb2802c44955ad391380" + "sha256:2b7818516e423bdaebb97c723f86a7c6b0a83d3f3b0970328d66f4d9104dc032", + "sha256:c96a0ba3bdddeaca37dc4cc7344aafad41cdb8c313f74fdfe387a867bba93355" ], - "markers": "python_version >= '3.6'", - "version": "==3.1.0" + "markers": "python_version >= '3.8'", + "version": "==3.2.0" } }, "develop": { "alabaster": { "hashes": [ - "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", - "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02" + "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3", + "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2" ], - "version": "==0.7.12" - }, - "attrs": { - "hashes": [ - "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", - "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==21.4.0" + "markers": "python_version >= '3.6'", + "version": "==0.7.13" }, "babel": { "hashes": [ - "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51", - "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb" + "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610", + "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455" ], - "markers": "python_version >= '3.6'", - "version": "==2.10.3" + "markers": "python_version >= '3.7'", + "version": "==2.12.1" }, "bleach": { "hashes": [ - "sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a", - "sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c" + "sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414", + "sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4" ], "markers": "python_version >= '3.7'", - "version": "==5.0.1" + "version": "==6.0.0" }, "certifi": { "hashes": [ - "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d", - "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412" + "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082", + "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9" ], "markers": "python_version >= '3.6'", - "version": "==2022.6.15" + "version": "==2023.7.22" }, "charset-normalizer": { "hashes": [ - "sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5", - "sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413" - ], - "markers": "python_version >= '3.6'", - "version": "==2.1.0" - }, - "commonmark": { - "hashes": [ - "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60", - "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9" + "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96", + "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c", + "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710", + "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706", + "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020", + "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252", + "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad", + "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329", + "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a", + "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f", + "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6", + "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4", + "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a", + "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46", + "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2", + "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23", + "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace", + "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd", + "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982", + "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10", + "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2", + "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea", + "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09", + "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5", + "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149", + "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489", + "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9", + "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80", + "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592", + "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3", + "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6", + "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed", + "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c", + "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200", + "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a", + "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e", + "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d", + "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6", + "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623", + "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669", + "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3", + "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa", + "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9", + "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2", + "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f", + "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1", + "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4", + "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a", + "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8", + "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3", + "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029", + "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f", + "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959", + "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22", + "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7", + "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952", + "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346", + "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e", + "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d", + "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299", + "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd", + "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a", + "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3", + "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037", + "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94", + "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c", + "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858", + "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a", + "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449", + "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c", + "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918", + "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1", + "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c", + "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac", + "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa" ], - "version": "==0.9.1" + "markers": "python_full_version >= '3.7.0'", + "version": "==3.2.0" }, "coverage": { "extras": [ "toml" ], "hashes": [ - "sha256:0895ea6e6f7f9939166cc835df8fa4599e2d9b759b02d1521b574e13b859ac32", - "sha256:0f211df2cba951ffcae210ee00e54921ab42e2b64e0bf2c0befc977377fb09b7", - "sha256:147605e1702d996279bb3cc3b164f408698850011210d133a2cb96a73a2f7996", - "sha256:24b04d305ea172ccb21bee5bacd559383cba2c6fcdef85b7701cf2de4188aa55", - "sha256:25b7ec944f114f70803d6529394b64f8749e93cbfac0fe6c5ea1b7e6c14e8a46", - "sha256:2b20286c2b726f94e766e86a3fddb7b7e37af5d0c635bdfa7e4399bc523563de", - "sha256:2dff52b3e7f76ada36f82124703f4953186d9029d00d6287f17c68a75e2e6039", - "sha256:2f8553878a24b00d5ab04b7a92a2af50409247ca5c4b7a2bf4eabe94ed20d3ee", - "sha256:3def6791adf580d66f025223078dc84c64696a26f174131059ce8e91452584e1", - "sha256:422fa44070b42fef9fb8dabd5af03861708cdd6deb69463adc2130b7bf81332f", - "sha256:4f89d8e03c8a3757aae65570d14033e8edf192ee9298303db15955cadcff0c63", - "sha256:5336e0352c0b12c7e72727d50ff02557005f79a0b8dcad9219c7c4940a930083", - "sha256:54d8d0e073a7f238f0666d3c7c0d37469b2aa43311e4024c925ee14f5d5a1cbe", - "sha256:5ef42e1db047ca42827a85e34abe973971c635f83aed49611b7f3ab49d0130f0", - "sha256:5f65e5d3ff2d895dab76b1faca4586b970a99b5d4b24e9aafffc0ce94a6022d6", - "sha256:6c3ccfe89c36f3e5b9837b9ee507472310164f352c9fe332120b764c9d60adbe", - "sha256:6d0b48aff8e9720bdec315d67723f0babd936a7211dc5df453ddf76f89c59933", - "sha256:6fe75dcfcb889b6800f072f2af5a331342d63d0c1b3d2bf0f7b4f6c353e8c9c0", - "sha256:79419370d6a637cb18553ecb25228893966bd7935a9120fa454e7076f13b627c", - "sha256:7bb00521ab4f99fdce2d5c05a91bddc0280f0afaee0e0a00425e28e209d4af07", - "sha256:80db4a47a199c4563d4a25919ff29c97c87569130375beca3483b41ad5f698e8", - "sha256:866ebf42b4c5dbafd64455b0a1cd5aa7b4837a894809413b930026c91e18090b", - "sha256:8af6c26ba8df6338e57bedbf916d76bdae6308e57fc8f14397f03b5da8622b4e", - "sha256:a13772c19619118903d65a91f1d5fea84be494d12fd406d06c849b00d31bf120", - "sha256:a697977157adc052284a7160569b36a8bbec09db3c3220642e6323b47cec090f", - "sha256:a9032f9b7d38bdf882ac9f66ebde3afb8145f0d4c24b2e600bc4c6304aafb87e", - "sha256:b5e28db9199dd3833cc8a07fa6cf429a01227b5d429facb56eccd765050c26cd", - "sha256:c77943ef768276b61c96a3eb854eba55633c7a3fddf0a79f82805f232326d33f", - "sha256:d230d333b0be8042ac34808ad722eabba30036232e7a6fb3e317c49f61c93386", - "sha256:d4548be38a1c810d79e097a38107b6bf2ff42151900e47d49635be69943763d8", - "sha256:d4e7ced84a11c10160c0697a6cc0b214a5d7ab21dfec1cd46e89fbf77cc66fae", - "sha256:d56f105592188ce7a797b2bd94b4a8cb2e36d5d9b0d8a1d2060ff2a71e6b9bbc", - "sha256:d714af0bdba67739598849c9f18efdcc5a0412f4993914a0ec5ce0f1e864d783", - "sha256:d774d9e97007b018a651eadc1b3970ed20237395527e22cbeb743d8e73e0563d", - "sha256:e0524adb49c716ca763dbc1d27bedce36b14f33e6b8af6dba56886476b42957c", - "sha256:e2618cb2cf5a7cc8d698306e42ebcacd02fb7ef8cfc18485c59394152c70be97", - "sha256:e36750fbbc422c1c46c9d13b937ab437138b998fe74a635ec88989afb57a3978", - "sha256:edfdabe7aa4f97ed2b9dd5dde52d2bb29cb466993bb9d612ddd10d0085a683cf", - "sha256:f22325010d8824594820d6ce84fa830838f581a7fd86a9235f0d2ed6deb61e29", - "sha256:f23876b018dfa5d3e98e96f5644b109090f16a4acb22064e0f06933663005d39", - "sha256:f7bd0ffbcd03dc39490a1f40b2669cc414fae0c4e16b77bb26806a4d0b7d1452" + "sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34", + "sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e", + "sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7", + "sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b", + "sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3", + "sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985", + "sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95", + "sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2", + "sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a", + "sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74", + "sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd", + "sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af", + "sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54", + "sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865", + "sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214", + "sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54", + "sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe", + "sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0", + "sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321", + "sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446", + "sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e", + "sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527", + "sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12", + "sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f", + "sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f", + "sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84", + "sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479", + "sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e", + "sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873", + "sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70", + "sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0", + "sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977", + "sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51", + "sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28", + "sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1", + "sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254", + "sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1", + "sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd", + "sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689", + "sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d", + "sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543", + "sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9", + "sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637", + "sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071", + "sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482", + "sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1", + "sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b", + "sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5", + "sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a", + "sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393", + "sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a", + "sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba" ], - "markers": "python_version >= '3.7'", - "version": "==6.4.2" + "markers": "python_version >= '3.8'", + "version": "==7.3.0" }, "docutils": { "hashes": [ - "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125", - "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61" + "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af", + "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==0.17.1" + "version": "==0.16" }, "flake8": { "hashes": [ - "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d", - "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d" + "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23", + "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5" ], - "markers": "python_version >= '3.6'", - "version": "==4.0.1" + "markers": "python_full_version >= '3.8.1'", + "version": "==6.1.0" }, "idna": { "hashes": [ - "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", - "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" + "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", + "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" ], "markers": "python_version >= '3.5'", - "version": "==3.3" + "version": "==3.4" }, "imagesize": { "hashes": [ @@ -259,18 +340,27 @@ }, "importlib-metadata": { "hashes": [ - "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670", - "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23" + "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb", + "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743" ], - "markers": "python_version >= '3.7'", - "version": "==4.12.0" + "markers": "python_version >= '3.8'", + "version": "==6.8.0" }, "iniconfig": { "hashes": [ - "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", - "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" + "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", + "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" ], - "version": "==1.1.1" + "markers": "python_version >= '3.7'", + "version": "==2.0.0" + }, + "jaraco.classes": { + "hashes": [ + "sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb", + "sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621" + ], + "markers": "python_version >= '3.8'", + "version": "==3.3.0" }, "jinja2": { "hashes": [ @@ -282,152 +372,173 @@ }, "keyring": { "hashes": [ - "sha256:782e1cd1132e91bf459fcd243bcf25b326015c1ac0b198e4408f91fa6791062b", - "sha256:e67fc91a7955785fd2efcbccdd72d7dacf136dbc381d27de305b2b660b3de886" + "sha256:4901caaf597bfd3bbd78c9a0c7c4c29fcd8310dab2cffefe749e916b6527acd6", + "sha256:ca0746a19ec421219f4d713f848fa297a661a8a8c1504867e55bfb5e09091509" ], - "markers": "python_version >= '3.7'", - "version": "==23.7.0" + "markers": "python_version >= '3.8'", + "version": "==24.2.0" + }, + "markdown-it-py": { + "hashes": [ + "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", + "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb" + ], + "markers": "python_version >= '3.8'", + "version": "==3.0.0" }, "markupsafe": { "hashes": [ - "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", - "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", - "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", - "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", - "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", - "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", - "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", - "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", - "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", - "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", - "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", - "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", - "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", - "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", - "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", - "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", - "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", - "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", - "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", - "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", - "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", - "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", - "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", - "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", - "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", - "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", - "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", - "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", - "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", - "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", - "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", - "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", - "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", - "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", - "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", - "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", - "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", - "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", - "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", - "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" + "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e", + "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e", + "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431", + "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686", + "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559", + "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc", + "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c", + "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0", + "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4", + "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9", + "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575", + "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba", + "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d", + "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3", + "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00", + "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155", + "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac", + "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52", + "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f", + "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8", + "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b", + "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24", + "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea", + "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198", + "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0", + "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee", + "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be", + "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2", + "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707", + "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6", + "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58", + "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779", + "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636", + "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c", + "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad", + "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee", + "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc", + "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2", + "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48", + "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7", + "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e", + "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b", + "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa", + "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5", + "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e", + "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb", + "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9", + "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57", + "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc", + "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2" ], "markers": "python_version >= '3.7'", - "version": "==2.1.1" + "version": "==2.1.3" }, "mccabe": { "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", + "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" ], - "version": "==0.6.1" + "markers": "python_version >= '3.6'", + "version": "==0.7.0" }, - "packaging": { + "mdurl": { "hashes": [ - "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", - "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" + "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", + "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" ], - "markers": "python_version >= '3.6'", - "version": "==21.3" + "markers": "python_version >= '3.7'", + "version": "==0.1.2" }, - "pkginfo": { + "more-itertools": { "hashes": [ - "sha256:848865108ec99d4901b2f7e84058b6e7660aae8ae10164e015a6dcf5b242a594", - "sha256:a84da4318dd86f870a9447a8c98340aa06216bfc6f2b7bdc4b8766984ae1867c" + "sha256:626c369fa0eb37bac0291bce8259b332fd59ac792fa5497b59837309cd5b114a", + "sha256:64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.8.3" + "markers": "python_version >= '3.8'", + "version": "==10.1.0" }, - "pluggy": { + "packaging": { "hashes": [ - "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", - "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" + "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61", + "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f" + ], + "markers": "python_version >= '3.7'", + "version": "==23.1" + }, + "pkginfo": { + "hashes": [ + "sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546", + "sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046" ], "markers": "python_version >= '3.6'", - "version": "==1.0.0" + "version": "==1.9.6" }, - "py": { + "pluggy": { "hashes": [ - "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", - "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" + "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12", + "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.11.0" + "markers": "python_version >= '3.8'", + "version": "==1.3.0" }, "pycodestyle": { "hashes": [ - "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20", - "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f" + "sha256:259bcc17857d8a8b3b4a2327324b79e5f020a13c16074670f9c8c8f872ea76d0", + "sha256:5d1013ba8dc7895b548be5afb05740ca82454fd899971563d2ef625d090326f8" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==2.8.0" + "markers": "python_version >= '3.8'", + "version": "==2.11.0" }, "pydocstyle": { "hashes": [ - "sha256:1d41b7c459ba0ee6c345f2eb9ae827cab14a7533a88c5c6f7e94923f72df92dc", - "sha256:6987826d6775056839940041beef5c08cc7e3d71d63149b48e36727f70144dc4" + "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019", + "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1" ], "markers": "python_version >= '3.6'", - "version": "==6.1.1" + "version": "==6.3.0" }, "pyflakes": { "hashes": [ - "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c", - "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e" + "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774", + "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.4.0" + "markers": "python_version >= '3.8'", + "version": "==3.1.0" }, "pygments": { "hashes": [ - "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb", - "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519" + "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692", + "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29" ], - "markers": "python_version >= '3.6'", - "version": "==2.12.0" - }, - "pyparsing": { - "hashes": [ - "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", - "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" - ], - "markers": "python_full_version >= '3.6.8'", - "version": "==3.0.9" + "markers": "python_version >= '3.7'", + "version": "==2.16.1" }, "pytest": { "hashes": [ - "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c", - "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45" + "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32", + "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a" ], "index": "pypi", - "version": "==7.1.2" + "markers": "python_version >= '3.7'", + "version": "==7.4.0" }, "pytest-cov": { "hashes": [ - "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6", - "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470" + "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6", + "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a" ], "index": "pypi", - "version": "==3.0.0" + "markers": "python_version >= '3.7'", + "version": "==4.1.0" }, "pytest-flake8": { "hashes": [ @@ -439,40 +550,35 @@ }, "pytest-pydocstyle": { "hashes": [ - "sha256:1f2d937349cfeb4965c530a0c0f2442b48c03299558db435b65549719510d32b" + "sha256:a30b28d49607b2fcd7b24678ab6c4e27a288710a34b3a0f1f90f3497e88771c3" ], "index": "pypi", - "version": "==2.3.0" - }, - "pytz": { - "hashes": [ - "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7", - "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c" - ], - "version": "==2022.1" + "markers": "python_version ~= '3.7'", + "version": "==2.3.2" }, "readme-renderer": { "hashes": [ - "sha256:73b84905d091c31f36e50b4ae05ae2acead661f6a09a9abb4df7d2ddcdb6a698", - "sha256:a727999acfc222fc21d82a12ed48c957c4989785e5865807c65a487d21677497" + "sha256:4f4b11e5893f5a5d725f592c5a343e0dc74f5f273cb3dcf8c42d9703a27073f7", + "sha256:a38243d5b6741b700a850026e62da4bd739edc7422071e95fd5c4bb60171df86" ], - "markers": "python_version >= '3.7'", - "version": "==35.0" + "markers": "python_version >= '3.8'", + "version": "==41.0" }, "requests": { "hashes": [ - "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", - "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349" + "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", + "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" ], - "markers": "python_version >= '3.7' and python_version < '4'", - "version": "==2.28.1" + "markers": "python_version >= '3.7'", + "version": "==2.31.0" }, "requests-toolbelt": { "hashes": [ - "sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f", - "sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0" + "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", + "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06" ], - "version": "==0.9.1" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.0.0" }, "rfc3986": { "hashes": [ @@ -484,11 +590,19 @@ }, "rich": { "hashes": [ - "sha256:2eb4e6894cde1e017976d2975ac210ef515d7548bc595ba20e195fb9628acdeb", - "sha256:63a5c5ce3673d3d5fbbf23cd87e11ab84b6b451436f1b7f19ec54b6bc36ed7ca" + "sha256:146a90b3b6b47cac4a73c12866a499e9817426423f57c5a66949c086191a8808", + "sha256:fb9d6c0a0f643c99eed3875b5377a184132ba9be4d61516a55273d3554d75a39" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==13.5.2" + }, + "setuptools": { + "hashes": [ + "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d", + "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b" ], - "markers": "python_version < '4' and python_full_version >= '3.6.3'", - "version": "==12.5.1" + "markers": "python_version >= '3.8'", + "version": "==68.1.2" }, "six": { "hashes": [ @@ -507,27 +621,28 @@ }, "sphinx": { "hashes": [ - "sha256:50661b4dbe6a4a1ac15692a7b6db48671da6bae1d4d507e814f1b8525b6bba86", - "sha256:7893d10d9d852c16673f9b1b7e9eda1606b420b7810270294d6e4b44c0accacc" + "sha256:23c846a1841af998cb736218539bb86d16f5eb95f5760b1966abcd2d584e62b8", + "sha256:3d513088236eef51e5b0adb78b0492eb22cc3b8ccdb0b36dd021173b365d4454" ], "index": "pypi", - "version": "==5.1.0" + "markers": "python_version >= '3.6'", + "version": "==4.1.1" }, "sphinx-rtd-theme": { "hashes": [ - "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8", - "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c" + "sha256:32bd3b5d13dc8186d7a42fc816a23d32e83a4827d7d9882948e7b837c232da5a", + "sha256:4a05bdbe8b1446d77a01e20a23ebc6777c74f43237035e76be89699308987d6f" ], "index": "pypi", - "version": "==1.0.0" + "version": "==0.5.2" }, "sphinxcontrib-applehelp": { "hashes": [ - "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a", - "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58" + "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228", + "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e" ], - "markers": "python_version >= '3.5'", - "version": "==1.0.2" + "markers": "python_version >= '3.8'", + "version": "==1.0.4" }, "sphinxcontrib-devhelp": { "hashes": [ @@ -539,11 +654,11 @@ }, "sphinxcontrib-htmlhelp": { "hashes": [ - "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07", - "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2" + "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff", + "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903" ], - "markers": "python_version >= '3.6'", - "version": "==2.0.0" + "markers": "python_version >= '3.8'", + "version": "==2.0.1" }, "sphinxcontrib-jsmath": { "hashes": [ @@ -569,29 +684,22 @@ "markers": "python_version >= '3.5'", "version": "==1.1.5" }, - "tomli": { - "hashes": [ - "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", - "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" - ], - "markers": "python_version >= '3.7'", - "version": "==2.0.1" - }, "twine": { "hashes": [ - "sha256:42026c18e394eac3e06693ee52010baa5313e4811d5a11050e7d48436cf41b9e", - "sha256:96b1cf12f7ae611a4a40b6ae8e9570215daff0611828f5fe1f37a16255ab24a0" + "sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8", + "sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8" ], "index": "pypi", - "version": "==4.0.1" + "markers": "python_version >= '3.7'", + "version": "==4.0.2" }, "urllib3": { "hashes": [ - "sha256:8298d6d56d39be0e3bc13c1c97d133f9b45d797169a0e11cdd0e0489d786f7ec", - "sha256:879ba4d1e89654d9769ce13121e0f94310ea32e8d2f8cf587b77c08bbcdb30d6" + "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11", + "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' and python_version < '4'", - "version": "==1.26.10" + "markers": "python_version >= '3.7'", + "version": "==2.0.4" }, "webencodings": { "hashes": [ @@ -602,11 +710,616 @@ }, "zipp": { "hashes": [ - "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2", - "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009" + "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0", + "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147" + ], + "markers": "python_version >= '3.8'", + "version": "==3.16.2" + } + }, + "extras": { + "aiosignal": { + "hashes": [ + "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", + "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17" + ], + "markers": "python_version >= '3.7'", + "version": "==1.3.1" + }, + "attrs": { + "hashes": [ + "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04", + "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015" + ], + "markers": "python_version >= '3.7'", + "version": "==23.1.0" + }, + "certifi": { + "hashes": [ + "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082", + "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9" + ], + "markers": "python_version >= '3.6'", + "version": "==2023.7.22" + }, + "charset-normalizer": { + "hashes": [ + "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96", + "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c", + "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710", + "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706", + "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020", + "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252", + "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad", + "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329", + "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a", + "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f", + "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6", + "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4", + "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a", + "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46", + "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2", + "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23", + "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace", + "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd", + "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982", + "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10", + "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2", + "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea", + "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09", + "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5", + "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149", + "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489", + "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9", + "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80", + "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592", + "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3", + "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6", + "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed", + "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c", + "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200", + "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a", + "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e", + "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d", + "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6", + "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623", + "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669", + "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3", + "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa", + "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9", + "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2", + "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f", + "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1", + "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4", + "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a", + "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8", + "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3", + "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029", + "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f", + "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959", + "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22", + "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7", + "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952", + "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346", + "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e", + "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d", + "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299", + "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd", + "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a", + "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3", + "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037", + "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94", + "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c", + "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858", + "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a", + "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449", + "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c", + "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918", + "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1", + "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c", + "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac", + "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==3.2.0" + }, + "click": { + "hashes": [ + "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", + "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" + ], + "markers": "python_version >= '3.7'", + "version": "==8.1.7" + }, + "filelock": { + "hashes": [ + "sha256:0ecc1dd2ec4672a10c8550a8182f1bd0c0a5088470ecd5a125e45f49472fac3d", + "sha256:f067e40ccc40f2b48395a80fcbd4728262fab54e232e090a4063ab804179efeb" + ], + "markers": "python_version >= '3.8'", + "version": "==3.12.3" + }, + "frozenlist": { + "hashes": [ + "sha256:007df07a6e3eb3e33e9a1fe6a9db7af152bbd8a185f9aaa6ece10a3529e3e1c6", + "sha256:008eb8b31b3ea6896da16c38c1b136cb9fec9e249e77f6211d479db79a4eaf01", + "sha256:09163bdf0b2907454042edb19f887c6d33806adc71fbd54afc14908bfdc22251", + "sha256:0c7c1b47859ee2cac3846fde1c1dc0f15da6cec5a0e5c72d101e0f83dcb67ff9", + "sha256:0e5c8764c7829343d919cc2dfc587a8db01c4f70a4ebbc49abde5d4b158b007b", + "sha256:10ff5faaa22786315ef57097a279b833ecab1a0bfb07d604c9cbb1c4cdc2ed87", + "sha256:17ae5cd0f333f94f2e03aaf140bb762c64783935cc764ff9c82dff626089bebf", + "sha256:19488c57c12d4e8095a922f328df3f179c820c212940a498623ed39160bc3c2f", + "sha256:1a0848b52815006ea6596c395f87449f693dc419061cc21e970f139d466dc0a0", + "sha256:1e78fb68cf9c1a6aa4a9a12e960a5c9dfbdb89b3695197aa7064705662515de2", + "sha256:261b9f5d17cac914531331ff1b1d452125bf5daa05faf73b71d935485b0c510b", + "sha256:2b8bcf994563466db019fab287ff390fffbfdb4f905fc77bc1c1d604b1c689cc", + "sha256:38461d02d66de17455072c9ba981d35f1d2a73024bee7790ac2f9e361ef1cd0c", + "sha256:490132667476f6781b4c9458298b0c1cddf237488abd228b0b3650e5ecba7467", + "sha256:491e014f5c43656da08958808588cc6c016847b4360e327a62cb308c791bd2d9", + "sha256:515e1abc578dd3b275d6a5114030b1330ba044ffba03f94091842852f806f1c1", + "sha256:556de4430ce324c836789fa4560ca62d1591d2538b8ceb0b4f68fb7b2384a27a", + "sha256:5833593c25ac59ede40ed4de6d67eb42928cca97f26feea219f21d0ed0959b79", + "sha256:6221d84d463fb110bdd7619b69cb43878a11d51cbb9394ae3105d082d5199167", + "sha256:6918d49b1f90821e93069682c06ffde41829c346c66b721e65a5c62b4bab0300", + "sha256:6c38721585f285203e4b4132a352eb3daa19121a035f3182e08e437cface44bf", + "sha256:71932b597f9895f011f47f17d6428252fc728ba2ae6024e13c3398a087c2cdea", + "sha256:7211ef110a9194b6042449431e08c4d80c0481e5891e58d429df5899690511c2", + "sha256:764226ceef3125e53ea2cb275000e309c0aa5464d43bd72abd661e27fffc26ab", + "sha256:7645a8e814a3ee34a89c4a372011dcd817964ce8cb273c8ed6119d706e9613e3", + "sha256:76d4711f6f6d08551a7e9ef28c722f4a50dd0fc204c56b4bcd95c6cc05ce6fbb", + "sha256:7f4f399d28478d1f604c2ff9119907af9726aed73680e5ed1ca634d377abb087", + "sha256:88f7bc0fcca81f985f78dd0fa68d2c75abf8272b1f5c323ea4a01a4d7a614efc", + "sha256:8d0edd6b1c7fb94922bf569c9b092ee187a83f03fb1a63076e7774b60f9481a8", + "sha256:901289d524fdd571be1c7be054f48b1f88ce8dddcbdf1ec698b27d4b8b9e5d62", + "sha256:93ea75c050c5bb3d98016b4ba2497851eadf0ac154d88a67d7a6816206f6fa7f", + "sha256:981b9ab5a0a3178ff413bca62526bb784249421c24ad7381e39d67981be2c326", + "sha256:9ac08e601308e41eb533f232dbf6b7e4cea762f9f84f6357136eed926c15d12c", + "sha256:a02eb8ab2b8f200179b5f62b59757685ae9987996ae549ccf30f983f40602431", + "sha256:a0c6da9aee33ff0b1a451e867da0c1f47408112b3391dd43133838339e410963", + "sha256:a6c8097e01886188e5be3e6b14e94ab365f384736aa1fca6a0b9e35bd4a30bc7", + "sha256:aa384489fefeb62321b238e64c07ef48398fe80f9e1e6afeff22e140e0850eef", + "sha256:ad2a9eb6d9839ae241701d0918f54c51365a51407fd80f6b8289e2dfca977cc3", + "sha256:b206646d176a007466358aa21d85cd8600a415c67c9bd15403336c331a10d956", + "sha256:b826d97e4276750beca7c8f0f1a4938892697a6bcd8ec8217b3312dad6982781", + "sha256:b89ac9768b82205936771f8d2eb3ce88503b1556324c9f903e7156669f521472", + "sha256:bd7bd3b3830247580de99c99ea2a01416dfc3c34471ca1298bccabf86d0ff4dc", + "sha256:bdf1847068c362f16b353163391210269e4f0569a3c166bc6a9f74ccbfc7e839", + "sha256:c11b0746f5d946fecf750428a95f3e9ebe792c1ee3b1e96eeba145dc631a9672", + "sha256:c5374b80521d3d3f2ec5572e05adc94601985cc526fb276d0c8574a6d749f1b3", + "sha256:ca265542ca427bf97aed183c1676e2a9c66942e822b14dc6e5f42e038f92a503", + "sha256:ce31ae3e19f3c902de379cf1323d90c649425b86de7bbdf82871b8a2a0615f3d", + "sha256:ceb6ec0a10c65540421e20ebd29083c50e6d1143278746a4ef6bcf6153171eb8", + "sha256:d081f13b095d74b67d550de04df1c756831f3b83dc9881c38985834387487f1b", + "sha256:d5655a942f5f5d2c9ed93d72148226d75369b4f6952680211972a33e59b1dfdc", + "sha256:d5a32087d720c608f42caed0ef36d2b3ea61a9d09ee59a5142d6070da9041b8f", + "sha256:d6484756b12f40003c6128bfcc3fa9f0d49a687e171186c2d85ec82e3758c559", + "sha256:dd65632acaf0d47608190a71bfe46b209719bf2beb59507db08ccdbe712f969b", + "sha256:de343e75f40e972bae1ef6090267f8260c1446a1695e77096db6cfa25e759a95", + "sha256:e29cda763f752553fa14c68fb2195150bfab22b352572cb36c43c47bedba70eb", + "sha256:e41f3de4df3e80de75845d3e743b3f1c4c8613c3997a912dbf0229fc61a8b963", + "sha256:e66d2a64d44d50d2543405fb183a21f76b3b5fd16f130f5c99187c3fb4e64919", + "sha256:e74b0506fa5aa5598ac6a975a12aa8928cbb58e1f5ac8360792ef15de1aa848f", + "sha256:f0ed05f5079c708fe74bf9027e95125334b6978bf07fd5ab923e9e55e5fbb9d3", + "sha256:f61e2dc5ad442c52b4887f1fdc112f97caeff4d9e6ebe78879364ac59f1663e1", + "sha256:fec520865f42e5c7f050c2a79038897b1c7d1595e907a9e08e3353293ffc948e" + ], + "markers": "python_version >= '3.8'", + "version": "==1.4.0" + }, + "grpcio": { + "hashes": [ + "sha256:00258cbe3f5188629828363ae8ff78477ce976a6f63fb2bb5e90088396faa82e", + "sha256:092fa155b945015754bdf988be47793c377b52b88d546e45c6a9f9579ac7f7b6", + "sha256:0f80bf37f09e1caba6a8063e56e2b87fa335add314cf2b78ebf7cb45aa7e3d06", + "sha256:20ec6fc4ad47d1b6e12deec5045ec3cd5402d9a1597f738263e98f490fe07056", + "sha256:2313b124e475aa9017a9844bdc5eafb2d5abdda9d456af16fc4535408c7d6da6", + "sha256:23e7d8849a0e58b806253fd206ac105b328171e01b8f18c7d5922274958cc87e", + "sha256:2f708a6a17868ad8bf586598bee69abded4996b18adf26fd2d91191383b79019", + "sha256:2f7349786da979a94690cc5c2b804cab4e8774a3cf59be40d037c4342c906649", + "sha256:34950353539e7d93f61c6796a007c705d663f3be41166358e3d88c45760c7d98", + "sha256:40b72effd4c789de94ce1be2b5f88d7b9b5f7379fe9645f198854112a6567d9a", + "sha256:4b089f7ad1eb00a104078bab8015b0ed0ebcb3b589e527ab009c53893fd4e613", + "sha256:4faea2cfdf762a664ab90589b66f416274887641ae17817de510b8178356bf73", + "sha256:5371bcd861e679d63b8274f73ac281751d34bd54eccdbfcd6aa00e692a82cd7b", + "sha256:5613a2fecc82f95d6c51d15b9a72705553aa0d7c932fad7aed7afb51dc982ee5", + "sha256:57b183e8b252825c4dd29114d6c13559be95387aafc10a7be645462a0fc98bbb", + "sha256:5b7a4ce8f862fe32b2a10b57752cf3169f5fe2915acfe7e6a1e155db3da99e79", + "sha256:5e5b58e32ae14658085c16986d11e99abd002ddbf51c8daae8a0671fffb3467f", + "sha256:60fe15288a0a65d5c1cb5b4a62b1850d07336e3ba728257a810317be14f0c527", + "sha256:6907b1cf8bb29b058081d2aad677b15757a44ef2d4d8d9130271d2ad5e33efca", + "sha256:76c44efa4ede1f42a9d5b2fed1fe9377e73a109bef8675fb0728eb80b0b8e8f2", + "sha256:7a635589201b18510ff988161b7b573f50c6a48fae9cb567657920ca82022b37", + "sha256:7b400807fa749a9eb286e2cd893e501b110b4d356a218426cb9c825a0474ca56", + "sha256:82640e57fb86ea1d71ea9ab54f7e942502cf98a429a200b2e743d8672171734f", + "sha256:871f9999e0211f9551f368612460442a5436d9444606184652117d6a688c9f51", + "sha256:9338bacf172e942e62e5889b6364e56657fbf8ac68062e8b25c48843e7b202bb", + "sha256:a8a8e560e8dbbdf29288872e91efd22af71e88b0e5736b0daf7773c1fecd99f0", + "sha256:aed90d93b731929e742967e236f842a4a2174dc5db077c8f9ad2c5996f89f63e", + "sha256:b363bbb5253e5f9c23d8a0a034dfdf1b7c9e7f12e602fc788c435171e96daccc", + "sha256:b4098b6b638d9e0ca839a81656a2fd4bc26c9486ea707e8b1437d6f9d61c3941", + "sha256:b53333627283e7241fcc217323f225c37783b5f0472316edcaa4479a213abfa6", + "sha256:b670c2faa92124b7397b42303e4d8eb64a4cd0b7a77e35a9e865a55d61c57ef9", + "sha256:bb396952cfa7ad2f01061fbc7dc1ad91dd9d69243bcb8110cf4e36924785a0fe", + "sha256:c60b83c43faeb6d0a9831f0351d7787a0753f5087cc6fa218d78fdf38e5acef0", + "sha256:c6ebecfb7a31385393203eb04ed8b6a08f5002f53df3d59e5e795edb80999652", + "sha256:d78d8b86fcdfa1e4c21f8896614b6cc7ee01a2a758ec0c4382d662f2a62cf766", + "sha256:d7f8df114d6b4cf5a916b98389aeaf1e3132035420a88beea4e3d977e5f267a5", + "sha256:e1cb52fa2d67d7f7fab310b600f22ce1ff04d562d46e9e0ac3e3403c2bb4cc16", + "sha256:e3fdf04e402f12e1de8074458549337febb3b45f21076cc02ef4ff786aff687e", + "sha256:e503cb45ed12b924b5b988ba9576dc9949b2f5283b8e33b21dcb6be74a7c58d0", + "sha256:f19ac6ac0a256cf77d3cc926ef0b4e64a9725cc612f97228cd5dc4bd9dbab03b", + "sha256:f1fb0fd4a1e9b11ac21c30c169d169ef434c6e9344ee0ab27cfa6f605f6387b2", + "sha256:fada6b07ec4f0befe05218181f4b85176f11d531911b64c715d1875c4736d73a", + "sha256:fd173b4cf02b20f60860dc2ffe30115c18972d7d6d2d69df97ac38dee03be5bf", + "sha256:fe752639919aad9ffb0dee0d87f29a6467d1ef764f13c4644d212a9a853a078d", + "sha256:fee387d2fab144e8a34e0e9c5ca0f45c9376b99de45628265cfa9886b1dbe62b" + ], + "markers": "python_version >= '3.10'", + "version": "==1.57.0" + }, + "idna": { + "hashes": [ + "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", + "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" + ], + "markers": "python_version >= '3.5'", + "version": "==3.4" + }, + "jsonschema": { + "hashes": [ + "sha256:043dc26a3845ff09d20e4420d6012a9c91c9aa8999fa184e7efcfeccb41e32cb", + "sha256:6e1e7569ac13be8139b2dd2c21a55d350066ee3f80df06c608b398cdc6f30e8f" + ], + "markers": "python_version >= '3.8'", + "version": "==4.19.0" + }, + "jsonschema-specifications": { + "hashes": [ + "sha256:05adf340b659828a004220a9613be00fa3f223f2b82002e273dee62fd50524b1", + "sha256:c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb" + ], + "markers": "python_version >= '3.8'", + "version": "==2023.7.1" + }, + "msgpack": { + "hashes": [ + "sha256:06f5174b5f8ed0ed919da0e62cbd4ffde676a374aba4020034da05fab67b9164", + "sha256:0c05a4a96585525916b109bb85f8cb6511db1c6f5b9d9cbcbc940dc6b4be944b", + "sha256:137850656634abddfb88236008339fdaba3178f4751b28f270d2ebe77a563b6c", + "sha256:17358523b85973e5f242ad74aa4712b7ee560715562554aa2134d96e7aa4cbbf", + "sha256:18334484eafc2b1aa47a6d42427da7fa8f2ab3d60b674120bce7a895a0a85bdd", + "sha256:1835c84d65f46900920b3708f5ba829fb19b1096c1800ad60bae8418652a951d", + "sha256:1967f6129fc50a43bfe0951c35acbb729be89a55d849fab7686004da85103f1c", + "sha256:1ab2f3331cb1b54165976a9d976cb251a83183631c88076613c6c780f0d6e45a", + "sha256:1c0f7c47f0087ffda62961d425e4407961a7ffd2aa004c81b9c07d9269512f6e", + "sha256:20a97bf595a232c3ee6d57ddaadd5453d174a52594bf9c21d10407e2a2d9b3bd", + "sha256:20c784e66b613c7f16f632e7b5e8a1651aa5702463d61394671ba07b2fc9e025", + "sha256:266fa4202c0eb94d26822d9bfd7af25d1e2c088927fe8de9033d929dd5ba24c5", + "sha256:28592e20bbb1620848256ebc105fc420436af59515793ed27d5c77a217477705", + "sha256:288e32b47e67f7b171f86b030e527e302c91bd3f40fd9033483f2cacc37f327a", + "sha256:3055b0455e45810820db1f29d900bf39466df96ddca11dfa6d074fa47054376d", + "sha256:332360ff25469c346a1c5e47cbe2a725517919892eda5cfaffe6046656f0b7bb", + "sha256:362d9655cd369b08fda06b6657a303eb7172d5279997abe094512e919cf74b11", + "sha256:366c9a7b9057e1547f4ad51d8facad8b406bab69c7d72c0eb6f529cf76d4b85f", + "sha256:36961b0568c36027c76e2ae3ca1132e35123dcec0706c4b7992683cc26c1320c", + "sha256:379026812e49258016dd84ad79ac8446922234d498058ae1d415f04b522d5b2d", + "sha256:382b2c77589331f2cb80b67cc058c00f225e19827dbc818d700f61513ab47bea", + "sha256:476a8fe8fae289fdf273d6d2a6cb6e35b5a58541693e8f9f019bfe990a51e4ba", + "sha256:48296af57cdb1d885843afd73c4656be5c76c0c6328db3440c9601a98f303d87", + "sha256:4867aa2df9e2a5fa5f76d7d5565d25ec76e84c106b55509e78c1ede0f152659a", + "sha256:4c075728a1095efd0634a7dccb06204919a2f67d1893b6aa8e00497258bf926c", + "sha256:4f837b93669ce4336e24d08286c38761132bc7ab29782727f8557e1eb21b2080", + "sha256:4f8d8b3bf1ff2672567d6b5c725a1b347fe838b912772aa8ae2bf70338d5a198", + "sha256:525228efd79bb831cf6830a732e2e80bc1b05436b086d4264814b4b2955b2fa9", + "sha256:5494ea30d517a3576749cad32fa27f7585c65f5f38309c88c6d137877fa28a5a", + "sha256:55b56a24893105dc52c1253649b60f475f36b3aa0fc66115bffafb624d7cb30b", + "sha256:56a62ec00b636583e5cb6ad313bbed36bb7ead5fa3a3e38938503142c72cba4f", + "sha256:57e1f3528bd95cc44684beda696f74d3aaa8a5e58c816214b9046512240ef437", + "sha256:586d0d636f9a628ddc6a17bfd45aa5b5efaf1606d2b60fa5d87b8986326e933f", + "sha256:5cb47c21a8a65b165ce29f2bec852790cbc04936f502966768e4aae9fa763cb7", + "sha256:6c4c68d87497f66f96d50142a2b73b97972130d93677ce930718f68828b382e2", + "sha256:821c7e677cc6acf0fd3f7ac664c98803827ae6de594a9f99563e48c5a2f27eb0", + "sha256:916723458c25dfb77ff07f4c66aed34e47503b2eb3188b3adbec8d8aa6e00f48", + "sha256:9e6ca5d5699bcd89ae605c150aee83b5321f2115695e741b99618f4856c50898", + "sha256:9f5ae84c5c8a857ec44dc180a8b0cc08238e021f57abdf51a8182e915e6299f0", + "sha256:a2b031c2e9b9af485d5e3c4520f4220d74f4d222a5b8dc8c1a3ab9448ca79c57", + "sha256:a61215eac016f391129a013c9e46f3ab308db5f5ec9f25811e811f96962599a8", + "sha256:a740fa0e4087a734455f0fc3abf5e746004c9da72fbd541e9b113013c8dc3282", + "sha256:a9985b214f33311df47e274eb788a5893a761d025e2b92c723ba4c63936b69b1", + "sha256:ab31e908d8424d55601ad7075e471b7d0140d4d3dd3272daf39c5c19d936bd82", + "sha256:ac9dd47af78cae935901a9a500104e2dea2e253207c924cc95de149606dc43cc", + "sha256:addab7e2e1fcc04bd08e4eb631c2a90960c340e40dfc4a5e24d2ff0d5a3b3edb", + "sha256:b1d46dfe3832660f53b13b925d4e0fa1432b00f5f7210eb3ad3bb9a13c6204a6", + "sha256:b2de4c1c0538dcb7010902a2b97f4e00fc4ddf2c8cda9749af0e594d3b7fa3d7", + "sha256:b5ef2f015b95f912c2fcab19c36814963b5463f1fb9049846994b007962743e9", + "sha256:b72d0698f86e8d9ddf9442bdedec15b71df3598199ba33322d9711a19f08145c", + "sha256:bae7de2026cbfe3782c8b78b0db9cbfc5455e079f1937cb0ab8d133496ac55e1", + "sha256:bf22a83f973b50f9d38e55c6aade04c41ddda19b00c4ebc558930d78eecc64ed", + "sha256:c075544284eadc5cddc70f4757331d99dcbc16b2bbd4849d15f8aae4cf36d31c", + "sha256:c396e2cc213d12ce017b686e0f53497f94f8ba2b24799c25d913d46c08ec422c", + "sha256:cb5aaa8c17760909ec6cb15e744c3ebc2ca8918e727216e79607b7bbce9c8f77", + "sha256:cdc793c50be3f01106245a61b739328f7dccc2c648b501e237f0699fe1395b81", + "sha256:d25dd59bbbbb996eacf7be6b4ad082ed7eacc4e8f3d2df1ba43822da9bfa122a", + "sha256:e42b9594cc3bf4d838d67d6ed62b9e59e201862a25e9a157019e171fbe672dd3", + "sha256:e57916ef1bd0fee4f21c4600e9d1da352d8816b52a599c46460e93a6e9f17086", + "sha256:ed40e926fa2f297e8a653c954b732f125ef97bdd4c889f243182299de27e2aa9", + "sha256:ef8108f8dedf204bb7b42994abf93882da1159728a2d4c5e82012edd92c9da9f", + "sha256:f933bbda5a3ee63b8834179096923b094b76f0c7a73c1cfe8f07ad608c58844b", + "sha256:fe5c63197c55bce6385d9aee16c4d0641684628f63ace85f73571e65ad1c1e8d" + ], + "version": "==1.0.5" + }, + "numpy": { + "hashes": [ + "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2", + "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55", + "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf", + "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01", + "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca", + "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901", + "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d", + "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4", + "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf", + "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380", + "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044", + "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545", + "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f", + "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f", + "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3", + "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364", + "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9", + "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418", + "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f", + "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295", + "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3", + "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187", + "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926", + "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357", + "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==1.25.2" + }, + "packaging": { + "hashes": [ + "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61", + "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f" + ], + "markers": "python_version >= '3.7'", + "version": "==23.1" + }, + "protobuf": { + "hashes": [ + "sha256:237b9a50bd3b7307d0d834c1b0eb1a6cd47d3f4c2da840802cd03ea288ae8880", + "sha256:25ae91d21e3ce8d874211110c2f7edd6384816fb44e06b2867afe35139e1fd1c", + "sha256:2b23bd6e06445699b12f525f3e92a916f2dcf45ffba441026357dea7fa46f42b", + "sha256:3b7b170d3491ceed33f723bbf2d5a260f8a4e23843799a3906f16ef736ef251e", + "sha256:4e69965e7e54de4db989289a9b971a099e626f6167a9351e9d112221fc691bc1", + "sha256:58e12d2c1aa428ece2281cef09bbaa6938b083bcda606db3da4e02e991a0d924", + "sha256:6bd26c1fa9038b26c5c044ee77e0ecb18463e957fefbaeb81a3feb419313a54e", + "sha256:77700b55ba41144fc64828e02afb41901b42497b8217b558e4a001f18a85f2e3", + "sha256:7fda70797ddec31ddfa3576cbdcc3ddbb6b3078b737a1a87ab9136af0570cd6e", + "sha256:839952e759fc40b5d46be319a265cf94920174d88de31657d5622b5d8d6be5cd", + "sha256:bb7aa97c252279da65584af0456f802bd4b2de429eb945bbc9b3d61a42a8cd16", + "sha256:c00c3c7eb9ad3833806e21e86dca448f46035242a680f81c3fe068ff65e79c74", + "sha256:c5cdd486af081bf752225b26809d2d0a85e575b80a84cde5172a05bbb1990099" + ], + "markers": "python_version >= '3.7'", + "version": "==4.24.2" + }, + "pyyaml": { + "hashes": [ + "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", + "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", + "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", + "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", + "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", + "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", + "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", + "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", + "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", + "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", + "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", + "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", + "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", + "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", + "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", + "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", + "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", + "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", + "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", + "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", + "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", + "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", + "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", + "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", + "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", + "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", + "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", + "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", + "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", + "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", + "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", + "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", + "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", + "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", + "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", + "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", + "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", + "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", + "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", + "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", + "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", + "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", + "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", + "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", + "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", + "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", + "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", + "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", + "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", + "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" + ], + "markers": "python_version >= '3.6'", + "version": "==6.0.1" + }, + "ray": { + "hashes": [ + "sha256:015a2aa30aba0719d20cdf8fa32c689b68016678cb20f46bd1df8b227c938b84", + "sha256:0a5870f9a16cb94080d770f83326d7e2163d88d75be240273cef4b932a071bb2", + "sha256:18d033cc468e5171d9995476c33f99a5b79f091c34265c7e9f3d8b1c9042437e", + "sha256:1a8de31a9a4049134cf7e97b725a4078c958a964d091cb3e812e31eddd013bd7", + "sha256:31f1dd05130e712b9b64ccad9e6eaa82c715bb25a0a45ffd48ebf4953f6fe347", + "sha256:3ccf809e5948333c1c8c81694514b5900259e79cbdc8bddd3680695820cafcf2", + "sha256:3e5a4bbc29268a64bd2a8d48ed60f32a5bcce285a2a4f4339174947733449e37", + "sha256:467b9aa63f09d20e3985457816d703fe27ea388cdcaa88ff5eff222f8074a05c", + "sha256:485e4cd46a569416a14a72c06fe7901b0e3902f3023100b375c477975824e707", + "sha256:4b4600c93e2e94b6ca75ef4b4cb92d7f98d4be5484273d6fbac4218fb82cf96f", + "sha256:56b920a1814decdd20a754b7c5048770684d6d3d242c83aa99da5d3e8c339f13", + "sha256:5923849ec0854ab3e5ca8873d47ed7e11074e1213a3c40f8864c9500de034313", + "sha256:787ec7f43f5b3ed85728cf4878bdfed0a334d9108b6af75ef3fe5c8d44a7f74d", + "sha256:81e2ee7252e2fbfb05a24124774a8de563daa261200a08d9cbc6b499f7262af1", + "sha256:8a3cde58dba07da7a62e1f804b3dae5b29de3be052e02e4559bff7e7cb4d4a3b", + "sha256:90b780e131f891185f9de2b9c08d1f2d729e5755c7389a1ddaa6f796fae0d787", + "sha256:a182a80aebf863b5d4e875bed0a80e83200e84f4f63c4126cef87cc01e43f067", + "sha256:a4ef2f52319286720be7f3bfe6043e9fd0b8cb7826cb2ffc90c23c1c42427464", + "sha256:abc6a537454506a5fa87137de058d12aeea38da7077aae6f0ebf6199e5f5b2a1", + "sha256:b358fd112876c3a249fd8cffbf20b26622817c78b2ade0a725a7036c693f8d70", + "sha256:bca66c8e8163f06dc5443623e7b221660529a39574a589ba9257f2188ea8bf6b", + "sha256:bdeacaafcbb97e5f1c3c3349e7fcc0c40f691cea2bf057027c5491ea1ac929b0", + "sha256:dff21468d621c8dac95b3df320e6c6121f6618f6827243fd75a057c8815c2498", + "sha256:e0f8eaf4c4592335722dad474685c2ffc98207b997e47a24b297a60db389a4cb" + ], + "index": "pypi", + "version": "==2.6.3" + }, + "referencing": { + "hashes": [ + "sha256:449b6669b6121a9e96a7f9e410b245d471e8d48964c67113ce9afe50c8dd7bdf", + "sha256:794ad8003c65938edcdbc027f1933215e0d0ccc0291e3ce20a4d87432b59efc0" + ], + "markers": "python_version >= '3.8'", + "version": "==0.30.2" + }, + "requests": { + "hashes": [ + "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", + "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + ], + "markers": "python_version >= '3.7'", + "version": "==2.31.0" + }, + "rpds-py": { + "hashes": [ + "sha256:00215f6a9058fbf84f9d47536902558eb61f180a6b2a0fa35338d06ceb9a2e5a", + "sha256:0028eb0967942d0d2891eae700ae1a27b7fd18604cfcb16a1ef486a790fee99e", + "sha256:0155c33af0676fc38e1107679be882077680ad1abb6303956b97259c3177e85e", + "sha256:063411228b852fb2ed7485cf91f8e7d30893e69b0acb207ec349db04cccc8225", + "sha256:0700c2133ba203c4068aaecd6a59bda22e06a5e46255c9da23cbf68c6942215d", + "sha256:08e08ccf5b10badb7d0a5c84829b914c6e1e1f3a716fdb2bf294e2bd01562775", + "sha256:0d292cabd7c8335bdd3237ded442480a249dbcdb4ddfac5218799364a01a0f5c", + "sha256:15932ec5f224b0e35764dc156514533a4fca52dcfda0dfbe462a1a22b37efd59", + "sha256:18f87baa20e02e9277ad8960cd89b63c79c05caf106f4c959a9595c43f2a34a5", + "sha256:1a6420a36975e0073acaeee44ead260c1f6ea56812cfc6c31ec00c1c48197173", + "sha256:1b401e8b9aece651512e62c431181e6e83048a651698a727ea0eb0699e9f9b74", + "sha256:1d7b7b71bcb82d8713c7c2e9c5f061415598af5938666beded20d81fa23e7640", + "sha256:23750a9b8a329844ba1fe267ca456bb3184984da2880ed17ae641c5af8de3fef", + "sha256:23a059143c1393015c68936370cce11690f7294731904bdae47cc3e16d0b2474", + "sha256:26d9fd624649a10e4610fab2bc820e215a184d193e47d0be7fe53c1c8f67f370", + "sha256:291c9ce3929a75b45ce8ddde2aa7694fc8449f2bc8f5bd93adf021efaae2d10b", + "sha256:298e8b5d8087e0330aac211c85428c8761230ef46a1f2c516d6a2f67fb8803c5", + "sha256:2c7c4266c1b61eb429e8aeb7d8ed6a3bfe6c890a1788b18dbec090c35c6b93fa", + "sha256:2d68a8e8a3a816629283faf82358d8c93fe5bd974dd2704152394a3de4cec22a", + "sha256:344b89384c250ba6a4ce1786e04d01500e4dac0f4137ceebcaad12973c0ac0b3", + "sha256:3455ecc46ea443b5f7d9c2f946ce4017745e017b0d0f8b99c92564eff97e97f5", + "sha256:3d544a614055b131111bed6edfa1cb0fb082a7265761bcb03321f2dd7b5c6c48", + "sha256:3e5c26905aa651cc8c0ddc45e0e5dea2a1296f70bdc96af17aee9d0493280a17", + "sha256:3f5cc8c7bc99d2bbcd704cef165ca7d155cd6464c86cbda8339026a42d219397", + "sha256:4992266817169997854f81df7f6db7bdcda1609972d8ffd6919252f09ec3c0f6", + "sha256:4d55528ef13af4b4e074d067977b1f61408602f53ae4537dccf42ba665c2c7bd", + "sha256:576da63eae7809f375932bfcbca2cf20620a1915bf2fedce4b9cc8491eceefe3", + "sha256:58fc4d66ee349a23dbf08c7e964120dc9027059566e29cf0ce6205d590ed7eca", + "sha256:5b9bf77008f2c55dabbd099fd3ac87009471d223a1c7ebea36873d39511b780a", + "sha256:5e7996aed3f65667c6dcc8302a69368435a87c2364079a066750a2eac75ea01e", + "sha256:5f7487be65b9c2c510819e744e375bd41b929a97e5915c4852a82fbb085df62c", + "sha256:6388e4e95a26717b94a05ced084e19da4d92aca883f392dffcf8e48c8e221a24", + "sha256:65af12f70355de29e1092f319f85a3467f4005e959ab65129cb697169ce94b86", + "sha256:668d2b45d62c68c7a370ac3dce108ffda482b0a0f50abd8b4c604a813a59e08f", + "sha256:71333c22f7cf5f0480b59a0aef21f652cf9bbaa9679ad261b405b65a57511d1e", + "sha256:7150b83b3e3ddaac81a8bb6a9b5f93117674a0e7a2b5a5b32ab31fdfea6df27f", + "sha256:748e472345c3a82cfb462d0dff998a7bf43e621eed73374cb19f307e97e08a83", + "sha256:75dbfd41a61bc1fb0536bf7b1abf272dc115c53d4d77db770cd65d46d4520882", + "sha256:7618a082c55cf038eede4a918c1001cc8a4411dfe508dc762659bcd48d8f4c6e", + "sha256:780fcb855be29153901c67fc9c5633d48aebef21b90aa72812fa181d731c6b00", + "sha256:78d10c431073dc6ebceed35ab22948a016cc2b5120963c13a41e38bdde4a7212", + "sha256:7a3a3d3e4f1e3cd2a67b93a0b6ed0f2499e33f47cc568e3a0023e405abdc0ff1", + "sha256:7b6975d3763d0952c111700c0634968419268e6bbc0b55fe71138987fa66f309", + "sha256:80772e3bda6787510d9620bc0c7572be404a922f8ccdfd436bf6c3778119464c", + "sha256:80992eb20755701753e30a6952a96aa58f353d12a65ad3c9d48a8da5ec4690cf", + "sha256:841128a22e6ac04070a0f84776d07e9c38c4dcce8e28792a95e45fc621605517", + "sha256:861d25ae0985a1dd5297fee35f476b60c6029e2e6e19847d5b4d0a43a390b696", + "sha256:872f3dcaa8bf2245944861d7311179d2c0c9b2aaa7d3b464d99a7c2e401f01fa", + "sha256:87c93b25d538c433fb053da6228c6290117ba53ff6a537c133b0f2087948a582", + "sha256:8856aa76839dc234d3469f1e270918ce6bec1d6a601eba928f45d68a15f04fc3", + "sha256:885e023e73ce09b11b89ab91fc60f35d80878d2c19d6213a32b42ff36543c291", + "sha256:899b5e7e2d5a8bc92aa533c2d4e55e5ebba095c485568a5e4bedbc163421259a", + "sha256:8ce8caa29ebbdcde67e5fd652c811d34bc01f249dbc0d61e5cc4db05ae79a83b", + "sha256:8e1c68303ccf7fceb50fbab79064a2636119fd9aca121f28453709283dbca727", + "sha256:8e7e2b3577e97fa43c2c2b12a16139b2cedbd0770235d5179c0412b4794efd9b", + "sha256:92f05fc7d832e970047662b3440b190d24ea04f8d3c760e33e7163b67308c878", + "sha256:97f5811df21703446b42303475b8b855ee07d6ab6cdf8565eff115540624f25d", + "sha256:9affee8cb1ec453382c27eb9043378ab32f49cd4bc24a24275f5c39bf186c279", + "sha256:a2da4a8c6d465fde36cea7d54bf47b5cf089073452f0e47c8632ecb9dec23c07", + "sha256:a6903cdca64f1e301af9be424798328c1fe3b4b14aede35f04510989fc72f012", + "sha256:a8ab1adf04ae2d6d65835995218fd3f3eb644fe20655ca8ee233e2c7270ff53b", + "sha256:a8edd467551c1102dc0f5754ab55cd0703431cd3044edf8c8e7d9208d63fa453", + "sha256:ac00c41dd315d147b129976204839ca9de699d83519ff1272afbe4fb9d362d12", + "sha256:ad277f74b1c164f7248afa968700e410651eb858d7c160d109fb451dc45a2f09", + "sha256:ae46a50d235f1631d9ec4670503f7b30405103034830bc13df29fd947207f795", + "sha256:afe6b5a04b2ab1aa89bad32ca47bf71358e7302a06fdfdad857389dca8fb5f04", + "sha256:b1cb078f54af0abd835ca76f93a3152565b73be0f056264da45117d0adf5e99c", + "sha256:b25136212a3d064a8f0b9ebbb6c57094c5229e0de76d15c79b76feff26aeb7b8", + "sha256:b3226b246facae14909b465061ddcfa2dfeadb6a64f407f24300d42d69bcb1a1", + "sha256:b98e75b21fc2ba5285aef8efaf34131d16af1c38df36bdca2f50634bea2d3060", + "sha256:bbd7b24d108509a1b9b6679fcc1166a7dd031dbef1f3c2c73788f42e3ebb3beb", + "sha256:bed57543c99249ab3a4586ddc8786529fbc33309e5e8a1351802a06ca2baf4c2", + "sha256:c0583f69522732bdd79dca4cd3873e63a29acf4a299769c7541f2ca1e4dd4bc6", + "sha256:c1e0e9916301e3b3d970814b1439ca59487f0616d30f36a44cead66ee1748c31", + "sha256:c651847545422c8131660704c58606d841e228ed576c8f1666d98b3d318f89da", + "sha256:c7853f27195598e550fe089f78f0732c66ee1d1f0eaae8ad081589a5a2f5d4af", + "sha256:cbae50d352e4717ffc22c566afc2d0da744380e87ed44a144508e3fb9114a3f4", + "sha256:cdbed8f21204398f47de39b0a9b180d7e571f02dfb18bf5f1b618e238454b685", + "sha256:d08395595c42bcd82c3608762ce734504c6d025eef1c06f42326a6023a584186", + "sha256:d4639111e73997567343df6551da9dd90d66aece1b9fc26c786d328439488103", + "sha256:d63787f289944cc4bde518ad2b5e70a4f0d6e2ce76324635359c74c113fd188f", + "sha256:d6d5f061f6a2aa55790b9e64a23dfd87b6664ab56e24cd06c78eb43986cb260b", + "sha256:d7865df1fb564092bcf46dac61b5def25342faf6352e4bc0e61a286e3fa26a3d", + "sha256:db6585b600b2e76e98131e0ac0e5195759082b51687ad0c94505970c90718f4a", + "sha256:e36d7369363d2707d5f68950a64c4e025991eb0177db01ccb6aa6facae48b69f", + "sha256:e7947d9a6264c727a556541b1630296bbd5d0a05068d21c38dde8e7a1c703ef0", + "sha256:eb2d59bc196e6d3b1827c7db06c1a898bfa0787c0574af398e65ccf2e97c0fbe", + "sha256:ee9c2f6ca9774c2c24bbf7b23086264e6b5fa178201450535ec0859739e6f78d", + "sha256:f4760e1b02173f4155203054f77a5dc0b4078de7645c922b208d28e7eb99f3e2", + "sha256:f70bec8a14a692be6dbe7ce8aab303e88df891cbd4a39af091f90b6702e28055", + "sha256:f869e34d2326e417baee430ae998e91412cc8e7fdd83d979277a90a0e79a5b47", + "sha256:f8b9a7cd381970e64849070aca7c32d53ab7d96c66db6c2ef7aa23c6e803f514", + "sha256:f99d74ddf9d3b6126b509e81865f89bd1283e3fc1b568b68cd7bd9dfa15583d7", + "sha256:f9e7e493ded7042712a374471203dd43ae3fff5b81e3de1a0513fa241af9fd41", + "sha256:fc72ae476732cdb7b2c1acb5af23b478b8a0d4b6fcf19b90dd150291e0d5b26b", + "sha256:fccbf0cd3411719e4c9426755df90bf3449d9fc5a89f077f4a7f1abd4f70c910", + "sha256:ffcf18ad3edf1c170e27e88b10282a2c449aa0358659592462448d71b2000cfc" + ], + "markers": "python_version >= '3.8'", + "version": "==0.10.0" + }, + "urllib3": { + "hashes": [ + "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11", + "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4" ], "markers": "python_version >= '3.7'", - "version": "==3.8.1" + "version": "==2.0.4" } } } diff --git a/docs/examples/plot_empty_levels.py b/docs/examples/plot_empty_levels.py index f3af3469..d7f6355e 100644 --- a/docs/examples/plot_empty_levels.py +++ b/docs/examples/plot_empty_levels.py @@ -11,6 +11,7 @@ .. figure:: ../algorithms/local_classifier_per_node.svg :align: center """ +import numpy as np from sklearn.linear_model import LogisticRegression from hiclass import LocalClassifierPerNode @@ -18,13 +19,16 @@ # Define data X_train = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]] X_test = [[9, 10], [7, 8], [5, 6], [3, 4], [1, 2]] -Y_train = [ - ["Bird"], - ["Reptile", "Snake"], - ["Reptile", "Lizard"], - ["Mammal", "Cat"], - ["Mammal", "Wolf", "Dog"], -] +Y_train = np.array( + [ + ["Bird"], + ["Reptile", "Snake"], + ["Reptile", "Lizard"], + ["Mammal", "Cat"], + ["Mammal", "Wolf", "Dog"], + ], + dtype=object, +) # Use random forest classifiers for every node rf = LogisticRegression() diff --git a/docs/requirements.txt b/docs/requirements.txt index 94392247..fc59178d 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -7,5 +7,5 @@ sphinx-gallery==0.10.1 matplotlib==3.5.2 pandas==1.4.2 ray==1.13.0 -numpy<1.24 +numpy git+https://github.com/charles9n/bert-sklearn.git@master diff --git a/hiclass/HierarchicalClassifier.py b/hiclass/HierarchicalClassifier.py index 306cc76b..7b8f1dba 100644 --- a/hiclass/HierarchicalClassifier.py +++ b/hiclass/HierarchicalClassifier.py @@ -1,7 +1,6 @@ """Shared code for all classifiers.""" import abc import logging -from typing import List import networkx as nx import numpy as np @@ -24,19 +23,17 @@ def make_leveled(y): Parameters ---------- - y : array-like of shape (n_samples, n_levels) or (n_samples, n_labels, n_levels) for multi-label classification + y : array-like of shape (n_samples, n_levels) The target values, i.e., hierarchical class labels for classification. Returns ------- - leveled_y : array-like of shape (n_samples, n_levels) or (n_samples, n_labels, n_levels) for multi-label classification + leveled_y : array-like of shape (n_samples, n_levels) The leveled target values, i.e., hierarchical class labels for classification. - Y is returned only to pass sklearn's checks. Notes ----- If rows are not iterable, returns the current y without modifications. - Y is returned only to pass sklearn's checks. Examples -------- @@ -46,28 +43,13 @@ def make_leveled(y): array([['a', ''], ['b', 'c']]) """ - # TODO: refactor this function to make it more readable - # TODO: add more tests, e.g., mixing different types and lists or np.ndarrays - if not isinstance(y, List): - return y - if not isinstance(y[0], List): - return y - elif not isinstance(y[0][0], List): + try: depth = max([len(row) for row in y]) - leveled_y = [[i for i in row] + [""] * (depth - len(row)) for row in y] - return np.array(leveled_y) - elif not isinstance(y[0][0][0], List): - rows = len(y) - multi_labels = max([len(row) for row in y]) - levels = max([len(label) for row in y for label in row]) - leveled_y = np.full((rows, multi_labels, levels), "", dtype=object) - for i, row in enumerate(y): - for j, multi_label in enumerate(row): - for k, label in enumerate(multi_label): - leveled_y[i, j, k] = y[i][j][k] - return np.array(leveled_y) - else: - raise ValueError("y.ndim must be <= 3") + except TypeError: + return y + y = np.array(y, dtype=object) + leveled_y = [[i for i in row] + [""] * (depth - len(row)) for row in y] + return np.array(leveled_y) class HierarchicalClassifier(abc.ABC): @@ -79,7 +61,6 @@ class HierarchicalClassifier(abc.ABC): def __init__( self, local_classifier: BaseEstimator = None, - tolerance: float = None, verbose: int = 0, edge_list: str = None, replace_classifiers: bool = True, @@ -87,7 +68,7 @@ def __init__( bert: bool = False, classifier_abbreviation: str = "", ): - r""" + """ Initialize a local hierarchical classifier. Parameters @@ -95,9 +76,6 @@ def __init__( local_classifier : BaseEstimator, default=LogisticRegression The local_classifier used to create the collection of local classifiers. Needs to have fit, predict and clone methods. - tolerance : float, default=None - The tolerance used to determine multi-labels. If set to None, only the child class with highest probability is predicted. - Otherwise, all child classes with :math:`probability >= max\_prob - tolerance` are predicted. verbose : int, default=0 Controls the verbosity when fitting and predicting. See https://verboselogs.readthedocs.io/en/latest/readme.html#overview-of-logging-levels @@ -116,7 +94,6 @@ def __init__( The abbreviation of the local hierarchical classifier to be displayed during logging. """ self.local_classifier = local_classifier - self.tolerance = tolerance self.verbose = verbose self.edge_list = edge_list self.replace_classifiers = replace_classifiers @@ -157,12 +134,6 @@ def _pre_fit(self, X, y, sample_weight): # Check that X and y have correct shape # and convert them to np.ndarray if need be - try: - if len(y) > 0: - y = make_leveled(y) - except TypeError: - pass - if not self.bert: self.X_, self.y_ = self._validate_data( X, y, multi_output=True, accept_sparse="csr", allow_nd=True @@ -176,6 +147,8 @@ def _pre_fit(self, X, y, sample_weight): else: self.sample_weight_ = None + self.y_ = make_leveled(self.y_) + # Create and configure logger self._create_logger() @@ -224,7 +197,6 @@ def _create_logger(self): self.logger_.addHandler(ch) def _disambiguate(self): - # TODO: refactor this function to make it more readable self.separator_ = "::HiClass::Separator::" if self.y_.ndim == 2: new_y = [] @@ -236,22 +208,6 @@ def _disambiguate(self): row.append(parent + self.separator_ + child) new_y.append(np.asarray(row, dtype=np.str_)) self.y_ = np.array(new_y) - if self.y_.ndim == 3: - new_y = [] - for i in range(self.y_.shape[0]): - new_y.append([]) - for j in range(self.y_.shape[1]): - new_y[i].append([str(self.y_[i, j, 0])]) - for k in range(1, self.y_.shape[2]): - new_cell = "" - if new_y[i][j][k - 1] != "": - new_cell = ( - new_y[i][j][k - 1] - + self.separator_ - + str(self.y_[i, j, k]) - ) - new_y[i][j].append(new_cell) - self.y_ = np.array(new_y) def _create_digraph(self): # Create DiGraph @@ -264,17 +220,13 @@ def _create_digraph(self): self._create_digraph_2d() - self._create_digraph_3d() - - if self.y_.ndim > 3: + if self.y_.ndim > 2: # Unsuported dimension self.logger_.error(f"y with {self.y_.ndim} dimensions detected") raise ValueError( f"Creating graph from y with {self.y_.ndim} dimensions is not supported" ) - self._save_classes() - def _create_digraph_1d(self): # Flatten 1D disguised as 2D if self.y_.ndim == 2 and self.y_.shape[1] == 1: @@ -283,7 +235,6 @@ def _create_digraph_1d(self): if self.y_.ndim == 1: # Create max_levels_ variable self.max_levels_ = 1 - self.ndim_ = 1 self.logger_.info(f"Creating digraph from {self.y_.size} 1D labels") for label in self.y_: self.hierarchy_.add_node(label) @@ -292,7 +243,6 @@ def _create_digraph_2d(self): if self.y_.ndim == 2: # Create max_levels variable self.max_levels_ = self.y_.shape[1] - self.ndim_ = 2 rows, columns = self.y_.shape self.logger_.info(f"Creating digraph from {rows} 2D labels") for row in range(rows): @@ -307,34 +257,6 @@ def _create_digraph_2d(self): elif parent != "" and column == 0: self.hierarchy_.add_node(parent) - def _create_digraph_3d(self): - if self.y_.ndim == 3: - self.max_multi_labels = self.y_.shape[1] - self.max_levels_ = self.y_.shape[2] - self.ndim_ = 3 - rows, multi_labels, columns = self.y_.shape - self.logger_.info(f"Creating digraph from {rows} 3D labels") - for row in range(rows): - for multi_label in range(multi_labels): - for column in range(columns - 1): - parent = self.y_[row, multi_label, column].split( - self.separator_ - )[-1] - child = self.y_[row, multi_label, column + 1].split( - self.separator_ - )[-1] - if parent != "" and child != "": - # Only add edge if both parent and child are not empty - self.hierarchy_.add_edge( - self.y_[row, multi_label, column], - self.y_[row, multi_label, column + 1], - ) - elif parent != "" and column == 0: - self.hierarchy_.add_node(parent) - - def _save_classes(self): - self.classes_ = np.array(self.hierarchy_.nodes) - def _export_digraph(self): # Check if edge_list is set if self.edge_list: @@ -388,18 +310,9 @@ def _convert_to_1d(self, y): def _remove_separator(self, y): # Remove separator from predictions if y.ndim == 2: - rows, columns = y.shape - for row in range(rows): - for column in range(1, columns): - y[row, column] = y[row, column].split(self.separator_)[-1] - elif y.ndim == 3: - rows, multi_labels, columns = y.shape - for row in range(rows): - for multi_label in range(multi_labels): - for column in range(1, columns): - y[row, multi_label, column] = y[row, multi_label, column].split( - self.separator_ - )[-1] + for i in range(y.shape[0]): + for j in range(1, y.shape[1]): + y[i, j] = y[i, j].split(self.separator_)[-1] def _fit_node_classifier( self, nodes, local_mode: bool = False, use_joblib: bool = False @@ -411,9 +324,9 @@ def _fit_node_classifier( local_mode=local_mode, ignore_reinit_error=True, ) - classifier = ray.put(self) + lcppn = ray.put(self) _parallel_fit = ray.remote(self._fit_classifier) - results = [_parallel_fit.remote(classifier, node) for node in nodes] + results = [_parallel_fit.remote(lcppn, node) for node in nodes] classifiers = ray.get(results) else: classifiers = Parallel(n_jobs=self.n_jobs)( diff --git a/hiclass/LocalClassifierPerLevel.py b/hiclass/LocalClassifierPerLevel.py index 91801d02..ce0c8f5d 100644 --- a/hiclass/LocalClassifierPerLevel.py +++ b/hiclass/LocalClassifierPerLevel.py @@ -140,7 +140,7 @@ def predict(self, X): # Input validation if not self.bert: - X = check_array(X, accept_sparse="csr") + X = check_array(X, accept_sparse="csr", allow_nd=True, ensure_2d=False) else: X = np.array(X) @@ -250,7 +250,10 @@ def _fit_classifier(self, level, separator): if len(unique_y) == 1 and self.replace_classifiers: classifier = ConstantClassifier() if not self.bert: - classifier.fit(X, y, sample_weight) + try: + classifier.fit(X, y, sample_weight) + except TypeError: + classifier.fit(X, y) else: classifier.fit(X, y) return classifier diff --git a/hiclass/LocalClassifierPerNode.py b/hiclass/LocalClassifierPerNode.py index b6da8f02..c26c57bb 100644 --- a/hiclass/LocalClassifierPerNode.py +++ b/hiclass/LocalClassifierPerNode.py @@ -150,7 +150,7 @@ def predict(self, X): # Input validation if not self.bert: - X = check_array(X, accept_sparse="csr") + X = check_array(X, accept_sparse="csr", allow_nd=True, ensure_2d=False) else: X = np.array(X) @@ -159,17 +159,36 @@ def predict(self, X): # TODO: Add threshold to stop prediction halfway if need be - self.logger_.info("Predicting") + bfs = nx.bfs_successors(self.hierarchy_, source=self.root_) - probabilities = self.predict_proba(X) + self.logger_.info("Predicting") - for row in range(X.shape[0]): - y[row, 0] = self._predict_successor(self.root_, probabilities[row, :]) - for level in range(1, self.max_levels_): - if y[row, level - 1] != "": - y[row, level] = self._predict_successor( - y[row, level - 1], probabilities[row, :] - ) + for predecessor, successors in bfs: + if predecessor == self.root_: + mask = [True] * X.shape[0] + subset_x = X[mask] + else: + mask = np.isin(y, predecessor).any(axis=1) + subset_x = X[mask] + if subset_x.shape[0] > 0: + probabilities = np.zeros((subset_x.shape[0], len(successors))) + for i, successor in enumerate(successors): + successor_name = str(successor).split(self.separator_)[-1] + self.logger_.info(f"Predicting for node '{successor_name}'") + classifier = self.hierarchy_.nodes[successor]["classifier"] + positive_index = np.where(classifier.classes_ == 1)[0] + probabilities[:, i] = classifier.predict_proba(subset_x)[ + :, positive_index + ][:, 0] + highest_probability = np.argmax(probabilities, axis=1) + prediction = [] + for i in highest_probability: + prediction.append(successors[i]) + level = nx.shortest_path_length( + self.hierarchy_, self.root_, predecessor + ) + prediction = np.array(prediction) + y[mask, level] = prediction y = self._convert_to_1d(y) @@ -177,56 +196,6 @@ def predict(self, X): return y - def predict_proba(self, X): - """ - Probability estimates. - - The returned estimates for all classes are ordered by the label of classes. - - Parameters - ---------- - X : {array-like, sparse matrix} of shape (n_samples, n_features) - Vector to be scored, where ``n_samples`` is the number of samples and - ``n_features`` is the number of features. - Internally, its dtype will be converted - to ``dtype=np.float32``. If a sparse matrix is provided, it will be - converted into a sparse ``csr_matrix``. - Returns - ------- - T : ndarray of shape (n_samples, n_classes) - Returns the probability of the sample for each class in the model, - where classes are ordered as they are in :code:`self.classes_`. - """ - # Check if fit has been called - check_is_fitted(self) - - # Input validation - if not self.bert: - X = check_array(X, accept_sparse="csr") - else: - X = np.array(X) - - T = np.zeros((X.shape[0], len(self.classes_))) - - for i, node in enumerate(self.classes_): - classifier = self.hierarchy_.nodes[node]["classifier"] - positive_index = np.where(classifier.classes_ == 1)[0] - T[:, i] = classifier.predict_proba(X)[:, positive_index][:, 0] - - return T - - def _predict_successor(self, node, probabilities): - successors = set(self.hierarchy_.successors(node)) - highest_probability = 0 - node_with_highest_probability = "" - if len(successors) > 0: - for i, node in enumerate(self.classes_): - if node in successors: - if probabilities[i] > highest_probability: - highest_probability = probabilities[i] - node_with_highest_probability = node - return node_with_highest_probability - def _initialize_binary_policy(self): if isinstance(self.binary_policy, str): self.logger_.info(f"Initializing {self.binary_policy} binary policy") @@ -272,7 +241,10 @@ def _fit_classifier(self, node): if len(unique_y) == 1 and self.replace_classifiers: classifier = ConstantClassifier() if not self.bert: - classifier.fit(X, y, sample_weight) + try: + classifier.fit(X, y, sample_weight) + except TypeError: + classifier.fit(X, y) else: classifier.fit(X, y) return classifier diff --git a/hiclass/LocalClassifierPerParentNode.py b/hiclass/LocalClassifierPerParentNode.py index 5324c977..14895fd7 100644 --- a/hiclass/LocalClassifierPerParentNode.py +++ b/hiclass/LocalClassifierPerParentNode.py @@ -7,8 +7,6 @@ import networkx as nx import numpy as np -from numpy import vstack -from scipy.sparse import csr_matrix from sklearn.base import BaseEstimator from sklearn.utils.validation import check_array, check_is_fitted @@ -38,14 +36,13 @@ class LocalClassifierPerParentNode(BaseEstimator, HierarchicalClassifier): def __init__( self, local_classifier: BaseEstimator = None, - tolerance: float = None, verbose: int = 0, edge_list: str = None, replace_classifiers: bool = True, n_jobs: int = 1, bert: bool = False, ): - r""" + """ Initialize a local classifier per parent node. Parameters @@ -53,9 +50,6 @@ def __init__( local_classifier : BaseEstimator, default=LogisticRegression The local_classifier used to create the collection of local classifiers. Needs to have fit, predict and clone methods. - tolerance : float, default=None - The tolerance used to determine multi-labels. If set to None, only the child class with highest probability is predicted. - Otherwise, all child classes with :math:`probability >= max\_prob - tolerance` are predicted. verbose : int, default=0 Controls the verbosity when fitting and predicting. See https://verboselogs.readthedocs.io/en/latest/readme.html#overview-of-logging-levels @@ -73,7 +67,6 @@ def __init__( """ super().__init__( local_classifier=local_classifier, - tolerance=tolerance, verbose=verbose, edge_list=edge_list, replace_classifiers=replace_classifiers, @@ -109,6 +102,8 @@ def fit(self, X, y, sample_weight=None): # Fit local classifiers in DAG super().fit(X, y) + # TODO: Store the classes seen during fit + # TODO: Add function to allow user to change local classifier # TODO: Add parameter to receive hierarchy as parameter in constructor @@ -138,20 +133,12 @@ def predict(self, X): # Input validation if not self.bert: - X = check_array(X, accept_sparse="csr") + X = check_array(X, accept_sparse="csr", allow_nd=True, ensure_2d=False) else: X = np.array(X) # Initialize array that holds predictions - # y = np.empty( - # (X.shape[0], self.multi_labels_, self.max_levels_), dtype=self.dtype_ - # ) - if self.ndim_ <= 2: - y = np.empty((X.shape[0], self.max_levels_), dtype=self.dtype_) - elif self.ndim_ == 3: - y = np.empty( - (X.shape[0], self.multi_labels_, self.max_levels_), dtype=self.dtype_ - ) + y = np.empty((X.shape[0], self.max_levels_), dtype=self.dtype_) # TODO: Add threshold to stop prediction halfway if need be @@ -169,44 +156,6 @@ def predict(self, X): return y - def predict_proba(self, X): - """ - Probability estimates. - - The returned estimates for all classes are ordered by the label of classes. - - Parameters - ---------- - X : {array-like, sparse matrix} of shape (n_samples, n_features) - Vector to be scored, where ``n_samples`` is the number of samples and - ``n_features`` is the number of features. - Internally, its dtype will be converted - to ``dtype=np.float32``. If a sparse matrix is provided, it will be - converted into a sparse ``csr_matrix``. - Returns - ------- - T : ndarray of shape (n_samples, n_classes) - Returns the probability of the sample for each class in the model, - where classes are ordered as they are in :code:`self.classes_`. - """ - # Check if fit has been called - check_is_fitted(self) - - # Input validation - if not self.bert: - X = check_array(X, accept_sparse="csr") - else: - X = np.array(X) - - T = np.zeros((X.shape[0], len(self.classes_))) - - # for i, node in enumerate(self.classes_): - # classifier = self.hierarchy_.nodes[node]["classifier"] - # positive_index = np.where(classifier.classes_ == 1)[0] - # T[:, i] = classifier.predict_proba(X)[:, positive_index][:, 0] - - return T - def _predict_remaining_levels(self, X, y): for level in range(1, y.shape[1]): predecessors = set(y[:, level - 1]) @@ -238,12 +187,6 @@ def _get_parents(self): return nodes def _get_successors(self, node): - if self.y_.ndim == 2: - return self._get_successors_2d(node) - elif self.y_.ndim == 3: - return self._get_successors_3d(node) - - def _get_successors_2d(self, node): successors = list(self.hierarchy_.successors(node)) mask = np.isin(self.y_, successors).any(axis=1) X = self.X_[mask] @@ -259,32 +202,6 @@ def _get_successors_2d(self, node): ) return X, y, sample_weight - def _get_successors_3d(self, node): - successors = list(self.hierarchy_.successors(node)) - mask = np.isin(self.y_, successors).any(axis=(2, 1)) - y = [] - if isinstance(self.X_, csr_matrix): - X = csr_matrix((0, self.X_.shape[1]), dtype=self.X_.dtype) - else: - X = [] - sample_weight = [] if self.sample_weight_ is not None else None - for i in range(self.y_.shape[0]): - if mask[i]: - row = self.y_[i] - labels = row[np.isin(row, successors)] - y.extend(labels) - for _ in range(labels.shape[0]): - if isinstance(self.X_, csr_matrix): - X = vstack([X, self.X_[i]]) - else: - X.append(self.X_[i]) - if self.sample_weight_ is not None: - sample_weight.append(self.sample_weight_[i]) - y = np.array(y) - if isinstance(self.X_, np.ndarray): - X = np.array(X) - return X, y, sample_weight - @staticmethod def _fit_classifier(self, node): classifier = self.hierarchy_.nodes[node]["classifier"] @@ -294,7 +211,10 @@ def _fit_classifier(self, node): if len(unique_y) == 1 and self.replace_classifiers: classifier = ConstantClassifier() if not self.bert: - classifier.fit(X, y, sample_weight) + try: + classifier.fit(X, y, sample_weight) + except TypeError: + classifier.fit(X, y) else: classifier.fit(X, y) return classifier diff --git a/setup.cfg b/setup.cfg index 0a4fd6be..fa25a94b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -14,7 +14,7 @@ exclude = **/__init__.py, docs/source/conf.py ;file.py: error [requires] -python_version = ">=3.7,<3.10" +python_version = ">=3.7,<3.12" # See the docstring in versioneer.py for instructions. Note that you must # re-run 'versioneer.py setup' after changing this section, and commit the diff --git a/setup.py b/setup.py index 14c3ac04..c156f4d8 100644 --- a/setup.py +++ b/setup.py @@ -22,11 +22,11 @@ URL_ISSUES = "https://github.com/scikit-learn-contrib/hiclass/issues" EMAIL = "fabio.malchermiranda@hpi.de, Niklas.Koehnecke@student.hpi.uni-potsdam.de" AUTHOR = "Fabio Malcher Miranda, Niklas Koehnecke" -REQUIRES_PYTHON = ">=3.7,<3.10" +REQUIRES_PYTHON = ">=3.7,<3.12" KEYWORDS = ["hierarchical classification"] DACS_SOFTWARE = "https://gitlab.com/dacs-hpi" # What packages are required for this module to be executed? -REQUIRED = ["networkx", "scikit-learn", "numpy<1.24"] +REQUIRED = ["networkx", "numpy", "scikit-learn"] # What packages are optional? # 'fancy feature': ['django'],} @@ -142,6 +142,7 @@ def run(self): "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", ], diff --git a/tests/test_HierarchicalClassifier.py b/tests/test_HierarchicalClassifier.py index c9c0e132..d800ff47 100644 --- a/tests/test_HierarchicalClassifier.py +++ b/tests/test_HierarchicalClassifier.py @@ -11,81 +11,33 @@ @pytest.fixture -def ambiguous_node_str_2d(): +def ambiguous_node_str(): classifier = HierarchicalClassifier() classifier.y_ = np.array([["a", "b"], ["b", "c"]]) return classifier -def test_disambiguate_str_2d(ambiguous_node_str_2d): - ground_truth = [ - ["a", "a::HiClass::Separator::b"], - ["b", "b::HiClass::Separator::c"], - ] - ambiguous_node_str_2d._disambiguate() - assert_array_equal(ground_truth, ambiguous_node_str_2d.y_) - - -@pytest.fixture -def ambiguous_node_str_3d(): - classifier = HierarchicalClassifier() - classifier.y_ = np.array( - [ - [["a", "b"], ["", ""]], - [["b", "c"], ["", ""]], - [["d", "e"], ["f", "g"]], - ] +def test_disambiguate_str(ambiguous_node_str): + ground_truth = np.array( + [["a", "a::HiClass::Separator::b"], ["b", "b::HiClass::Separator::c"]] ) - return classifier - - -def test_disambiguate_str_3d(ambiguous_node_str_3d): - ground_truth = [ - [["a", "a::HiClass::Separator::b"], ["", ""]], - [["b", "b::HiClass::Separator::c"], ["", ""]], - [["d", "d::HiClass::Separator::e"], ["f", "f::HiClass::Separator::g"]], - ] - ambiguous_node_str_3d._disambiguate() - assert_array_equal(ground_truth, ambiguous_node_str_3d.y_) + ambiguous_node_str._disambiguate() + assert_array_equal(ground_truth, ambiguous_node_str.y_) @pytest.fixture -def ambiguous_node_int_2d(): +def ambiguous_node_int(): classifier = HierarchicalClassifier() classifier.y_ = np.array([[1, 2], [2, 3]]) return classifier -def test_disambiguate_int_2d(ambiguous_node_int_2d): - ground_truth = [ - ["1", "1::HiClass::Separator::2"], - ["2", "2::HiClass::Separator::3"], - ] - ambiguous_node_int_2d._disambiguate() - assert_array_equal(ground_truth, ambiguous_node_int_2d.y_) - - -@pytest.fixture -def ambiguous_node_int_3d(): - classifier = HierarchicalClassifier() - classifier.y_ = np.array( - [ - [[1, 2], ["", ""]], - [[2, 3], ["", ""]], - [[4, 5], [6, 7]], - ] +def test_disambiguate_int(ambiguous_node_int): + ground_truth = np.array( + [["1", "1::HiClass::Separator::2"], ["2", "2::HiClass::Separator::3"]] ) - return classifier - - -def test_disambiguate_int_3d(ambiguous_node_int_3d): - ground_truth = [ - [["1", "1::HiClass::Separator::2"], ["", ""]], - [["2", "2::HiClass::Separator::3"], ["", ""]], - [["4", "4::HiClass::Separator::5"], ["6", "6::HiClass::Separator::7"]], - ] - ambiguous_node_int_3d._disambiguate() - assert_array_equal(ground_truth, ambiguous_node_int_3d.y_) + ambiguous_node_int._disambiguate() + assert_array_equal(ground_truth, ambiguous_node_int.y_) @pytest.fixture @@ -98,7 +50,7 @@ def graph_1d(): def test_create_digraph_1d(graph_1d): ground_truth = nx.DiGraph() - ground_truth.add_nodes_from(["a", "b", "c", "d"]) + ground_truth.add_nodes_from(np.array(["a", "b", "c", "d"])) graph_1d._create_digraph() assert nx.is_isomorphic(ground_truth, graph_1d.hierarchy_) assert list(ground_truth.nodes) == list(graph_1d.hierarchy_.nodes) @@ -115,7 +67,7 @@ def graph_1d_disguised_as_2d(): def test_create_digraph_1d_disguised_as_2d(graph_1d_disguised_as_2d): ground_truth = nx.DiGraph() - ground_truth.add_nodes_from(["a", "b", "c", "d"]) + ground_truth.add_nodes_from(np.array(["a", "b", "c", "d"])) graph_1d_disguised_as_2d._create_digraph() assert nx.is_isomorphic(ground_truth, graph_1d_disguised_as_2d.hierarchy_) assert list(ground_truth.nodes) == list(graph_1d_disguised_as_2d.hierarchy_.nodes) @@ -126,7 +78,9 @@ def test_create_digraph_1d_disguised_as_2d(graph_1d_disguised_as_2d): def digraph_2d(): classifier = HierarchicalClassifier() classifier.y_ = np.array([["a", "b", "c"], ["d", "e", "f"]]) + classifier.hierarchy_ = nx.DiGraph([("a", "b"), ("b", "c"), ("d", "e"), ("e", "f")]) classifier.logger_ = logging.getLogger("HC") + classifier.edge_list = tempfile.TemporaryFile() classifier.separator_ = "::HiClass::Separator::" return classifier @@ -142,68 +96,17 @@ def test_create_digraph_2d(digraph_2d): @pytest.fixture def digraph_3d(): classifier = HierarchicalClassifier() - classifier.y_ = np.array( - [ - [["a", "b", "c"]], - [["d", "e", "f"]], - ] - ) + classifier.y_ = np.arange(27).reshape((3, 3, 3)) classifier.logger_ = logging.getLogger("HC") - classifier.separator_ = "::HiClass::Separator::" return classifier def test_create_digraph_3d(digraph_3d): - ground_truth = nx.DiGraph( - [ - ("a", "b"), - ("b", "c"), - ("d", "e"), - ("e", "f"), - ] - ) - digraph_3d._create_digraph() - assert nx.is_isomorphic(ground_truth, digraph_3d.hierarchy_) - assert list(ground_truth.nodes) == list(digraph_3d.hierarchy_.nodes) - assert list(ground_truth.edges) == list(digraph_3d.hierarchy_.edges) - - -@pytest.fixture -def digraph_3d_multi_label(): - classifier = HierarchicalClassifier() - classifier.y_ = np.array( - [ - [["a", "b", "c"], ["d", "e", "f"]], - [["g", "h", "i"], ["j", "k", "l"]], - ] - ) - classifier.logger_ = logging.getLogger("HC") - classifier.separator_ = "::HiClass::Separator::" - return classifier - - -def test_create_digraph_3d_multi_label(digraph_3d_multi_label): - ground_truth = nx.DiGraph( - [ - ("a", "b"), - ("b", "c"), - ("d", "e"), - ("e", "f"), - ("g", "h"), - ("h", "i"), - ("j", "k"), - ("k", "l"), - ] - ) - digraph_3d_multi_label._create_digraph() - assert nx.is_isomorphic(ground_truth, digraph_3d_multi_label.hierarchy_) - assert list(ground_truth.nodes) == list(digraph_3d_multi_label.hierarchy_.nodes) - assert list(ground_truth.edges) == list(digraph_3d_multi_label.hierarchy_.edges) + with pytest.raises(ValueError): + digraph_3d._create_digraph() def test_export_digraph(digraph_2d): - digraph_2d.hierarchy_ = nx.DiGraph([("a", "b"), ("b", "c"), ("d", "e"), ("e", "f")]) - digraph_2d.edge_list = tempfile.TemporaryFile() ground_truth = b'"a","b",{}\n"b","c",{}\n"d","e",{}\n"e","f",{}\n' digraph_2d._export_digraph() digraph_2d.edge_list.seek(0) @@ -277,7 +180,7 @@ def test_clean_up(digraph_multiple_roots): @pytest.fixture -def empty_levels_2d(): +def empty_levels(): y = [ ["a"], ["b", "c"], @@ -286,67 +189,15 @@ def empty_levels_2d(): return y -def test_make_leveled_2d(empty_levels_2d): - ground_truth = [ - ["a", "", ""], - ["b", "c", ""], - ["d", "e", "f"], - ] - result = make_leveled(empty_levels_2d) - assert_array_equal(ground_truth, result) - - -@pytest.fixture -def empty_levels_3d(): - y = [ - [["a"]], - [["b", "c"]], - [["d", "e", "f"]], - [["g", "h", "i"], ["j", "k", "l"]], - [["m", "n", "o"]], - ] - return y - - -@pytest.fixture -def empty_levels_3d_large_strings(): - y = [ - [["fish", "mermaid"]], - [["human", "mermaid"]], - [["bull", "minotaur"]], - [["human", "minotaur"]], - [["fish", "mermaid"], ["human", "mermaid"]], - [["bull", "minotaur"], ["human", "minotaur"]], - ] - return y - - -def test_make_leveled_3d_1(empty_levels_3d): - ground_truth = [ - # Labels that are the same as in the Single-Label Test case - [["a", "", ""], ["", "", ""]], - [["b", "c", ""], ["", "", ""]], - [["d", "e", "f"], ["", "", ""]], - # Multi-label Test cases - [["g", "h", "i"], ["j", "k", "l"]], - [["m", "n", "o"], ["", "", ""]], - ] - result = make_leveled(empty_levels_3d) - assert_array_equal(ground_truth, result) - - -def test_make_leveled_3d_2(empty_levels_3d_large_strings): - ground_truth = [ - # Labels that are the same as in the Single-Label Test case - [["fish", "mermaid"], ["", ""]], - [["human", "mermaid"], ["", ""]], - [["bull", "minotaur"], ["", ""]], - [["human", "minotaur"], ["", ""]], - # Multi-label Test cases - [["fish", "mermaid"], ["human", "mermaid"]], - [["bull", "minotaur"], ["human", "minotaur"]], - ] - result = make_leveled(empty_levels_3d_large_strings) +def test_make_leveled(empty_levels): + ground_truth = np.array( + [ + ["a", "", ""], + ["b", "c", ""], + ["d", "e", "f"], + ] + ) + result = make_leveled(empty_levels) assert_array_equal(ground_truth, result) @@ -357,8 +208,7 @@ def noniterable_y(): def test_make_leveled_non_iterable_y(noniterable_y): - result = make_leveled(noniterable_y) - assert_array_equal(noniterable_y, result) + assert noniterable_y == make_leveled(noniterable_y) def test_fit_classifier(): @@ -374,108 +224,3 @@ def test_pre_fit_bert(): y = [["a", "b"], ["c", "d"]] sample_weight = None classifier._pre_fit(x, y, sample_weight) - - -@pytest.fixture -def separator_2d(): - hc = HierarchicalClassifier() - hc.separator_ = "::HiClass::Separator::" - y = np.array( - [ - [ - "a", - "a::HiClass::Separator::b", - "a::HiClass::Separator::b::HiClass::Separator::c", - ], - [ - "d", - "d::HiClass::Separator::e", - "d::HiClass::Separator::e::HiClass::Separator::f", - ], - [ - "g", - "g::HiClass::Separator::h", - "g::HiClass::Separator::h::HiClass::Separator::i", - ], - ] - ) - return hc, y - - -def test_remove_separator_2d(separator_2d): - ground_truth = [ - ["a", "b", "c"], - ["d", "e", "f"], - ["g", "h", "i"], - ] - hc, y = separator_2d - hc._remove_separator(y) - assert_array_equal(ground_truth, y) - - -@pytest.fixture -def separator_3d(): - hc = HierarchicalClassifier() - hc.separator_ = "::HiClass::Separator::" - y = np.array( - [ - [ - [ - "a", - "a::HiClass::Separator::b", - "a::HiClass::Separator::b::HiClass::Separator::c", - ] - ], - [ - [ - "d", - "d::HiClass::Separator::e", - "d::HiClass::Separator::e::HiClass::Separator::f", - ] - ], - [ - [ - "g", - "g::HiClass::Separator::h", - "g::HiClass::Separator::h::HiClass::Separator::i", - ] - ], - ] - ) - return hc, y - - -def test_remove_separator_3d(separator_3d): - ground_truth = [ - [["a", "b", "c"]], - [["d", "e", "f"]], - [["g", "h", "i"]], - ] - hc, y = separator_3d - hc._remove_separator(y) - assert_array_equal(ground_truth, y) - - -@pytest.fixture -def separator_3d_multi_label(): - hc = HierarchicalClassifier() - hc.separator_ = "::HiClass::Separator::" - y = np.array( - [ - [["a", "a::HiClass::Separator::b"], ["a", "a::HiClass::Separator::c"]], - [["d", "d::HiClass::Separator::e"], ["d", "d::HiClass::Separator::f"]], - [["g", "g::HiClass::Separator::h"], ["g", "g::HiClass::Separator::i"]], - ] - ) - return hc, y - - -def test_remove_separator_3d_multi_label(separator_3d_multi_label): - ground_truth = [ - [["a", "b"], ["a", "c"]], - [["d", "e"], ["d", "f"]], - [["g", "h"], ["g", "i"]], - ] - hc, y = separator_3d_multi_label - hc._remove_separator(y) - assert_array_equal(ground_truth, y) diff --git a/tests/test_LocalClassifierPerLevel.py b/tests/test_LocalClassifierPerLevel.py index a80d89e5..27312f85 100644 --- a/tests/test_LocalClassifierPerLevel.py +++ b/tests/test_LocalClassifierPerLevel.py @@ -10,7 +10,6 @@ from sklearn.utils.estimator_checks import parametrize_with_checks from sklearn.utils.validation import check_is_fitted from hiclass import LocalClassifierPerLevel -from hiclass.ConstantClassifier import ConstantClassifier @parametrize_with_checks([LocalClassifierPerLevel()]) @@ -77,16 +76,6 @@ def test_fit_digraph_joblib_multiprocessing(digraph_logistic_regression): assert 1 -def test_fit_1_class(): - lcpl = LocalClassifierPerLevel(local_classifier=LogisticRegression(), n_jobs=2) - y = np.array([["1", "2"]]) - X = np.array([[1, 2]]) - ground_truth = np.array([["1", "2"]]) - lcpl.fit(X, y) - prediction = lcpl.predict(X) - assert_array_equal(ground_truth, prediction) - - @pytest.fixture def fitted_logistic_regression(): digraph = LocalClassifierPerLevel(local_classifier=LogisticRegression()) @@ -144,54 +133,3 @@ def test_fit_predict(): pytest.fail(repr(e)) predictions = lcpl.predict(x) assert_array_equal(y, predictions) - - -@pytest.fixture -def empty_levels(): - X = [ - [1], - [2], - [3], - ] - y = [ - ["1"], - ["2", "2.1"], - ["3", "3.1", "3.1.2"], - ] - return X, y - - -def test_empty_levels(empty_levels): - lcppn = LocalClassifierPerLevel() - X, y = empty_levels - lcppn.fit(X, y) - predictions = lcppn.predict(X) - ground_truth = [ - ["1", "", ""], - ["2", "2.1", ""], - ["3", "3.1", "3.1.2"], - ] - assert list(lcppn.hierarchy_.nodes) == [ - "1", - "2", - "2" + lcppn.separator_ + "2.1", - "3", - "3" + lcppn.separator_ + "3.1", - "3" + lcppn.separator_ + "3.1" + lcppn.separator_ + "3.1.2", - lcppn.root_, - ] - assert_array_equal(ground_truth, predictions) - - -def test_fit_bert(): - bert = ConstantClassifier() - lcpn = LocalClassifierPerLevel( - local_classifier=bert, - bert=True, - ) - X = ["Text 1", "Text 2"] - y = ["a", "a"] - lcpn.fit(X, y) - check_is_fitted(lcpn) - predictions = lcpn.predict(X) - assert_array_equal(y, predictions) diff --git a/tests/test_LocalClassifierPerNode.py b/tests/test_LocalClassifierPerNode.py index a8ad98e3..670c9823 100644 --- a/tests/test_LocalClassifierPerNode.py +++ b/tests/test_LocalClassifierPerNode.py @@ -12,7 +12,6 @@ from hiclass import LocalClassifierPerNode from hiclass.BinaryPolicy import ExclusivePolicy -from hiclass.ConstantClassifier import ConstantClassifier @parametrize_with_checks([LocalClassifierPerNode()]) @@ -134,16 +133,6 @@ def test_fit_digraph_joblib_multiprocessing(digraph_logistic_regression): assert 1 -def test_fit_1_class(): - lcpn = LocalClassifierPerNode(local_classifier=LogisticRegression(), n_jobs=2) - y = np.array([["1", "2"]]) - X = np.array([[1, 2]]) - ground_truth = np.array([["1", "2"]]) - lcpn.fit(X, y) - prediction = lcpn.predict(X) - assert_array_equal(ground_truth, prediction) - - def test_clean_up(digraph_logistic_regression): digraph_logistic_regression._clean_up() with pytest.raises(AttributeError): @@ -182,7 +171,6 @@ def fitted_logistic_regression(): classifiers["2.1"]["classifier"].fit(digraph.X_, [0, 0, 1, 0]) classifiers["2.2"]["classifier"].fit(digraph.X_, [0, 0, 0, 1]) nx.set_node_attributes(digraph.hierarchy_, classifiers) - digraph.classes_ = np.array(["1", "1.1", "1.2", "2", "2.1", "2.2"]) return digraph @@ -207,69 +195,3 @@ def test_fit_predict(): lcpn.fit(x, y) predictions = lcpn.predict(x) assert_array_equal(y, predictions) - - -@pytest.fixture -def empty_levels(): - X = [ - [1], - [2], - [3], - ] - y = [ - ["1"], - ["2", "2.1"], - ["3", "3.1", "3.1.2"], - ] - return X, y - - -def test_empty_levels(empty_levels): - lcpn = LocalClassifierPerNode() - X, y = empty_levels - lcpn.fit(X, y) - predictions = lcpn.predict(X) - ground_truth = [ - ["1", "", ""], - ["2", "2.1", ""], - ["3", "3.1", "3.1.2"], - ] - assert list(lcpn.hierarchy_.nodes) == [ - "1", - "2", - "2" + lcpn.separator_ + "2.1", - "3", - "3" + lcpn.separator_ + "3.1", - "3" + lcpn.separator_ + "3.1" + lcpn.separator_ + "3.1.2", - lcpn.root_, - ] - assert_array_equal(ground_truth, predictions) - - -def test_fit_bert(): - bert = ConstantClassifier() - lcpn = LocalClassifierPerNode( - local_classifier=bert, - bert=True, - ) - X = ["Text 1", "Text 2"] - y = ["a", "a"] - lcpn.fit(X, y) - check_is_fitted(lcpn) - predictions = lcpn.predict(X) - assert_array_equal(y, predictions) - - -def test_classes(empty_levels): - lcpn = LocalClassifierPerNode() - X, y = empty_levels - lcpn.fit(X, y) - ground_truth = [ - "1", - "2", - "2" + lcpn.separator_ + "2.1", - "3", - "3" + lcpn.separator_ + "3.1", - "3" + lcpn.separator_ + "3.1" + lcpn.separator_ + "3.1.2", - ] - assert_array_equal(ground_truth, lcpn.classes_) diff --git a/tests/test_LocalClassifierPerParentNode.py b/tests/test_LocalClassifierPerParentNode.py index 0011dc67..922a03a3 100644 --- a/tests/test_LocalClassifierPerParentNode.py +++ b/tests/test_LocalClassifierPerParentNode.py @@ -12,7 +12,6 @@ from sklearn.utils.validation import check_is_fitted from hiclass import LocalClassifierPerParentNode -from hiclass.ConstantClassifier import ConstantClassifier @parametrize_with_checks([LocalClassifierPerParentNode()]) @@ -21,7 +20,7 @@ def test_sklearn_compatible_estimator(estimator, check): @pytest.fixture -def digraph_logistic_regression_2d(): +def digraph_logistic_regression(): digraph = LocalClassifierPerParentNode(local_classifier=LogisticRegression()) digraph.hierarchy_ = nx.DiGraph([("a", "b"), ("a", "c")]) digraph.y_ = np.array([["a", "b"], ["a", "c"]]) @@ -33,114 +32,60 @@ def digraph_logistic_regression_2d(): return digraph -def test_initialize_local_classifiers(digraph_logistic_regression_2d): - digraph_logistic_regression_2d._initialize_local_classifiers() - for node in digraph_logistic_regression_2d.hierarchy_.nodes: - if node == digraph_logistic_regression_2d.root_: +def test_initialize_local_classifiers(digraph_logistic_regression): + digraph_logistic_regression._initialize_local_classifiers() + for node in digraph_logistic_regression.hierarchy_.nodes: + if node == digraph_logistic_regression.root_: assert isinstance( - digraph_logistic_regression_2d.hierarchy_.nodes[node]["classifier"], + digraph_logistic_regression.hierarchy_.nodes[node]["classifier"], LogisticRegression, ) else: with pytest.raises(KeyError): isinstance( - digraph_logistic_regression_2d.hierarchy_.nodes[node]["classifier"], + digraph_logistic_regression.hierarchy_.nodes[node]["classifier"], LogisticRegression, ) -@pytest.mark.parametrize("use_joblib", [True, False]) -def test_fit_digraph_2d(digraph_logistic_regression_2d, use_joblib): +def test_fit_digraph(digraph_logistic_regression): classifiers = { "a": {"classifier": LogisticRegression()}, } - digraph_logistic_regression_2d.n_jobs = 2 - nx.set_node_attributes(digraph_logistic_regression_2d.hierarchy_, classifiers) - digraph_logistic_regression_2d._fit_digraph(local_mode=True, use_joblib=use_joblib) + digraph_logistic_regression.n_jobs = 2 + nx.set_node_attributes(digraph_logistic_regression.hierarchy_, classifiers) + digraph_logistic_regression._fit_digraph(local_mode=True) try: - check_is_fitted( - digraph_logistic_regression_2d.hierarchy_.nodes["a"]["classifier"] - ) + check_is_fitted(digraph_logistic_regression.hierarchy_.nodes["a"]["classifier"]) except NotFittedError as e: pytest.fail(repr(e)) for node in ["b", "c"]: with pytest.raises(KeyError): check_is_fitted( - digraph_logistic_regression_2d.hierarchy_.nodes[node]["classifier"] + digraph_logistic_regression.hierarchy_.nodes[node]["classifier"] ) assert 1 -@pytest.fixture -def digraph_logistic_regression_3d(): - digraph = LocalClassifierPerParentNode(local_classifier=LogisticRegression()) - digraph.hierarchy_ = nx.DiGraph( - [ - ("a", "b"), - ("a", "c"), - ("d", "e"), - ("d", "f"), - ] - ) - digraph.y_ = np.array( - [ - [["a", "b"], ["", ""]], - [["a", "c"], ["", ""]], - [["a", "b"], ["a", "c"]], - [["d", "e"], ["d", "f"]], - ] - ) - digraph.X_ = np.array( - [ - [1, 2], - [3, 4], - [5, 6], - [7, 8], - ] - ) - digraph.logger_ = logging.getLogger("LCPPN") - digraph.root_ = "a" - digraph.separator_ = "::HiClass::Separator::" - digraph.sample_weight_ = None +def test_fit_digraph_joblib_multiprocessing(digraph_logistic_regression): classifiers = { "a": {"classifier": LogisticRegression()}, - "d": {"classifier": LogisticRegression()}, } - digraph.n_jobs = 2 - nx.set_node_attributes(digraph.hierarchy_, classifiers) - return digraph - - -@pytest.mark.parametrize("use_joblib", [True, False]) -def test_fit_digraph_3d(digraph_logistic_regression_3d, use_joblib): - digraph_logistic_regression_3d._fit_digraph(local_mode=True, use_joblib=use_joblib) + digraph_logistic_regression.n_jobs = 2 + nx.set_node_attributes(digraph_logistic_regression.hierarchy_, classifiers) + digraph_logistic_regression._fit_digraph(local_mode=True, use_joblib=True) try: - for node in ["a", "d"]: - check_is_fitted( - digraph_logistic_regression_3d.hierarchy_.nodes[node]["classifier"] - ) + check_is_fitted(digraph_logistic_regression.hierarchy_.nodes["a"]["classifier"]) except NotFittedError as e: pytest.fail(repr(e)) - for node in ["b", "c", "e", "f"]: + for node in ["b", "c"]: with pytest.raises(KeyError): check_is_fitted( - digraph_logistic_regression_3d.hierarchy_.nodes[node]["classifier"] + digraph_logistic_regression.hierarchy_.nodes[node]["classifier"] ) assert 1 -def test_fit_1_class(): - lcppn = LocalClassifierPerParentNode( - local_classifier=LogisticRegression(), n_jobs=2 - ) - y = np.array([["1", "2"]]) - X = np.array([[1, 2]]) - ground_truth = np.array([["1", "2"]]) - lcppn.fit(X, y) - prediction = lcppn.predict(X) - assert_array_equal(ground_truth, prediction) - - @pytest.fixture def digraph_2d(): classifier = LocalClassifierPerParentNode() @@ -159,7 +104,7 @@ def test_get_parents(digraph_2d): @pytest.fixture -def x_and_y_arrays_2d(): +def x_and_y_arrays(): graph = LocalClassifierPerParentNode() graph.X_ = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) graph.y_ = np.array([["a", "b", "c"], ["a", "e", "f"], ["d", "g", "h"]]) @@ -171,93 +116,33 @@ def x_and_y_arrays_2d(): return graph -def test_get_successors_2d_1(x_and_y_arrays_2d): - x, y, weights = x_and_y_arrays_2d._get_successors("a") - assert_array_equal(x_and_y_arrays_2d.X_[0:2], x) +def test_get_successors(x_and_y_arrays): + x, y, weights = x_and_y_arrays._get_successors("a") + assert_array_equal(x_and_y_arrays.X_[0:2], x) assert_array_equal(["b", "e"], y) assert weights is None - - -def test_get_successors_2d_2(x_and_y_arrays_2d): - x, y, weights = x_and_y_arrays_2d._get_successors("d") - assert_array_equal([x_and_y_arrays_2d.X_[-1]], x) + x, y, weights = x_and_y_arrays._get_successors("d") + assert_array_equal([x_and_y_arrays.X_[-1]], x) assert_array_equal(["g"], y) assert weights is None - - -def test_get_successors_2d_3(x_and_y_arrays_2d): - x, y, weights = x_and_y_arrays_2d._get_successors("b") - assert_array_equal([x_and_y_arrays_2d.X_[0]], x) + x, y, weights = x_and_y_arrays._get_successors("b") + assert_array_equal([x_and_y_arrays.X_[0]], x) assert_array_equal(["c"], y) assert weights is None -@pytest.fixture -def x_and_y_arrays_3d(): - graph = LocalClassifierPerParentNode() - graph.X_ = np.array( - [ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - # Multi-label - [10, 11, 12], - [13, 14, 15], - ] - ) - graph.y_ = np.array( - [ - [["a", "b", "c"], ["", "", ""]], - [["a", "e", "f"], ["", "", ""]], - [["d", "g", "h"], ["", "", ""]], - # Multi-label - [["a", "b", "c"], ["a", "e", "f"]], - [["a", "b", "c"], ["d", "g", "h"]], - ] - ) - graph.hierarchy_ = nx.DiGraph( - [("a", "b"), ("b", "c"), ("a", "e"), ("e", "f"), ("d", "g"), ("g", "h")] - ) - graph.root_ = "r" - graph.sample_weight_ = None - return graph - - -def test_get_successors_3d_1(x_and_y_arrays_3d): - x, y, weights = x_and_y_arrays_3d._get_successors("a") - ground_truth_x = np.array( - [[1, 2, 3], [4, 5, 6], [10, 11, 12], [10, 11, 12], [13, 14, 15]] - ) - ground_truth_y = np.array(["b", "e", "b", "e", "b"]) - assert_array_equal(ground_truth_x, x) - assert_array_equal(ground_truth_y, y) - assert weights is None - - -def test_get_successors_3d_2(x_and_y_arrays_3d): - x, y, weights = x_and_y_arrays_3d._get_successors("d") - ground_truth_x = x_and_y_arrays_3d.X_[[False, False, True, False, True]] - ground_truth_y = np.array(["g", "g"]) - assert_array_equal(ground_truth_x, x) - assert_array_equal(ground_truth_y, y) - assert weights is None - - -def test_get_successors_3d_3(x_and_y_arrays_3d): - x, y, weights = x_and_y_arrays_3d._get_successors("b") - ground_truth_x = x_and_y_arrays_3d.X_[[True, False, False, True, True]] - ground_truth_y = np.array(["c", "c", "c"]) - assert_array_equal(ground_truth_x, x) - assert ground_truth_y.shape == y.shape - assert_array_equal(ground_truth_y, y) - assert weights is None - - @pytest.fixture def fitted_logistic_regression(): digraph = LocalClassifierPerParentNode(local_classifier=LogisticRegression()) digraph.hierarchy_ = nx.DiGraph( - [("r", "1"), ("r", "2"), ("1", "1.1"), ("1", "1.2"), ("2", "2.1"), ("2", "2.2")] + [ + ("r", "1"), + ("r", "2"), + ("1", "1.1"), + ("1", "1.2"), + ("2", "2.1"), + ("2", "2.2"), + ] ) digraph.y_ = np.array([["1", "1.1"], ["1", "1.2"], ["2", "2.1"], ["2", "2.2"]]) digraph.X_ = np.array([[1, 2], [3, 4], [5, 6], [7, 8]]) @@ -266,7 +151,6 @@ def fitted_logistic_regression(): digraph.dtype_ = "