diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 407cb5a..0000000 --- a/.coveragerc +++ /dev/null @@ -1,5 +0,0 @@ -[run] -omit = - .tox/* - setup.py - eeweather/database.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..c656ae6 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,49 @@ +name: Test + +on: + push: + branches: + - master + pull_request: + types: + - opened + - synchronize + - reopened + schedule: + # run monthly to monitor dependency updates + - cron: "0 0 1 * *" + +jobs: + build: + strategy: + fail-fast: false + matrix: + python: ["3.10", "3.11", "3.12", "3.13", "3.14"] + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python }} on ${{ matrix.os }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python }} + - name: Install tox + run: pip install tox + - name: Run tox + run: tox -e ${{ matrix.python }} + + # Fan-in over the build matrix so branch protection can require a single + # context instead of every (python, os) combination. needs.build.result is + # 'success' only if every matrix combination passed. + build-all: + name: build (all) + if: always() + needs: build + runs-on: ubuntu-latest + steps: + - name: Verify all matrix jobs passed + if: needs.build.result != 'success' + run: | + echo "build matrix result: ${{ needs.build.result }}" + exit 1 diff --git a/.gitignore b/.gitignore index d95402d..f1f5006 100644 --- a/.gitignore +++ b/.gitignore @@ -13,10 +13,11 @@ _build/ build/ dist/ +# coverage +coverage.xml + # config files .* !.github/ !.gitignore -!.coveragerc -!.travis.yml !.gitattributes diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c66911e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,39 +0,0 @@ -dist: xenial -sudo: false - -cache: - directories: - - $HOME/.pip-cache/ - - .tox - -addons: - apt: - packages: - - libenchant-dev - - binutils - - libproj-dev - - gdal-bin - - libgeos-dev - -language: python - -python: - - 2.7 - - 3.5 - - 3.6 - - 3.7 - -notifications: - email: false - -install: - - pip install tox-travis - - pip install coveralls - - pip install codecov - -script: - - tox - -after_script: - - coveralls - - codecov diff --git a/CHANGELOG.md b/CHANGELOG.md index e364796..fbd8adc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,24 @@ Development * Remove deprecated `typing` dependency * Switch from snapshottest to syrupy for snapshot testing. * Update internal database (2025-03-12). +* Modernize packaging: pyproject.toml with hatchling replaces setup.py, + Pipfile, and MANIFEST.in; python >=3.10. +* Add test workflow (python/os matrix) and tox environments for current + python versions. +* Rewrite key-value cache on stdlib sqlite3; sqlalchemy is no longer used + or required. Cache urls must have the sqlite:/// form. +* Replace retry and attrs dependencies with stdlib equivalents; fix + pkg_resources import broken on setuptools >=81. +* Warn when loaded data is empty, truncated, or contains a multi-day + internal gap. Requests ending after a station's last available + observation previously returned NaN-padded series silently. +* Fix crash (`No objects to concatenate`) when all years in a requested + range are missing and `error_on_missing_years=False`. +* Loaders always return a series covering the full requested range. +* Add `error_on_missing_years` to daily ISD/GSOD loaders; default is True + for all loaders, matching the ISDStation method default. +* Tests run fully offline against captured NCEI access api payloads; + add coverage floor. 0.3.29 ------ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 34da119..e271246 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,35 +23,9 @@ Releasing 5. make a new branch called release/vX.X.X 6. bump version - edit `__version__.py` with the new version 7. Rename `Development` section with the new version in CHANGELOG.md -8. commit changes -9. create a tag called vX.X.X on release/vX.X.X branch -10. push tag and branch -11. submit to pypi with `pipenv run python setup.py upload` (must have proper credentials) -12. merge release branch to master - -Release command cheatsheet - -``` -git checkout master -git pull -git checkout -b release/vX.X.X - -# then bump versions -vim eeweather/__version__.py -vim CHANGELOG.md -git commit -am "Bump version" - -git tag vX.X.X -git push -u origin release/vX.X.X --tags -docker-compose run --rm pipenv run python setup.py upload -git checkout master -git pull -git merge release/vX.X.X -git push -``` - -Or, use the `./bump_version.sh X.X.X Y.Y.Y` command to generate some more -specific commands. +8. commit changes, create and merge the release PR +9. create a GitHub release with a tag called vX.X.X; the publish workflow + builds and uploads the package to pypi Updating the internal db ------------------------ diff --git a/Dockerfile b/Dockerfile index f3a1bca..f548d42 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,4 @@ FROM python:3.12-bookworm -# bullseye required for GEOS>3.7.1 which is needed for newest cartopy RUN apt-get update \ && apt-get install -yqq \ @@ -12,18 +11,12 @@ RUN apt-get update \ # node for mapshaper nodejs npm \ # for access to metadata.db - sqlite3 libsqlite3-dev + sqlite3 libsqlite3-dev RUN npm install -g mapshaper -COPY Pipfile Pipfile -COPY Pipfile.lock Pipfile.lock -RUN pip install pipenv -RUN set -ex && pipenv install --system --deploy --dev -ENV PYTHONPATH=/app - -COPY setup.py README.rst /app/ +COPY pyproject.toml README.md LICENSE /app/ COPY eeweather/ /app/eeweather -RUN set -ex && cd /usr/local/lib/ && python /app/setup.py develop +RUN set -ex && pip install -e /app[dev] WORKDIR /app diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 17f9c2f..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -include README.rst LICENSE pytest.ini -recursive-include tests *.py -recursive-include eeweather *.db -recursive-include eeweather *.gz diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 44ff698..0000000 --- a/Pipfile +++ /dev/null @@ -1,37 +0,0 @@ -[[source]] - -url = "https://pypi.python.org/simple" -verify_ssl = true -name = "pypi" - - -[packages] - -"beautifulsoup4" = "*" -Cython = "*" -matplotlib = "*" -Pillow = "*" -pandas = ">=1.0.0" -pyproj = "*" -requests ="*" -Shapely = {extras = ["vectorized"]} -SQLAlchemy = "*" -scipy = "*" -simplejson = "*" - - -[dev-packages] - -black = "*" -coverage = "*" -cartopy = "*" -jupyterlab = "*" -pytest = "*" -pytest-cov = "*" -pytest-xdist = "*" -tox = "*" -twine = "*" -Sphinx = "*" -syrupy = "*" -sphinx-autobuild = "*" -sphinxcontrib-spelling = "*" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index ab94a93..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,3513 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "061d60e2ad8bd04ee3d429ff4edb90b37dcfffb1a52f9bbcde2d465ad7ec1030" - }, - "pipfile-spec": 6, - "requires": {}, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.python.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "beautifulsoup4": { - "hashes": [ - "sha256:1bd32405dacc920b42b83ba01644747ed77456a65760e285fbc47633ceddaf8b", - "sha256:99045d7d3f08f91f0d656bc9b7efbae189426cd913d830294a15eefa0ea4df16" - ], - "index": "pypi", - "markers": "python_full_version >= '3.7.0'", - "version": "==4.13.3" - }, - "certifi": { - "hashes": [ - "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", - "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe" - ], - "markers": "python_version >= '3.6'", - "version": "==2025.1.31" - }, - "charset-normalizer": { - "hashes": [ - "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537", - "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa", - "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a", - "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294", - "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b", - "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", - "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", - "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", - "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4", - "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", - "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2", - "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", - "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", - "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", - "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", - "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", - "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", - "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496", - "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", - "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", - "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e", - "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a", - "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4", - "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca", - "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78", - "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", - "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5", - "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", - "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", - "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", - "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765", - "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6", - "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", - "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", - "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", - "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd", - "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c", - "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", - "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", - "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", - "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770", - "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824", - "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f", - "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf", - "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487", - "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d", - "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd", - "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", - "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534", - "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", - "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", - "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", - "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd", - "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", - "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9", - "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", - "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", - "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d", - "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", - "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", - "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", - "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7", - "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", - "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", - "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8", - "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41", - "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", - "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", - "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", - "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", - "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", - "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", - "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", - "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", - "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", - "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", - "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", - "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e", - "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6", - "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", - "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", - "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e", - "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", - "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", - "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c", - "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", - "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", - "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089", - "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", - "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e", - "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", - "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616" - ], - "markers": "python_version >= '3.7'", - "version": "==3.4.1" - }, - "contourpy": { - "hashes": [ - "sha256:041b640d4ec01922083645a94bb3b2e777e6b626788f4095cf21abbe266413c1", - "sha256:05e806338bfeaa006acbdeba0ad681a10be63b26e1b17317bfac3c5d98f36cda", - "sha256:08d9d449a61cf53033612cb368f3a1b26cd7835d9b8cd326647efe43bca7568d", - "sha256:0ffa84be8e0bd33410b17189f7164c3589c229ce5db85798076a3fa136d0e509", - "sha256:113231fe3825ebf6f15eaa8bc1f5b0ddc19d42b733345eae0934cb291beb88b6", - "sha256:14c102b0eab282427b662cb590f2e9340a9d91a1c297f48729431f2dcd16e14f", - "sha256:174e758c66bbc1c8576992cec9599ce8b6672b741b5d336b5c74e35ac382b18e", - "sha256:19c1555a6801c2f084c7ddc1c6e11f02eb6a6016ca1318dd5452ba3f613a1751", - "sha256:19d40d37c1c3a4961b4619dd9d77b12124a453cc3d02bb31a07d58ef684d3d86", - "sha256:1bf98051f1045b15c87868dbaea84f92408337d4f81d0e449ee41920ea121d3b", - "sha256:20914c8c973f41456337652a6eeca26d2148aa96dd7ac323b74516988bea89fc", - "sha256:287ccc248c9e0d0566934e7d606201abd74761b5703d804ff3df8935f523d546", - "sha256:2ba94a401342fc0f8b948e57d977557fbf4d515f03c67682dd5c6191cb2d16ec", - "sha256:31c1b55c1f34f80557d3830d3dd93ba722ce7e33a0b472cba0ec3b6535684d8f", - "sha256:36987a15e8ace5f58d4d5da9dca82d498c2bbb28dff6e5d04fbfcc35a9cb3a82", - "sha256:3a04ecd68acbd77fa2d39723ceca4c3197cb2969633836ced1bea14e219d077c", - "sha256:3e8b974d8db2c5610fb4e76307e265de0edb655ae8169e8b21f41807ccbeec4b", - "sha256:3ea9924d28fc5586bf0b42d15f590b10c224117e74409dd7a0be3b62b74a501c", - "sha256:4318af1c925fb9a4fb190559ef3eec206845f63e80fb603d47f2d6d67683901c", - "sha256:44a29502ca9c7b5ba389e620d44f2fbe792b1fb5734e8b931ad307071ec58c53", - "sha256:47734d7073fb4590b4a40122b35917cd77be5722d80683b249dac1de266aac80", - "sha256:4d76d5993a34ef3df5181ba3c92fabb93f1eaa5729504fb03423fcd9f3177242", - "sha256:4dbbc03a40f916a8420e420d63e96a1258d3d1b58cbdfd8d1f07b49fcbd38e85", - "sha256:500360b77259914f7805af7462e41f9cb7ca92ad38e9f94d6c8641b089338124", - "sha256:523a8ee12edfa36f6d2a49407f705a6ef4c5098de4f498619787e272de93f2d5", - "sha256:573abb30e0e05bf31ed067d2f82500ecfdaec15627a59d63ea2d95714790f5c2", - "sha256:5b75aa69cb4d6f137b36f7eb2ace9280cfb60c55dc5f61c731fdf6f037f958a3", - "sha256:61332c87493b00091423e747ea78200659dc09bdf7fd69edd5e98cef5d3e9a8d", - "sha256:805617228ba7e2cbbfb6c503858e626ab528ac2a32a04a2fe88ffaf6b02c32bc", - "sha256:841ad858cff65c2c04bf93875e384ccb82b654574a6d7f30453a04f04af71342", - "sha256:89785bb2a1980c1bd87f0cb1517a71cde374776a5f150936b82580ae6ead44a1", - "sha256:8eb96e79b9f3dcadbad2a3891672f81cdcab7f95b27f28f1c67d75f045b6b4f1", - "sha256:974d8145f8ca354498005b5b981165b74a195abfae9a8129df3e56771961d595", - "sha256:9ddeb796389dadcd884c7eb07bd14ef12408aaae358f0e2ae24114d797eede30", - "sha256:a045f341a77b77e1c5de31e74e966537bba9f3c4099b35bf4c2e3939dd54cdab", - "sha256:a0cffcbede75c059f535725c1680dfb17b6ba8753f0c74b14e6a9c68c29d7ea3", - "sha256:a761d9ccfc5e2ecd1bf05534eda382aa14c3e4f9205ba5b1684ecfe400716ef2", - "sha256:a7895f46d47671fa7ceec40f31fae721da51ad34bdca0bee83e38870b1f47ffd", - "sha256:a9fa36448e6a3a1a9a2ba23c02012c43ed88905ec80163f2ffe2421c7192a5d7", - "sha256:ab29962927945d89d9b293eabd0d59aea28d887d4f3be6c22deaefbb938a7277", - "sha256:abbb49fb7dac584e5abc6636b7b2a7227111c4f771005853e7d25176daaf8453", - "sha256:ac4578ac281983f63b400f7fe6c101bedc10651650eef012be1ccffcbacf3697", - "sha256:adce39d67c0edf383647a3a007de0a45fd1b08dedaa5318404f1a73059c2512b", - "sha256:ade08d343436a94e633db932e7e8407fe7de8083967962b46bdfc1b0ced39454", - "sha256:b2bdca22a27e35f16794cf585832e542123296b4687f9fd96822db6bae17bfc9", - "sha256:b2f926efda994cdf3c8d3fdb40b9962f86edbc4457e739277b961eced3d0b4c1", - "sha256:b457d6430833cee8e4b8e9b6f07aa1c161e5e0d52e118dc102c8f9bd7dd060d6", - "sha256:c414fc1ed8ee1dbd5da626cf3710c6013d3d27456651d156711fa24f24bd1291", - "sha256:cb76c1a154b83991a3cbbf0dfeb26ec2833ad56f95540b442c73950af2013750", - "sha256:dfd97abd83335045a913e3bcc4a09c0ceadbe66580cf573fe961f4a825efa699", - "sha256:e914a8cb05ce5c809dd0fe350cfbb4e881bde5e2a38dc04e3afe1b3e58bd158e", - "sha256:ece6df05e2c41bd46776fbc712e0996f7c94e0d0543af1656956d150c4ca7c81", - "sha256:efa874e87e4a647fd2e4f514d5e91c7d493697127beb95e77d2f7561f6905bd9", - "sha256:f611e628ef06670df83fce17805c344710ca5cde01edfdc72751311da8585375" - ], - "markers": "python_version >= '3.10'", - "version": "==1.3.1" - }, - "cycler": { - "hashes": [ - "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", - "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c" - ], - "markers": "python_version >= '3.8'", - "version": "==0.12.1" - }, - "cython": { - "hashes": [ - "sha256:0038c9bae46c459669390e53a1ec115f8096b2e4647ae007ff1bf4e6dee92806", - "sha256:0faa5e39e5c8cdf6f9c3b1c3f24972826e45911e7f5b99cf99453fca5432f45e", - "sha256:120681093772bf3600caddb296a65b352a0d3556e962b9b147efcfb8e8c9801b", - "sha256:1e5eadef80143026944ea8f9904715a008f5108d1d644a89f63094cc37351e73", - "sha256:25529ee948f44d9a165ff960c49d4903267c20b5edf2df79b45924802e4cca6e", - "sha256:2d53de996ed340e9ab0fc85a88aaa8932f2591a2746e1ab1c06e262bd4ec4be7", - "sha256:3083465749911ac3b2ce001b6bf17f404ac9dd35d8b08469d19dc7e717f5877a", - "sha256:309c081057930bb79dc9ea3061a1af5086c679c968206e9c9c2ec90ab7cb471a", - "sha256:3109e1d44425a2639e9a677b66cd7711721a5b606b65867cb2d8ef7a97e2237b", - "sha256:34ce459808f7d8d5d4007bc5486fe50532529096b43957af6cbffcb4d9cc5c8d", - "sha256:36fcd584dae547de6f095500a380f4a0cce72b7a7e409e9ff03cb9beed6ac7a1", - "sha256:398d4576c1e1f6316282aa0b4a55139254fbed965cba7813e6d9900d3092b128", - "sha256:3ccd1228cc203b1f1b8a3d403f5a20ad1c40e5879b3fbf5851ce09d948982f2c", - "sha256:3e4fa855d98bc7bd6a2049e0c7dc0dcf595e2e7f571a26e808f3efd84d2db374", - "sha256:43c48b5789398b228ea97499f5b864843ba9b1ab837562a9227c6f58d16ede8b", - "sha256:4aa255781b093a8401109d8f2104bbb2e52de7639d5896aefafddc85c30e0894", - "sha256:4ee6f1ea1bead8e6cbc4e64571505b5d8dbdb3b58e679d31f3a84160cebf1a1a", - "sha256:54115fcc126840926ff3b53cfd2152eae17b3522ae7f74888f8a41413bd32f25", - "sha256:563de1728c8e48869d2380a1b76bbc1b1b1d01aba948480d68c1d05e52d20c92", - "sha256:57aefa6d3341109e46ec1a13e3a763aaa2cbeb14e82af2485b318194be1d9170", - "sha256:5a93cbda00a5451175b97dea5a9440a3fcee9e54b4cba7a7dbcba9a764b22aec", - "sha256:5e5f17c48a4f41557fbcc7ee660ccfebe4536a34c557f553b6893c1b3c83df2d", - "sha256:629db614b9c364596d7c975fa3fb3978e8c5349524353dbe11429896a783fc1e", - "sha256:62b79dcc0de49efe9e84b9d0e2ae0a6fc9b14691a65565da727aa2e2e63c6a28", - "sha256:63d840f2975e44d74512f8f34f1f7cb8121c9428e26a3f6116ff273deb5e60a2", - "sha256:680f1d6ed4436ae94805db264d6155ed076d2835d84f20dcb31a7a3ad7f8668c", - "sha256:712c3f31adec140dc60d064a7f84741f50e2c25a8edd7ae746d5eb4d3ef7072a", - "sha256:731d719423e041242c9303c80cae4327467299b90ffe62d4cc407e11e9ea3160", - "sha256:75c5acd40b97cff16fadcf6901a91586cbca5dcdba81f738efaf1f4c6bc8dccb", - "sha256:77d48f2d4bab9fe1236eb753d18f03e8b2619af5b6f05d51df0532a92dfb38ab", - "sha256:7cffc3464f641c8d0dda942c7c53015291beea11ec4d32421bed2f13b386b819", - "sha256:86c304b20bd57c727c7357e90d5ba1a2b6f1c45492de2373814d7745ef2e63b4", - "sha256:879ae9023958d63c0675015369384642d0afb9c9d1f3473df9186c42f7a9d265", - "sha256:8ab9f5198af74eb16502cc143cdde9ca1cbbf66ea2912e67440dd18a36e3b5fa", - "sha256:8c9efe9a0895abee3cadfdad4130b30f7b5e57f6e6a51ef2a44f9fc66a913880", - "sha256:8d32856716c369d01f2385ad9177cdd1a11079ac89ea0932dc4882de1aa19174", - "sha256:8ee841c0e114efa1e849c281ac9b8df8aa189af10b4a103b1c5fd71cbb799679", - "sha256:90cf599372c5a22120609f7d3a963f17814799335d56dd0dcf8fe615980a8ae1", - "sha256:9f8c48748a9c94ea5d59c26ab49ad0fad514d36f894985879cf3c3ca0e600bf4", - "sha256:a4032e48d4734d2df68235d21920c715c451ac9de15fa14c71b378e8986b83be", - "sha256:a7fec4f052b8fe173fe70eae75091389955b9a23d5cec3d576d21c5913b49d47", - "sha256:af081838b0f9e12a83ec4c3809a00a64c817f489f7c512b0e3ecaf5f90a2a816", - "sha256:b588c0a089a9f4dd316d2f9275230bad4a7271e5af04e1dc41d2707c816be44b", - "sha256:b988bb297ce76c671e28c97d017b95411010f7c77fa6623dd0bb47eed1aee1bc", - "sha256:ba67eee9413b66dd9fbacd33f0bc2e028a2a120991d77b5fd4b19d0b1e4039b9", - "sha256:bee2717e5b5f7d966d0c6e27d2efe3698c357aa4d61bb3201997c7a4f9fe485a", - "sha256:bfb75123dd4ff767baa37d7036da0de2dfb6781ff256eef69b11b88b9a0691d1", - "sha256:c0b91c7ebace030dd558ea28730de8c580680b50768e5af66db2904a3716c3e3", - "sha256:c151082884be468f2f405645858a857298ac7f7592729e5b54788b5c572717ba", - "sha256:c1879c073e2b34924ce9b7ca64c212705dcc416af4337c45f371242b2e5f6d32", - "sha256:c3238a29f37999e27494d120983eca90d14896b2887a0bd858a381204549137a", - "sha256:d3a8f81980ffbd74e52f9186d8f1654e347d0c44bfea6b5997028977f481a179", - "sha256:d4b70fc339adba1e2111b074ee6119fe9fd6072c957d8597bce9a0dd1c3c6784", - "sha256:d6945694c5b9170cfbd5f2c0d00ef7487a2de7aba83713a64ee4ebce7fad9e05", - "sha256:d6c6cd6a75c8393e6805d17f7126b96a894f310a1a9ea91c47d141fb9341bfa8", - "sha256:dcdc3e5d4ce0e7a4af6903ed580833015641e968d18d528d8371e2435a34132c", - "sha256:dfdbea486e702c328338314adb8e80f5f9741f06a0ae83aaec7463bc166d12e8", - "sha256:e62564457851db1c40399bd95a5346b9bb99e17a819bf583b362f418d8f3457a", - "sha256:ea3a0e19ab77266c738aa110684a753a04da4e709472cadeff487133354d6ab8", - "sha256:ebc24609613fa06d0d896309f7164ba168f7e8d71c1e490ed2a08d23351c3f41", - "sha256:f39640f8df0400cde6882e23c734f15bb8196de0a008ae5dc6c8d1ec5957d7c8", - "sha256:fe030d4a00afb2844f5f70896b7f2a1a0d7da09bf3aa3d884cbe5f73fff5d310", - "sha256:feb86122a823937cc06e4c029d80ff69f082ebb0b959ab52a5af6cdd271c5dc3", - "sha256:ff5c0b6a65b08117d0534941d404833d516dac422eee88c6b4fd55feb409a5ed" - ], - "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==3.0.12" - }, - "fonttools": { - "hashes": [ - "sha256:003548eadd674175510773f73fb2060bb46adb77c94854af3e0cc5bc70260049", - "sha256:0073b62c3438cf0058488c002ea90489e8801d3a7af5ce5f7c05c105bee815c3", - "sha256:1088182f68c303b50ca4dc0c82d42083d176cba37af1937e1a976a31149d4d14", - "sha256:133bedb9a5c6376ad43e6518b7e2cd2f866a05b1998f14842631d5feb36b5786", - "sha256:14a3e3e6b211660db54ca1ef7006401e4a694e53ffd4553ab9bc87ead01d0f05", - "sha256:17f39313b649037f6c800209984a11fc256a6137cbe5487091c6c7187cae4685", - "sha256:193b86e9f769320bc98ffdb42accafb5d0c8c49bd62884f1c0702bc598b3f0a2", - "sha256:2d351275f73ebdd81dd5b09a8b8dac7a30f29a279d41e1c1192aedf1b6dced40", - "sha256:300c310bb725b2bdb4f5fc7e148e190bd69f01925c7ab437b9c0ca3e1c7cd9ba", - "sha256:331954d002dbf5e704c7f3756028e21db07097c19722569983ba4d74df014000", - "sha256:38b947de71748bab150259ee05a775e8a0635891568e9fdb3cdd7d0e0004e62f", - "sha256:3cf4f8d2a30b454ac682e12c61831dcb174950c406011418e739de592bbf8f76", - "sha256:3fd3fccb7b9adaaecfa79ad51b759f2123e1aba97f857936ce044d4f029abd71", - "sha256:442ad4122468d0e47d83bc59d0e91b474593a8c813839e1872e47c7a0cb53b10", - "sha256:47b5e4680002ae1756d3ae3b6114e20aaee6cc5c69d1e5911f5ffffd3ee46c6b", - "sha256:53f5e9767978a4daf46f28e09dbeb7d010319924ae622f7b56174b777258e5ba", - "sha256:62b4c6802fa28e14dba010e75190e0e6228513573f1eeae57b11aa1a39b7e5b1", - "sha256:62cc1253827d1e500fde9dbe981219fea4eb000fd63402283472d38e7d8aa1c6", - "sha256:654ac4583e2d7c62aebc6fc6a4c6736f078f50300e18aa105d87ce8925cfac31", - "sha256:661a8995d11e6e4914a44ca7d52d1286e2d9b154f685a4d1f69add8418961563", - "sha256:6c1d38642ca2dddc7ae992ef5d026e5061a84f10ff2b906be5680ab089f55bb8", - "sha256:6e81c1cc80c1d8bf071356cc3e0e25071fbba1c75afc48d41b26048980b3c771", - "sha256:705837eae384fe21cee5e5746fd4f4b2f06f87544fa60f60740007e0aa600311", - "sha256:7ef04bc7827adb7532be3d14462390dd71287644516af3f1e67f1e6ff9c6d6df", - "sha256:86b2a1013ef7a64d2e94606632683f07712045ed86d937c11ef4dde97319c086", - "sha256:8d1613abd5af2f93c05867b3a3759a56e8bf97eb79b1da76b2bc10892f96ff16", - "sha256:965d0209e6dbdb9416100123b6709cb13f5232e2d52d17ed37f9df0cc31e2b35", - "sha256:96a4271f63a615bcb902b9f56de00ea225d6896052c49f20d0c91e9f43529a29", - "sha256:9d94449ad0a5f2a8bf5d2f8d71d65088aee48adbe45f3c5f8e00e3ad861ed81a", - "sha256:9da650cb29bc098b8cfd15ef09009c914b35c7986c8fa9f08b51108b7bc393b4", - "sha256:a05d1f07eb0a7d755fbe01fee1fd255c3a4d3730130cf1bfefb682d18fd2fcea", - "sha256:a114d1567e1a1586b7e9e7fc2ff686ca542a82769a296cef131e4c4af51e58f4", - "sha256:a1af375734018951c31c0737d04a9d5fd0a353a0253db5fbed2ccd44eac62d8c", - "sha256:b23d30a2c0b992fb1c4f8ac9bfde44b5586d23457759b6cf9a787f1a35179ee0", - "sha256:bc871904a53a9d4d908673c6faa15689874af1c7c5ac403a8e12d967ebd0c0dc", - "sha256:bce60f9a977c9d3d51de475af3f3581d9b36952e1f8fc19a1f2254f1dda7ce9c", - "sha256:bd9825822e7bb243f285013e653f6741954d8147427aaa0324a862cdbf4cbf62", - "sha256:ca7962e8e5fc047cc4e59389959843aafbf7445b6c08c20d883e60ced46370a5", - "sha256:d0cb73ccf7f6d7ca8d0bc7ea8ac0a5b84969a41c56ac3ac3422a24df2680546f", - "sha256:d54a45d30251f1d729e69e5b675f9a08b7da413391a1227781e2a297fa37f6d2", - "sha256:d6ca96d1b61a707ba01a43318c9c40aaf11a5a568d1e61146fafa6ab20890793", - "sha256:d6f195c14c01bd057bc9b4f70756b510e009c83c5ea67b25ced3e2c38e6ee6e9", - "sha256:e2cad98c94833465bcf28f51c248aaf07ca022efc6a3eba750ad9c1e0256d278", - "sha256:e2e993e8db36306cc3f1734edc8ea67906c55f98683d6fd34c3fc5593fdbba4c", - "sha256:e9270505a19361e81eecdbc2c251ad1e1a9a9c2ad75fa022ccdee533f55535dc", - "sha256:f20e2c0dfab82983a90f3d00703ac0960412036153e5023eed2b4641d7d5e692", - "sha256:f36a0868f47b7566237640c026c65a86d09a3d9ca5df1cd039e30a1da73098a0", - "sha256:f59746f7953f69cc3290ce2f971ab01056e55ddd0fb8b792c31a8acd7fee2d28", - "sha256:fa760e5fe8b50cbc2d71884a1eff2ed2b95a005f02dda2fa431560db0ddd927f", - "sha256:ffda9b8cd9cb8b301cae2602ec62375b59e2e2108a117746f12215145e3f786c" - ], - "markers": "python_version >= '3.8'", - "version": "==4.56.0" - }, - "idna": { - "hashes": [ - "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", - "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" - ], - "markers": "python_version >= '3.6'", - "version": "==3.10" - }, - "kiwisolver": { - "hashes": [ - "sha256:01c3d31902c7db5fb6182832713d3b4122ad9317c2c5877d0539227d96bb2e50", - "sha256:034d2c891f76bd3edbdb3ea11140d8510dca675443da7304205a2eaa45d8334c", - "sha256:085940635c62697391baafaaeabdf3dd7a6c3643577dde337f4d66eba021b2b8", - "sha256:08e77738ed7538f036cd1170cbed942ef749137b1311fa2bbe2a7fda2f6bf3cc", - "sha256:111793b232842991be367ed828076b03d96202c19221b5ebab421ce8bcad016f", - "sha256:11e1022b524bd48ae56c9b4f9296bce77e15a2e42a502cceba602f804b32bb79", - "sha256:151dffc4865e5fe6dafce5480fab84f950d14566c480c08a53c663a0020504b6", - "sha256:16523b40aab60426ffdebe33ac374457cf62863e330a90a0383639ce14bf44b2", - "sha256:1732e065704b47c9afca7ffa272f845300a4eb959276bf6970dc07265e73b605", - "sha256:1c8ceb754339793c24aee1c9fb2485b5b1f5bb1c2c214ff13368431e51fc9a09", - "sha256:23454ff084b07ac54ca8be535f4174170c1094a4cff78fbae4f73a4bcc0d4dab", - "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e", - "sha256:257af1622860e51b1a9d0ce387bf5c2c4f36a90594cb9514f55b074bcc787cfc", - "sha256:286b18e86682fd2217a48fc6be6b0f20c1d0ed10958d8dc53453ad58d7be0bf8", - "sha256:291331973c64bb9cce50bbe871fb2e675c4331dab4f31abe89f175ad7679a4d7", - "sha256:2f0121b07b356a22fb0414cec4666bbe36fd6d0d759db3d37228f496ed67c880", - "sha256:3452046c37c7692bd52b0e752b87954ef86ee2224e624ef7ce6cb21e8c41cc1b", - "sha256:34d142fba9c464bc3bbfeff15c96eab0e7310343d6aefb62a79d51421fcc5f1b", - "sha256:369b75d40abedc1da2c1f4de13f3482cb99e3237b38726710f4a793432b1c5ff", - "sha256:36dbbfd34838500a31f52c9786990d00150860e46cd5041386f217101350f0d3", - "sha256:370fd2df41660ed4e26b8c9d6bbcad668fbe2560462cba151a721d49e5b6628c", - "sha256:3a96c0e790ee875d65e340ab383700e2b4891677b7fcd30a699146f9384a2bb0", - "sha256:3b9b4d2892fefc886f30301cdd80debd8bb01ecdf165a449eb6e78f79f0fabd6", - "sha256:3cd3bc628b25f74aedc6d374d5babf0166a92ff1317f46267f12d2ed54bc1d30", - "sha256:3ddc373e0eef45b59197de815b1b28ef89ae3955e7722cc9710fb91cd77b7f47", - "sha256:4191ee8dfd0be1c3666ccbac178c5a05d5f8d689bbe3fc92f3c4abec817f8fe0", - "sha256:54a62808ac74b5e55a04a408cda6156f986cefbcf0ada13572696b507cc92fa1", - "sha256:577facaa411c10421314598b50413aa1ebcf5126f704f1e5d72d7e4e9f020d90", - "sha256:641f2ddf9358c80faa22e22eb4c9f54bd3f0e442e038728f500e3b978d00aa7d", - "sha256:65ea09a5a3faadd59c2ce96dc7bf0f364986a315949dc6374f04396b0d60e09b", - "sha256:68269e60ee4929893aad82666821aaacbd455284124817af45c11e50a4b42e3c", - "sha256:69b5637c3f316cab1ec1c9a12b8c5f4750a4c4b71af9157645bf32830e39c03a", - "sha256:7506488470f41169b86d8c9aeff587293f530a23a23a49d6bc64dab66bedc71e", - "sha256:768cade2c2df13db52475bd28d3a3fac8c9eff04b0e9e2fda0f3760f20b3f7fc", - "sha256:77e6f57a20b9bd4e1e2cedda4d0b986ebd0216236f0106e55c28aea3d3d69b16", - "sha256:782bb86f245ec18009890e7cb8d13a5ef54dcf2ebe18ed65f795e635a96a1c6a", - "sha256:7a3ad337add5148cf51ce0b55642dc551c0b9d6248458a757f98796ca7348712", - "sha256:7cd2785b9391f2873ad46088ed7599a6a71e762e1ea33e87514b1a441ed1da1c", - "sha256:7e9a60b50fe8b2ec6f448fe8d81b07e40141bfced7f896309df271a0b92f80f3", - "sha256:84a2f830d42707de1d191b9490ac186bf7997a9495d4e9072210a1296345f7dc", - "sha256:856b269c4d28a5c0d5e6c1955ec36ebfd1651ac00e1ce0afa3e28da95293b561", - "sha256:858416b7fb777a53f0c59ca08190ce24e9abbd3cffa18886a5781b8e3e26f65d", - "sha256:87b287251ad6488e95b4f0b4a79a6d04d3ea35fde6340eb38fbd1ca9cd35bbbc", - "sha256:88c6f252f6816a73b1f8c904f7bbe02fd67c09a69f7cb8a0eecdbf5ce78e63db", - "sha256:893f5525bb92d3d735878ec00f781b2de998333659507d29ea4466208df37bed", - "sha256:89c107041f7b27844179ea9c85d6da275aa55ecf28413e87624d033cf1f6b751", - "sha256:918139571133f366e8362fa4a297aeba86c7816b7ecf0bc79168080e2bd79957", - "sha256:99cea8b9dd34ff80c521aef46a1dddb0dcc0283cf18bde6d756f1e6f31772165", - "sha256:a17b7c4f5b2c51bb68ed379defd608a03954a1845dfed7cc0117f1cc8a9b7fd2", - "sha256:a3c44cb68861de93f0c4a8175fbaa691f0aa22550c331fefef02b618a9dcb476", - "sha256:a4d3601908c560bdf880f07d94f31d734afd1bb71e96585cace0e38ef44c6d84", - "sha256:a5ce1e481a74b44dd5e92ff03ea0cb371ae7a0268318e202be06c8f04f4f1246", - "sha256:a66f60f8d0c87ab7f59b6fb80e642ebb29fec354a4dfad687ca4092ae69d04f4", - "sha256:b21dbe165081142b1232a240fc6383fd32cdd877ca6cc89eab93e5f5883e1c25", - "sha256:b47a465040146981dc9db8647981b8cb96366fbc8d452b031e4f8fdffec3f26d", - "sha256:b5773efa2be9eb9fcf5415ea3ab70fc785d598729fd6057bea38d539ead28271", - "sha256:b83dc6769ddbc57613280118fb4ce3cd08899cc3369f7d0e0fab518a7cf37fdb", - "sha256:bade438f86e21d91e0cf5dd7c0ed00cda0f77c8c1616bd83f9fc157fa6760d31", - "sha256:bcb1ebc3547619c3b58a39e2448af089ea2ef44b37988caf432447374941574e", - "sha256:be4816dc51c8a471749d664161b434912eee82f2ea66bd7628bd14583a833e85", - "sha256:c07b29089b7ba090b6f1a669f1411f27221c3662b3a1b7010e67b59bb5a6f10b", - "sha256:c2b9a96e0f326205af81a15718a9073328df1173a2619a68553decb7097fd5d7", - "sha256:c5020c83e8553f770cb3b5fc13faac40f17e0b205bd237aebd21d53d733adb03", - "sha256:c72941acb7b67138f35b879bbe85be0f6c6a70cab78fe3ef6db9c024d9223e5b", - "sha256:c8bf637892dc6e6aad2bc6d4d69d08764166e5e3f69d469e55427b6ac001b19d", - "sha256:cc978a80a0db3a66d25767b03688f1147a69e6237175c0f4ffffaaedf744055a", - "sha256:ce2cf1e5688edcb727fdf7cd1bbd0b6416758996826a8be1d958f91880d0809d", - "sha256:d47b28d1dfe0793d5e96bce90835e17edf9a499b53969b03c6c47ea5985844c3", - "sha256:d47cfb2650f0e103d4bf68b0b5804c68da97272c84bb12850d877a95c056bd67", - "sha256:d5536185fce131780ebd809f8e623bf4030ce1b161353166c49a3c74c287897f", - "sha256:d561d2d8883e0819445cfe58d7ddd673e4015c3c57261d7bdcd3710d0d14005c", - "sha256:d6af5e8815fd02997cb6ad9bbed0ee1e60014438ee1a5c2444c96f87b8843502", - "sha256:d6d6bd87df62c27d4185de7c511c6248040afae67028a8a22012b010bc7ad062", - "sha256:dace81d28c787956bfbfbbfd72fdcef014f37d9b48830829e488fdb32b49d954", - "sha256:e063ef9f89885a1d68dd8b2e18f5ead48653176d10a0e324e3b0030e3a69adeb", - "sha256:e7a019419b7b510f0f7c9dceff8c5eae2392037eae483a7f9162625233802b0a", - "sha256:eaa973f1e05131de5ff3569bbba7f5fd07ea0595d3870ed4a526d486fe57fa1b", - "sha256:eb158fe28ca0c29f2260cca8c43005329ad58452c36f0edf298204de32a9a3ed", - "sha256:ed33ca2002a779a2e20eeb06aea7721b6e47f2d4b8a8ece979d8ba9e2a167e34", - "sha256:fc2ace710ba7c1dfd1a3b42530b62b9ceed115f19a1656adefce7b1782a37794" - ], - "markers": "python_version >= '3.10'", - "version": "==1.4.8" - }, - "matplotlib": { - "hashes": [ - "sha256:01e63101ebb3014e6e9f80d9cf9ee361a8599ddca2c3e166c563628b39305dbb", - "sha256:02582304e352f40520727984a5a18f37e8187861f954fea9be7ef06569cf85b4", - "sha256:057206ff2d6ab82ff3e94ebd94463d084760ca682ed5f150817b859372ec4401", - "sha256:0721a3fd3d5756ed593220a8b86808a36c5031fce489adb5b31ee6dbb47dd5b2", - "sha256:0f69dc9713e4ad2fb21a1c30e37bd445d496524257dfda40ff4a8efb3604ab5c", - "sha256:11b65088c6f3dae784bc72e8d039a2580186285f87448babb9ddb2ad0082993a", - "sha256:1985ad3d97f51307a2cbfc801a930f120def19ba22864182dacef55277102ba6", - "sha256:19b06241ad89c3ae9469e07d77efa87041eac65d78df4fcf9cac318028009b01", - "sha256:2589659ea30726284c6c91037216f64a506a9822f8e50592d48ac16a2f29e044", - "sha256:35e87384ee9e488d8dd5a2dd7baf471178d38b90618d8ea147aced4ab59c9bea", - "sha256:3f06bad951eea6422ac4e8bdebcf3a70c59ea0a03338c5d2b109f57b64eb3972", - "sha256:4c59af3e8aca75d7744b68e8e78a669e91ccbcf1ac35d0102a7b1b46883f1dd7", - "sha256:4f0647b17b667ae745c13721602b540f7aadb2a32c5b96e924cd4fea5dcb90f1", - "sha256:56c5d9fcd9879aa8040f196a235e2dcbdf7dd03ab5b07c0696f80bc6cf04bedd", - "sha256:5d45d3f5245be5b469843450617dcad9af75ca50568acf59997bed9311131a0b", - "sha256:648406f1899f9a818cef8c0231b44dcfc4ff36f167101c3fd1c9151f24220fdc", - "sha256:66e907a06e68cb6cfd652c193311d61a12b54f56809cafbed9736ce5ad92f107", - "sha256:7e496c01441be4c7d5f96d4e40f7fca06e20dcb40e44c8daa2e740e1757ad9e6", - "sha256:8e875b95ac59a7908978fe307ecdbdd9a26af7fa0f33f474a27fcf8c99f64a19", - "sha256:8e8e25b1209161d20dfe93037c8a7f7ca796ec9aa326e6e4588d8c4a5dd1e473", - "sha256:a144867dd6bf8ba8cb5fc81a158b645037e11b3e5cf8a50bd5f9917cb863adfe", - "sha256:a3dfb036f34873b46978f55e240cff7a239f6c4409eac62d8145bad3fc6ba5a3", - "sha256:a97ff127f295817bc34517255c9db6e71de8eddaab7f837b7d341dee9f2f587f", - "sha256:aa3854b5f9473564ef40a41bc922be978fab217776e9ae1545c9b3a5cf2092a3", - "sha256:bc411ebd5889a78dabbc457b3fa153203e22248bfa6eedc6797be5df0164dbf9", - "sha256:c42eee41e1b60fd83ee3292ed83a97a5f2a8239b10c26715d8a6172226988d7b", - "sha256:c96f2c2f825d1257e437a1482c5a2cf4fee15db4261bd6fc0750f81ba2b4ba3d", - "sha256:cfd414bce89cc78a7e1d25202e979b3f1af799e416010a20ab2b5ebb3a02425c", - "sha256:d0673b4b8f131890eb3a1ad058d6e065fb3c6e71f160089b65f8515373394698", - "sha256:d3809916157ba871bcdd33d3493acd7fe3037db5daa917ca6e77975a94cef779", - "sha256:dc6ab14a7ab3b4d813b88ba957fc05c79493a037f54e246162033591e770de6f", - "sha256:e8d2d0e3881b129268585bf4765ad3ee73a4591d77b9a18c214ac7e3a79fb2ba", - "sha256:e9b4bb156abb8fa5e5b2b460196f7db7264fc6d62678c03457979e7d5254b7be", - "sha256:ff2ae14910be903f4a24afdbb6d7d3a6c44da210fc7d42790b87aeac92238a16" - ], - "index": "pypi", - "markers": "python_version >= '3.10'", - "version": "==3.10.1" - }, - "numpy": { - "hashes": [ - "sha256:05c076d531e9998e7e694c36e8b349969c56eadd2cdcd07242958489d79a7286", - "sha256:0d54974f9cf14acf49c60f0f7f4084b6579d24d439453d5fc5805d46a165b542", - "sha256:11c43995255eb4127115956495f43e9343736edb7fcdb0d973defd9de14cd84f", - "sha256:188dcbca89834cc2e14eb2f106c96d6d46f200fe0200310fc29089657379c58d", - "sha256:1974afec0b479e50438fc3648974268f972e2d908ddb6d7fb634598cdb8260a0", - "sha256:1cf4e5c6a278d620dee9ddeb487dc6a860f9b199eadeecc567f777daace1e9e7", - "sha256:207a2b8441cc8b6a2a78c9ddc64d00d20c303d79fba08c577752f080c4007ee3", - "sha256:218f061d2faa73621fa23d6359442b0fc658d5b9a70801373625d958259eaca3", - "sha256:2aad3c17ed2ff455b8eaafe06bcdae0062a1db77cb99f4b9cbb5f4ecb13c5146", - "sha256:2fa8fa7697ad1646b5c93de1719965844e004fcad23c91228aca1cf0800044a1", - "sha256:31504f970f563d99f71a3512d0c01a645b692b12a63630d6aafa0939e52361e6", - "sha256:3387dd7232804b341165cedcb90694565a6015433ee076c6754775e85d86f1fc", - "sha256:4ba5054787e89c59c593a4169830ab362ac2bee8a969249dc56e5d7d20ff8df9", - "sha256:4f92084defa704deadd4e0a5ab1dc52d8ac9e8a8ef617f3fbb853e79b0ea3592", - "sha256:65ef3468b53269eb5fdb3a5c09508c032b793da03251d5f8722b1194f1790c00", - "sha256:6f527d8fdb0286fd2fd97a2a96c6be17ba4232da346931d967a0630050dfd298", - "sha256:7051ee569db5fbac144335e0f3b9c2337e0c8d5c9fee015f259a5bd70772b7e8", - "sha256:7716e4a9b7af82c06a2543c53ca476fa0b57e4d760481273e09da04b74ee6ee2", - "sha256:79bd5f0a02aa16808fcbc79a9a376a147cc1045f7dfe44c6e7d53fa8b8a79392", - "sha256:7a4e84a6283b36632e2a5b56e121961f6542ab886bc9e12f8f9818b3c266bfbb", - "sha256:8120575cb4882318c791f839a4fd66161a6fa46f3f0a5e613071aae35b5dd8f8", - "sha256:81413336ef121a6ba746892fad881a83351ee3e1e4011f52e97fba79233611fd", - "sha256:8146f3550d627252269ac42ae660281d673eb6f8b32f113538e0cc2a9aed42b9", - "sha256:879cf3a9a2b53a4672a168c21375166171bc3932b7e21f622201811c43cdd3b0", - "sha256:892c10d6a73e0f14935c31229e03325a7b3093fafd6ce0af704be7f894d95687", - "sha256:92bda934a791c01d6d9d8e038363c50918ef7c40601552a58ac84c9613a665bc", - "sha256:9ba03692a45d3eef66559efe1d1096c4b9b75c0986b5dff5530c378fb8331d4f", - "sha256:9eeea959168ea555e556b8188da5fa7831e21d91ce031e95ce23747b7609f8a4", - "sha256:a0258ad1f44f138b791327961caedffbf9612bfa504ab9597157806faa95194a", - "sha256:a761ba0fa886a7bb33c6c8f6f20213735cb19642c580a931c625ee377ee8bd39", - "sha256:a7b9084668aa0f64e64bd00d27ba5146ef1c3a8835f3bd912e7a9e01326804c4", - "sha256:a84eda42bd12edc36eb5b53bbcc9b406820d3353f1994b6cfe453a33ff101775", - "sha256:ab2939cd5bec30a7430cbdb2287b63151b77cf9624de0532d629c9a1c59b1d5c", - "sha256:ac0280f1ba4a4bfff363a99a6aceed4f8e123f8a9b234c89140f5e894e452ecd", - "sha256:adf8c1d66f432ce577d0197dceaac2ac00c0759f573f28516246351c58a85020", - "sha256:b4adfbbc64014976d2f91084915ca4e626fbf2057fb81af209c1a6d776d23e3d", - "sha256:bb649f8b207ab07caebba230d851b579a3c8711a851d29efe15008e31bb4de24", - "sha256:bce43e386c16898b91e162e5baaad90c4b06f9dcbe36282490032cec98dc8ae7", - "sha256:bd3ad3b0a40e713fc68f99ecfd07124195333f1e689387c180813f0e94309d6f", - "sha256:c3f7ac96b16955634e223b579a3e5798df59007ca43e8d451a0e6a50f6bfdfba", - "sha256:cf28633d64294969c019c6df4ff37f5698e8326db68cc2b66576a51fad634880", - "sha256:d0f35b19894a9e08639fd60a1ec1978cb7f5f7f1eace62f38dd36be8aecdef4d", - "sha256:db1f1c22173ac1c58db249ae48aa7ead29f534b9a948bc56828337aa84a32ed6", - "sha256:dbe512c511956b893d2dacd007d955a3f03d555ae05cfa3ff1c1ff6df8851854", - "sha256:df2f57871a96bbc1b69733cd4c51dc33bea66146b8c63cacbfed73eec0883017", - "sha256:e2f085ce2e813a50dfd0e01fbfc0c12bbe5d2063d99f8b29da30e544fb6483b8", - "sha256:e642d86b8f956098b564a45e6f6ce68a22c2c97a04f5acd3f221f57b8cb850ae", - "sha256:e9e0a277bb2eb5d8a7407e14688b85fd8ad628ee4e0c7930415687b6564207a4", - "sha256:ea2bb7e2ae9e37d96835b3576a4fa4b3a97592fbea8ef7c3587078b0068b8f09", - "sha256:ee4d528022f4c5ff67332469e10efe06a267e32f4067dc76bb7e2cddf3cd25ff", - "sha256:f05d4198c1bacc9124018109c5fba2f3201dbe7ab6e92ff100494f236209c960", - "sha256:f34dc300df798742b3d06515aa2a0aee20941c13579d7a2f2e10af01ae4901ee", - "sha256:f4162988a360a29af158aeb4a2f4f09ffed6a969c9776f8f3bdee9b06a8ab7e5", - "sha256:f486038e44caa08dbd97275a9a35a283a8f1d2f0ee60ac260a1790e76660833c", - "sha256:f7de08cbe5551911886d1ab60de58448c6df0f67d9feb7d1fb21e9875ef95e91" - ], - "markers": "python_version >= '3.10'", - "version": "==2.2.4" - }, - "packaging": { - "hashes": [ - "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", - "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" - ], - "markers": "python_version >= '3.8'", - "version": "==24.2" - }, - "pandas": { - "hashes": [ - "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", - "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d", - "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5", - "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4", - "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0", - "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32", - "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea", - "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28", - "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f", - "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348", - "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18", - "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468", - "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5", - "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e", - "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", - "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645", - "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", - "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30", - "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", - "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d", - "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb", - "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3", - "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039", - "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", - "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd", - "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761", - "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659", - "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57", - "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c", - "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c", - "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", - "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a", - "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", - "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42", - "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2", - "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39", - "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc", - "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698", - "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed", - "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015", - "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24", - "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==2.2.3" - }, - "pillow": { - "hashes": [ - "sha256:015c6e863faa4779251436db398ae75051469f7c903b043a48f078e437656f83", - "sha256:0a2f91f8a8b367e7a57c6e91cd25af510168091fb89ec5146003e424e1558a96", - "sha256:11633d58b6ee5733bde153a8dafd25e505ea3d32e261accd388827ee987baf65", - "sha256:2062ffb1d36544d42fcaa277b069c88b01bb7298f4efa06731a7fd6cc290b81a", - "sha256:31eba6bbdd27dde97b0174ddf0297d7a9c3a507a8a1480e1e60ef914fe23d352", - "sha256:3362c6ca227e65c54bf71a5f88b3d4565ff1bcbc63ae72c34b07bbb1cc59a43f", - "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20", - "sha256:36ba10b9cb413e7c7dfa3e189aba252deee0602c86c309799da5a74009ac7a1c", - "sha256:3764d53e09cdedd91bee65c2527815d315c6b90d7b8b79759cc48d7bf5d4f114", - "sha256:3a5fe20a7b66e8135d7fd617b13272626a28278d0e578c98720d9ba4b2439d49", - "sha256:3cdcdb0b896e981678eee140d882b70092dac83ac1cdf6b3a60e2216a73f2b91", - "sha256:4637b88343166249fe8aa94e7c4a62a180c4b3898283bb5d3d2fd5fe10d8e4e0", - "sha256:4db853948ce4e718f2fc775b75c37ba2efb6aaea41a1a5fc57f0af59eee774b2", - "sha256:4dd43a78897793f60766563969442020e90eb7847463eca901e41ba186a7d4a5", - "sha256:54251ef02a2309b5eec99d151ebf5c9904b77976c8abdcbce7891ed22df53884", - "sha256:54ce1c9a16a9561b6d6d8cb30089ab1e5eb66918cb47d457bd996ef34182922e", - "sha256:593c5fd6be85da83656b93ffcccc2312d2d149d251e98588b14fbc288fd8909c", - "sha256:5bb94705aea800051a743aa4874bb1397d4695fb0583ba5e425ee0328757f196", - "sha256:67cd427c68926108778a9005f2a04adbd5e67c442ed21d95389fe1d595458756", - "sha256:70ca5ef3b3b1c4a0812b5c63c57c23b63e53bc38e758b37a951e5bc466449861", - "sha256:73ddde795ee9b06257dac5ad42fcb07f3b9b813f8c1f7f870f402f4dc54b5269", - "sha256:758e9d4ef15d3560214cddbc97b8ef3ef86ce04d62ddac17ad39ba87e89bd3b1", - "sha256:7d33d2fae0e8b170b6a6c57400e077412240f6f5bb2a342cf1ee512a787942bb", - "sha256:7fdadc077553621911f27ce206ffcbec7d3f8d7b50e0da39f10997e8e2bb7f6a", - "sha256:8000376f139d4d38d6851eb149b321a52bb8893a88dae8ee7d95840431977081", - "sha256:837060a8599b8f5d402e97197d4924f05a2e0d68756998345c829c33186217b1", - "sha256:89dbdb3e6e9594d512780a5a1c42801879628b38e3efc7038094430844e271d8", - "sha256:8c730dc3a83e5ac137fbc92dfcfe1511ce3b2b5d7578315b63dbbb76f7f51d90", - "sha256:8e275ee4cb11c262bd108ab2081f750db2a1c0b8c12c1897f27b160c8bd57bbc", - "sha256:9044b5e4f7083f209c4e35aa5dd54b1dd5b112b108648f5c902ad586d4f945c5", - "sha256:93a18841d09bcdd774dcdc308e4537e1f867b3dec059c131fde0327899734aa1", - "sha256:9409c080586d1f683df3f184f20e36fb647f2e0bc3988094d4fd8c9f4eb1b3b3", - "sha256:96f82000e12f23e4f29346e42702b6ed9a2f2fea34a740dd5ffffcc8c539eb35", - "sha256:9aa9aeddeed452b2f616ff5507459e7bab436916ccb10961c4a382cd3e03f47f", - "sha256:9ee85f0696a17dd28fbcfceb59f9510aa71934b483d1f5601d1030c3c8304f3c", - "sha256:a07dba04c5e22824816b2615ad7a7484432d7f540e6fa86af60d2de57b0fcee2", - "sha256:a3cd561ded2cf2bbae44d4605837221b987c216cff94f49dfeed63488bb228d2", - "sha256:a697cd8ba0383bba3d2d3ada02b34ed268cb548b369943cd349007730c92bddf", - "sha256:a76da0a31da6fcae4210aa94fd779c65c75786bc9af06289cd1c184451ef7a65", - "sha256:a85b653980faad27e88b141348707ceeef8a1186f75ecc600c395dcac19f385b", - "sha256:a8d65b38173085f24bc07f8b6c505cbb7418009fa1a1fcb111b1f4961814a442", - "sha256:aa8dd43daa836b9a8128dbe7d923423e5ad86f50a7a14dc688194b7be5c0dea2", - "sha256:ab8a209b8485d3db694fa97a896d96dd6533d63c22829043fd9de627060beade", - "sha256:abc56501c3fd148d60659aae0af6ddc149660469082859fa7b066a298bde9482", - "sha256:ad5db5781c774ab9a9b2c4302bbf0c1014960a0a7be63278d13ae6fdf88126fe", - "sha256:ae98e14432d458fc3de11a77ccb3ae65ddce70f730e7c76140653048c71bfcbc", - "sha256:b20be51b37a75cc54c2c55def3fa2c65bb94ba859dde241cd0a4fd302de5ae0a", - "sha256:b523466b1a31d0dcef7c5be1f20b942919b62fd6e9a9be199d035509cbefc0ec", - "sha256:b5d658fbd9f0d6eea113aea286b21d3cd4d3fd978157cbf2447a6035916506d3", - "sha256:b6123aa4a59d75f06e9dd3dac5bf8bc9aa383121bb3dd9a7a612e05eabc9961a", - "sha256:bd165131fd51697e22421d0e467997ad31621b74bfc0b75956608cb2906dda07", - "sha256:bf902d7413c82a1bfa08b06a070876132a5ae6b2388e2712aab3a7cbc02205c6", - "sha256:c12fc111ef090845de2bb15009372175d76ac99969bdf31e2ce9b42e4b8cd88f", - "sha256:c1eec9d950b6fe688edee07138993e54ee4ae634c51443cfb7c1e7613322718e", - "sha256:c640e5a06869c75994624551f45e5506e4256562ead981cce820d5ab39ae2192", - "sha256:cc1331b6d5a6e144aeb5e626f4375f5b7ae9934ba620c0ac6b3e43d5e683a0f0", - "sha256:cfd5cd998c2e36a862d0e27b2df63237e67273f2fc78f47445b14e73a810e7e6", - "sha256:d3d8da4a631471dfaf94c10c85f5277b1f8e42ac42bade1ac67da4b4a7359b73", - "sha256:d44ff19eea13ae4acdaaab0179fa68c0c6f2f45d66a4d8ec1eda7d6cecbcc15f", - "sha256:dd0052e9db3474df30433f83a71b9b23bd9e4ef1de13d92df21a52c0303b8ab6", - "sha256:dd0e081319328928531df7a0e63621caf67652c8464303fd102141b785ef9547", - "sha256:dda60aa465b861324e65a78c9f5cf0f4bc713e4309f83bc387be158b077963d9", - "sha256:e06695e0326d05b06833b40b7ef477e475d0b1ba3a6d27da1bb48c23209bf457", - "sha256:e1abe69aca89514737465752b4bcaf8016de61b3be1397a8fc260ba33321b3a8", - "sha256:e267b0ed063341f3e60acd25c05200df4193e15a4a5807075cd71225a2386e26", - "sha256:e5449ca63da169a2e6068dd0e2fcc8d91f9558aba89ff6d02121ca8ab11e79e5", - "sha256:e63e4e5081de46517099dc30abe418122f54531a6ae2ebc8680bcd7096860eab", - "sha256:f189805c8be5ca5add39e6f899e6ce2ed824e65fb45f3c28cb2841911da19070", - "sha256:f7955ecf5609dee9442cbface754f2c6e541d9e6eda87fad7f7a989b0bdb9d71", - "sha256:f86d3a7a9af5d826744fabf4afd15b9dfef44fe69a98541f666f66fbb8d3fef9", - "sha256:fbd43429d0d7ed6533b25fc993861b8fd512c42d04514a0dd6337fb3ccf22761" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==11.1.0" - }, - "pyparsing": { - "hashes": [ - "sha256:2a857aee851f113c2de9d4bfd9061baea478cb0f1c7ca6cbf594942d6d111575", - "sha256:6ab05e1cb111cc72acc8ed811a3ca4c2be2af8d7b6df324347f04fd057d8d793" - ], - "markers": "python_version >= '3.9'", - "version": "==3.2.2" - }, - "pyproj": { - "hashes": [ - "sha256:04abc517a8555d1b05fcee768db3280143fe42ec39fdd926a2feef31631a1f2f", - "sha256:0829865c1d3a3543f918b3919dc601eea572d6091c0dd175e1a054db9c109274", - "sha256:084c0a475688f934d386c2ab3b6ce03398a473cd48adfda70d9ab8f87f2394a0", - "sha256:0b853ae99bda66cbe24b4ccfe26d70601d84375940a47f553413d9df570065e0", - "sha256:1e47c4e93b88d99dd118875ee3ca0171932444cdc0b52d493371b5d98d0f30ee", - "sha256:263b54ba5004b6b957d55757d846fc5081bc02980caa0279c4fc95fa0fff6067", - "sha256:2781029d90df7f8d431e29562a3f2d8eafdf233c4010d6fc0381858dc7373217", - "sha256:3537668992a709a2e7f068069192138618c00d0ba113572fdd5ee5ffde8222f3", - "sha256:3c2e7449840a44ce860d8bea2c6c1c4bc63fa07cba801dcce581d14dcb031a02", - "sha256:3e8d276caeae34fcbe4813855d0d97b9b825bab8d7a8b86d859c24a6213a5a0d", - "sha256:5ad0ff443a785d84e2b380869fdd82e6bfc11eba6057d25b4409a9bbfa867970", - "sha256:5f0da2711364d7cb9f115b52289d4a9b61e8bca0da57f44a3a9d6fc9bdeb7274", - "sha256:5f8d02ef4431dee414d1753d13fa82a21a2f61494737b5f642ea668d76164d6d", - "sha256:60d72facd7b6b79853f19744779abcd3f804c4e0d4fa8815469db20c9f640a47", - "sha256:6181960b4b812e82e588407fe5c9c68ada267c3b084db078f248db5d7f45d18a", - "sha256:6575b2e53cc9e3e461ad6f0692a5564b96e7782c28631c7771c668770915e169", - "sha256:83db380c52087f9e9bdd8a527943b2e7324f275881125e39475c4f9277bdeec4", - "sha256:87229e42b75e89f4dad6459200f92988c5998dfb093c7c631fb48524c86cd5dc", - "sha256:8c5dcf24ede53d8abab7d8a77f69ff1936c6a8843ef4fcc574646e4be66e5739", - "sha256:8cb516ee35ed57789b46b96080edf4e503fdb62dbb2e3c6581e0d6c83fca014b", - "sha256:a20727a23b1e49c7dc7fe3c3df8e56a8a7acdade80ac2f5cca29d7ca5564c145", - "sha256:a8b15b0463d1303bab113d1a6af2860a0d79013c3a66fcc5475ce26ef717fd4f", - "sha256:a94e26c1a4950cea40116775588a2ca7cf56f1f434ff54ee35a84718f3841a3d", - "sha256:aee664a9d806612af30a19dba49e55a7a78ebfec3e9d198f6a6176e1d140ec98", - "sha256:b35ed213892e211a3ce2bea002aa1183e1a2a9b79e51bb3c6b15549a831ae528", - "sha256:bf09dbeb333c34e9c546364e7df1ff40474f9fddf9e70657ecb0e4f670ff0b0e", - "sha256:bf84d766646f1ebd706d883755df4370aaf02b48187cedaa7e4239f16bc8213d", - "sha256:d3caac7473be22b6d6e102dde6c46de73b96bc98334e577dfaee9886f102ea2e", - "sha256:d61bf8ab04c73c1da08eedaf21a103b72fa5b0a9b854762905f65ff8b375d394", - "sha256:d666c3a3faaf3b1d7fc4a544059c4eab9d06f84a604b070b7aa2f318e227798e", - "sha256:f173f851ee75e54acdaa053382b6825b400cb2085663a9bb073728a59c60aebb", - "sha256:f550281ed6e5ea88fcf04a7c6154e246d5714be495c50c9e8e6b12d3fb63e158", - "sha256:f6d6a2ccd5607cd15ef990c51e6f2dd27ec0a741e72069c387088bba3aab60fa" - ], - "index": "pypi", - "markers": "python_version >= '3.10'", - "version": "==3.7.1" - }, - "python-dateutil": { - "hashes": [ - "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", - "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", - "version": "==2.9.0.post0" - }, - "pytz": { - "hashes": [ - "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57", - "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e" - ], - "version": "==2025.1" - }, - "requests": { - "hashes": [ - "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", - "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==2.32.3" - }, - "scipy": { - "hashes": [ - "sha256:01edfac9f0798ad6b46d9c4c9ca0e0ad23dbf0b1eb70e96adb9fa7f525eff0bf", - "sha256:03205d57a28e18dfd39f0377d5002725bf1f19a46f444108c29bdb246b6c8a11", - "sha256:08b57a9336b8e79b305a143c3655cc5bdbe6d5ece3378578888d2afbb51c4e37", - "sha256:11e7ad32cf184b74380f43d3c0a706f49358b904fa7d5345f16ddf993609184d", - "sha256:28a0d2c2075946346e4408b211240764759e0fabaeb08d871639b5f3b1aca8a0", - "sha256:2b871df1fe1a3ba85d90e22742b93584f8d2b8e6124f8372ab15c71b73e428b8", - "sha256:302093e7dfb120e55515936cb55618ee0b895f8bcaf18ff81eca086c17bd80af", - "sha256:42dabaaa798e987c425ed76062794e93a243be8f0f20fff6e7a89f4d61cb3d40", - "sha256:447ce30cee6a9d5d1379087c9e474628dab3db4a67484be1b7dc3196bfb2fac9", - "sha256:4c6676490ad76d1c2894d77f976144b41bd1a4052107902238047fb6a473e971", - "sha256:54c462098484e7466362a9f1672d20888f724911a74c22ae35b61f9c5919183d", - "sha256:597a0c7008b21c035831c39927406c6181bcf8f60a73f36219b69d010aa04737", - "sha256:5a6fd6eac1ce74a9f77a7fc724080d507c5812d61e72bd5e4c489b042455865e", - "sha256:5ea7ed46d437fc52350b028b1d44e002646e28f3e8ddc714011aaf87330f2f32", - "sha256:601881dfb761311045b03114c5fe718a12634e5608c3b403737ae463c9885d53", - "sha256:62ca1ff3eb513e09ed17a5736929429189adf16d2d740f44e53270cc800ecff1", - "sha256:69ea6e56d00977f355c0f84eba69877b6df084516c602d93a33812aa04d90a3d", - "sha256:6a8e34cf4c188b6dd004654f88586d78f95639e48a25dfae9c5e34a6dc34547e", - "sha256:6d0194c37037707b2afa7a2f2a924cf7bac3dc292d51b6a925e5fcb89bc5c776", - "sha256:6f223753c6ea76983af380787611ae1291e3ceb23917393079dcc746ba60cfb5", - "sha256:6f5e296ec63c5da6ba6fa0343ea73fd51b8b3e1a300b0a8cae3ed4b1122c7462", - "sha256:7cd5b77413e1855351cdde594eca99c1f4a588c2d63711388b6a1f1c01f62274", - "sha256:869269b767d5ee7ea6991ed7e22b3ca1f22de73ab9a49c44bad338b725603301", - "sha256:87994da02e73549dfecaed9e09a4f9d58a045a053865679aeb8d6d43747d4df3", - "sha256:888307125ea0c4466287191e5606a2c910963405ce9671448ff9c81c53f85f58", - "sha256:92233b2df6938147be6fa8824b8136f29a18f016ecde986666be5f4d686a91a4", - "sha256:9412f5e408b397ff5641080ed1e798623dbe1ec0d78e72c9eca8992976fa65aa", - "sha256:9b18aa747da280664642997e65aab1dd19d0c3d17068a04b3fe34e2559196cb9", - "sha256:9de9d1416b3d9e7df9923ab23cd2fe714244af10b763975bea9e4f2e81cebd27", - "sha256:a2ec871edaa863e8213ea5df811cd600734f6400b4af272e1c011e69401218e9", - "sha256:a5080a79dfb9b78b768cebf3c9dcbc7b665c5875793569f48bf0e2b1d7f68f6f", - "sha256:a8bf5cb4a25046ac61d38f8d3c3426ec11ebc350246a4642f2f315fe95bda655", - "sha256:b09ae80010f52efddb15551025f9016c910296cf70adbf03ce2a8704f3a5ad20", - "sha256:b5e025e903b4f166ea03b109bb241355b9c42c279ea694d8864d033727205e65", - "sha256:bad78d580270a4d32470563ea86c6590b465cb98f83d760ff5b0990cb5518a93", - "sha256:bae43364d600fdc3ac327db99659dcb79e6e7ecd279a75fe1266669d9a652828", - "sha256:c4697a10da8f8765bb7c83e24a470da5797e37041edfd77fd95ba3811a47c4fd", - "sha256:c90ebe8aaa4397eaefa8455a8182b164a6cc1d59ad53f79943f266d99f68687f", - "sha256:cd58a314d92838f7e6f755c8a2167ead4f27e1fd5c1251fd54289569ef3495ec", - "sha256:cf72ff559a53a6a6d77bd8eefd12a17995ffa44ad86c77a5df96f533d4e6c6bb", - "sha256:def751dd08243934c884a3221156d63e15234a3155cf25978b0a668409d45eb6", - "sha256:e7c68b6a43259ba0aab737237876e5c2c549a031ddb7abc28c7b47f22e202ded", - "sha256:ecf797d2d798cf7c838c6d98321061eb3e72a74710e6c40540f0e8087e3b499e", - "sha256:f031846580d9acccd0044efd1a90e6f4df3a6e12b4b6bd694a7bc03a89892b28", - "sha256:fb530e4794fc8ea76a4a21ccb67dea33e5e0e60f07fc38a49e821e1eae3b71a0", - "sha256:fe8a9eb875d430d81755472c5ba75e84acc980e4a8f6204d402849234d3017db" - ], - "index": "pypi", - "markers": "python_version >= '3.10'", - "version": "==1.15.2" - }, - "shapely": { - "extras": [ - "vectorized" - ], - "hashes": [ - "sha256:0145387565fcf8f7c028b073c802956431308da933ef41d08b1693de49990d27", - "sha256:04a65d882456e13c8b417562c36324c0cd1e5915f3c18ad516bb32ee3f5fc895", - "sha256:06ff6020949b44baa8fc2e5e57e0f3d09486cd5c33b47d669f847c54136e7027", - "sha256:19cbc8808efe87a71150e785b71d8a0e614751464e21fb679d97e274eca7bd43", - "sha256:1a2e03277128e62f9a49a58eb7eb813fa9b343925fca5e7d631d50f4c0e8e0b8", - "sha256:1e9fed9a7d6451979d914cb6ebbb218b4b4e77c0d50da23e23d8327948662611", - "sha256:25085a30a2462cee4e850a6e3fb37431cbbe4ad51cbcc163af0cea1eaa9eb96d", - "sha256:28fe2997aab9a9dc026dc6a355d04e85841546b2a5d232ed953e3321ab958ee5", - "sha256:2934834c7f417aeb7cba3b0d9b4441a76ebcecf9ea6e80b455c33c7c62d96a24", - "sha256:2e4a1749ad64bc6e7668c8f2f9479029f079991f4ae3cb9e6b25440e35a4b532", - "sha256:2f6e4759cf680a0f00a54234902415f2fa5fe02f6b05546c662654001f0793a2", - "sha256:33fb10e50b16113714ae40adccf7670379e9ccf5b7a41d0002046ba2b8f0f691", - "sha256:35524cc8d40ee4752520819f9894b9f28ba339a42d4922e92c99b148bed3be39", - "sha256:3697bd078b4459f5a1781015854ef5ea5d824dbf95282d0b60bfad6ff83ec8dc", - "sha256:4abeb44b3b946236e4e1a1b3d2a0987fb4d8a63bfb3fdefb8a19d142b72001e5", - "sha256:4c2b9859424facbafa54f4a19b625a752ff958ab49e01bc695f254f7db1835fa", - "sha256:5aed1c6764f51011d69a679fdf6b57e691371ae49ebe28c3edb5486537ffbd51", - "sha256:5cf23400cb25deccf48c56a7cdda8197ae66c0e9097fcdd122ac2007e320bc34", - "sha256:5d6dbf096f961ca6bec5640e22e65ccdec11e676344e8157fe7d636e7904fd36", - "sha256:6bca5095e86be9d4ef3cb52d56bdd66df63ff111d580855cb8546f06c3c907cd", - "sha256:73c9ae8cf443187d784d57202199bf9fd2d4bb7d5521fe8926ba40db1bc33e8e", - "sha256:7977d8a39c4cf0e06247cd2dca695ad4e020b81981d4c82152c996346cf1094b", - "sha256:7e97104d28e60b69f9b6a957c4d3a2a893b27525bc1fc96b47b3ccef46726bf2", - "sha256:8ae5cb6b645ac3fba34ad84b32fbdccb2ab321facb461954925bde807a0d3b74", - "sha256:8f623b64bb219d62014781120f47499a7adc30cf7787e24b659e56651ceebcb0", - "sha256:98697c842d5c221408ba8aa573d4f49caef4831e9bc6b6e785ce38aca42d1999", - "sha256:a0c09e3e02f948631c7763b4fd3dd175bc45303a0ae04b000856dedebefe13cb", - "sha256:a3fb7fbae257e1b042f440289ee7235d03f433ea880e73e687f108d044b24db5", - "sha256:a7f04691ce1c7ed974c2f8b34a1fe4c3c5dfe33128eae886aa32d730f1ec1913", - "sha256:a9469f49ff873ef566864cb3516091881f217b5d231c8164f7883990eec88b73", - "sha256:aaaf5f7e6cc234c1793f2a2760da464b604584fb58c6b6d7d94144fd2692d67e", - "sha256:adeddfb1e22c20548e840403e5e0b3d9dc3daf66f05fa59f1fcf5b5f664f0e98", - "sha256:b52f3ab845d32dfd20afba86675c91919a622f4627182daec64974db9b0b4608", - "sha256:cd0e75d9124b73e06a42bf1615ad3d7d805f66871aa94538c3a9b7871d620013", - "sha256:cf6c50cd879831955ac47af9c907ce0310245f9d162e298703f82e1785e38c98", - "sha256:d8f1da01c04527f7da59ee3755d8ee112cd8967c15fab9e43bba936b81e2a013", - "sha256:dd37d65519b3f8ed8976fa4302a2827cbb96e0a461a2e504db583b08a22f0b98", - "sha256:e1c4f1071fe9c09af077a69b6c75f17feb473caeea0c3579b3e94834efcbdc36", - "sha256:e6d95703efaa64aaabf278ced641b888fc23d9c6dd71f8215091afd8a26a66e3", - "sha256:f44eda8bd7a4bccb0f281264b34bf3518d8c4c9a8ffe69a1a05dabf6e8461147", - "sha256:f86e2c0259fe598c4532acfcf638c1f520fa77c1275912bbc958faecbf00b108", - "sha256:fc19b78cc966db195024d8011649b4e22812f805dd49264323980715ab80accc" - ], - "markers": "python_version >= '3.7'", - "version": "==2.0.7" - }, - "simplejson": { - "hashes": [ - "sha256:000602141d0bddfcff60ea6a6e97d5e10c9db6b17fd2d6c66199fa481b6214bb", - "sha256:03d7a426e416fe0d3337115f04164cd9427eb4256e843a6b8751cacf70abc832", - "sha256:03db8cb64154189a92a7786209f24e391644f3a3fa335658be2df2af1960b8d8", - "sha256:03ec618ed65caab48e81e3ed29586236a8e57daef792f1f3bb59504a7e98cd10", - "sha256:0821871404a537fd0e22eba240c74c0467c28af6cc435903eca394cfc74a0497", - "sha256:1190f9a3ce644fd50ec277ac4a98c0517f532cfebdcc4bd975c0979a9f05e1fb", - "sha256:15c7de4c88ab2fbcb8781a3b982ef883696736134e20b1210bca43fb42ff1acf", - "sha256:1b9fd15853b90aec3b1739f4471efbf1ac05066a2c7041bf8db821bb73cd2ddc", - "sha256:1bd6bfe5678d73fbd5328eea6a35216503796428fc47f1237432522febaf3a0c", - "sha256:272cc767826e924a6bd369ea3dbf18e166ded29059c7a4d64d21a9a22424b5b5", - "sha256:299b1007b8101d50d95bc0db1bf5c38dc372e85b504cf77f596462083ee77e3f", - "sha256:2b6436c48e64378fa844d8c9e58a5ed0352bbcfd4028369a9b46679b7ab79d2d", - "sha256:2e671dd62051129185d3a9a92c60101f56cbc174854a1a3dfb69114ebd9e1699", - "sha256:325b8c107253d3217e89d7b50c71015b5b31e2433e6c5bf38967b2f80630a8ca", - "sha256:339f407373325a36b7fd744b688ba5bae0666b5d340ec6d98aebc3014bf3d8ea", - "sha256:3466d2839fdc83e1af42e07b90bc8ff361c4e8796cd66722a40ba14e458faddd", - "sha256:391345b4157cc4e120027e013bd35c45e2c191e2bf48b8913af488cdc3b9243c", - "sha256:3c4f0a61cdc05550782ca4a2cdb311ea196c2e6be6b24a09bf71360ca8c3ca9b", - "sha256:3d7310172d5340febd258cb147f46aae30ad57c445f4d7e1ae8461c10aaf43b0", - "sha256:3e7963197d958fcf9e98b212b80977d56c022384621ff463d98afc3b6b1ce7e8", - "sha256:455a882ff3f97d810709f7b620007d4e0aca8da71d06fc5c18ba11daf1c4df49", - "sha256:463f1fca8fbf23d088e5850fdd0dd4d5faea8900a9f9680270bd98fd649814ca", - "sha256:4762e05577955312a4c6802f58dd02e040cc79ae59cda510aa1564d84449c102", - "sha256:489c3a43116082bad56795215786313832ba3991cca1f55838e52a553f451ab6", - "sha256:49d059b8363327eee3c94799dd96782314b2dbd7bcc293b4ad48db69d6f4d362", - "sha256:4a586ce4f78cec11f22fe55c5bee0f067e803aab9bad3441afe2181693b5ebb5", - "sha256:4a8e197e4cf6d42c2c57e7c52cd7c1e7b3e37c5911df1314fb393320131e2101", - "sha256:4a92e948bad8df7fa900ba2ba0667a98303f3db206cbaac574935c332838208e", - "sha256:51b41f284d603c4380732d7d619f8b34bd04bc4aa0ed0ed5f4ffd0539b14da44", - "sha256:5c0de368f3052a59a1acf21f8b2dd28686a9e4eba2da7efae7ed9554cb31e7bc", - "sha256:627d4486a1ea7edf1f66bb044ace1ce6b4c1698acd1b05353c97ba4864ea2e17", - "sha256:652d8eecbb9a3b6461b21ec7cf11fd0acbab144e45e600c817ecf18e4580b99e", - "sha256:69dd28d4ce38390ea4aaf212902712c0fd1093dc4c1ff67e09687c3c3e15a749", - "sha256:6a6dd11ee282937ad749da6f3b8d87952ad585b26e5edfa10da3ae2536c73078", - "sha256:6bd09c8c75666e7f62a33d2f1fb57f81da1fcbb19a9fe7d7910b5756e1dd6048", - "sha256:6c21f5c026ca633cfffcb6bc1fac2e99f65cb2b24657d3bef21aed9916cc3bbf", - "sha256:6d4f320c33277a5b715db5bf5b10dae10c19076bd6d66c2843e04bd12d1f1ea5", - "sha256:6dd3a1d5aca87bf947f3339b0f8e8e329f1badf548bdbff37fac63c17936da8e", - "sha256:6e18345c8dda5d699be8166b61f9d80aaee4545b709f1363f60813dc032dac53", - "sha256:6e6697a3067d281f01de0fe96fc7cba4ea870d96d7deb7bfcf85186d74456503", - "sha256:71b75d448fd0ceb2e7c90e72bb82c41f8462550d48529980bc0bab1d2495bfbb", - "sha256:71e849e7ceb2178344998cbe5ade101f1b329460243c79c27fbfc51c0447a7c3", - "sha256:74a1608f9e6e8c27a4008d70a54270868306d80ed48c9df7872f9f4b8ac87808", - "sha256:7551682b60bba3a9e2780742e101cf0a64250e76de7d09b1c4b0c8a7c7cc6834", - "sha256:76461ec929282dde4a08061071a47281ad939d0202dc4e63cdd135844e162fbc", - "sha256:78520f04b7548a5e476b5396c0847e066f1e0a4c0c5e920da1ad65e95f410b11", - "sha256:7ceed598e4bacbf5133fe7a418f7991bb2df0683f3ac11fbf9e36a2bc7aa4b85", - "sha256:7e9d73f46119240e4f4f07868241749d67d09873f40cb968d639aa9ccc488b86", - "sha256:7eaae2b88eb5da53caaffdfa50e2e12022553949b88c0df4f9a9663609373f72", - "sha256:87fc623d457173a0213bc9ca4e346b83c9d443f63ed5cca847fb0cacea3cfc95", - "sha256:884e6183d16b725e113b83a6fc0230152ab6627d4d36cb05c89c2c5bccfa7bc6", - "sha256:88a7baa8211089b9e58d78fbc1b0b322103f3f3d459ff16f03a36cece0d0fcf0", - "sha256:896a6c04d7861d507d800da7642479c3547060bf97419d9ef73d98ced8258766", - "sha256:8a6c1bbac39fa4a79f83cbf1df6ccd8ff7069582a9fd8db1e52cea073bc2c697", - "sha256:8bb98fdf318c05aefd08a92583bd6ee148e93c6756fb1befb7b2d5f27824be78", - "sha256:8c09948f1a486a89251ee3a67c9f8c969b379f6ffff1a6064b41fea3bce0a112", - "sha256:8d23b7f8d6b72319d6d55a0261089ff621ce87e54731c2d3de6a9bf7be5c028c", - "sha256:90b573693d1526bed576f6817e2a492eaaef68f088b57d7a9e83d122bbb49e51", - "sha256:9a74e70818818981294b8e6956ce3496c5e1bd4726ac864fae473197671f7b85", - "sha256:9c079606f461a6e950099167e21e13985147c8a24be8eea66c9ad68f73fad744", - "sha256:9daf8cdc7ee8a9e9f7a3b313ba0a003391857e90d0e82fbcd4d614aa05cb7c3b", - "sha256:9e8eacf6a3491bf76ea91a8d46726368a6be0eb94993f60b8583550baae9439e", - "sha256:9faceb68fba27ef17eda306e4cd97a7b4b14fdadca5fbb15790ba8b26ebeec0c", - "sha256:a2cc4f6486f9f515b62f5831ff1888886619b84fc837de68f26d919ba7bbdcbc", - "sha256:a3c2df555ee4016148fa192e2b9cd9e60bc1d40769366134882685e90aee2a1e", - "sha256:a7e15b716d09f318c8cda3e20f82fae81684ce3d3acd1d7770fa3007df1769de", - "sha256:a8011f1dd1d676befcd4d675ebdbfdbbefd3bf350052b956ba8c699fca7d8cef", - "sha256:ab19c2da8c043607bde4d4ef3a6b633e668a7d2e3d56f40a476a74c5ea71949f", - "sha256:ab980fcc446ab87ea0879edad41a5c28f2d86020014eb035cf5161e8de4474c6", - "sha256:ae6e637dc24f8fee332ed23dd070e81394138e42cd4fd9d0923e5045ba122e27", - "sha256:ae81e482476eaa088ef9d0120ae5345de924f23962c0c1e20abbdff597631f87", - "sha256:af8377a8af78226e82e3a4349efdde59ffa421ae88be67e18cef915e4023a595", - "sha256:b122a19b552b212fc3b5b96fc5ce92333d4a9ac0a800803e1f17ebb16dac4be5", - "sha256:b2578bedaedf6294415197b267d4ef678fea336dd78ee2a6d2f4b028e9d07be3", - "sha256:b63fdbab29dc3868d6f009a59797cefaba315fd43cd32ddd998ee1da28e50e29", - "sha256:bd9577ec1c8c3a43040e3787711e4c257c70035b7551a21854b5dec88dad09e1", - "sha256:c02f4868a3a46ffe284a51a88d134dc96feff6079a7115164885331a1ba8ed9f", - "sha256:c1336ba7bcb722ad487cd265701ff0583c0bb6de638364ca947bb84ecc0015d1", - "sha256:c6fdcc9debb711ddd2ad6d69f9386a3d9e8e253234bbb30513e0a7caa9510c51", - "sha256:c7edf279c1376f28bf41e916c015a2a08896597869d57d621f55b6a30c7e1e6d", - "sha256:c939a1e576bded47d7d03aa2afc2ae90b928b2cf1d9dc2070ceec51fd463f430", - "sha256:cbbd7b215ad4fc6f058b5dd4c26ee5c59f72e031dfda3ac183d7968a99e4ca3a", - "sha256:cd2cdead1d3197f0ff43373cf4730213420523ba48697743e135e26f3d179f38", - "sha256:cda5c32a98f392909088111ecec23f2b0d39346ceae1a0fea23ab2d1f84ec21d", - "sha256:ceab2ce2acdc7fbaa433a93006758db6ba9a659e80c4faa13b80b9d2318e9b17", - "sha256:d34d04bf90b4cea7c22d8b19091633908f14a096caa301b24c2f3d85b5068fb8", - "sha256:d492ed8e92f3a9f9be829205f44b1d0a89af6582f0cf43e0d129fa477b93fe0c", - "sha256:d8853c269a4c5146ddca4aa7c70e631795e9d11239d5fedb1c6bbc91ffdebcac", - "sha256:d9202b9de38f12e99a40addd1a8d508a13c77f46d87ab1f9095f154667f4fe81", - "sha256:dfe7a9da5fd2a3499436cd350f31539e0a6ded5da6b5b3d422df016444d65e43", - "sha256:e041add470e8f8535cc05509485eb7205729a84441f03b25cde80ad48823792e", - "sha256:e25b2a0c396f3b84fb89573d07b0e1846ed563eb364f2ea8230ca92b8a8cb786", - "sha256:e39eaa57c7757daa25bcd21f976c46be443b73dd6c3da47fe5ce7b7048ccefe2", - "sha256:e580aa65d5f6c3bf41b9b4afe74be5d5ddba9576701c107c772d936ea2b5043a", - "sha256:e64139b4ec4f1f24c142ff7dcafe55a22b811a74d86d66560c8815687143037d", - "sha256:e66712b17d8425bb7ff8968d4c7c7fd5a2dd7bd63728b28356223c000dd2f91f", - "sha256:e836fb88902799eac8debc2b642300748f4860a197fa3d9ea502112b6bb8e142", - "sha256:e91703a4c5fec53e36875ae426ad785f4120bd1d93b65bed4752eeccd1789e0c", - "sha256:e975aac6a5acd8b510eba58d5591e10a03e3d16c1cf8a8624ca177491f7230f0", - "sha256:ec6a1e0a7aff76f0e008bebfa950188b9c50b58c1885d898145f48fc8e189a56", - "sha256:ed6a17fd397f0e2b3ad668fc9e19253ed2e3875ad9086bd7f795c29a3223f4a1", - "sha256:ede69c765e9901861ad7c6139023b7b7d5807c48a2539d817b4ab40018002d5f", - "sha256:eea7e2b7d858f6fdfbf0fe3cb846d6bd8a45446865bc09960e51f3d473c2271b", - "sha256:efd3bc6c6b17e3d4620eb6be5196f0d1c08b6ce7c3101fa8e292b79e0908944b", - "sha256:f31c4a3a7ab18467ee73a27f3e59158255d1520f3aad74315edde7a940f1be23", - "sha256:f4bd49ecde87b0fe9f55cc971449a32832bca9910821f7072bbfae1155eaa007", - "sha256:f5272b5866b259fe6c33c4a8c5073bf8b359c3c97b70c298a2f09a69b52c7c41", - "sha256:f5aee2a4cb6b146bd17333ac623610f069f34e8f31d2f4f0c1a2186e50c594f0", - "sha256:f924b485537b640dc69434565463fd6fc0c68c65a8c6e01a823dd26c9983cf79", - "sha256:fc0f523ce923e7f38eb67804bc80e0a028c76d7868500aa3f59225574b5d0453" - ], - "index": "pypi", - "markers": "python_version >= '2.5' and python_version not in '3.0, 3.1, 3.2'", - "version": "==3.20.1" - }, - "six": { - "hashes": [ - "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", - "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", - "version": "==1.17.0" - }, - "soupsieve": { - "hashes": [ - "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", - "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9" - ], - "markers": "python_version >= '3.8'", - "version": "==2.6" - }, - "sqlalchemy": { - "hashes": [ - "sha256:018ee97c558b499b58935c5a152aeabf6d36b3d55d91656abeb6d93d663c0c4c", - "sha256:01da15490c9df352fbc29859d3c7ba9cd1377791faeeb47c100832004c99472c", - "sha256:04545042969833cb92e13b0a3019549d284fd2423f318b6ba10e7aa687690a3c", - "sha256:06205eb98cb3dd52133ca6818bf5542397f1dd1b69f7ea28aa84413897380b06", - "sha256:08cf721bbd4391a0e765fe0fe8816e81d9f43cece54fdb5ac465c56efafecb3d", - "sha256:0d7e3866eb52d914aea50c9be74184a0feb86f9af8aaaa4daefe52b69378db0b", - "sha256:125a7763b263218a80759ad9ae2f3610aaf2c2fbbd78fff088d584edf81f3782", - "sha256:23c5aa33c01bd898f879db158537d7e7568b503b15aad60ea0c8da8109adf3e7", - "sha256:2600a50d590c22d99c424c394236899ba72f849a02b10e65b4c70149606408b5", - "sha256:2d7332868ce891eda48896131991f7f2be572d65b41a4050957242f8e935d5d7", - "sha256:2ed107331d188a286611cea9022de0afc437dd2d3c168e368169f27aa0f61338", - "sha256:3395e7ed89c6d264d38bea3bfb22ffe868f906a7985d03546ec7dc30221ea980", - "sha256:344cd1ec2b3c6bdd5dfde7ba7e3b879e0f8dd44181f16b895940be9b842fd2b6", - "sha256:34d5c49f18778a3665d707e6286545a30339ad545950773d43977e504815fa70", - "sha256:35e72518615aa5384ef4fae828e3af1b43102458b74a8c481f69af8abf7e802a", - "sha256:3eb14ba1a9d07c88669b7faf8f589be67871d6409305e73e036321d89f1d904e", - "sha256:412c6c126369ddae171c13987b38df5122cb92015cba6f9ee1193b867f3f1530", - "sha256:4600c7a659d381146e1160235918826c50c80994e07c5b26946a3e7ec6c99249", - "sha256:463ecfb907b256e94bfe7bcb31a6d8c7bc96eca7cbe39803e448a58bb9fcad02", - "sha256:4a06e6c8e31c98ddc770734c63903e39f1947c9e3e5e4bef515c5491b7737dde", - "sha256:4b2de1523d46e7016afc7e42db239bd41f2163316935de7c84d0e19af7e69538", - "sha256:4dabd775fd66cf17f31f8625fc0e4cfc5765f7982f94dc09b9e5868182cb71c0", - "sha256:4eff9c270afd23e2746e921e80182872058a7a592017b2713f33f96cc5f82e32", - "sha256:52607d0ebea43cf214e2ee84a6a76bc774176f97c5a774ce33277514875a718e", - "sha256:533e0f66c32093a987a30df3ad6ed21170db9d581d0b38e71396c49718fbb1ca", - "sha256:5493a8120d6fc185f60e7254fc056a6742f1db68c0f849cfc9ab46163c21df47", - "sha256:5d2d1fe548def3267b4c70a8568f108d1fed7cbbeccb9cc166e05af2abc25c22", - "sha256:5dfbc543578058c340360f851ddcecd7a1e26b0d9b5b69259b526da9edfa8875", - "sha256:66a40003bc244e4ad86b72abb9965d304726d05a939e8c09ce844d27af9e6d37", - "sha256:67de057fbcb04a066171bd9ee6bcb58738d89378ee3cabff0bffbf343ae1c787", - "sha256:6827f8c1b2f13f1420545bd6d5b3f9e0b85fe750388425be53d23c760dcf176b", - "sha256:6b35e07f1d57b79b86a7de8ecdcefb78485dab9851b9638c2c793c50203b2ae8", - "sha256:7399d45b62d755e9ebba94eb89437f80512c08edde8c63716552a3aade61eb42", - "sha256:788b6ff6728072b313802be13e88113c33696a9a1f2f6d634a97c20f7ef5ccce", - "sha256:78f1b79132a69fe8bd6b5d91ef433c8eb40688ba782b26f8c9f3d2d9ca23626f", - "sha256:79f4f502125a41b1b3b34449e747a6abfd52a709d539ea7769101696bdca6716", - "sha256:7a8517b6d4005facdbd7eb4e8cf54797dbca100a7df459fdaff4c5123265c1cd", - "sha256:7bd5c5ee1448b6408734eaa29c0d820d061ae18cb17232ce37848376dcfa3e92", - "sha256:7f5243357e6da9a90c56282f64b50d29cba2ee1f745381174caacc50d501b109", - "sha256:805cb481474e111ee3687c9047c5f3286e62496f09c0e82e8853338aaaa348f8", - "sha256:871f55e478b5a648c08dd24af44345406d0e636ffe021d64c9b57a4a11518304", - "sha256:87a1ce1f5e5dc4b6f4e0aac34e7bb535cb23bd4f5d9c799ed1633b65c2bcad8c", - "sha256:8a10ca7f8a1ea0fd5630f02feb055b0f5cdfcd07bb3715fc1b6f8cb72bf114e4", - "sha256:995c2bacdddcb640c2ca558e6760383dcdd68830160af92b5c6e6928ffd259b4", - "sha256:9f03143f8f851dd8de6b0c10784363712058f38209e926723c80654c1b40327a", - "sha256:a1c6b0a5e3e326a466d809b651c63f278b1256146a377a528b6938a279da334f", - "sha256:a28f9c238f1e143ff42ab3ba27990dfb964e5d413c0eb001b88794c5c4a528a9", - "sha256:b2cf5b5ddb69142511d5559c427ff00ec8c0919a1e6c09486e9c32636ea2b9dd", - "sha256:b761a6847f96fdc2d002e29e9e9ac2439c13b919adfd64e8ef49e75f6355c548", - "sha256:bf555f3e25ac3a70c67807b2949bfe15f377a40df84b71ab2c58d8593a1e036e", - "sha256:c08a972cbac2a14810463aec3a47ff218bb00c1a607e6689b531a7c589c50723", - "sha256:c457a38351fb6234781d054260c60e531047e4d07beca1889b558ff73dc2014b", - "sha256:c4c433f78c2908ae352848f56589c02b982d0e741b7905228fad628999799de4", - "sha256:d9f119e7736967c0ea03aff91ac7d04555ee038caf89bb855d93bbd04ae85b41", - "sha256:e6b0a1c7ed54a5361aaebb910c1fa864bae34273662bb4ff788a527eafd6e14d", - "sha256:f2bcb085faffcacf9319b1b1445a7e1cfdc6fb46c03f2dce7bc2d9a4b3c1cdc5", - "sha256:fe193d3ae297c423e0e567e240b4324d6b6c280a048e64c77a3ea6886cc2aa87" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.0.39" - }, - "typing-extensions": { - "hashes": [ - "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", - "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" - ], - "markers": "python_version >= '3.8'", - "version": "==4.12.2" - }, - "tzdata": { - "hashes": [ - "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", - "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9" - ], - "markers": "python_version >= '2'", - "version": "==2025.2" - }, - "urllib3": { - "hashes": [ - "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", - "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" - ], - "markers": "python_version >= '3.9'", - "version": "==2.3.0" - } - }, - "develop": { - "alabaster": { - "hashes": [ - "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", - "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b" - ], - "markers": "python_version >= '3.10'", - "version": "==1.0.0" - }, - "anyio": { - "hashes": [ - "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", - "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c" - ], - "markers": "python_version >= '3.9'", - "version": "==4.9.0" - }, - "appnope": { - "hashes": [ - "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", - "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c" - ], - "markers": "python_version >= '3.6'", - "version": "==0.1.4" - }, - "argon2-cffi": { - "hashes": [ - "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08", - "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea" - ], - "markers": "python_version >= '3.7'", - "version": "==23.1.0" - }, - "argon2-cffi-bindings": { - "hashes": [ - "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670", - "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f", - "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583", - "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194", - "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c", - "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a", - "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082", - "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5", - "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f", - "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7", - "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d", - "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f", - "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae", - "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3", - "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86", - "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367", - "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d", - "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93", - "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb", - "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e", - "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351" - ], - "markers": "python_version >= '3.6'", - "version": "==21.2.0" - }, - "arrow": { - "hashes": [ - "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", - "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85" - ], - "markers": "python_version >= '3.8'", - "version": "==1.3.0" - }, - "asttokens": { - "hashes": [ - "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", - "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2" - ], - "markers": "python_version >= '3.8'", - "version": "==3.0.0" - }, - "async-lru": { - "hashes": [ - "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", - "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943" - ], - "markers": "python_version >= '3.9'", - "version": "==2.0.5" - }, - "attrs": { - "hashes": [ - "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", - "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b" - ], - "markers": "python_version >= '3.8'", - "version": "==25.3.0" - }, - "babel": { - "hashes": [ - "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", - "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2" - ], - "markers": "python_version >= '3.8'", - "version": "==2.17.0" - }, - "beautifulsoup4": { - "hashes": [ - "sha256:1bd32405dacc920b42b83ba01644747ed77456a65760e285fbc47633ceddaf8b", - "sha256:99045d7d3f08f91f0d656bc9b7efbae189426cd913d830294a15eefa0ea4df16" - ], - "index": "pypi", - "markers": "python_full_version >= '3.7.0'", - "version": "==4.13.3" - }, - "black": { - "hashes": [ - "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171", - "sha256:055e59b198df7ac0b7efca5ad7ff2516bca343276c466be72eb04a3bcc1f82d7", - "sha256:0e519ecf93120f34243e6b0054db49c00a35f84f195d5bce7e9f5cfc578fc2da", - "sha256:172b1dbff09f86ce6f4eb8edf9dede08b1fce58ba194c87d7a4f1a5aa2f5b3c2", - "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc", - "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666", - "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f", - "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b", - "sha256:759e7ec1e050a15f89b770cefbf91ebee8917aac5c20483bc2d80a6c3a04df32", - "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f", - "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", - "sha256:96c1c7cd856bba8e20094e36e0f948718dc688dba4a9d78c3adde52b9e6c2299", - "sha256:a1ee0a0c330f7b5130ce0caed9936a904793576ef4d2b98c40835d6a65afa6a0", - "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18", - "sha256:a39337598244de4bae26475f77dda852ea00a93bd4c728e09eacd827ec929df0", - "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3", - "sha256:bacabb307dca5ebaf9c118d2d2f6903da0d62c9faa82bd21a33eecc319559355", - "sha256:bce2e264d59c91e52d8000d507eb20a9aca4a778731a08cfff7e5ac4a4bb7096", - "sha256:d9e6827d563a2c820772b32ce8a42828dc6790f095f441beef18f96aa6f8294e", - "sha256:db8ea9917d6f8fc62abd90d944920d95e73c83a5ee3383493e35d271aca872e9", - "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba", - "sha256:f3df5f1bf91d36002b0a75389ca8663510cf0531cca8aa5c1ef695b46d98655f" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==25.1.0" - }, - "bleach": { - "extras": [ - "css" - ], - "hashes": [ - "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e", - "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f" - ], - "markers": "python_version >= '3.9'", - "version": "==6.2.0" - }, - "cachetools": { - "hashes": [ - "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4", - "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a" - ], - "markers": "python_version >= '3.7'", - "version": "==5.5.2" - }, - "cartopy": { - "hashes": [ - "sha256:01c910d5634c69a7efdec46e0a17d473d2328767f001d4dc0b5c4b48e585c8bd", - "sha256:2f354a1d902a8d6ee33b099acc86ac2e1af528bbc0ea718b834111c97e604981", - "sha256:4a14638b63d7df2858f73e9f8f4f4826d7c9cf13781aa6824fa0134fbaebbd98", - "sha256:511f992340baea2c171cb17b3ef595537e5355640f3baa7ac895de25df016a70", - "sha256:54f4d23961e0f9436baaf4747928361ccdcc893fa9b7bad9f615551bc8aa3fe8", - "sha256:71d8a6d061d0764aba3baf357a68f3d73796a8a46d34b8c9fb241171b273c69e", - "sha256:a984e33977daed8f760c09c331c8368a6af060db1190af89d74a027c272e39c3", - "sha256:b17cf23dd74d0a922c2a5682dacef3c0bf89fa8c0bd0eae96b87fb684f966b15", - "sha256:b1bb2d02b31884ee1d4f14e5b436bbf95745eac39c6fc0d6c67c83bb907b55b3", - "sha256:ce0c83314570c61a695a1f7c3a4a22dc75f79d28f4c68b88a8aeaf13d6a2343c", - "sha256:d279968b845f72e3423e454b2b0b985fb2389e6ccd18fb73324abeca4e43f516", - "sha256:d74b4a3eae9e570f474276fb61847112cdccdead396ec2ddad226dad9eaf4564", - "sha256:dfa38fb216cfd16cc266fd6f86b60ebdf0056839b490f38d2d89229b03abc877", - "sha256:dfdde0a6e0e56c5fc46f4e7d332237eb31bbd9908417f0f190fda5d322754184", - "sha256:e0b55526b605a9dee4fa3d7e5659b6d7d9d30e609bc5e62487bc4f7d8e90873b", - "sha256:f0963b80a048252815c56fbd21bc4e5d163618a9eaa36c8898ce2c60b6c03979", - "sha256:f440ddb61171319adf34ecec4d91202864cd514a7bc8a252e0ff7788a6604031" - ], - "index": "pypi", - "markers": "python_version >= '3.10'", - "version": "==0.24.1" - }, - "certifi": { - "hashes": [ - "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", - "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe" - ], - "markers": "python_version >= '3.6'", - "version": "==2025.1.31" - }, - "cffi": { - "hashes": [ - "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", - "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", - "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", - "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", - "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", - "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", - "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", - "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", - "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", - "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", - "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", - "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", - "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", - "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", - "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", - "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", - "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", - "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", - "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", - "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", - "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", - "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", - "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", - "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", - "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", - "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", - "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", - "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", - "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", - "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", - "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", - "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", - "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", - "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", - "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", - "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", - "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", - "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", - "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", - "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", - "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", - "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", - "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", - "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", - "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", - "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", - "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", - "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", - "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", - "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", - "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", - "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", - "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", - "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", - "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", - "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", - "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", - "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", - "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", - "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", - "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", - "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", - "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", - "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", - "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", - "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", - "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" - ], - "markers": "python_version >= '3.8'", - "version": "==1.17.1" - }, - "chardet": { - "hashes": [ - "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", - "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970" - ], - "markers": "python_version >= '3.7'", - "version": "==5.2.0" - }, - "charset-normalizer": { - "hashes": [ - "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537", - "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa", - "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a", - "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294", - "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b", - "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", - "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", - "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", - "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4", - "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", - "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2", - "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", - "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", - "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", - "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", - "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", - "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", - "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496", - "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", - "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", - "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e", - "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a", - "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4", - "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca", - "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78", - "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", - "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5", - "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", - "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", - "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", - "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765", - "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6", - "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", - "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", - "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", - "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd", - "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c", - "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", - "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", - "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", - "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770", - "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824", - "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f", - "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf", - "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487", - "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d", - "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd", - "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", - "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534", - "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", - "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", - "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", - "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd", - "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", - "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9", - "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", - "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", - "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d", - "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", - "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", - "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", - "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7", - "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", - "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", - "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8", - "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41", - "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", - "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", - "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", - "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", - "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", - "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", - "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", - "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", - "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", - "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", - "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", - "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e", - "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6", - "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", - "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", - "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e", - "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", - "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", - "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c", - "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", - "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", - "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089", - "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", - "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e", - "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", - "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616" - ], - "markers": "python_version >= '3.7'", - "version": "==3.4.1" - }, - "click": { - "hashes": [ - "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", - "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a" - ], - "markers": "python_version >= '3.7'", - "version": "==8.1.8" - }, - "colorama": { - "hashes": [ - "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", - "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", - "version": "==0.4.6" - }, - "comm": { - "hashes": [ - "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e", - "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3" - ], - "markers": "python_version >= '3.8'", - "version": "==0.2.2" - }, - "contourpy": { - "hashes": [ - "sha256:041b640d4ec01922083645a94bb3b2e777e6b626788f4095cf21abbe266413c1", - "sha256:05e806338bfeaa006acbdeba0ad681a10be63b26e1b17317bfac3c5d98f36cda", - "sha256:08d9d449a61cf53033612cb368f3a1b26cd7835d9b8cd326647efe43bca7568d", - "sha256:0ffa84be8e0bd33410b17189f7164c3589c229ce5db85798076a3fa136d0e509", - "sha256:113231fe3825ebf6f15eaa8bc1f5b0ddc19d42b733345eae0934cb291beb88b6", - "sha256:14c102b0eab282427b662cb590f2e9340a9d91a1c297f48729431f2dcd16e14f", - "sha256:174e758c66bbc1c8576992cec9599ce8b6672b741b5d336b5c74e35ac382b18e", - "sha256:19c1555a6801c2f084c7ddc1c6e11f02eb6a6016ca1318dd5452ba3f613a1751", - "sha256:19d40d37c1c3a4961b4619dd9d77b12124a453cc3d02bb31a07d58ef684d3d86", - "sha256:1bf98051f1045b15c87868dbaea84f92408337d4f81d0e449ee41920ea121d3b", - "sha256:20914c8c973f41456337652a6eeca26d2148aa96dd7ac323b74516988bea89fc", - "sha256:287ccc248c9e0d0566934e7d606201abd74761b5703d804ff3df8935f523d546", - "sha256:2ba94a401342fc0f8b948e57d977557fbf4d515f03c67682dd5c6191cb2d16ec", - "sha256:31c1b55c1f34f80557d3830d3dd93ba722ce7e33a0b472cba0ec3b6535684d8f", - "sha256:36987a15e8ace5f58d4d5da9dca82d498c2bbb28dff6e5d04fbfcc35a9cb3a82", - "sha256:3a04ecd68acbd77fa2d39723ceca4c3197cb2969633836ced1bea14e219d077c", - "sha256:3e8b974d8db2c5610fb4e76307e265de0edb655ae8169e8b21f41807ccbeec4b", - "sha256:3ea9924d28fc5586bf0b42d15f590b10c224117e74409dd7a0be3b62b74a501c", - "sha256:4318af1c925fb9a4fb190559ef3eec206845f63e80fb603d47f2d6d67683901c", - "sha256:44a29502ca9c7b5ba389e620d44f2fbe792b1fb5734e8b931ad307071ec58c53", - "sha256:47734d7073fb4590b4a40122b35917cd77be5722d80683b249dac1de266aac80", - "sha256:4d76d5993a34ef3df5181ba3c92fabb93f1eaa5729504fb03423fcd9f3177242", - "sha256:4dbbc03a40f916a8420e420d63e96a1258d3d1b58cbdfd8d1f07b49fcbd38e85", - "sha256:500360b77259914f7805af7462e41f9cb7ca92ad38e9f94d6c8641b089338124", - "sha256:523a8ee12edfa36f6d2a49407f705a6ef4c5098de4f498619787e272de93f2d5", - "sha256:573abb30e0e05bf31ed067d2f82500ecfdaec15627a59d63ea2d95714790f5c2", - "sha256:5b75aa69cb4d6f137b36f7eb2ace9280cfb60c55dc5f61c731fdf6f037f958a3", - "sha256:61332c87493b00091423e747ea78200659dc09bdf7fd69edd5e98cef5d3e9a8d", - "sha256:805617228ba7e2cbbfb6c503858e626ab528ac2a32a04a2fe88ffaf6b02c32bc", - "sha256:841ad858cff65c2c04bf93875e384ccb82b654574a6d7f30453a04f04af71342", - "sha256:89785bb2a1980c1bd87f0cb1517a71cde374776a5f150936b82580ae6ead44a1", - "sha256:8eb96e79b9f3dcadbad2a3891672f81cdcab7f95b27f28f1c67d75f045b6b4f1", - "sha256:974d8145f8ca354498005b5b981165b74a195abfae9a8129df3e56771961d595", - "sha256:9ddeb796389dadcd884c7eb07bd14ef12408aaae358f0e2ae24114d797eede30", - "sha256:a045f341a77b77e1c5de31e74e966537bba9f3c4099b35bf4c2e3939dd54cdab", - "sha256:a0cffcbede75c059f535725c1680dfb17b6ba8753f0c74b14e6a9c68c29d7ea3", - "sha256:a761d9ccfc5e2ecd1bf05534eda382aa14c3e4f9205ba5b1684ecfe400716ef2", - "sha256:a7895f46d47671fa7ceec40f31fae721da51ad34bdca0bee83e38870b1f47ffd", - "sha256:a9fa36448e6a3a1a9a2ba23c02012c43ed88905ec80163f2ffe2421c7192a5d7", - "sha256:ab29962927945d89d9b293eabd0d59aea28d887d4f3be6c22deaefbb938a7277", - "sha256:abbb49fb7dac584e5abc6636b7b2a7227111c4f771005853e7d25176daaf8453", - "sha256:ac4578ac281983f63b400f7fe6c101bedc10651650eef012be1ccffcbacf3697", - "sha256:adce39d67c0edf383647a3a007de0a45fd1b08dedaa5318404f1a73059c2512b", - "sha256:ade08d343436a94e633db932e7e8407fe7de8083967962b46bdfc1b0ced39454", - "sha256:b2bdca22a27e35f16794cf585832e542123296b4687f9fd96822db6bae17bfc9", - "sha256:b2f926efda994cdf3c8d3fdb40b9962f86edbc4457e739277b961eced3d0b4c1", - "sha256:b457d6430833cee8e4b8e9b6f07aa1c161e5e0d52e118dc102c8f9bd7dd060d6", - "sha256:c414fc1ed8ee1dbd5da626cf3710c6013d3d27456651d156711fa24f24bd1291", - "sha256:cb76c1a154b83991a3cbbf0dfeb26ec2833ad56f95540b442c73950af2013750", - "sha256:dfd97abd83335045a913e3bcc4a09c0ceadbe66580cf573fe961f4a825efa699", - "sha256:e914a8cb05ce5c809dd0fe350cfbb4e881bde5e2a38dc04e3afe1b3e58bd158e", - "sha256:ece6df05e2c41bd46776fbc712e0996f7c94e0d0543af1656956d150c4ca7c81", - "sha256:efa874e87e4a647fd2e4f514d5e91c7d493697127beb95e77d2f7561f6905bd9", - "sha256:f611e628ef06670df83fce17805c344710ca5cde01edfdc72751311da8585375" - ], - "markers": "python_version >= '3.10'", - "version": "==1.3.1" - }, - "coverage": { - "extras": [ - "toml" - ], - "hashes": [ - "sha256:02fad4f8faa4153db76f9246bc95c1d99f054f4e0a884175bff9155cf4f856cb", - "sha256:092b134129a8bb940c08b2d9ceb4459af5fb3faea77888af63182e17d89e1cf1", - "sha256:0ce92c5a9d7007d838456f4b77ea159cb628187a137e1895331e530973dcf862", - "sha256:0dab4ef76d7b14f432057fdb7a0477e8bffca0ad39ace308be6e74864e632271", - "sha256:1165490be0069e34e4f99d08e9c5209c463de11b471709dfae31e2a98cbd49fd", - "sha256:11dd6f52c2a7ce8bf0a5f3b6e4a8eb60e157ffedc3c4b4314a41c1dfbd26ce58", - "sha256:15d54ecef1582b1d3ec6049b20d3c1a07d5e7f85335d8a3b617c9960b4f807e0", - "sha256:171e9977c6a5d2b2be9efc7df1126fd525ce7cad0eb9904fe692da007ba90d81", - "sha256:177d837339883c541f8524683e227adcaea581eca6bb33823a2a1fdae4c988e1", - "sha256:18f544356bceef17cc55fcf859e5664f06946c1b68efcea6acdc50f8f6a6e776", - "sha256:199a1272e642266b90c9f40dec7fd3d307b51bf639fa0d15980dc0b3246c1393", - "sha256:1e6f867379fd033a0eeabb1be0cffa2bd660582b8b0c9478895c509d875a9d9e", - "sha256:2444fbe1ba1889e0b29eb4d11931afa88f92dc507b7248f45be372775b3cef4f", - "sha256:25fe40967717bad0ce628a0223f08a10d54c9d739e88c9cbb0f77b5959367542", - "sha256:264ff2bcce27a7f455b64ac0dfe097680b65d9a1a293ef902675fa8158d20b24", - "sha256:2a79c4a09765d18311c35975ad2eb1ac613c0401afdd9cb1ca4110aeb5dd3c4c", - "sha256:2c492401bdb3a85824669d6a03f57b3dfadef0941b8541f035f83bbfc39d4282", - "sha256:315ff74b585110ac3b7ab631e89e769d294f303c6d21302a816b3554ed4c81af", - "sha256:34a3bf6b92e6621fc4dcdaab353e173ccb0ca9e4bfbcf7e49a0134c86c9cd303", - "sha256:37351dc8123c154fa05b7579fdb126b9f8b1cf42fd6f79ddf19121b7bdd4aa04", - "sha256:385618003e3d608001676bb35dc67ae3ad44c75c0395d8de5780af7bb35be6b2", - "sha256:392cc8fd2b1b010ca36840735e2a526fcbd76795a5d44006065e79868cc76ccf", - "sha256:3d03287eb03186256999539d98818c425c33546ab4901028c8fa933b62c35c3a", - "sha256:44683f2556a56c9a6e673b583763096b8efbd2df022b02995609cf8e64fc8ae0", - "sha256:44af11c00fd3b19b8809487630f8a0039130d32363239dfd15238e6d37e41a48", - "sha256:452735fafe8ff5918236d5fe1feac322b359e57692269c75151f9b4ee4b7e1bc", - "sha256:4c181ceba2e6808ede1e964f7bdc77bd8c7eb62f202c63a48cc541e5ffffccb6", - "sha256:4dd532dac197d68c478480edde74fd4476c6823355987fd31d01ad9aa1e5fb59", - "sha256:520af84febb6bb54453e7fbb730afa58c7178fd018c398a8fcd8e269a79bf96d", - "sha256:553ba93f8e3c70e1b0031e4dfea36aba4e2b51fe5770db35e99af8dc5c5a9dfe", - "sha256:5b7b02e50d54be6114cc4f6a3222fec83164f7c42772ba03b520138859b5fde1", - "sha256:63306486fcb5a827449464f6211d2991f01dfa2965976018c9bab9d5e45a35c8", - "sha256:75c82b27c56478d5e1391f2e7b2e7f588d093157fa40d53fd9453a471b1191f2", - "sha256:7ba5ff236c87a7b7aa1441a216caf44baee14cbfbd2256d306f926d16b026578", - "sha256:7e688010581dbac9cab72800e9076e16f7cccd0d89af5785b70daa11174e94de", - "sha256:80b5b207a8b08c6a934b214e364cab2fa82663d4af18981a6c0a9e95f8df7602", - "sha256:822fa99dd1ac686061e1219b67868e25d9757989cf2259f735a4802497d6da31", - "sha256:881cae0f9cbd928c9c001487bb3dcbfd0b0af3ef53ae92180878591053be0cb3", - "sha256:88d96127ae01ff571d465d4b0be25c123789cef88ba0879194d673fdea52f54e", - "sha256:8b1c65a739447c5ddce5b96c0a388fd82e4bbdff7251396a70182b1d83631019", - "sha256:8fed429c26b99641dc1f3a79179860122b22745dd9af36f29b141e178925070a", - "sha256:9bb47cc9f07a59a451361a850cb06d20633e77a9118d05fd0f77b1864439461b", - "sha256:a6b6b3bd121ee2ec4bd35039319f3423d0be282b9752a5ae9f18724bc93ebe7c", - "sha256:ae13ed5bf5542d7d4a0a42ff5160e07e84adc44eda65ddaa635c484ff8e55917", - "sha256:af94fb80e4f159f4d93fb411800448ad87b6039b0500849a403b73a0d36bb5ae", - "sha256:b4c144c129343416a49378e05c9451c34aae5ccf00221e4fa4f487db0816ee2f", - "sha256:b52edb940d087e2a96e73c1523284a2e94a4e66fa2ea1e2e64dddc67173bad94", - "sha256:b559adc22486937786731dac69e57296cb9aede7e2687dfc0d2696dbd3b1eb6b", - "sha256:b838a91e84e1773c3436f6cc6996e000ed3ca5721799e7789be18830fad009a2", - "sha256:ba8480ebe401c2f094d10a8c4209b800a9b77215b6c796d16b6ecdf665048950", - "sha256:bc96441c9d9ca12a790b5ae17d2fa6654da4b3962ea15e0eabb1b1caed094777", - "sha256:c90e9141e9221dd6fbc16a2727a5703c19443a8d9bf7d634c792fa0287cee1ab", - "sha256:d2e73e2ac468536197e6b3ab79bc4a5c9da0f078cd78cfcc7fe27cf5d1195ef0", - "sha256:d3154b369141c3169b8133973ac00f63fcf8d6dbcc297d788d36afbb7811e511", - "sha256:d66ff48ab3bb6f762a153e29c0fc1eb5a62a260217bc64470d7ba602f5886d20", - "sha256:d6874929d624d3a670f676efafbbc747f519a6121b581dd41d012109e70a5ebd", - "sha256:e33426a5e1dc7743dd54dfd11d3a6c02c5d127abfaa2edd80a6e352b58347d1a", - "sha256:e52eb31ae3afacdacfe50705a15b75ded67935770c460d88c215a9c0c40d0e9c", - "sha256:eae79f8e3501133aa0e220bbc29573910d096795882a70e6f6e6637b09522133", - "sha256:eebd927b86761a7068a06d3699fd6c20129becf15bb44282db085921ea0f1585", - "sha256:eff187177d8016ff6addf789dcc421c3db0d014e4946c1cc3fbf697f7852459d", - "sha256:f5f99a93cecf799738e211f9746dc83749b5693538fbfac279a61682ba309387", - "sha256:fbba59022e7c20124d2f520842b75904c7b9f16c854233fa46575c69949fb5b9" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==7.7.1" - }, - "cycler": { - "hashes": [ - "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", - "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c" - ], - "markers": "python_version >= '3.8'", - "version": "==0.12.1" - }, - "debugpy": { - "hashes": [ - "sha256:06859f68e817966723ffe046b896b1bd75c665996a77313370336ee9e1de3e90", - "sha256:2b8de94c5c78aa0d0ed79023eb27c7c56a64c68217d881bee2ffbcb13951d0c1", - "sha256:31abc9618be4edad0b3e3a85277bc9ab51a2d9f708ead0d99ffb5bb750e18503", - "sha256:32b6857f8263a969ce2ca098f228e5cc0604d277447ec05911a8c46cf3e7e307", - "sha256:3872ce5453b17837ef47fb9f3edc25085ff998ce63543f45ba7af41e7f7d370f", - "sha256:3dae443739c6b604802da9f3e09b0f45ddf1cf23c99161f3a1a8039f61a8bb89", - "sha256:46abe0b821cad751fc1fb9f860fb2e68d75e2c5d360986d0136cd1db8cad4428", - "sha256:4caca674206e97c85c034c1efab4483f33971d4e02e73081265ecb612af65377", - "sha256:5268ae7fdca75f526d04465931cb0bd24577477ff50e8bb03dab90983f4ebd02", - "sha256:62f9b4a861c256f37e163ada8cf5a81f4c8d5148fc17ee31fb46813bd658cdcc", - "sha256:63ca7670563c320503fea26ac688988d9d6b9c6a12abc8a8cf2e7dd8e5f6b6ea", - "sha256:6fab771639332bd8ceb769aacf454a30d14d7a964f2012bf9c4e04c60f16e85b", - "sha256:79ce4ed40966c4c1631d0131606b055a5a2f8e430e3f7bf8fd3744b09943e8e8", - "sha256:7d9a05efc6973b5aaf076d779cf3a6bbb1199e059a17738a2aa9d27a53bcc888", - "sha256:837e7bef95bdefba426ae38b9a94821ebdc5bea55627879cd48165c90b9e50ce", - "sha256:887d54276cefbe7290a754424b077e41efa405a3e07122d8897de54709dbe522", - "sha256:924464d87e7d905eb0d79fb70846558910e906d9ee309b60c4fe597a2e802590", - "sha256:a0bd87557f97bced5513a74088af0b84982b6ccb2e254b9312e29e8a5c4270eb", - "sha256:acf39a6e98630959763f9669feddee540745dfc45ad28dbc9bd1f9cd60639391", - "sha256:cb56c2db69fb8df3168bc857d7b7d2494fed295dfdbde9a45f27b4b152f37520", - "sha256:d4ba115cdd0e3a70942bd562adba9ec8c651fe69ddde2298a1be296fc331906f", - "sha256:dc7b77f5d32674686a5f06955e4b18c0e41fb5a605f5b33cf225790f114cfeec", - "sha256:ea869fe405880327497e6945c09365922c79d2a1eed4c3ae04d77ac7ae34b2b5", - "sha256:ed93c3155fc1f888ab2b43626182174e457fc31b7781cd1845629303790b8ad1", - "sha256:eee02b2ed52a563126c97bf04194af48f2fe1f68bb522a312b05935798e922ff", - "sha256:f14d2c4efa1809da125ca62df41050d9c7cd9cb9e380a2685d1e453c4d450ccb" - ], - "markers": "python_version >= '3.8'", - "version": "==1.8.13" - }, - "decorator": { - "hashes": [ - "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", - "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a" - ], - "markers": "python_version >= '3.8'", - "version": "==5.2.1" - }, - "defusedxml": { - "hashes": [ - "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", - "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==0.7.1" - }, - "distlib": { - "hashes": [ - "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", - "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403" - ], - "version": "==0.3.9" - }, - "docutils": { - "hashes": [ - "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", - "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2" - ], - "markers": "python_version >= '3.9'", - "version": "==0.21.2" - }, - "execnet": { - "hashes": [ - "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", - "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3" - ], - "markers": "python_version >= '3.8'", - "version": "==2.1.1" - }, - "executing": { - "hashes": [ - "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa", - "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755" - ], - "markers": "python_version >= '3.8'", - "version": "==2.2.0" - }, - "fastjsonschema": { - "hashes": [ - "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4", - "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667" - ], - "version": "==2.21.1" - }, - "filelock": { - "hashes": [ - "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", - "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de" - ], - "markers": "python_version >= '3.9'", - "version": "==3.18.0" - }, - "fonttools": { - "hashes": [ - "sha256:003548eadd674175510773f73fb2060bb46adb77c94854af3e0cc5bc70260049", - "sha256:0073b62c3438cf0058488c002ea90489e8801d3a7af5ce5f7c05c105bee815c3", - "sha256:1088182f68c303b50ca4dc0c82d42083d176cba37af1937e1a976a31149d4d14", - "sha256:133bedb9a5c6376ad43e6518b7e2cd2f866a05b1998f14842631d5feb36b5786", - "sha256:14a3e3e6b211660db54ca1ef7006401e4a694e53ffd4553ab9bc87ead01d0f05", - "sha256:17f39313b649037f6c800209984a11fc256a6137cbe5487091c6c7187cae4685", - "sha256:193b86e9f769320bc98ffdb42accafb5d0c8c49bd62884f1c0702bc598b3f0a2", - "sha256:2d351275f73ebdd81dd5b09a8b8dac7a30f29a279d41e1c1192aedf1b6dced40", - "sha256:300c310bb725b2bdb4f5fc7e148e190bd69f01925c7ab437b9c0ca3e1c7cd9ba", - "sha256:331954d002dbf5e704c7f3756028e21db07097c19722569983ba4d74df014000", - "sha256:38b947de71748bab150259ee05a775e8a0635891568e9fdb3cdd7d0e0004e62f", - "sha256:3cf4f8d2a30b454ac682e12c61831dcb174950c406011418e739de592bbf8f76", - "sha256:3fd3fccb7b9adaaecfa79ad51b759f2123e1aba97f857936ce044d4f029abd71", - "sha256:442ad4122468d0e47d83bc59d0e91b474593a8c813839e1872e47c7a0cb53b10", - "sha256:47b5e4680002ae1756d3ae3b6114e20aaee6cc5c69d1e5911f5ffffd3ee46c6b", - "sha256:53f5e9767978a4daf46f28e09dbeb7d010319924ae622f7b56174b777258e5ba", - "sha256:62b4c6802fa28e14dba010e75190e0e6228513573f1eeae57b11aa1a39b7e5b1", - "sha256:62cc1253827d1e500fde9dbe981219fea4eb000fd63402283472d38e7d8aa1c6", - "sha256:654ac4583e2d7c62aebc6fc6a4c6736f078f50300e18aa105d87ce8925cfac31", - "sha256:661a8995d11e6e4914a44ca7d52d1286e2d9b154f685a4d1f69add8418961563", - "sha256:6c1d38642ca2dddc7ae992ef5d026e5061a84f10ff2b906be5680ab089f55bb8", - "sha256:6e81c1cc80c1d8bf071356cc3e0e25071fbba1c75afc48d41b26048980b3c771", - "sha256:705837eae384fe21cee5e5746fd4f4b2f06f87544fa60f60740007e0aa600311", - "sha256:7ef04bc7827adb7532be3d14462390dd71287644516af3f1e67f1e6ff9c6d6df", - "sha256:86b2a1013ef7a64d2e94606632683f07712045ed86d937c11ef4dde97319c086", - "sha256:8d1613abd5af2f93c05867b3a3759a56e8bf97eb79b1da76b2bc10892f96ff16", - "sha256:965d0209e6dbdb9416100123b6709cb13f5232e2d52d17ed37f9df0cc31e2b35", - "sha256:96a4271f63a615bcb902b9f56de00ea225d6896052c49f20d0c91e9f43529a29", - "sha256:9d94449ad0a5f2a8bf5d2f8d71d65088aee48adbe45f3c5f8e00e3ad861ed81a", - "sha256:9da650cb29bc098b8cfd15ef09009c914b35c7986c8fa9f08b51108b7bc393b4", - "sha256:a05d1f07eb0a7d755fbe01fee1fd255c3a4d3730130cf1bfefb682d18fd2fcea", - "sha256:a114d1567e1a1586b7e9e7fc2ff686ca542a82769a296cef131e4c4af51e58f4", - "sha256:a1af375734018951c31c0737d04a9d5fd0a353a0253db5fbed2ccd44eac62d8c", - "sha256:b23d30a2c0b992fb1c4f8ac9bfde44b5586d23457759b6cf9a787f1a35179ee0", - "sha256:bc871904a53a9d4d908673c6faa15689874af1c7c5ac403a8e12d967ebd0c0dc", - "sha256:bce60f9a977c9d3d51de475af3f3581d9b36952e1f8fc19a1f2254f1dda7ce9c", - "sha256:bd9825822e7bb243f285013e653f6741954d8147427aaa0324a862cdbf4cbf62", - "sha256:ca7962e8e5fc047cc4e59389959843aafbf7445b6c08c20d883e60ced46370a5", - "sha256:d0cb73ccf7f6d7ca8d0bc7ea8ac0a5b84969a41c56ac3ac3422a24df2680546f", - "sha256:d54a45d30251f1d729e69e5b675f9a08b7da413391a1227781e2a297fa37f6d2", - "sha256:d6ca96d1b61a707ba01a43318c9c40aaf11a5a568d1e61146fafa6ab20890793", - "sha256:d6f195c14c01bd057bc9b4f70756b510e009c83c5ea67b25ced3e2c38e6ee6e9", - "sha256:e2cad98c94833465bcf28f51c248aaf07ca022efc6a3eba750ad9c1e0256d278", - "sha256:e2e993e8db36306cc3f1734edc8ea67906c55f98683d6fd34c3fc5593fdbba4c", - "sha256:e9270505a19361e81eecdbc2c251ad1e1a9a9c2ad75fa022ccdee533f55535dc", - "sha256:f20e2c0dfab82983a90f3d00703ac0960412036153e5023eed2b4641d7d5e692", - "sha256:f36a0868f47b7566237640c026c65a86d09a3d9ca5df1cd039e30a1da73098a0", - "sha256:f59746f7953f69cc3290ce2f971ab01056e55ddd0fb8b792c31a8acd7fee2d28", - "sha256:fa760e5fe8b50cbc2d71884a1eff2ed2b95a005f02dda2fa431560db0ddd927f", - "sha256:ffda9b8cd9cb8b301cae2602ec62375b59e2e2108a117746f12215145e3f786c" - ], - "markers": "python_version >= '3.8'", - "version": "==4.56.0" - }, - "fqdn": { - "hashes": [ - "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", - "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.5.1" - }, - "h11": { - "hashes": [ - "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", - "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" - ], - "markers": "python_version >= '3.7'", - "version": "==0.14.0" - }, - "httpcore": { - "hashes": [ - "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", - "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd" - ], - "markers": "python_version >= '3.8'", - "version": "==1.0.7" - }, - "httpx": { - "hashes": [ - "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", - "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad" - ], - "markers": "python_version >= '3.8'", - "version": "==0.28.1" - }, - "id": { - "hashes": [ - "sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d", - "sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658" - ], - "markers": "python_version >= '3.8'", - "version": "==1.5.0" - }, - "idna": { - "hashes": [ - "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", - "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" - ], - "markers": "python_version >= '3.6'", - "version": "==3.10" - }, - "imagesize": { - "hashes": [ - "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", - "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.4.1" - }, - "iniconfig": { - "hashes": [ - "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", - "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" - ], - "markers": "python_version >= '3.8'", - "version": "==2.1.0" - }, - "ipykernel": { - "hashes": [ - "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5", - "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215" - ], - "markers": "python_version >= '3.8'", - "version": "==6.29.5" - }, - "ipython": { - "hashes": [ - "sha256:143ef3ea6fb1e1bffb4c74b114051de653ffb7737a3f7ab1670e657ca6ae8c44", - "sha256:ec7b479e3e5656bf4f58c652c120494df1820f4f28f522fb7ca09e213c2aab52" - ], - "markers": "python_version >= '3.11'", - "version": "==9.0.2" - }, - "ipython-pygments-lexers": { - "hashes": [ - "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", - "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c" - ], - "markers": "python_version >= '3.8'", - "version": "==1.1.1" - }, - "isoduration": { - "hashes": [ - "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", - "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042" - ], - "markers": "python_version >= '3.7'", - "version": "==20.11.0" - }, - "jaraco.classes": { - "hashes": [ - "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", - "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790" - ], - "markers": "python_version >= '3.8'", - "version": "==3.4.0" - }, - "jaraco.context": { - "hashes": [ - "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", - "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4" - ], - "markers": "python_version >= '3.8'", - "version": "==6.0.1" - }, - "jaraco.functools": { - "hashes": [ - "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d", - "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649" - ], - "markers": "python_version >= '3.8'", - "version": "==4.1.0" - }, - "jedi": { - "hashes": [ - "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", - "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9" - ], - "markers": "python_version >= '3.6'", - "version": "==0.19.2" - }, - "jinja2": { - "hashes": [ - "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", - "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67" - ], - "markers": "python_version >= '3.7'", - "version": "==3.1.6" - }, - "json5": { - "hashes": [ - "sha256:19b23410220a7271e8377f81ba8aacba2fdd56947fbb137ee5977cbe1f5e8dfa", - "sha256:e66941c8f0a02026943c52c2eb34ebeb2a6f819a0be05920a6f5243cd30fd559" - ], - "markers": "python_full_version >= '3.8.0'", - "version": "==0.10.0" - }, - "jsonpointer": { - "hashes": [ - "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", - "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef" - ], - "markers": "python_version >= '3.7'", - "version": "==3.0.0" - }, - "jsonschema": { - "extras": [ - "format-nongpl" - ], - "hashes": [ - "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", - "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566" - ], - "markers": "python_version >= '3.8'", - "version": "==4.23.0" - }, - "jsonschema-specifications": { - "hashes": [ - "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", - "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf" - ], - "markers": "python_version >= '3.9'", - "version": "==2024.10.1" - }, - "jupyter-client": { - "hashes": [ - "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", - "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f" - ], - "markers": "python_version >= '3.8'", - "version": "==8.6.3" - }, - "jupyter-core": { - "hashes": [ - "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409", - "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9" - ], - "markers": "python_version >= '3.8'", - "version": "==5.7.2" - }, - "jupyter-events": { - "hashes": [ - "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", - "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b" - ], - "markers": "python_version >= '3.9'", - "version": "==0.12.0" - }, - "jupyter-lsp": { - "hashes": [ - "sha256:45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da", - "sha256:793147a05ad446f809fd53ef1cd19a9f5256fd0a2d6b7ce943a982cb4f545001" - ], - "markers": "python_version >= '3.8'", - "version": "==2.2.5" - }, - "jupyter-server": { - "hashes": [ - "sha256:872d989becf83517012ee669f09604aa4a28097c0bd90b2f424310156c2cdae3", - "sha256:9d446b8697b4f7337a1b7cdcac40778babdd93ba614b6d68ab1c0c918f1c4084" - ], - "markers": "python_version >= '3.9'", - "version": "==2.15.0" - }, - "jupyter-server-terminals": { - "hashes": [ - "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", - "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269" - ], - "markers": "python_version >= '3.8'", - "version": "==0.5.3" - }, - "jupyterlab": { - "hashes": [ - "sha256:2900ffdbfca9ed37c4ad7fdda3eb76582fd945d46962af3ac64741ae2d6b2ff4", - "sha256:fc9eb0455562a56a9bd6d2977cf090842f321fa1a298fcee9bf8c19de353d5fd" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==4.3.6" - }, - "jupyterlab-pygments": { - "hashes": [ - "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", - "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780" - ], - "markers": "python_version >= '3.8'", - "version": "==0.3.0" - }, - "jupyterlab-server": { - "hashes": [ - "sha256:e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4", - "sha256:eb36caca59e74471988f0ae25c77945610b887f777255aa21f8065def9e51ed4" - ], - "markers": "python_version >= '3.8'", - "version": "==2.27.3" - }, - "keyring": { - "hashes": [ - "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66", - "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd" - ], - "markers": "python_version >= '3.9'", - "version": "==25.6.0" - }, - "kiwisolver": { - "hashes": [ - "sha256:01c3d31902c7db5fb6182832713d3b4122ad9317c2c5877d0539227d96bb2e50", - "sha256:034d2c891f76bd3edbdb3ea11140d8510dca675443da7304205a2eaa45d8334c", - "sha256:085940635c62697391baafaaeabdf3dd7a6c3643577dde337f4d66eba021b2b8", - "sha256:08e77738ed7538f036cd1170cbed942ef749137b1311fa2bbe2a7fda2f6bf3cc", - "sha256:111793b232842991be367ed828076b03d96202c19221b5ebab421ce8bcad016f", - "sha256:11e1022b524bd48ae56c9b4f9296bce77e15a2e42a502cceba602f804b32bb79", - "sha256:151dffc4865e5fe6dafce5480fab84f950d14566c480c08a53c663a0020504b6", - "sha256:16523b40aab60426ffdebe33ac374457cf62863e330a90a0383639ce14bf44b2", - "sha256:1732e065704b47c9afca7ffa272f845300a4eb959276bf6970dc07265e73b605", - "sha256:1c8ceb754339793c24aee1c9fb2485b5b1f5bb1c2c214ff13368431e51fc9a09", - "sha256:23454ff084b07ac54ca8be535f4174170c1094a4cff78fbae4f73a4bcc0d4dab", - "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e", - "sha256:257af1622860e51b1a9d0ce387bf5c2c4f36a90594cb9514f55b074bcc787cfc", - "sha256:286b18e86682fd2217a48fc6be6b0f20c1d0ed10958d8dc53453ad58d7be0bf8", - "sha256:291331973c64bb9cce50bbe871fb2e675c4331dab4f31abe89f175ad7679a4d7", - "sha256:2f0121b07b356a22fb0414cec4666bbe36fd6d0d759db3d37228f496ed67c880", - "sha256:3452046c37c7692bd52b0e752b87954ef86ee2224e624ef7ce6cb21e8c41cc1b", - "sha256:34d142fba9c464bc3bbfeff15c96eab0e7310343d6aefb62a79d51421fcc5f1b", - "sha256:369b75d40abedc1da2c1f4de13f3482cb99e3237b38726710f4a793432b1c5ff", - "sha256:36dbbfd34838500a31f52c9786990d00150860e46cd5041386f217101350f0d3", - "sha256:370fd2df41660ed4e26b8c9d6bbcad668fbe2560462cba151a721d49e5b6628c", - "sha256:3a96c0e790ee875d65e340ab383700e2b4891677b7fcd30a699146f9384a2bb0", - "sha256:3b9b4d2892fefc886f30301cdd80debd8bb01ecdf165a449eb6e78f79f0fabd6", - "sha256:3cd3bc628b25f74aedc6d374d5babf0166a92ff1317f46267f12d2ed54bc1d30", - "sha256:3ddc373e0eef45b59197de815b1b28ef89ae3955e7722cc9710fb91cd77b7f47", - "sha256:4191ee8dfd0be1c3666ccbac178c5a05d5f8d689bbe3fc92f3c4abec817f8fe0", - "sha256:54a62808ac74b5e55a04a408cda6156f986cefbcf0ada13572696b507cc92fa1", - "sha256:577facaa411c10421314598b50413aa1ebcf5126f704f1e5d72d7e4e9f020d90", - "sha256:641f2ddf9358c80faa22e22eb4c9f54bd3f0e442e038728f500e3b978d00aa7d", - "sha256:65ea09a5a3faadd59c2ce96dc7bf0f364986a315949dc6374f04396b0d60e09b", - "sha256:68269e60ee4929893aad82666821aaacbd455284124817af45c11e50a4b42e3c", - "sha256:69b5637c3f316cab1ec1c9a12b8c5f4750a4c4b71af9157645bf32830e39c03a", - "sha256:7506488470f41169b86d8c9aeff587293f530a23a23a49d6bc64dab66bedc71e", - "sha256:768cade2c2df13db52475bd28d3a3fac8c9eff04b0e9e2fda0f3760f20b3f7fc", - "sha256:77e6f57a20b9bd4e1e2cedda4d0b986ebd0216236f0106e55c28aea3d3d69b16", - "sha256:782bb86f245ec18009890e7cb8d13a5ef54dcf2ebe18ed65f795e635a96a1c6a", - "sha256:7a3ad337add5148cf51ce0b55642dc551c0b9d6248458a757f98796ca7348712", - "sha256:7cd2785b9391f2873ad46088ed7599a6a71e762e1ea33e87514b1a441ed1da1c", - "sha256:7e9a60b50fe8b2ec6f448fe8d81b07e40141bfced7f896309df271a0b92f80f3", - "sha256:84a2f830d42707de1d191b9490ac186bf7997a9495d4e9072210a1296345f7dc", - "sha256:856b269c4d28a5c0d5e6c1955ec36ebfd1651ac00e1ce0afa3e28da95293b561", - "sha256:858416b7fb777a53f0c59ca08190ce24e9abbd3cffa18886a5781b8e3e26f65d", - "sha256:87b287251ad6488e95b4f0b4a79a6d04d3ea35fde6340eb38fbd1ca9cd35bbbc", - "sha256:88c6f252f6816a73b1f8c904f7bbe02fd67c09a69f7cb8a0eecdbf5ce78e63db", - "sha256:893f5525bb92d3d735878ec00f781b2de998333659507d29ea4466208df37bed", - "sha256:89c107041f7b27844179ea9c85d6da275aa55ecf28413e87624d033cf1f6b751", - "sha256:918139571133f366e8362fa4a297aeba86c7816b7ecf0bc79168080e2bd79957", - "sha256:99cea8b9dd34ff80c521aef46a1dddb0dcc0283cf18bde6d756f1e6f31772165", - "sha256:a17b7c4f5b2c51bb68ed379defd608a03954a1845dfed7cc0117f1cc8a9b7fd2", - "sha256:a3c44cb68861de93f0c4a8175fbaa691f0aa22550c331fefef02b618a9dcb476", - "sha256:a4d3601908c560bdf880f07d94f31d734afd1bb71e96585cace0e38ef44c6d84", - "sha256:a5ce1e481a74b44dd5e92ff03ea0cb371ae7a0268318e202be06c8f04f4f1246", - "sha256:a66f60f8d0c87ab7f59b6fb80e642ebb29fec354a4dfad687ca4092ae69d04f4", - "sha256:b21dbe165081142b1232a240fc6383fd32cdd877ca6cc89eab93e5f5883e1c25", - "sha256:b47a465040146981dc9db8647981b8cb96366fbc8d452b031e4f8fdffec3f26d", - "sha256:b5773efa2be9eb9fcf5415ea3ab70fc785d598729fd6057bea38d539ead28271", - "sha256:b83dc6769ddbc57613280118fb4ce3cd08899cc3369f7d0e0fab518a7cf37fdb", - "sha256:bade438f86e21d91e0cf5dd7c0ed00cda0f77c8c1616bd83f9fc157fa6760d31", - "sha256:bcb1ebc3547619c3b58a39e2448af089ea2ef44b37988caf432447374941574e", - "sha256:be4816dc51c8a471749d664161b434912eee82f2ea66bd7628bd14583a833e85", - "sha256:c07b29089b7ba090b6f1a669f1411f27221c3662b3a1b7010e67b59bb5a6f10b", - "sha256:c2b9a96e0f326205af81a15718a9073328df1173a2619a68553decb7097fd5d7", - "sha256:c5020c83e8553f770cb3b5fc13faac40f17e0b205bd237aebd21d53d733adb03", - "sha256:c72941acb7b67138f35b879bbe85be0f6c6a70cab78fe3ef6db9c024d9223e5b", - "sha256:c8bf637892dc6e6aad2bc6d4d69d08764166e5e3f69d469e55427b6ac001b19d", - "sha256:cc978a80a0db3a66d25767b03688f1147a69e6237175c0f4ffffaaedf744055a", - "sha256:ce2cf1e5688edcb727fdf7cd1bbd0b6416758996826a8be1d958f91880d0809d", - "sha256:d47b28d1dfe0793d5e96bce90835e17edf9a499b53969b03c6c47ea5985844c3", - "sha256:d47cfb2650f0e103d4bf68b0b5804c68da97272c84bb12850d877a95c056bd67", - "sha256:d5536185fce131780ebd809f8e623bf4030ce1b161353166c49a3c74c287897f", - "sha256:d561d2d8883e0819445cfe58d7ddd673e4015c3c57261d7bdcd3710d0d14005c", - "sha256:d6af5e8815fd02997cb6ad9bbed0ee1e60014438ee1a5c2444c96f87b8843502", - "sha256:d6d6bd87df62c27d4185de7c511c6248040afae67028a8a22012b010bc7ad062", - "sha256:dace81d28c787956bfbfbbfd72fdcef014f37d9b48830829e488fdb32b49d954", - "sha256:e063ef9f89885a1d68dd8b2e18f5ead48653176d10a0e324e3b0030e3a69adeb", - "sha256:e7a019419b7b510f0f7c9dceff8c5eae2392037eae483a7f9162625233802b0a", - "sha256:eaa973f1e05131de5ff3569bbba7f5fd07ea0595d3870ed4a526d486fe57fa1b", - "sha256:eb158fe28ca0c29f2260cca8c43005329ad58452c36f0edf298204de32a9a3ed", - "sha256:ed33ca2002a779a2e20eeb06aea7721b6e47f2d4b8a8ece979d8ba9e2a167e34", - "sha256:fc2ace710ba7c1dfd1a3b42530b62b9ceed115f19a1656adefce7b1782a37794" - ], - "markers": "python_version >= '3.10'", - "version": "==1.4.8" - }, - "markdown-it-py": { - "hashes": [ - "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", - "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb" - ], - "markers": "python_version >= '3.8'", - "version": "==3.0.0" - }, - "markupsafe": { - "hashes": [ - "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", - "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", - "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", - "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", - "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", - "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", - "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", - "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", - "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", - "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", - "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", - "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", - "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", - "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", - "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", - "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", - "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", - "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", - "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", - "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", - "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", - "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", - "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", - "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", - "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", - "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", - "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", - "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", - "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", - "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", - "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", - "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", - "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", - "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", - "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", - "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", - "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", - "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", - "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", - "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", - "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", - "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", - "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", - "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", - "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", - "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", - "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", - "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", - "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", - "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", - "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", - "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", - "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", - "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", - "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", - "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", - "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", - "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", - "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", - "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", - "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50" - ], - "markers": "python_version >= '3.9'", - "version": "==3.0.2" - }, - "matplotlib": { - "hashes": [ - "sha256:01e63101ebb3014e6e9f80d9cf9ee361a8599ddca2c3e166c563628b39305dbb", - "sha256:02582304e352f40520727984a5a18f37e8187861f954fea9be7ef06569cf85b4", - "sha256:057206ff2d6ab82ff3e94ebd94463d084760ca682ed5f150817b859372ec4401", - "sha256:0721a3fd3d5756ed593220a8b86808a36c5031fce489adb5b31ee6dbb47dd5b2", - "sha256:0f69dc9713e4ad2fb21a1c30e37bd445d496524257dfda40ff4a8efb3604ab5c", - "sha256:11b65088c6f3dae784bc72e8d039a2580186285f87448babb9ddb2ad0082993a", - "sha256:1985ad3d97f51307a2cbfc801a930f120def19ba22864182dacef55277102ba6", - "sha256:19b06241ad89c3ae9469e07d77efa87041eac65d78df4fcf9cac318028009b01", - "sha256:2589659ea30726284c6c91037216f64a506a9822f8e50592d48ac16a2f29e044", - "sha256:35e87384ee9e488d8dd5a2dd7baf471178d38b90618d8ea147aced4ab59c9bea", - "sha256:3f06bad951eea6422ac4e8bdebcf3a70c59ea0a03338c5d2b109f57b64eb3972", - "sha256:4c59af3e8aca75d7744b68e8e78a669e91ccbcf1ac35d0102a7b1b46883f1dd7", - "sha256:4f0647b17b667ae745c13721602b540f7aadb2a32c5b96e924cd4fea5dcb90f1", - "sha256:56c5d9fcd9879aa8040f196a235e2dcbdf7dd03ab5b07c0696f80bc6cf04bedd", - "sha256:5d45d3f5245be5b469843450617dcad9af75ca50568acf59997bed9311131a0b", - "sha256:648406f1899f9a818cef8c0231b44dcfc4ff36f167101c3fd1c9151f24220fdc", - "sha256:66e907a06e68cb6cfd652c193311d61a12b54f56809cafbed9736ce5ad92f107", - "sha256:7e496c01441be4c7d5f96d4e40f7fca06e20dcb40e44c8daa2e740e1757ad9e6", - "sha256:8e875b95ac59a7908978fe307ecdbdd9a26af7fa0f33f474a27fcf8c99f64a19", - "sha256:8e8e25b1209161d20dfe93037c8a7f7ca796ec9aa326e6e4588d8c4a5dd1e473", - "sha256:a144867dd6bf8ba8cb5fc81a158b645037e11b3e5cf8a50bd5f9917cb863adfe", - "sha256:a3dfb036f34873b46978f55e240cff7a239f6c4409eac62d8145bad3fc6ba5a3", - "sha256:a97ff127f295817bc34517255c9db6e71de8eddaab7f837b7d341dee9f2f587f", - "sha256:aa3854b5f9473564ef40a41bc922be978fab217776e9ae1545c9b3a5cf2092a3", - "sha256:bc411ebd5889a78dabbc457b3fa153203e22248bfa6eedc6797be5df0164dbf9", - "sha256:c42eee41e1b60fd83ee3292ed83a97a5f2a8239b10c26715d8a6172226988d7b", - "sha256:c96f2c2f825d1257e437a1482c5a2cf4fee15db4261bd6fc0750f81ba2b4ba3d", - "sha256:cfd414bce89cc78a7e1d25202e979b3f1af799e416010a20ab2b5ebb3a02425c", - "sha256:d0673b4b8f131890eb3a1ad058d6e065fb3c6e71f160089b65f8515373394698", - "sha256:d3809916157ba871bcdd33d3493acd7fe3037db5daa917ca6e77975a94cef779", - "sha256:dc6ab14a7ab3b4d813b88ba957fc05c79493a037f54e246162033591e770de6f", - "sha256:e8d2d0e3881b129268585bf4765ad3ee73a4591d77b9a18c214ac7e3a79fb2ba", - "sha256:e9b4bb156abb8fa5e5b2b460196f7db7264fc6d62678c03457979e7d5254b7be", - "sha256:ff2ae14910be903f4a24afdbb6d7d3a6c44da210fc7d42790b87aeac92238a16" - ], - "index": "pypi", - "markers": "python_version >= '3.10'", - "version": "==3.10.1" - }, - "matplotlib-inline": { - "hashes": [ - "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", - "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca" - ], - "markers": "python_version >= '3.8'", - "version": "==0.1.7" - }, - "mdurl": { - "hashes": [ - "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", - "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" - ], - "markers": "python_version >= '3.7'", - "version": "==0.1.2" - }, - "mistune": { - "hashes": [ - "sha256:1a32314113cff28aa6432e99e522677c8587fd83e3d51c29b82a52409c842bd9", - "sha256:a7035c21782b2becb6be62f8f25d3df81ccb4d6fa477a6525b15af06539f02a0" - ], - "markers": "python_version >= '3.8'", - "version": "==3.1.3" - }, - "more-itertools": { - "hashes": [ - "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b", - "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89" - ], - "markers": "python_version >= '3.9'", - "version": "==10.6.0" - }, - "mypy-extensions": { - "hashes": [ - "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", - "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.0" - }, - "nbclient": { - "hashes": [ - "sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d", - "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193" - ], - "markers": "python_full_version >= '3.9.0'", - "version": "==0.10.2" - }, - "nbconvert": { - "hashes": [ - "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", - "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582" - ], - "markers": "python_version >= '3.8'", - "version": "==7.16.6" - }, - "nbformat": { - "hashes": [ - "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", - "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b" - ], - "markers": "python_version >= '3.8'", - "version": "==5.10.4" - }, - "nest-asyncio": { - "hashes": [ - "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", - "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c" - ], - "markers": "python_version >= '3.5'", - "version": "==1.6.0" - }, - "nh3": { - "hashes": [ - "sha256:087ffadfdcd497658c3adc797258ce0f06be8a537786a7217649fc1c0c60c293", - "sha256:20979783526641c81d2f5bfa6ca5ccca3d1e4472474b162c6256745fbfe31cd1", - "sha256:2a5174551f95f2836f2ad6a8074560f261cf9740a48437d6151fd2d4d7d617ab", - "sha256:31eedcd7d08b0eae28ba47f43fd33a653b4cdb271d64f1aeda47001618348fde", - "sha256:4990e7ee6a55490dbf00d61a6f476c9a3258e31e711e13713b2ea7d6616f670e", - "sha256:55823c5ea1f6b267a4fad5de39bc0524d49a47783e1fe094bcf9c537a37df251", - "sha256:6141caabe00bbddc869665b35fc56a478eb774a8c1dfd6fba9fe1dfdf29e6efa", - "sha256:637d4a10c834e1b7d9548592c7aad760611415fcd5bd346f77fd8a064309ae6d", - "sha256:63ca02ac6f27fc80f9894409eb61de2cb20ef0a23740c7e29f9ec827139fa578", - "sha256:6ae319f17cd8960d0612f0f0ddff5a90700fa71926ca800e9028e7851ce44a6f", - "sha256:6c9c30b8b0d291a7c5ab0967ab200598ba33208f754f2f4920e9343bdd88f79a", - "sha256:713d16686596e556b65e7f8c58328c2df63f1a7abe1277d87625dcbbc012ef82", - "sha256:818f2b6df3763e058efa9e69677b5a92f9bc0acff3295af5ed013da544250d5b", - "sha256:9d67709bc0d7d1f5797b21db26e7a8b3d15d21c9c5f58ccfe48b5328483b685b", - "sha256:a5f77e62aed5c4acad635239ac1290404c7e940c81abe561fd2af011ff59f585", - "sha256:a772dec5b7b7325780922dd904709f0f5f3a79fbf756de5291c01370f6df0967", - "sha256:a7ea28cd49293749d67e4fcf326c554c83ec912cd09cd94aa7ec3ab1921c8283", - "sha256:ac7006c3abd097790e611fe4646ecb19a8d7f2184b882f6093293b8d9b887431", - "sha256:b3b5c58161e08549904ac4abd450dacd94ff648916f7c376ae4b2c0652b98ff9", - "sha256:b8d55ea1fc7ae3633d758a92aafa3505cd3cc5a6e40470c9164d54dff6f96d42", - "sha256:bb0014948f04d7976aabae43fcd4cb7f551f9f8ce785a4c9ef66e6c2590f8629", - "sha256:d002b648592bf3033adfd875a48f09b8ecc000abd7f6a8769ed86b6ccc70c759", - "sha256:d426d7be1a2f3d896950fe263332ed1662f6c78525b4520c8e9861f8d7f0d243", - "sha256:fcff321bd60c6c5c9cb4ddf2554e22772bb41ebd93ad88171bbbb6f271255286" - ], - "markers": "python_version >= '3.8'", - "version": "==0.2.21" - }, - "notebook-shim": { - "hashes": [ - "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", - "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb" - ], - "markers": "python_version >= '3.7'", - "version": "==0.2.4" - }, - "numpy": { - "hashes": [ - "sha256:05c076d531e9998e7e694c36e8b349969c56eadd2cdcd07242958489d79a7286", - "sha256:0d54974f9cf14acf49c60f0f7f4084b6579d24d439453d5fc5805d46a165b542", - "sha256:11c43995255eb4127115956495f43e9343736edb7fcdb0d973defd9de14cd84f", - "sha256:188dcbca89834cc2e14eb2f106c96d6d46f200fe0200310fc29089657379c58d", - "sha256:1974afec0b479e50438fc3648974268f972e2d908ddb6d7fb634598cdb8260a0", - "sha256:1cf4e5c6a278d620dee9ddeb487dc6a860f9b199eadeecc567f777daace1e9e7", - "sha256:207a2b8441cc8b6a2a78c9ddc64d00d20c303d79fba08c577752f080c4007ee3", - "sha256:218f061d2faa73621fa23d6359442b0fc658d5b9a70801373625d958259eaca3", - "sha256:2aad3c17ed2ff455b8eaafe06bcdae0062a1db77cb99f4b9cbb5f4ecb13c5146", - "sha256:2fa8fa7697ad1646b5c93de1719965844e004fcad23c91228aca1cf0800044a1", - "sha256:31504f970f563d99f71a3512d0c01a645b692b12a63630d6aafa0939e52361e6", - "sha256:3387dd7232804b341165cedcb90694565a6015433ee076c6754775e85d86f1fc", - "sha256:4ba5054787e89c59c593a4169830ab362ac2bee8a969249dc56e5d7d20ff8df9", - "sha256:4f92084defa704deadd4e0a5ab1dc52d8ac9e8a8ef617f3fbb853e79b0ea3592", - "sha256:65ef3468b53269eb5fdb3a5c09508c032b793da03251d5f8722b1194f1790c00", - "sha256:6f527d8fdb0286fd2fd97a2a96c6be17ba4232da346931d967a0630050dfd298", - "sha256:7051ee569db5fbac144335e0f3b9c2337e0c8d5c9fee015f259a5bd70772b7e8", - "sha256:7716e4a9b7af82c06a2543c53ca476fa0b57e4d760481273e09da04b74ee6ee2", - "sha256:79bd5f0a02aa16808fcbc79a9a376a147cc1045f7dfe44c6e7d53fa8b8a79392", - "sha256:7a4e84a6283b36632e2a5b56e121961f6542ab886bc9e12f8f9818b3c266bfbb", - "sha256:8120575cb4882318c791f839a4fd66161a6fa46f3f0a5e613071aae35b5dd8f8", - "sha256:81413336ef121a6ba746892fad881a83351ee3e1e4011f52e97fba79233611fd", - "sha256:8146f3550d627252269ac42ae660281d673eb6f8b32f113538e0cc2a9aed42b9", - "sha256:879cf3a9a2b53a4672a168c21375166171bc3932b7e21f622201811c43cdd3b0", - "sha256:892c10d6a73e0f14935c31229e03325a7b3093fafd6ce0af704be7f894d95687", - "sha256:92bda934a791c01d6d9d8e038363c50918ef7c40601552a58ac84c9613a665bc", - "sha256:9ba03692a45d3eef66559efe1d1096c4b9b75c0986b5dff5530c378fb8331d4f", - "sha256:9eeea959168ea555e556b8188da5fa7831e21d91ce031e95ce23747b7609f8a4", - "sha256:a0258ad1f44f138b791327961caedffbf9612bfa504ab9597157806faa95194a", - "sha256:a761ba0fa886a7bb33c6c8f6f20213735cb19642c580a931c625ee377ee8bd39", - "sha256:a7b9084668aa0f64e64bd00d27ba5146ef1c3a8835f3bd912e7a9e01326804c4", - "sha256:a84eda42bd12edc36eb5b53bbcc9b406820d3353f1994b6cfe453a33ff101775", - "sha256:ab2939cd5bec30a7430cbdb2287b63151b77cf9624de0532d629c9a1c59b1d5c", - "sha256:ac0280f1ba4a4bfff363a99a6aceed4f8e123f8a9b234c89140f5e894e452ecd", - "sha256:adf8c1d66f432ce577d0197dceaac2ac00c0759f573f28516246351c58a85020", - "sha256:b4adfbbc64014976d2f91084915ca4e626fbf2057fb81af209c1a6d776d23e3d", - "sha256:bb649f8b207ab07caebba230d851b579a3c8711a851d29efe15008e31bb4de24", - "sha256:bce43e386c16898b91e162e5baaad90c4b06f9dcbe36282490032cec98dc8ae7", - "sha256:bd3ad3b0a40e713fc68f99ecfd07124195333f1e689387c180813f0e94309d6f", - "sha256:c3f7ac96b16955634e223b579a3e5798df59007ca43e8d451a0e6a50f6bfdfba", - "sha256:cf28633d64294969c019c6df4ff37f5698e8326db68cc2b66576a51fad634880", - "sha256:d0f35b19894a9e08639fd60a1ec1978cb7f5f7f1eace62f38dd36be8aecdef4d", - "sha256:db1f1c22173ac1c58db249ae48aa7ead29f534b9a948bc56828337aa84a32ed6", - "sha256:dbe512c511956b893d2dacd007d955a3f03d555ae05cfa3ff1c1ff6df8851854", - "sha256:df2f57871a96bbc1b69733cd4c51dc33bea66146b8c63cacbfed73eec0883017", - "sha256:e2f085ce2e813a50dfd0e01fbfc0c12bbe5d2063d99f8b29da30e544fb6483b8", - "sha256:e642d86b8f956098b564a45e6f6ce68a22c2c97a04f5acd3f221f57b8cb850ae", - "sha256:e9e0a277bb2eb5d8a7407e14688b85fd8ad628ee4e0c7930415687b6564207a4", - "sha256:ea2bb7e2ae9e37d96835b3576a4fa4b3a97592fbea8ef7c3587078b0068b8f09", - "sha256:ee4d528022f4c5ff67332469e10efe06a267e32f4067dc76bb7e2cddf3cd25ff", - "sha256:f05d4198c1bacc9124018109c5fba2f3201dbe7ab6e92ff100494f236209c960", - "sha256:f34dc300df798742b3d06515aa2a0aee20941c13579d7a2f2e10af01ae4901ee", - "sha256:f4162988a360a29af158aeb4a2f4f09ffed6a969c9776f8f3bdee9b06a8ab7e5", - "sha256:f486038e44caa08dbd97275a9a35a283a8f1d2f0ee60ac260a1790e76660833c", - "sha256:f7de08cbe5551911886d1ab60de58448c6df0f67d9feb7d1fb21e9875ef95e91" - ], - "markers": "python_version >= '3.10'", - "version": "==2.2.4" - }, - "overrides": { - "hashes": [ - "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", - "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49" - ], - "markers": "python_version >= '3.6'", - "version": "==7.7.0" - }, - "packaging": { - "hashes": [ - "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", - "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" - ], - "markers": "python_version >= '3.8'", - "version": "==24.2" - }, - "pandocfilters": { - "hashes": [ - "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", - "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.5.1" - }, - "parso": { - "hashes": [ - "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", - "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d" - ], - "markers": "python_version >= '3.6'", - "version": "==0.8.4" - }, - "pathspec": { - "hashes": [ - "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", - "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" - ], - "markers": "python_version >= '3.8'", - "version": "==0.12.1" - }, - "pexpect": { - "hashes": [ - "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", - "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f" - ], - "markers": "sys_platform != 'win32' and sys_platform != 'emscripten'", - "version": "==4.9.0" - }, - "pillow": { - "hashes": [ - "sha256:015c6e863faa4779251436db398ae75051469f7c903b043a48f078e437656f83", - "sha256:0a2f91f8a8b367e7a57c6e91cd25af510168091fb89ec5146003e424e1558a96", - "sha256:11633d58b6ee5733bde153a8dafd25e505ea3d32e261accd388827ee987baf65", - "sha256:2062ffb1d36544d42fcaa277b069c88b01bb7298f4efa06731a7fd6cc290b81a", - "sha256:31eba6bbdd27dde97b0174ddf0297d7a9c3a507a8a1480e1e60ef914fe23d352", - "sha256:3362c6ca227e65c54bf71a5f88b3d4565ff1bcbc63ae72c34b07bbb1cc59a43f", - "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20", - "sha256:36ba10b9cb413e7c7dfa3e189aba252deee0602c86c309799da5a74009ac7a1c", - "sha256:3764d53e09cdedd91bee65c2527815d315c6b90d7b8b79759cc48d7bf5d4f114", - "sha256:3a5fe20a7b66e8135d7fd617b13272626a28278d0e578c98720d9ba4b2439d49", - "sha256:3cdcdb0b896e981678eee140d882b70092dac83ac1cdf6b3a60e2216a73f2b91", - "sha256:4637b88343166249fe8aa94e7c4a62a180c4b3898283bb5d3d2fd5fe10d8e4e0", - "sha256:4db853948ce4e718f2fc775b75c37ba2efb6aaea41a1a5fc57f0af59eee774b2", - "sha256:4dd43a78897793f60766563969442020e90eb7847463eca901e41ba186a7d4a5", - "sha256:54251ef02a2309b5eec99d151ebf5c9904b77976c8abdcbce7891ed22df53884", - "sha256:54ce1c9a16a9561b6d6d8cb30089ab1e5eb66918cb47d457bd996ef34182922e", - "sha256:593c5fd6be85da83656b93ffcccc2312d2d149d251e98588b14fbc288fd8909c", - "sha256:5bb94705aea800051a743aa4874bb1397d4695fb0583ba5e425ee0328757f196", - "sha256:67cd427c68926108778a9005f2a04adbd5e67c442ed21d95389fe1d595458756", - "sha256:70ca5ef3b3b1c4a0812b5c63c57c23b63e53bc38e758b37a951e5bc466449861", - "sha256:73ddde795ee9b06257dac5ad42fcb07f3b9b813f8c1f7f870f402f4dc54b5269", - "sha256:758e9d4ef15d3560214cddbc97b8ef3ef86ce04d62ddac17ad39ba87e89bd3b1", - "sha256:7d33d2fae0e8b170b6a6c57400e077412240f6f5bb2a342cf1ee512a787942bb", - "sha256:7fdadc077553621911f27ce206ffcbec7d3f8d7b50e0da39f10997e8e2bb7f6a", - "sha256:8000376f139d4d38d6851eb149b321a52bb8893a88dae8ee7d95840431977081", - "sha256:837060a8599b8f5d402e97197d4924f05a2e0d68756998345c829c33186217b1", - "sha256:89dbdb3e6e9594d512780a5a1c42801879628b38e3efc7038094430844e271d8", - "sha256:8c730dc3a83e5ac137fbc92dfcfe1511ce3b2b5d7578315b63dbbb76f7f51d90", - "sha256:8e275ee4cb11c262bd108ab2081f750db2a1c0b8c12c1897f27b160c8bd57bbc", - "sha256:9044b5e4f7083f209c4e35aa5dd54b1dd5b112b108648f5c902ad586d4f945c5", - "sha256:93a18841d09bcdd774dcdc308e4537e1f867b3dec059c131fde0327899734aa1", - "sha256:9409c080586d1f683df3f184f20e36fb647f2e0bc3988094d4fd8c9f4eb1b3b3", - "sha256:96f82000e12f23e4f29346e42702b6ed9a2f2fea34a740dd5ffffcc8c539eb35", - "sha256:9aa9aeddeed452b2f616ff5507459e7bab436916ccb10961c4a382cd3e03f47f", - "sha256:9ee85f0696a17dd28fbcfceb59f9510aa71934b483d1f5601d1030c3c8304f3c", - "sha256:a07dba04c5e22824816b2615ad7a7484432d7f540e6fa86af60d2de57b0fcee2", - "sha256:a3cd561ded2cf2bbae44d4605837221b987c216cff94f49dfeed63488bb228d2", - "sha256:a697cd8ba0383bba3d2d3ada02b34ed268cb548b369943cd349007730c92bddf", - "sha256:a76da0a31da6fcae4210aa94fd779c65c75786bc9af06289cd1c184451ef7a65", - "sha256:a85b653980faad27e88b141348707ceeef8a1186f75ecc600c395dcac19f385b", - "sha256:a8d65b38173085f24bc07f8b6c505cbb7418009fa1a1fcb111b1f4961814a442", - "sha256:aa8dd43daa836b9a8128dbe7d923423e5ad86f50a7a14dc688194b7be5c0dea2", - "sha256:ab8a209b8485d3db694fa97a896d96dd6533d63c22829043fd9de627060beade", - "sha256:abc56501c3fd148d60659aae0af6ddc149660469082859fa7b066a298bde9482", - "sha256:ad5db5781c774ab9a9b2c4302bbf0c1014960a0a7be63278d13ae6fdf88126fe", - "sha256:ae98e14432d458fc3de11a77ccb3ae65ddce70f730e7c76140653048c71bfcbc", - "sha256:b20be51b37a75cc54c2c55def3fa2c65bb94ba859dde241cd0a4fd302de5ae0a", - "sha256:b523466b1a31d0dcef7c5be1f20b942919b62fd6e9a9be199d035509cbefc0ec", - "sha256:b5d658fbd9f0d6eea113aea286b21d3cd4d3fd978157cbf2447a6035916506d3", - "sha256:b6123aa4a59d75f06e9dd3dac5bf8bc9aa383121bb3dd9a7a612e05eabc9961a", - "sha256:bd165131fd51697e22421d0e467997ad31621b74bfc0b75956608cb2906dda07", - "sha256:bf902d7413c82a1bfa08b06a070876132a5ae6b2388e2712aab3a7cbc02205c6", - "sha256:c12fc111ef090845de2bb15009372175d76ac99969bdf31e2ce9b42e4b8cd88f", - "sha256:c1eec9d950b6fe688edee07138993e54ee4ae634c51443cfb7c1e7613322718e", - "sha256:c640e5a06869c75994624551f45e5506e4256562ead981cce820d5ab39ae2192", - "sha256:cc1331b6d5a6e144aeb5e626f4375f5b7ae9934ba620c0ac6b3e43d5e683a0f0", - "sha256:cfd5cd998c2e36a862d0e27b2df63237e67273f2fc78f47445b14e73a810e7e6", - "sha256:d3d8da4a631471dfaf94c10c85f5277b1f8e42ac42bade1ac67da4b4a7359b73", - "sha256:d44ff19eea13ae4acdaaab0179fa68c0c6f2f45d66a4d8ec1eda7d6cecbcc15f", - "sha256:dd0052e9db3474df30433f83a71b9b23bd9e4ef1de13d92df21a52c0303b8ab6", - "sha256:dd0e081319328928531df7a0e63621caf67652c8464303fd102141b785ef9547", - "sha256:dda60aa465b861324e65a78c9f5cf0f4bc713e4309f83bc387be158b077963d9", - "sha256:e06695e0326d05b06833b40b7ef477e475d0b1ba3a6d27da1bb48c23209bf457", - "sha256:e1abe69aca89514737465752b4bcaf8016de61b3be1397a8fc260ba33321b3a8", - "sha256:e267b0ed063341f3e60acd25c05200df4193e15a4a5807075cd71225a2386e26", - "sha256:e5449ca63da169a2e6068dd0e2fcc8d91f9558aba89ff6d02121ca8ab11e79e5", - "sha256:e63e4e5081de46517099dc30abe418122f54531a6ae2ebc8680bcd7096860eab", - "sha256:f189805c8be5ca5add39e6f899e6ce2ed824e65fb45f3c28cb2841911da19070", - "sha256:f7955ecf5609dee9442cbface754f2c6e541d9e6eda87fad7f7a989b0bdb9d71", - "sha256:f86d3a7a9af5d826744fabf4afd15b9dfef44fe69a98541f666f66fbb8d3fef9", - "sha256:fbd43429d0d7ed6533b25fc993861b8fd512c42d04514a0dd6337fb3ccf22761" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==11.1.0" - }, - "platformdirs": { - "hashes": [ - "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94", - "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351" - ], - "markers": "python_version >= '3.9'", - "version": "==4.3.7" - }, - "pluggy": { - "hashes": [ - "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", - "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" - ], - "markers": "python_version >= '3.8'", - "version": "==1.5.0" - }, - "prometheus-client": { - "hashes": [ - "sha256:252505a722ac04b0456be05c05f75f45d760c2911ffc45f2a06bcaed9f3ae3fb", - "sha256:594b45c410d6f4f8888940fe80b5cc2521b305a1fafe1c58609ef715a001f301" - ], - "markers": "python_version >= '3.8'", - "version": "==0.21.1" - }, - "prompt-toolkit": { - "hashes": [ - "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab", - "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198" - ], - "markers": "python_full_version >= '3.8.0'", - "version": "==3.0.50" - }, - "psutil": { - "hashes": [ - "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", - "sha256:1e744154a6580bc968a0195fd25e80432d3afec619daf145b9e5ba16cc1d688e", - "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", - "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", - "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", - "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", - "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", - "sha256:84df4eb63e16849689f76b1ffcb36db7b8de703d1bc1fe41773db487621b6c17", - "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", - "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99" - ], - "markers": "python_version >= '3.6'", - "version": "==7.0.0" - }, - "ptyprocess": { - "hashes": [ - "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", - "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220" - ], - "markers": "os_name != 'nt'", - "version": "==0.7.0" - }, - "pure-eval": { - "hashes": [ - "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", - "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42" - ], - "version": "==0.2.3" - }, - "pycparser": { - "hashes": [ - "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", - "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc" - ], - "markers": "python_version >= '3.8'", - "version": "==2.22" - }, - "pyenchant": { - "hashes": [ - "sha256:1cf830c6614362a78aab78d50eaf7c6c93831369c52e1bb64ffae1df0341e637", - "sha256:5a636832987eaf26efe971968f4d1b78e81f62bca2bde0a9da210c7de43c3bce", - "sha256:5facc821ece957208a81423af7d6ec7810dad29697cb0d77aae81e4e11c8e5a6", - "sha256:6153f521852e23a5add923dbacfbf4bebbb8d70c4e4bad609a8e0f9faeb915d1" - ], - "markers": "python_version >= '3.5'", - "version": "==3.2.2" - }, - "pygments": { - "hashes": [ - "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", - "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c" - ], - "markers": "python_version >= '3.8'", - "version": "==2.19.1" - }, - "pyparsing": { - "hashes": [ - "sha256:2a857aee851f113c2de9d4bfd9061baea478cb0f1c7ca6cbf594942d6d111575", - "sha256:6ab05e1cb111cc72acc8ed811a3ca4c2be2af8d7b6df324347f04fd057d8d793" - ], - "markers": "python_version >= '3.9'", - "version": "==3.2.2" - }, - "pyproj": { - "hashes": [ - "sha256:04abc517a8555d1b05fcee768db3280143fe42ec39fdd926a2feef31631a1f2f", - "sha256:0829865c1d3a3543f918b3919dc601eea572d6091c0dd175e1a054db9c109274", - "sha256:084c0a475688f934d386c2ab3b6ce03398a473cd48adfda70d9ab8f87f2394a0", - "sha256:0b853ae99bda66cbe24b4ccfe26d70601d84375940a47f553413d9df570065e0", - "sha256:1e47c4e93b88d99dd118875ee3ca0171932444cdc0b52d493371b5d98d0f30ee", - "sha256:263b54ba5004b6b957d55757d846fc5081bc02980caa0279c4fc95fa0fff6067", - "sha256:2781029d90df7f8d431e29562a3f2d8eafdf233c4010d6fc0381858dc7373217", - "sha256:3537668992a709a2e7f068069192138618c00d0ba113572fdd5ee5ffde8222f3", - "sha256:3c2e7449840a44ce860d8bea2c6c1c4bc63fa07cba801dcce581d14dcb031a02", - "sha256:3e8d276caeae34fcbe4813855d0d97b9b825bab8d7a8b86d859c24a6213a5a0d", - "sha256:5ad0ff443a785d84e2b380869fdd82e6bfc11eba6057d25b4409a9bbfa867970", - "sha256:5f0da2711364d7cb9f115b52289d4a9b61e8bca0da57f44a3a9d6fc9bdeb7274", - "sha256:5f8d02ef4431dee414d1753d13fa82a21a2f61494737b5f642ea668d76164d6d", - "sha256:60d72facd7b6b79853f19744779abcd3f804c4e0d4fa8815469db20c9f640a47", - "sha256:6181960b4b812e82e588407fe5c9c68ada267c3b084db078f248db5d7f45d18a", - "sha256:6575b2e53cc9e3e461ad6f0692a5564b96e7782c28631c7771c668770915e169", - "sha256:83db380c52087f9e9bdd8a527943b2e7324f275881125e39475c4f9277bdeec4", - "sha256:87229e42b75e89f4dad6459200f92988c5998dfb093c7c631fb48524c86cd5dc", - "sha256:8c5dcf24ede53d8abab7d8a77f69ff1936c6a8843ef4fcc574646e4be66e5739", - "sha256:8cb516ee35ed57789b46b96080edf4e503fdb62dbb2e3c6581e0d6c83fca014b", - "sha256:a20727a23b1e49c7dc7fe3c3df8e56a8a7acdade80ac2f5cca29d7ca5564c145", - "sha256:a8b15b0463d1303bab113d1a6af2860a0d79013c3a66fcc5475ce26ef717fd4f", - "sha256:a94e26c1a4950cea40116775588a2ca7cf56f1f434ff54ee35a84718f3841a3d", - "sha256:aee664a9d806612af30a19dba49e55a7a78ebfec3e9d198f6a6176e1d140ec98", - "sha256:b35ed213892e211a3ce2bea002aa1183e1a2a9b79e51bb3c6b15549a831ae528", - "sha256:bf09dbeb333c34e9c546364e7df1ff40474f9fddf9e70657ecb0e4f670ff0b0e", - "sha256:bf84d766646f1ebd706d883755df4370aaf02b48187cedaa7e4239f16bc8213d", - "sha256:d3caac7473be22b6d6e102dde6c46de73b96bc98334e577dfaee9886f102ea2e", - "sha256:d61bf8ab04c73c1da08eedaf21a103b72fa5b0a9b854762905f65ff8b375d394", - "sha256:d666c3a3faaf3b1d7fc4a544059c4eab9d06f84a604b070b7aa2f318e227798e", - "sha256:f173f851ee75e54acdaa053382b6825b400cb2085663a9bb073728a59c60aebb", - "sha256:f550281ed6e5ea88fcf04a7c6154e246d5714be495c50c9e8e6b12d3fb63e158", - "sha256:f6d6a2ccd5607cd15ef990c51e6f2dd27ec0a741e72069c387088bba3aab60fa" - ], - "index": "pypi", - "markers": "python_version >= '3.10'", - "version": "==3.7.1" - }, - "pyproject-api": { - "hashes": [ - "sha256:326df9d68dea22d9d98b5243c46e3ca3161b07a1b9b18e213d1e24fd0e605766", - "sha256:7e8a9854b2dfb49454fae421cb86af43efbb2b2454e5646ffb7623540321ae6e" - ], - "markers": "python_version >= '3.9'", - "version": "==1.9.0" - }, - "pyshp": { - "hashes": [ - "sha256:4caec82fd8dd096feba8217858068bacb2a3b5950f43c048c6dc32a3489d5af1", - "sha256:67024c0ccdc352ba5db777c4e968483782dfa78f8e200672a90d2d30fd8b7b49" - ], - "markers": "python_version >= '2.7'", - "version": "==2.3.1" - }, - "pytest": { - "hashes": [ - "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", - "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==8.3.5" - }, - "pytest-cov": { - "hashes": [ - "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", - "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==6.0.0" - }, - "pytest-xdist": { - "hashes": [ - "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7", - "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==3.6.1" - }, - "python-dateutil": { - "hashes": [ - "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", - "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", - "version": "==2.9.0.post0" - }, - "python-json-logger": { - "hashes": [ - "sha256:12b7e74b17775e7d565129296105bbe3910842d9d0eb083fc83a6a617aa8df84", - "sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7" - ], - "markers": "python_version >= '3.8'", - "version": "==3.3.0" - }, - "pyyaml": { - "hashes": [ - "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", - "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", - "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", - "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", - "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", - "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", - "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", - "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", - "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", - "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", - "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", - "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", - "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", - "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", - "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", - "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", - "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", - "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", - "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", - "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", - "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", - "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", - "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", - "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", - "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", - "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", - "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", - "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", - "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", - "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", - "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", - "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", - "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", - "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", - "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", - "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", - "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", - "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", - "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", - "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", - "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", - "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", - "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", - "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", - "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", - "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", - "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", - "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", - "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", - "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", - "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", - "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", - "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" - ], - "markers": "python_version >= '3.8'", - "version": "==6.0.2" - }, - "pyzmq": { - "hashes": [ - "sha256:009a38241c76184cb004c869e82a99f0aee32eda412c1eb44df5820324a01d25", - "sha256:016d89bee8c7d566fad75516b4e53ec7c81018c062d4c51cd061badf9539be52", - "sha256:0240289e33e3fbae44a5db73e54e955399179332a6b1d47c764a4983ec1524c3", - "sha256:03caa2ffd64252122139d50ec92987f89616b9b92c9ba72920b40e92709d5e26", - "sha256:04bfe59852d76d56736bfd10ac1d49d421ab8ed11030b4a0332900691507f557", - "sha256:0b42403ad7d1194dca9574cd3c56691c345f4601fa2d0a33434f35142baec7ac", - "sha256:0f3dfb68cf7bf4cfdf34283a75848e077c5defa4907506327282afe92780084d", - "sha256:14e0b81753424bd374075df6cc30b87f2c99e5f022501d97eff66544ca578941", - "sha256:1586944f4736515af5c6d3a5b150c7e8ca2a2d6e46b23057320584d6f2438f4a", - "sha256:1595533de3a80bf8363372c20bafa963ec4bf9f2b8f539b1d9a5017f430b84c9", - "sha256:1614fcd116275d24f2346ffca4047a741c546ad9d561cbf7813f11226ca4ed2c", - "sha256:18183cc3851b995fdc7e5f03d03b8a4e1b12b0f79dff1ec1da75069af6357a05", - "sha256:1fc81d5d60c9d40e692de14b8d884d43cf67562402b931681f0ccb3ce6b19875", - "sha256:1fe05bd0d633a0f672bb28cb8b4743358d196792e1caf04973b7898a0d70b046", - "sha256:209d09f0ab6ddbcebe64630d1e6ca940687e736f443c265ae15bc4bfad833597", - "sha256:21399b31753bf321043ea60c360ed5052cc7be20739785b1dff1820f819e35b3", - "sha256:214038aaa88e801e54c2ef0cfdb2e6df27eb05f67b477380a452b595c5ecfa37", - "sha256:21c6ddb98557a77cfe3366af0c5600fb222a1b2de5f90d9cd052b324e0c295e8", - "sha256:240b1634b9e530ef6a277d95cbca1a6922f44dfddc5f0a3cd6c722a8de867f14", - "sha256:2833602d9d42c94b9d0d2a44d2b382d3d3a4485be018ba19dddc401a464c617a", - "sha256:2aa1a9f236d5b835fb8642f27de95f9edcfd276c4bc1b6ffc84f27c6fb2e2981", - "sha256:2cf9ab0dff4dbaa2e893eb608373c97eb908e53b7d9793ad00ccbd082c0ee12f", - "sha256:2d3459b6311463c96abcb97808ee0a1abb0d932833edb6aa81c30d622fd4a12d", - "sha256:2dc46ec09f5d36f606ac8393303149e69d17121beee13c8dac25e2a2078e31c4", - "sha256:2eaed0d911fb3280981d5495978152fab6afd9fe217fd16f411523665089cef1", - "sha256:356ec0e39c5a9cda872b65aca1fd8a5d296ffdadf8e2442b70ff32e73ef597b1", - "sha256:3ec332675f6a138db57aad93ae6387953763f85419bdbd18e914cb279ee1c451", - "sha256:3fc9e71490d989144981ea21ef4fdfaa7b6aa84aff9632d91c736441ce2f6b00", - "sha256:49334faa749d55b77f084389a80654bf2e68ab5191c0235066f0140c1b670d64", - "sha256:4b127cfe10b4c56e4285b69fd4b38ea1d368099ea4273d8fb349163fce3cd598", - "sha256:4c22a12713707467abedc6d75529dd365180c4c2a1511268972c6e1d472bd63e", - "sha256:4e2cafe7e9c7fed690e8ecf65af119f9c482923b5075a78f6f7629c63e1b4b1d", - "sha256:52b064fafef772d0f5dbf52d4c39f092be7bc62d9a602fe6e82082e001326de3", - "sha256:5e17cc198dc50a25a0f245e6b1e56f692df2acec3ccae82d1f60c34bfb72bbec", - "sha256:6d64e74143587efe7c9522bb74d1448128fdf9897cc9b6d8b9927490922fd558", - "sha256:6e317ee1d4528a03506cb1c282cd9db73660a35b3564096de37de7350e7d87a7", - "sha256:6fb539a6382a048308b409d8c66d79bf636eda1b24f70c78f2a1fd16e92b037b", - "sha256:70b3acb9ad729a53d4e751dace35404a024f188aad406013454216aba5485b4e", - "sha256:73ca9ae9a9011b714cf7650450cd9c8b61a135180b708904f1f0a05004543dce", - "sha256:749d671b0eec8e738bbf0b361168369d8c682b94fcd458c20741dc4d69ef5278", - "sha256:7897b8c8bbbb2bd8cad887bffcb07aede71ef1e45383bd4d6ac049bf0af312a4", - "sha256:7998b60ef1c105846fb3bfca494769fde3bba6160902e7cd27a8df8257890ee9", - "sha256:7a4ac2ffa34f1212dd586af90f4ba894e424f0cabb3a49cdcff944925640f6ac", - "sha256:8ab78dc21c7b1e13053086bcf0b4246440b43b5409904b73bfd1156654ece8a1", - "sha256:8c088e009a6d6b9f563336adb906e3a8d3fd64db129acc8d8fd0e9fe22b2dac8", - "sha256:9176856f36c34a8aa5c0b35ddf52a5d5cd8abeece57c2cd904cfddae3fd9acd3", - "sha256:91dead2daca698ae52ce70ee2adbb94ddd9b5f96877565fd40aa4efd18ecc6a3", - "sha256:92a30840f4f2a31f7049d0a7de5fc69dd03b19bd5d8e7fed8d0bde49ce49b589", - "sha256:943a22ebb3daacb45f76a9bcca9a7b74e7d94608c0c0505da30af900b998ca8d", - "sha256:952085a09ff32115794629ba47f8940896d7842afdef1283332109d38222479d", - "sha256:96c0006a8d1d00e46cb44c8e8d7316d4a232f3d8f2ed43179d4578dbcb0829b6", - "sha256:979486d444ca3c469cd1c7f6a619ce48ff08b3b595d451937db543754bfacb65", - "sha256:9b0137a1c40da3b7989839f9b78a44de642cdd1ce20dcef341de174c8d04aa53", - "sha256:a995404bd3982c089e57b428c74edd5bfc3b0616b3dbcd6a8e270f1ee2110f36", - "sha256:aa7efc695d1fc9f72d91bf9b6c6fe2d7e1b4193836ec530a98faf7d7a7577a58", - "sha256:ad03f4252d9041b0635c37528dfa3f44b39f46024ae28c8567f7423676ee409b", - "sha256:b2db7c82f08b8ce44c0b9d1153ce63907491972a7581e8b6adea71817f119df8", - "sha256:b2eddfbbfb473a62c3a251bb737a6d58d91907f6e1d95791431ebe556f47d916", - "sha256:b380e9087078ba91e45fb18cdd0c25275ffaa045cf63c947be0ddae6186bc9d9", - "sha256:b4fc9903a73c25be9d5fe45c87faababcf3879445efa16140146b08fccfac017", - "sha256:b72206eb041f780451c61e1e89dbc3705f3d66aaaa14ee320d4f55864b13358a", - "sha256:b7b578d604e79e99aa39495becea013fd043fa9f36e4b490efa951f3d847a24d", - "sha256:ba698c7c252af83b6bba9775035263f0df5f807f0404019916d4b71af8161f66", - "sha256:bad7fe0372e505442482ca3ccbc0d6f38dae81b1650f57a0aa6bbee18e7df495", - "sha256:bbef99eb8d18ba9a40f00e8836b8040cdcf0f2fa649684cf7a66339599919d21", - "sha256:bd84441e4021cec6e4dd040550386cd9c9ea1d9418ea1a8002dbb7b576026b2b", - "sha256:be77efd735bb1064605be8dec6e721141c1421ef0b115ef54e493a64e50e9a52", - "sha256:c0b519fa2159c42272f8a244354a0e110d65175647e5185b04008ec00df9f079", - "sha256:c15b69af22030960ac63567e98ad8221cddf5d720d9cf03d85021dfd452324ef", - "sha256:c1bd75d692cd7c6d862a98013bfdf06702783b75cffbf5dae06d718fecefe8f2", - "sha256:c208a977843d18d3bd185f323e4eaa912eb4869cb230947dc6edd8a27a4e558a", - "sha256:c4430c7cba23bb0e2ee203eee7851c1654167d956fc6d4b3a87909ccaf3c5825", - "sha256:c80653332c6136da7f4d4e143975e74ac0fa14f851f716d90583bc19e8945cea", - "sha256:cf6db401f4957afbf372a4730c6d5b2a234393af723983cbf4bcd13d54c71e1a", - "sha256:cf736cc1298ef15280d9fcf7a25c09b05af016656856dc6fe5626fd8912658dd", - "sha256:d015efcd96aca8882057e7e6f06224f79eecd22cad193d3e6a0a91ec67590d1f", - "sha256:d35cc1086f1d4f907df85c6cceb2245cb39a04f69c3f375993363216134d76d4", - "sha256:d7165bcda0dbf203e5ad04d79955d223d84b2263df4db92f525ba370b03a12ab", - "sha256:d8270d104ec7caa0bdac246d31d48d94472033ceab5ba142881704350b28159c", - "sha256:da87e977f92d930a3683e10ba2b38bcc59adfc25896827e0b9d78b208b7757a6", - "sha256:e281a8071a06888575a4eb523c4deeefdcd2f5fe4a2d47e02ac8bf3a5b49f695", - "sha256:e34a63f71d2ecffb3c643909ad2d488251afeb5ef3635602b3448e609611a7ed", - "sha256:eb96568a22fe070590942cd4780950e2172e00fb033a8b76e47692583b1bd97c", - "sha256:eddc2be28a379c218e0d92e4a432805dcb0ca5870156a90b54c03cd9799f9f8a", - "sha256:efba4f53ac7752eea6d8ca38a4ddac579e6e742fba78d1e99c12c95cd2acfc64", - "sha256:f1cd68b8236faab78138a8fc703f7ca0ad431b17a3fcac696358600d4e6243b3", - "sha256:f52eba83272a26b444f4b8fc79f2e2c83f91d706d693836c9f7ccb16e6713c31", - "sha256:f950f17ae608e0786298340163cac25a4c5543ef25362dd5ddb6dcb10b547be9", - "sha256:fa85953df84beb7b8b73cb3ec3f5d92b62687a09a8e71525c6734e020edf56fd", - "sha256:fbf206e5329e20937fa19bd41cf3af06d5967f8f7e86b59d783b26b40ced755c", - "sha256:fd30fc80fe96efb06bea21667c5793bbd65c0dc793187feb39b8f96990680b00", - "sha256:fe67291775ea4c2883764ba467eb389c29c308c56b86c1e19e49c9e1ed0cbeca", - "sha256:fea7efbd7e49af9d7e5ed6c506dfc7de3d1a628790bd3a35fd0e3c904dc7d464" - ], - "markers": "python_version >= '3.8'", - "version": "==26.3.0" - }, - "readme-renderer": { - "hashes": [ - "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151", - "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1" - ], - "markers": "python_version >= '3.9'", - "version": "==44.0" - }, - "referencing": { - "hashes": [ - "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", - "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0" - ], - "markers": "python_version >= '3.9'", - "version": "==0.36.2" - }, - "requests": { - "hashes": [ - "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", - "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==2.32.3" - }, - "requests-toolbelt": { - "hashes": [ - "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", - "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.0.0" - }, - "rfc3339-validator": { - "hashes": [ - "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", - "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==0.1.4" - }, - "rfc3986": { - "hashes": [ - "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd", - "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c" - ], - "markers": "python_version >= '3.7'", - "version": "==2.0.0" - }, - "rfc3986-validator": { - "hashes": [ - "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", - "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==0.1.1" - }, - "rich": { - "hashes": [ - "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", - "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90" - ], - "markers": "python_full_version >= '3.8.0'", - "version": "==13.9.4" - }, - "roman-numerals-py": { - "hashes": [ - "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", - "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d" - ], - "markers": "python_version >= '3.9'", - "version": "==3.1.0" - }, - "rpds-py": { - "hashes": [ - "sha256:09cd7dbcb673eb60518231e02874df66ec1296c01a4fcd733875755c02014b19", - "sha256:0f3288930b947cbebe767f84cf618d2cbe0b13be476e749da0e6a009f986248c", - "sha256:0fced9fd4a07a1ded1bac7e961ddd9753dd5d8b755ba8e05acba54a21f5f1522", - "sha256:112b8774b0b4ee22368fec42749b94366bd9b536f8f74c3d4175d4395f5cbd31", - "sha256:11dd60b2ffddba85715d8a66bb39b95ddbe389ad2cfcf42c833f1bcde0878eaf", - "sha256:178f8a60fc24511c0eb756af741c476b87b610dba83270fce1e5a430204566a4", - "sha256:1b08027489ba8fedde72ddd233a5ea411b85a6ed78175f40285bd401bde7466d", - "sha256:1bf5be5ba34e19be579ae873da515a2836a2166d8d7ee43be6ff909eda42b72b", - "sha256:1ed7de3c86721b4e83ac440751329ec6a1102229aa18163f84c75b06b525ad7e", - "sha256:1eedaaccc9bb66581d4ae7c50e15856e335e57ef2734dbc5fd8ba3e2a4ab3cb6", - "sha256:243241c95174b5fb7204c04595852fe3943cc41f47aa14c3828bc18cd9d3b2d6", - "sha256:26bb3e8de93443d55e2e748e9fd87deb5f8075ca7bc0502cfc8be8687d69a2ec", - "sha256:271fa2184cf28bdded86bb6217c8e08d3a169fe0bbe9be5e8d96e8476b707122", - "sha256:28358c54fffadf0ae893f6c1050e8f8853e45df22483b7fff2f6ab6152f5d8bf", - "sha256:285019078537949cecd0190f3690a0b0125ff743d6a53dfeb7a4e6787af154f5", - "sha256:2893d778d4671ee627bac4037a075168b2673c57186fb1a57e993465dbd79a93", - "sha256:2a54027554ce9b129fc3d633c92fa33b30de9f08bc61b32c053dc9b537266fed", - "sha256:2c6ae11e6e93728d86aafc51ced98b1658a0080a7dd9417d24bfb955bb09c3c2", - "sha256:2cfa07c346a7ad07019c33fb9a63cf3acb1f5363c33bc73014e20d9fe8b01cdd", - "sha256:35d5631ce0af26318dba0ae0ac941c534453e42f569011585cb323b7774502a5", - "sha256:3614d280bf7aab0d3721b5ce0e73434acb90a2c993121b6e81a1c15c665298ac", - "sha256:3902df19540e9af4cc0c3ae75974c65d2c156b9257e91f5101a51f99136d834c", - "sha256:3aaf141d39f45322e44fc2c742e4b8b4098ead5317e5f884770c8df0c332da70", - "sha256:3d8abf7896a91fb97e7977d1aadfcc2c80415d6dc2f1d0fca5b8d0df247248f3", - "sha256:3e77febf227a1dc3220159355dba68faa13f8dca9335d97504abf428469fb18b", - "sha256:3e9212f52074fc9d72cf242a84063787ab8e21e0950d4d6709886fb62bcb91d5", - "sha256:3ee9d6f0b38efb22ad94c3b68ffebe4c47865cdf4b17f6806d6c674e1feb4246", - "sha256:4233df01a250b3984465faed12ad472f035b7cd5240ea3f7c76b7a7016084495", - "sha256:4263320ed887ed843f85beba67f8b2d1483b5947f2dc73a8b068924558bfeace", - "sha256:4ab923167cfd945abb9b51a407407cf19f5bee35001221f2911dc85ffd35ff4f", - "sha256:4caafd1a22e5eaa3732acb7672a497123354bef79a9d7ceed43387d25025e935", - "sha256:50fb62f8d8364978478b12d5f03bf028c6bc2af04082479299139dc26edf4c64", - "sha256:55ff4151cfd4bc635e51cfb1c59ac9f7196b256b12e3a57deb9e5742e65941ad", - "sha256:5b98b6c953e5c2bda51ab4d5b4f172617d462eebc7f4bfdc7c7e6b423f6da957", - "sha256:5c9ff044eb07c8468594d12602291c635da292308c8c619244e30698e7fc455a", - "sha256:5e9c206a1abc27e0588cf8b7c8246e51f1a16a103734f7750830a1ccb63f557a", - "sha256:5fb89edee2fa237584e532fbf78f0ddd1e49a47c7c8cfa153ab4849dc72a35e6", - "sha256:633462ef7e61d839171bf206551d5ab42b30b71cac8f10a64a662536e057fdef", - "sha256:66f8d2a17e5838dd6fb9be6baaba8e75ae2f5fa6b6b755d597184bfcd3cb0eba", - "sha256:6959bb9928c5c999aba4a3f5a6799d571ddc2c59ff49917ecf55be2bbb4e3722", - "sha256:698a79d295626ee292d1730bc2ef6e70a3ab135b1d79ada8fde3ed0047b65a10", - "sha256:721f9c4011b443b6e84505fc00cc7aadc9d1743f1c988e4c89353e19c4a968ee", - "sha256:72e680c1518733b73c994361e4b06441b92e973ef7d9449feec72e8ee4f713da", - "sha256:75307599f0d25bf6937248e5ac4e3bde5ea72ae6618623b86146ccc7845ed00b", - "sha256:754fba3084b70162a6b91efceee8a3f06b19e43dac3f71841662053c0584209a", - "sha256:759462b2d0aa5a04be5b3e37fb8183615f47014ae6b116e17036b131985cb731", - "sha256:7938c7b0599a05246d704b3f5e01be91a93b411d0d6cc62275f025293b8a11ce", - "sha256:7b77e07233925bd33fc0022b8537774423e4c6680b6436316c5075e79b6384f4", - "sha256:7e5413d2e2d86025e73f05510ad23dad5950ab8417b7fc6beaad99be8077138b", - "sha256:7f3240dcfa14d198dba24b8b9cb3b108c06b68d45b7babd9eefc1038fdf7e707", - "sha256:7f9682a8f71acdf59fd554b82b1c12f517118ee72c0f3944eda461606dfe7eb9", - "sha256:8d67beb6002441faef8251c45e24994de32c4c8686f7356a1f601ad7c466f7c3", - "sha256:9441af1d25aed96901f97ad83d5c3e35e6cd21a25ca5e4916c82d7dd0490a4fa", - "sha256:98b257ae1e83f81fb947a363a274c4eb66640212516becaff7bef09a5dceacaa", - "sha256:9e9f3a3ac919406bc0414bbbd76c6af99253c507150191ea79fab42fdb35982a", - "sha256:a1c66e71ecfd2a4acf0e4bd75e7a3605afa8f9b28a3b497e4ba962719df2be57", - "sha256:a1e17d8dc8e57d8e0fd21f8f0f0a5211b3fa258b2e444c2053471ef93fe25a00", - "sha256:a20cb698c4a59c534c6701b1c24a968ff2768b18ea2991f886bd8985ce17a89f", - "sha256:a970bfaf130c29a679b1d0a6e0f867483cea455ab1535fb427566a475078f27f", - "sha256:a98f510d86f689fcb486dc59e6e363af04151e5260ad1bdddb5625c10f1e95f8", - "sha256:a9d3b728f5a5873d84cba997b9d617c6090ca5721caaa691f3b1a78c60adc057", - "sha256:ad76f44f70aac3a54ceb1813ca630c53415da3a24fd93c570b2dfb4856591017", - "sha256:ae28144c1daa61366205d32abd8c90372790ff79fc60c1a8ad7fd3c8553a600e", - "sha256:b03a8d50b137ee758e4c73638b10747b7c39988eb8e6cd11abb7084266455165", - "sha256:b5a96fcac2f18e5a0a23a75cd27ce2656c66c11c127b0318e508aab436b77428", - "sha256:b5ef909a37e9738d146519657a1aab4584018746a18f71c692f2f22168ece40c", - "sha256:b79f5ced71efd70414a9a80bbbfaa7160da307723166f09b69773153bf17c590", - "sha256:b91cceb5add79ee563bd1f70b30896bd63bc5f78a11c1f00a1e931729ca4f1f4", - "sha256:b92f5654157de1379c509b15acec9d12ecf6e3bc1996571b6cb82a4302060447", - "sha256:c04ca91dda8a61584165825907f5c967ca09e9c65fe8966ee753a3f2b019fe1e", - "sha256:c1f8afa346ccd59e4e5630d5abb67aba6a9812fddf764fd7eb11f382a345f8cc", - "sha256:c5334a71f7dc1160382d45997e29f2637c02f8a26af41073189d79b95d3321f1", - "sha256:c617d7453a80e29d9973b926983b1e700a9377dbe021faa36041c78537d7b08c", - "sha256:c632419c3870507ca20a37c8f8f5352317aca097639e524ad129f58c125c61c6", - "sha256:c6760211eee3a76316cf328f5a8bd695b47b1626d21c8a27fb3b2473a884d597", - "sha256:c698d123ce5d8f2d0cd17f73336615f6a2e3bdcedac07a1291bb4d8e7d82a05a", - "sha256:c76b32eb2ab650a29e423525e84eb197c45504b1c1e6e17b6cc91fcfeb1a4b1d", - "sha256:c8f7e90b948dc9dcfff8003f1ea3af08b29c062f681c05fd798e36daa3f7e3e8", - "sha256:c9e799dac1ffbe7b10c1fd42fe4cd51371a549c6e108249bde9cd1200e8f59b4", - "sha256:cafa48f2133d4daa028473ede7d81cd1b9f9e6925e9e4003ebdf77010ee02f35", - "sha256:ce473a2351c018b06dd8d30d5da8ab5a0831056cc53b2006e2a8028172c37ce5", - "sha256:d31ed4987d72aabdf521eddfb6a72988703c091cfc0064330b9e5f8d6a042ff5", - "sha256:d550d7e9e7d8676b183b37d65b5cd8de13676a738973d330b59dc8312df9c5dc", - "sha256:d6adb81564af0cd428910f83fa7da46ce9ad47c56c0b22b50872bc4515d91966", - "sha256:d6f6512a90bd5cd9030a6237f5346f046c6f0e40af98657568fa45695d4de59d", - "sha256:d7031d493c4465dbc8d40bd6cafefef4bd472b17db0ab94c53e7909ee781b9ef", - "sha256:d9f75a06ecc68f159d5d7603b734e1ff6daa9497a929150f794013aa9f6e3f12", - "sha256:db7707dde9143a67b8812c7e66aeb2d843fe33cc8e374170f4d2c50bd8f2472d", - "sha256:e0397dd0b3955c61ef9b22838144aa4bef6f0796ba5cc8edfc64d468b93798b4", - "sha256:e0df046f2266e8586cf09d00588302a32923eb6386ced0ca5c9deade6af9a149", - "sha256:e14f86b871ea74c3fddc9a40e947d6a5d09def5adc2076ee61fb910a9014fb35", - "sha256:e5963ea87f88bddf7edd59644a35a0feecf75f8985430124c253612d4f7d27ae", - "sha256:e768267cbe051dd8d1c5305ba690bb153204a09bf2e3de3ae530de955f5b5580", - "sha256:e9cb79ecedfc156c0692257ac7ed415243b6c35dd969baa461a6888fc79f2f07", - "sha256:ed6f011bedca8585787e5082cce081bac3d30f54520097b2411351b3574e1219", - "sha256:f3429fb8e15b20961efca8c8b21432623d85db2228cc73fe22756c6637aa39e7", - "sha256:f35eff113ad430b5272bbfc18ba111c66ff525828f24898b4e146eb479a2cdda", - "sha256:f3a6cb95074777f1ecda2ca4fa7717caa9ee6e534f42b7575a8f0d4cb0c24013", - "sha256:f7356a6da0562190558c4fcc14f0281db191cdf4cb96e7604c06acfcee96df15", - "sha256:f88626e3f5e57432e6191cd0c5d6d6b319b635e70b40be2ffba713053e5147dd", - "sha256:fad784a31869747df4ac968a351e070c06ca377549e4ace94775aaa3ab33ee06", - "sha256:fc869af5cba24d45fb0399b0cfdbcefcf6910bf4dee5d74036a57cf5264b3ff4", - "sha256:fee513135b5a58f3bb6d89e48326cd5aa308e4bcdf2f7d59f67c861ada482bf8" - ], - "markers": "python_version >= '3.9'", - "version": "==0.23.1" - }, - "send2trash": { - "hashes": [ - "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9", - "sha256:b18e7a3966d99871aefeb00cfbcfdced55ce4871194810fc71f4aa484b953abf" - ], - "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" - }, - "setuptools": { - "hashes": [ - "sha256:1cc9b32ee94f93224d6c80193cbb768004667aa2f2732a473d6949b0236c1d4e", - "sha256:4321d2dc2157b976dee03e1037c9f2bc5fea503c0c47d3c9458e0e8e49e659ce" - ], - "markers": "python_version >= '3.9'", - "version": "==78.0.1" - }, - "shapely": { - "extras": [ - "vectorized" - ], - "hashes": [ - "sha256:0145387565fcf8f7c028b073c802956431308da933ef41d08b1693de49990d27", - "sha256:04a65d882456e13c8b417562c36324c0cd1e5915f3c18ad516bb32ee3f5fc895", - "sha256:06ff6020949b44baa8fc2e5e57e0f3d09486cd5c33b47d669f847c54136e7027", - "sha256:19cbc8808efe87a71150e785b71d8a0e614751464e21fb679d97e274eca7bd43", - "sha256:1a2e03277128e62f9a49a58eb7eb813fa9b343925fca5e7d631d50f4c0e8e0b8", - "sha256:1e9fed9a7d6451979d914cb6ebbb218b4b4e77c0d50da23e23d8327948662611", - "sha256:25085a30a2462cee4e850a6e3fb37431cbbe4ad51cbcc163af0cea1eaa9eb96d", - "sha256:28fe2997aab9a9dc026dc6a355d04e85841546b2a5d232ed953e3321ab958ee5", - "sha256:2934834c7f417aeb7cba3b0d9b4441a76ebcecf9ea6e80b455c33c7c62d96a24", - "sha256:2e4a1749ad64bc6e7668c8f2f9479029f079991f4ae3cb9e6b25440e35a4b532", - "sha256:2f6e4759cf680a0f00a54234902415f2fa5fe02f6b05546c662654001f0793a2", - "sha256:33fb10e50b16113714ae40adccf7670379e9ccf5b7a41d0002046ba2b8f0f691", - "sha256:35524cc8d40ee4752520819f9894b9f28ba339a42d4922e92c99b148bed3be39", - "sha256:3697bd078b4459f5a1781015854ef5ea5d824dbf95282d0b60bfad6ff83ec8dc", - "sha256:4abeb44b3b946236e4e1a1b3d2a0987fb4d8a63bfb3fdefb8a19d142b72001e5", - "sha256:4c2b9859424facbafa54f4a19b625a752ff958ab49e01bc695f254f7db1835fa", - "sha256:5aed1c6764f51011d69a679fdf6b57e691371ae49ebe28c3edb5486537ffbd51", - "sha256:5cf23400cb25deccf48c56a7cdda8197ae66c0e9097fcdd122ac2007e320bc34", - "sha256:5d6dbf096f961ca6bec5640e22e65ccdec11e676344e8157fe7d636e7904fd36", - "sha256:6bca5095e86be9d4ef3cb52d56bdd66df63ff111d580855cb8546f06c3c907cd", - "sha256:73c9ae8cf443187d784d57202199bf9fd2d4bb7d5521fe8926ba40db1bc33e8e", - "sha256:7977d8a39c4cf0e06247cd2dca695ad4e020b81981d4c82152c996346cf1094b", - "sha256:7e97104d28e60b69f9b6a957c4d3a2a893b27525bc1fc96b47b3ccef46726bf2", - "sha256:8ae5cb6b645ac3fba34ad84b32fbdccb2ab321facb461954925bde807a0d3b74", - "sha256:8f623b64bb219d62014781120f47499a7adc30cf7787e24b659e56651ceebcb0", - "sha256:98697c842d5c221408ba8aa573d4f49caef4831e9bc6b6e785ce38aca42d1999", - "sha256:a0c09e3e02f948631c7763b4fd3dd175bc45303a0ae04b000856dedebefe13cb", - "sha256:a3fb7fbae257e1b042f440289ee7235d03f433ea880e73e687f108d044b24db5", - "sha256:a7f04691ce1c7ed974c2f8b34a1fe4c3c5dfe33128eae886aa32d730f1ec1913", - "sha256:a9469f49ff873ef566864cb3516091881f217b5d231c8164f7883990eec88b73", - "sha256:aaaf5f7e6cc234c1793f2a2760da464b604584fb58c6b6d7d94144fd2692d67e", - "sha256:adeddfb1e22c20548e840403e5e0b3d9dc3daf66f05fa59f1fcf5b5f664f0e98", - "sha256:b52f3ab845d32dfd20afba86675c91919a622f4627182daec64974db9b0b4608", - "sha256:cd0e75d9124b73e06a42bf1615ad3d7d805f66871aa94538c3a9b7871d620013", - "sha256:cf6c50cd879831955ac47af9c907ce0310245f9d162e298703f82e1785e38c98", - "sha256:d8f1da01c04527f7da59ee3755d8ee112cd8967c15fab9e43bba936b81e2a013", - "sha256:dd37d65519b3f8ed8976fa4302a2827cbb96e0a461a2e504db583b08a22f0b98", - "sha256:e1c4f1071fe9c09af077a69b6c75f17feb473caeea0c3579b3e94834efcbdc36", - "sha256:e6d95703efaa64aaabf278ced641b888fc23d9c6dd71f8215091afd8a26a66e3", - "sha256:f44eda8bd7a4bccb0f281264b34bf3518d8c4c9a8ffe69a1a05dabf6e8461147", - "sha256:f86e2c0259fe598c4532acfcf638c1f520fa77c1275912bbc958faecbf00b108", - "sha256:fc19b78cc966db195024d8011649b4e22812f805dd49264323980715ab80accc" - ], - "markers": "python_version >= '3.7'", - "version": "==2.0.7" - }, - "six": { - "hashes": [ - "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", - "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", - "version": "==1.17.0" - }, - "sniffio": { - "hashes": [ - "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", - "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" - ], - "markers": "python_version >= '3.7'", - "version": "==1.3.1" - }, - "snowballstemmer": { - "hashes": [ - "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", - "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a" - ], - "version": "==2.2.0" - }, - "soupsieve": { - "hashes": [ - "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", - "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9" - ], - "markers": "python_version >= '3.8'", - "version": "==2.6" - }, - "sphinx": { - "hashes": [ - "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", - "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3" - ], - "index": "pypi", - "markers": "python_version >= '3.11'", - "version": "==8.2.3" - }, - "sphinx-autobuild": { - "hashes": [ - "sha256:158e16c36f9d633e613c9aaf81c19b0fc458ca78b112533b20dafcda430d60fa", - "sha256:248150f8f333e825107b6d4b86113ab28fa51750e5f9ae63b59dc339be951fb1" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==2024.10.3" - }, - "sphinxcontrib-applehelp": { - "hashes": [ - "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", - "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5" - ], - "markers": "python_version >= '3.9'", - "version": "==2.0.0" - }, - "sphinxcontrib-devhelp": { - "hashes": [ - "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", - "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2" - ], - "markers": "python_version >= '3.9'", - "version": "==2.0.0" - }, - "sphinxcontrib-htmlhelp": { - "hashes": [ - "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", - "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9" - ], - "markers": "python_version >= '3.9'", - "version": "==2.1.0" - }, - "sphinxcontrib-jsmath": { - "hashes": [ - "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", - "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.1" - }, - "sphinxcontrib-qthelp": { - "hashes": [ - "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", - "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb" - ], - "markers": "python_version >= '3.9'", - "version": "==2.0.0" - }, - "sphinxcontrib-serializinghtml": { - "hashes": [ - "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", - "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d" - ], - "markers": "python_version >= '3.9'", - "version": "==2.0.0" - }, - "sphinxcontrib-spelling": { - "hashes": [ - "sha256:21704857c1b5e26e06bb07d15927df41c9d7ecfc1843169ecd22cb59f24069ac", - "sha256:f0447b6413c78b613b916c7891e36be85a105d1919c99784c53dfea2d8f8040f" - ], - "index": "pypi", - "markers": "python_version >= '3.10'", - "version": "==8.0.1" - }, - "stack-data": { - "hashes": [ - "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", - "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695" - ], - "version": "==0.6.3" - }, - "starlette": { - "hashes": [ - "sha256:3c88d58ee4bd1bb807c0d1acb381838afc7752f9ddaec81bbe4383611d833230", - "sha256:77c74ed9d2720138b25875133f3a2dae6d854af2ec37dceb56aef370c1d8a227" - ], - "markers": "python_version >= '3.9'", - "version": "==0.46.1" - }, - "syrupy": { - "hashes": [ - "sha256:b7d0fcadad80a7d2f6c4c71917918e8ebe2483e8c703dfc8d49cdbb01081f9a4", - "sha256:b94cc12ed0e5e75b448255430af642516842a2374a46936dd2650cfb6dd20eda" - ], - "index": "pypi", - "markers": "python_full_version >= '3.8.1'", - "version": "==4.9.1" - }, - "terminado": { - "hashes": [ - "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", - "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e" - ], - "markers": "python_version >= '3.8'", - "version": "==0.18.1" - }, - "tinycss2": { - "hashes": [ - "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", - "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289" - ], - "markers": "python_version >= '3.8'", - "version": "==1.4.0" - }, - "tornado": { - "hashes": [ - "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803", - "sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec", - "sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482", - "sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634", - "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38", - "sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b", - "sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c", - "sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf", - "sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946", - "sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73", - "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1" - ], - "markers": "python_version >= '3.8'", - "version": "==6.4.2" - }, - "tox": { - "hashes": [ - "sha256:92e8290e76ad4e15748860a205865696409a2d014eedeb796a34a0f3b5e7336e", - "sha256:d5948b350f76fae436d6545a5e87c2b676ab7a0d7d88c1308651245eadbe8aea" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==4.24.2" - }, - "traitlets": { - "hashes": [ - "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", - "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f" - ], - "markers": "python_version >= '3.8'", - "version": "==5.14.3" - }, - "twine": { - "hashes": [ - "sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384", - "sha256:be324f6272eff91d07ee93f251edf232fc647935dd585ac003539b42404a8dbd" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==6.1.0" - }, - "types-python-dateutil": { - "hashes": [ - "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb", - "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53" - ], - "markers": "python_version >= '3.8'", - "version": "==2.9.0.20241206" - }, - "typing-extensions": { - "hashes": [ - "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", - "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" - ], - "markers": "python_version >= '3.8'", - "version": "==4.12.2" - }, - "uri-template": { - "hashes": [ - "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", - "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363" - ], - "markers": "python_version >= '3.7'", - "version": "==1.3.0" - }, - "urllib3": { - "hashes": [ - "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", - "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" - ], - "markers": "python_version >= '3.9'", - "version": "==2.3.0" - }, - "uvicorn": { - "hashes": [ - "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4", - "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9" - ], - "markers": "python_version >= '3.9'", - "version": "==0.34.0" - }, - "virtualenv": { - "hashes": [ - "sha256:3e3d00f5807e83b234dfb6122bf37cfadf4be216c53a49ac059d02414f819170", - "sha256:95e39403fcf3940ac45bc717597dba16110b74506131845d9b687d5e73d947ac" - ], - "markers": "python_version >= '3.8'", - "version": "==20.29.3" - }, - "watchfiles": { - "hashes": [ - "sha256:02a526ee5b5a09e8168314c905fc545c9bc46509896ed282aeb5a8ba9bd6ca27", - "sha256:05d341c71f3d7098920f8551d4df47f7b57ac5b8dad56558064c3431bdfc0b74", - "sha256:076f293100db3b0b634514aa0d294b941daa85fc777f9c698adb1009e5aca0b1", - "sha256:0799ae68dfa95136dde7c472525700bd48777875a4abb2ee454e3ab18e9fc712", - "sha256:0986902677a1a5e6212d0c49b319aad9cc48da4bd967f86a11bde96ad9676ca1", - "sha256:0bc80d91ddaf95f70258cf78c471246846c1986bcc5fd33ccc4a1a67fcb40f9a", - "sha256:13c2ce7b72026cfbca120d652f02c7750f33b4c9395d79c9790b27f014c8a5a2", - "sha256:1941b4e39de9b38b868a69b911df5e89dc43767feeda667b40ae032522b9b5f1", - "sha256:1eacd91daeb5158c598fe22d7ce66d60878b6294a86477a4715154990394c9b3", - "sha256:229e6ec880eca20e0ba2f7e2249c85bae1999d330161f45c78d160832e026ee2", - "sha256:22bb55a7c9e564e763ea06c7acea24fc5d2ee5dfc5dafc5cfbedfe58505e9f90", - "sha256:278aaa395f405972e9f523bd786ed59dfb61e4b827856be46a42130605fd0899", - "sha256:2a9f93f8439639dc244c4d2902abe35b0279102bca7bbcf119af964f51d53c19", - "sha256:308ac265c56f936636e3b0e3f59e059a40003c655228c131e1ad439957592303", - "sha256:31f1a379c9dcbb3f09cf6be1b7e83b67c0e9faabed0471556d9438a4a4e14202", - "sha256:32b026a6ab64245b584acf4931fe21842374da82372d5c039cba6bf99ef722f3", - "sha256:342622287b5604ddf0ed2d085f3a589099c9ae8b7331df3ae9845571586c4f3d", - "sha256:39f4914548b818540ef21fd22447a63e7be6e24b43a70f7642d21f1e73371590", - "sha256:3f68d8e9d5a321163ddacebe97091000955a1b74cd43724e346056030b0bacee", - "sha256:43b168bba889886b62edb0397cab5b6490ffb656ee2fcb22dec8bfeb371a9e12", - "sha256:47eb32ef8c729dbc4f4273baece89398a4d4b5d21a1493efea77a17059f4df8a", - "sha256:4810ea2ae622add560f4aa50c92fef975e475f7ac4900ce5ff5547b2434642d8", - "sha256:4e997802d78cdb02623b5941830ab06f8860038faf344f0d288d325cc9c5d2ff", - "sha256:4ebbeca9360c830766b9f0df3640b791be569d988f4be6c06d6fae41f187f105", - "sha256:4f8c4998506241dedf59613082d1c18b836e26ef2a4caecad0ec41e2a15e4226", - "sha256:55ccfd27c497b228581e2838d4386301227fc0cb47f5a12923ec2fe4f97b95af", - "sha256:5717021b199e8353782dce03bd8a8f64438832b84e2885c4a645f9723bf656d9", - "sha256:5c11ea22304d17d4385067588123658e9f23159225a27b983f343fcffc3e796a", - "sha256:5e0227b8ed9074c6172cf55d85b5670199c99ab11fd27d2c473aa30aec67ee42", - "sha256:62c9953cf85529c05b24705639ffa390f78c26449e15ec34d5339e8108c7c407", - "sha256:6ba473efd11062d73e4f00c2b730255f9c1bdd73cd5f9fe5b5da8dbd4a717205", - "sha256:740d103cd01458f22462dedeb5a3382b7f2c57d07ff033fbc9465919e5e1d0f3", - "sha256:74cb3ca19a740be4caa18f238298b9d472c850f7b2ed89f396c00a4c97e2d9ff", - "sha256:7b75fee5a16826cf5c46fe1c63116e4a156924d668c38b013e6276f2582230f0", - "sha256:7cf684aa9bba4cd95ecb62c822a56de54e3ae0598c1a7f2065d51e24637a3c5d", - "sha256:8012bd820c380c3d3db8435e8cf7592260257b378b649154a7948a663b5f84e9", - "sha256:857f5fc3aa027ff5e57047da93f96e908a35fe602d24f5e5d8ce64bf1f2fc733", - "sha256:8b1f135238e75d075359cf506b27bf3f4ca12029c47d3e769d8593a2024ce161", - "sha256:8d0d0630930f5cd5af929040e0778cf676a46775753e442a3f60511f2409f48f", - "sha256:90192cdc15ab7254caa7765a98132a5a41471cf739513cc9bcf7d2ffcc0ec7b2", - "sha256:95b42cac65beae3a362629950c444077d1b44f1790ea2772beaea95451c086bb", - "sha256:9745a4210b59e218ce64c91deb599ae8775c8a9da4e95fb2ee6fe745fc87d01a", - "sha256:9d1ef56b56ed7e8f312c934436dea93bfa3e7368adfcf3df4c0da6d4de959a1e", - "sha256:9eea33ad8c418847dd296e61eb683cae1c63329b6d854aefcd412e12d94ee235", - "sha256:9f25d0ba0fe2b6d2c921cf587b2bf4c451860086534f40c384329fb96e2044d1", - "sha256:9fe37a2de80aa785d340f2980276b17ef697ab8db6019b07ee4fd28a8359d2f3", - "sha256:a38320582736922be8c865d46520c043bff350956dfc9fbaee3b2df4e1740a4b", - "sha256:a462490e75e466edbb9fc4cd679b62187153b3ba804868452ef0577ec958f5ff", - "sha256:a5ae5706058b27c74bac987d615105da17724172d5aaacc6c362a40599b6de43", - "sha256:aa216f87594f951c17511efe5912808dfcc4befa464ab17c98d387830ce07b60", - "sha256:ab0311bb2ffcd9f74b6c9de2dda1612c13c84b996d032cd74799adb656af4e8b", - "sha256:ab594e75644421ae0a2484554832ca5895f8cab5ab62de30a1a57db460ce06c6", - "sha256:aee397456a29b492c20fda2d8961e1ffb266223625346ace14e4b6d861ba9c80", - "sha256:b045c800d55bc7e2cadd47f45a97c7b29f70f08a7c2fa13241905010a5493f94", - "sha256:b77d5622ac5cc91d21ae9c2b284b5d5c51085a0bdb7b518dba263d0af006132c", - "sha256:ba5bb3073d9db37c64520681dd2650f8bd40902d991e7b4cfaeece3e32561d08", - "sha256:bdef5a1be32d0b07dcea3318a0be95d42c98ece24177820226b56276e06b63b0", - "sha256:c2acfa49dd0ad0bf2a9c0bb9a985af02e89345a7189be1efc6baa085e0f72d7c", - "sha256:c7cce76c138a91e720d1df54014a047e680b652336e1b73b8e3ff3158e05061e", - "sha256:cc27a65069bcabac4552f34fd2dce923ce3fcde0721a16e4fb1b466d63ec831f", - "sha256:cdbd912a61543a36aef85e34f212e5d2486e7c53ebfdb70d1e0b060cc50dd0bf", - "sha256:cdcc92daeae268de1acf5b7befcd6cfffd9a047098199056c72e4623f531de18", - "sha256:d3452c1ec703aa1c61e15dfe9d482543e4145e7c45a6b8566978fbb044265a21", - "sha256:d6097538b0ae5c1b88c3b55afa245a66793a8fec7ada6755322e465fb1a0e8cc", - "sha256:d8d3d9203705b5797f0af7e7e5baa17c8588030aaadb7f6a86107b7247303817", - "sha256:e0611d244ce94d83f5b9aff441ad196c6e21b55f77f3c47608dcf651efe54c4a", - "sha256:f12969a3765909cf5dc1e50b2436eb2c0e676a3c75773ab8cc3aa6175c16e902", - "sha256:f44a39aee3cbb9b825285ff979ab887a25c5d336e5ec3574f1506a4671556a8d", - "sha256:f9ce064e81fe79faa925ff03b9f4c1a98b0bbb4a1b8c1b015afa93030cb21a49", - "sha256:fb2c46e275fbb9f0c92e7654b231543c7bbfa1df07cdc4b99fa73bedfde5c844", - "sha256:fc2eb5d14a8e0d5df7b36288979176fbb39672d45184fc4b1c004d7c3ce29317" - ], - "markers": "python_version >= '3.9'", - "version": "==1.0.4" - }, - "wcwidth": { - "hashes": [ - "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", - "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5" - ], - "version": "==0.2.13" - }, - "webcolors": { - "hashes": [ - "sha256:515291393b4cdf0eb19c155749a096f779f7d909f7cceea072791cb9095b92e9", - "sha256:ecb3d768f32202af770477b8b65f318fa4f566c22948673a977b00d589dd80f6" - ], - "markers": "python_version >= '3.9'", - "version": "==24.11.1" - }, - "webencodings": { - "hashes": [ - "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", - "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" - ], - "version": "==0.5.1" - }, - "websocket-client": { - "hashes": [ - "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", - "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da" - ], - "markers": "python_version >= '3.8'", - "version": "==1.8.0" - }, - "websockets": { - "hashes": [ - "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", - "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", - "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", - "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", - "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", - "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", - "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", - "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", - "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", - "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880", - "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123", - "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", - "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", - "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed", - "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", - "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411", - "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", - "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", - "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", - "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", - "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb", - "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e", - "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee", - "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f", - "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", - "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", - "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", - "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", - "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", - "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", - "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", - "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", - "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", - "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5", - "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", - "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", - "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", - "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9", - "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", - "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", - "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", - "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", - "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940", - "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", - "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", - "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", - "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", - "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b", - "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a", - "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054", - "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", - "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", - "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", - "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4", - "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", - "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", - "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", - "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b", - "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", - "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770", - "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", - "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", - "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", - "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", - "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", - "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", - "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", - "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", - "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7" - ], - "markers": "python_version >= '3.9'", - "version": "==15.0.1" - } - } -} diff --git a/README.md b/README.md new file mode 100644 index 0000000..40a447f --- /dev/null +++ b/README.md @@ -0,0 +1,135 @@ +# EEweather: Weather station wrangling for EEmeter + +[![License](https://img.shields.io/github/license/opendsm/eeweather.svg)](https://github.com/opendsm/eeweather) +[![Documentation Status](https://readthedocs.org/projects/eeweather/badge/?version=latest)](http://eeweather.readthedocs.io/en/latest/?badge=latest) +[![PyPI Version](https://img.shields.io/pypi/v/eeweather.svg)](https://pypi.python.org/pypi/eeweather) + +--- + +**EEweather** — tools for matching to and fetching data from NCEI ISD, TMY3, or CZ2010 weather stations. + +EEweather comes with a database of weather station metadata, ZCTA metadata, and GIS data that makes it easier to find the right weather station to use for a particular ZIP code or lat/long coordinate. + +[Read the docs.](https://eeweather.readthedocs.org/) + +## Installation + +EEweather is a python package and can be installed with pip. + +``` +$ pip install eeweather +``` + +## Supported Sources of Weather Data + +- NCEI Integrated Surface Database (ISD) +- Global Summary of the Day (GSOD) +- NREL Typical Meteorological Year 3 (TMY3) +- California Energy Commission 1998-2009 Weather Normals (CZ2010) + +## Features + +- Match by ZIP code (ZCTA) or by lat/long coordinates +- Use user-supplied weather station mappings +- Match within climate zones + - IECC Climate Zones + - IECC Moisture Regimes + - Building America Climate Zones + - California Building Climate Zone Areas +- User-friendly SQLite database of metadata compiled from primary sources + - US Census Bureau (ZCTAs, county shapefiles) + - Building America climate zone county lists + - NOAA NCEI Integrated Surface Database Station History + - NREL TMY3 site +- Plot maps of outputs + +## Contributing + +Dev installation: + +``` +$ python -m venv .venv +$ source .venv/bin/activate +$ pip install -e .[dev] +``` + +Build docs: + +``` +$ make -C docs html +``` + +Autobuild docs: + +``` +$ make -C docs livehtml +``` + +Check spelling in docs: + +``` +$ make -C docs spelling +``` + +Run tests: + +``` +$ pytest +``` + +Run tests on multiple python versions: + +``` +$ tox +``` + +## Use with Docker + +To use with docker-compose, use the following: + +Run a tutorial notebook (copy link w/ token, open tutorial.ipynb): + +``` +$ docker-compose up jupyter +``` + +Live-edit docs: + +``` +$ docker-compose up docs +``` + +Open a shell: + +``` +$ docker-compose run --rm shell +``` + +Run tests: + +``` +$ docker-compose run --rm test +``` + +Run the CLI: + +``` +$ docker-compose run --rm eeweather --help +``` + +## Notice Regarding CZ2010 Data + +There may be conditions placed on their international commercial use. +They can be used within the U.S. or for non-commercial international activities without restriction. +The non-U.S. data cannot be redistributed for commercial purposes. +Re-distribution of these data by others must provide this same notification. + +See [further explanation](http://weather.whiteboxtechnologies.com/faq#Q12/) here. + +## Metadata Yearly Updates + +Every year, the metadata database needs to be updated. This can be done by running: + +``` +docker-compose run --rm eeweather rebuild-db +``` diff --git a/README.rst b/README.rst deleted file mode 100644 index 708485b..0000000 --- a/README.rst +++ /dev/null @@ -1,141 +0,0 @@ -EEweather: Weather station wrangling for EEmeter -================================================ - -.. image:: https://travis-ci.org/openeemeter/eeweather.svg?branch=master - :target: https://travis-ci.org/openeemeter/eeweather - -.. image:: https://img.shields.io/github/license/openeemeter/eeweather.svg - :target: https://github.com/openeemeter/eeweather - -.. image:: https://readthedocs.org/projects/eeweather/badge/?version=latest - :target: http://eeweather.readthedocs.io/en/latest/?badge=latest - -.. image:: https://img.shields.io/pypi/v/eeweather.svg - :target: https://pypi.python.org/pypi/eeweather - -.. image:: https://codecov.io/gh/openeemeter/eeweather/branch/master/graph/badge.svg - :target: https://codecov.io/gh/openeemeter/eeweather - ---------------- - -**EEweather** — tools for matching to and fetching data from NCEI ISD, TMY3, or CZ2010 weather stations. - -EEweather comes with a database of weather station metadata, ZCTA metadata, and GIS data that makes it easier to find the right weather station to use for a particular ZIP code or lat/long coordinate. - -`Read the docs. `_ - -Installation ------------- - -EEweather is a python package and can be installed with pip. - -:: - - $ pip install eeweather - -Supported Sources of Weather Data ---------------------------------- - -- NCEI Integrated Surface Database (ISD) -- Global Summary of the Day (GSOD) -- NREL Typical Meteorological Year 3 (TMY3) -- California Energy Commission 1998-2009 Weather Normals (CZ2010) - -Features --------- - -- Match by ZIP code (ZCTA) or by lat/long coordinates -- Use user-supplied weather station mappings -- Match within climate zones - - - IECC Climate Zones - - IECC Moisture Regimes - - Building America Climate Zones - - California Building Climate Zone Areas - -- User-friendly SQLite database of metadata compiled from primary sources - - - US Census Bureau (ZCTAs, county shapefiles) - - Building America climate zone county lists - - NOAA NCEI Integrated Surface Database Station History - - NREL TMY3 site - -- Plot maps of outputs - -Contributing ------------- - -Dev installation:: - - $ pipenv --python 3.6.4 # create virtualenv with python 3.6.4 - $ pipenv install --dev # install dev requirements with pipenv - $ pipenv install -e . # install package in editable mode - $ pipenv shell # activate pipenv virtual environment - -Build docs:: - - $ make -C docs html - -Autobuild docs:: - - $ make -C docs livehtml - -Check spelling in docs:: - - $ make -C docs spelling - -Run tests:: - - $ pytest - -Run tests on multiple python versions:: - - $ tox - -Upload to pypi (using twine):: - - $ python setup.py upload - -Use with Docker ---------------- - -To use with docker-compose, use the following: - -Run a tutorial notebook (copy link w/ token, open tutorial.ipynb):: - - $ docker-compose up jupyter - -Live-edit docs:: - - $ docker-compose up docs - -Open a shell:: - - $ docker-compose run --rm shell - -Run tests:: - - $ docker-compose run --rm test - -Run the CLI:: - - $ docker-compose run --rm eeweather --help - - -Notice Regarding CZ2010 Data ----------------------------- - -There may be conditions placed on their international commercial use. -They can be used within the U.S. or for non-commercial international activities without restriction. -The non-U.S. data cannot be redistributed for commercial purposes. -Re-distribution of these data by others must provide this same notification. - -See `further explanation `_ here. - -Metadata Yearly Updates ------------------------ -Every year, the metadata database needs to be updated. This can be done by running: - -``` -docker-compose run --rm eeweather rebuild-db -``` diff --git a/bump_version.sh b/bump_version.sh deleted file mode 100755 index dc9f723..0000000 --- a/bump_version.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -#################################### -# # -# Prints commands necessary to # -# do a version bump. Usage: # -# # -# ./bump_version.sh X.X.X Y.Y.Y # -# # -# where X.X.X is the old version # -# and X.X.X is the new version # -# # -#################################### - -set -e # fail script on any error, show commands - -OLD_VERSION=$1 # e.g., 0.0.0 -NEW_VERSION=$2 # e.g., 0.0.1 -NEW_VERSION_LENGTH=$(printf "%s" "$NEW_VERSION" | wc -c) -DASHES=$(printf "%${NEW_VERSION_LENGTH}s" | sed 's/ /-/g') - -echo "git checkout master" -echo "git pull" -echo "git checkout -b release/v${NEW_VERSION}" -echo "" -echo "sed -i -e 's/${OLD_VERSION}/${NEW_VERSION}/g' eeweather/__version__.py" -echo "sed -i -e '/Development/,/-----------/ c\\ -Development\\ ------------\\ -\\ -* Placeholder\\ -\\ -${NEW_VERSION}\\ -${DASHES}\\ -' CHANGELOG.md" -echo "rm -f eeweather/__version__.py-e" -echo "rm -f CHANGELOG.md-e" -echo "" -echo "git commit -am \"Bump version\"" -echo "git tag v${NEW_VERSION}" -echo "git push -u origin release/v${NEW_VERSION} --tags" -echo "docker-compose run --rm python setup.py upload" -echo "git checkout master" -echo "git pull" -echo "git merge release/v${NEW_VERSION}" -echo "git push" diff --git a/eeweather/access_api.py b/eeweather/access_api.py index 7675fec..5a07bde 100644 --- a/eeweather/access_api.py +++ b/eeweather/access_api.py @@ -24,17 +24,21 @@ import csv import io -import attrs +from dataclasses import dataclass + import requests -import retry + + + +API_REQUEST_TRIES = 3 class DatasetType: - ISD = "IDS" + ISD = "ISD" GSOD = "GSOD" -@attrs.define +@dataclass class FileParseResult: """ contains information about file that will be useful @@ -95,10 +99,12 @@ def from_file_path(cls, file_path: str): usaf_id, wban_id, year = file_name_dash_split year = int(year) - return FileParseResult( + result = FileParseResult( dataset_type=dataset_type, usaf_id=usaf_id, wban_id=wban_id, year=year ) + return result + def _get_api_request_params(dataset_type: str, usaf_id: str, wban_id: str, year: int): params = {} @@ -123,7 +129,6 @@ def _get_api_request_params(dataset_type: str, usaf_id: str, wban_id: str, year: return params -@retry.retry(tries=3) def make_api_request( dataset_type: str, usaf_id: str, wban_id: str, year: int ) -> list[tuple[datetime.datetime, float]]: @@ -131,6 +136,9 @@ def make_api_request( makes api request to the access api when given the necessary information about the weather station to fetch data for. + the request is retried on connection and http errors, as the api has been + shown to intermittently fail. + returns a list of tuples where the first element is the datetime and the second is the temperature that the datetime refers to """ @@ -138,11 +146,17 @@ def make_api_request( dataset_type=dataset_type, usaf_id=usaf_id, wban_id=wban_id, year=year ) - resp = requests.get( - url="https://www.ncei.noaa.gov/access/services/data/v1", params=params - ) - - resp.raise_for_status() + for attempt in range(API_REQUEST_TRIES): + try: + resp = requests.get( + url="https://www.ncei.noaa.gov/access/services/data/v1", params=params + ) + resp.raise_for_status() + except requests.RequestException: + if attempt == API_REQUEST_TRIES - 1: + raise + else: + break csv_data = io.StringIO(resp.text) dict_reader = csv.DictReader(csv_data) diff --git a/eeweather/cache.py b/eeweather/cache.py index 491a58b..cf04880 100644 --- a/eeweather/cache.py +++ b/eeweather/cache.py @@ -17,47 +17,38 @@ limitations under the License. """ -import os +import contextlib +import datetime import json +import os +import sqlite3 -try: - from sqlalchemy import ( - create_engine, - MetaData, - Table, - Column, - String, - DateTime, - ) - from sqlalchemy.orm import Session - from sqlalchemy.sql import select, func - from sqlalchemy.exc import IntegrityError -except ImportError: # pragma: no cover - has_sqlalchemy = False -else: - has_sqlalchemy = True import pytz -def get_datetime_if_exists(data): - if data is None: - return None - else: - dt = data[0] - if is_tz_naive(dt): - return pytz.UTC.localize(data[0]) - else: - return dt +SQLITE_URL_PREFIX = "sqlite:///" + + +def _sqlite_path_from_url(url): + if not url.startswith(SQLITE_URL_PREFIX): + raise ValueError( + "EEweather cache urls must have the form sqlite:///path/to/cache.db," + " got: {}".format(url) + ) -def is_tz_naive(dt): - return dt.tzinfo is None or dt.tzinfo.utcoffset(dt) is None + return url[len(SQLITE_URL_PREFIX) :] class KeyValueStore(object): + """JSON key-value store on a local sqlite database. + + The database location is taken from the url argument, the + EEWEATHER_CACHE_URL environment variable, or ~/.eeweather/cache.db, + in that order. Urls have the form sqlite:///path/to/cache.db. + """ + def __init__(self, url=None): - if not has_sqlalchemy: # pragma: no cover - raise ImportError("KeyValueStore requires sqlalchemy.") self._prepare_db(url) def __repr__(self): @@ -70,76 +61,70 @@ def _get_url(self): # pragma: no cover (tests always provide url) if not os.path.exists(directory): os.makedirs(directory) url = "sqlite:///{}/cache.db".format(directory) + return url def _prepare_db(self, url=None): - # set url if url is None: # pragma: no cover (tests always provide url) url = self._get_url() self.url = url - self.eng = create_engine(url) - metadata = MetaData() - - tbl_items = Table( - "items", - metadata, - Column("key", String, unique=True, index=True), # arbitrary unique key - Column("data", String), # arbitrary json - Column("updated", DateTime(timezone=True)), # time of last transaction - ) - - # only create if not already created - tbl_items.create(checkfirst=True, bind=self.eng) + self._path = _sqlite_path_from_url(url) + with self._connect() as conn, conn: + conn.execute( + "create table if not exists items (" + " key text unique," + " data text," + " updated text)" + ) + conn.execute("create index if not exists ix_items_key on items (key)") - self.items = tbl_items + def _connect(self): + # closes the connection on exit; writes commit via the inner + # transaction context in each caller + return contextlib.closing(sqlite3.connect(self._path)) def key_exists(self, key): - s = select(self.items.c.key).where(self.items.c.key == key) - with Session(self.eng) as session: - result = session.execute(s) - return result.fetchone() is not None + with self._connect() as conn: + row = conn.execute("select 1 from items where key = ?", (key,)).fetchone() + + return row is not None def save_json(self, key, data): data = json.dumps(data, separators=(",", ":")) - updated = func.now() - try: - s = self.items.insert().values(key=key, data=data, updated=updated) - with Session(self.eng) as session: - session.execute(s) - session.commit() - except IntegrityError: - s = ( - self.items.update() - .where(self.items.c.key == key) - .values(key=key, data=data, updated=updated) + updated = datetime.datetime.now(pytz.UTC).isoformat() + with self._connect() as conn, conn: + conn.execute( + "insert into items (key, data, updated) values (?, ?, ?)" + " on conflict (key) do update set data = ?, updated = ?", + (key, data, updated, data, updated), ) - with Session(self.eng) as session: - session.execute(s) - session.commit() def retrieve_json(self, key): - s = select(self.items.c.data).where(self.items.c.key == key) - with Session(self.eng) as session: - result = session.execute(s) - data = result.fetchone() - if data is None: - return None - else: - return json.loads(data[0]) + with self._connect() as conn: + row = conn.execute( + "select data from items where key = ?", (key,) + ).fetchone() + + if row is None: + return None + + return json.loads(row[0]) def key_updated(self, key): - s = select(self.items.c.updated).where(self.items.c.key == key) - with Session(self.eng) as session: - result = session.execute(s) - data = result.fetchone() - return get_datetime_if_exists(data) + with self._connect() as conn: + row = conn.execute( + "select updated from items where key = ?", (key,) + ).fetchone() + + if row is None: + return None + + return datetime.datetime.fromisoformat(row[0]) def clear(self, key=None): - if key is None: - s = self.items.delete() - else: - s = self.items.delete().where(self.items.c.key == key) - with Session(self.eng) as session: - session.execute(s) - session.commit() + with self._connect() as conn, conn: + if key is None: + conn.execute("delete from items") + else: + conn.execute("delete from items where key = ?", (key,)) diff --git a/eeweather/connections.py b/eeweather/connections.py index a03166b..46d5bdb 100644 --- a/eeweather/connections.py +++ b/eeweather/connections.py @@ -23,6 +23,7 @@ import logging import os import sqlite3 +import threading from .cache import KeyValueStore @@ -91,16 +92,33 @@ def read_file_as_bytes(self, filename): # pragma: no cover class MetadataDBConnectionProxy(object): + """Serves a cached read connection to the packaged metadata database. + + Connections are cached per thread and reused, so callers do not close + them. + """ + def __init__(self): root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) path = os.path.join(root_dir, "eeweather", "resources") self.db_path = os.path.join(path, "metadata.db") + self._local = threading.local() def get_connection(self): - return sqlite3.connect(self.db_path) + connection = getattr(self._local, "connection", None) + if connection is None: + connection = sqlite3.connect(self.db_path) + self._local.connection = connection + + return connection def reset_database(self): # pragma: no cover + connection = getattr(self._local, "connection", None) + if connection is not None: + connection.close() + self._local.connection = None os.remove(self.db_path) + return self.get_connection() diff --git a/eeweather/stations.py b/eeweather/stations.py index 93bf6cf..741f0c8 100644 --- a/eeweather/stations.py +++ b/eeweather/stations.py @@ -19,6 +19,8 @@ """ from datetime import datetime, timedelta, timezone import gzip +import warnings as pywarnings + import pandas as pd import pytz @@ -115,6 +117,73 @@ def _datetime_is_utc(dt): return False if orig_tzinfo is None else dt.utcoffset().seconds == 0 +TRAILING_GAP_WARNING_THRESHOLD = timedelta(days=1) +INTERNAL_GAP_WARNING_THRESHOLD = timedelta(days=7) + + +def _data_gap_warnings(ts): + """EEWeatherWarnings for requested ranges the returned data does not cover. + + Emitted when the series is entirely empty, when it ends more than + TRAILING_GAP_WARNING_THRESHOLD before the end of the requested range, or + when it contains an internal gap longer than INTERNAL_GAP_WARNING_THRESHOLD. + """ + warnings = [] + if len(ts) == 0: + return warnings + + if ts.isna().all(): + warnings.append( + EEWeatherWarning( + qualified_name="eeweather.no_data_in_requested_range", + description="No data was available within the requested range.", + data={ + "requested_start": ts.index[0].isoformat(), + "requested_end": ts.index[-1].isoformat(), + }, + ) + ) + + return warnings + + last_valid = ts.last_valid_index() + trailing_gap = ts.index[-1] - last_valid + if trailing_gap > TRAILING_GAP_WARNING_THRESHOLD: + warnings.append( + EEWeatherWarning( + qualified_name="eeweather.data_truncated", + description=( + "Data ends {} before the end of the requested range.".format( + trailing_gap + ) + ), + data={ + "last_valid": last_valid.isoformat(), + "requested_end": ts.index[-1].isoformat(), + }, + ) + ) + + interior = ts.loc[ts.first_valid_index() : last_valid] + if len(interior) > 1: + period = interior.index[1] - interior.index[0] + is_missing = interior.isna() + max_gap_periods = int(is_missing.groupby((~is_missing).cumsum()).sum().max()) + max_gap = max_gap_periods * period + if max_gap > INTERNAL_GAP_WARNING_THRESHOLD: + warnings.append( + EEWeatherWarning( + qualified_name="eeweather.data_gap", + description=( + "Data contains an internal gap of {}.".format(max_gap) + ), + data={"max_gap_days": max_gap / timedelta(days=1)}, + ) + ) + + return warnings + + def get_isd_filenames(usaf_id, target_year=None, filename_format=None, with_host=False): valid_usaf_id_or_raise(usaf_id) if filename_format is None: @@ -864,7 +933,7 @@ def load_isd_hourly_temp_data( end, read_from_cache=True, write_to_cache=True, - error_on_missing_years=False, + error_on_missing_years=True, fetch_from_web=True, ): warnings = [] @@ -894,7 +963,6 @@ def load_isd_hourly_temp_data( data={"year": year}, ) ) - pass else: data = [ load_isd_hourly_temp_data_cached_proxy( @@ -907,99 +975,145 @@ def load_isd_hourly_temp_data( for year in range(start.year, end.year + 1) ] - # get raw data from loaded years into hourly form - ts = pd.concat(data).resample("h").mean() + if data: + # get raw data from loaded years into hourly form + ts = pd.concat(data).resample("h").mean() - # whittle down to desired range - ts = ts[start:end] + # whittle down to desired range + ts = ts[start:end] + else: + ts = pd.Series([], dtype=float, index=pd.DatetimeIndex([], tz=pytz.UTC)) + + # because start and end dates need to fall exactly on hours + ts_start = datetime(start.year, start.month, start.day, start.hour, tzinfo=pytz.UTC) + # add an hour if not already exactly on an hour, which guarantees + # that ts_start is greater than or equal to start. + if ts_start < start: + ts_start += timedelta(seconds=3600) + ts_end = datetime(end.year, end.month, end.day, end.hour, tzinfo=pytz.UTC) + + # fill in gaps, covering the full requested range even when no data loaded + ts = ts.reindex(pd.date_range(ts_start, ts_end, freq="h", tz=pytz.UTC)) + warnings.extend(_data_gap_warnings(ts)) - if len(ts) > 0: - # because start and end dates need.to fall exactly on hours - ts_start = datetime( - start.year, start.month, start.day, start.hour, tzinfo=pytz.UTC - ) - # add an hour if not already exactly on an hour, which guarantees - # that ts_start is greater than or equal to start. - if ts_start < start: - ts_start += timedelta(seconds=3600) - ts_end = datetime(end.year, end.month, end.day, end.hour, tzinfo=pytz.UTC) - # fill in gaps - ts = ts.reindex(pd.date_range(ts_start, ts_end, freq="h", tz=pytz.UTC)) return ts, warnings def load_isd_daily_temp_data( - usaf_id, start, end, read_from_cache=True, write_to_cache=True, fetch_from_web=True + usaf_id, + start, + end, + read_from_cache=True, + write_to_cache=True, + error_on_missing_years=True, + fetch_from_web=True, ): # CalTRACK 2.3.3 if start.tzinfo != pytz.UTC: raise NonUTCTimezoneInfoError(start) if end.tzinfo != pytz.UTC: raise NonUTCTimezoneInfoError(end) - data = [ - load_isd_daily_temp_data_cached_proxy( - usaf_id, - year, - read_from_cache=read_from_cache, - write_to_cache=write_to_cache, - fetch_from_web=fetch_from_web, - ) - for year in range(start.year, end.year + 1) - ] - # get raw data - ts = pd.concat(data).resample("D").mean() + data = [] + for year in range(start.year, end.year + 1): + try: + data.append( + load_isd_daily_temp_data_cached_proxy( + usaf_id, + year, + read_from_cache=read_from_cache, + write_to_cache=write_to_cache, + fetch_from_web=fetch_from_web, + ) + ) + except ISDDataNotAvailableError: + if error_on_missing_years: + raise + pywarnings.warn( + "eeweather: ISD data not available for {} in {}".format(usaf_id, year) + ) - # whittle down - ts = ts[start:end] + if data: + # get raw data + ts = pd.concat(data).resample("D").mean() + + # whittle down + ts = ts[start:end] + else: + ts = pd.Series([], dtype=float, index=pd.DatetimeIndex([], tz=pytz.UTC)) + + # because start and end dates need to fall exactly on days + ts_start = datetime(start.year, start.month, start.day, tzinfo=pytz.UTC) + # add a day if not already exactly on a day, which guarantees + # that ts_start is greater than or equal to start. + if ts_start < start: + ts_start += timedelta(days=1) + ts_end = datetime(end.year, end.month, end.day, tzinfo=pytz.UTC) + + # fill in gaps, covering the full requested range even when no data loaded + ts = ts.reindex(pd.date_range(ts_start, ts_end, freq="D", tz=pytz.UTC)) + for warning in _data_gap_warnings(ts): + pywarnings.warn("eeweather: {}".format(warning.description)) - if len(ts) > 0: - # because start and end dates need.to fall exactly on days - ts_start = datetime(start.year, start.month, start.day, tzinfo=pytz.UTC) - # add a day if not already exactly on a day, which guarantees - # that ts_start is greater than or equal to start. - if ts_start < start: - ts_start += timedelta(days=1) - ts_end = datetime(end.year, end.month, end.day, tzinfo=pytz.UTC) - # fill in gaps - ts = ts.reindex(pd.date_range(ts_start, ts_end, freq="D", tz=pytz.UTC)) return ts def load_gsod_daily_temp_data( - usaf_id, start, end, read_from_cache=True, write_to_cache=True, fetch_from_web=True + usaf_id, + start, + end, + read_from_cache=True, + write_to_cache=True, + error_on_missing_years=True, + fetch_from_web=True, ): # CalTRACK 2.3.3 if start.tzinfo != pytz.UTC: raise NonUTCTimezoneInfoError(start) if end.tzinfo != pytz.UTC: raise NonUTCTimezoneInfoError(end) - data = [ - load_gsod_daily_temp_data_cached_proxy( - usaf_id, - year, - read_from_cache=read_from_cache, - write_to_cache=write_to_cache, - fetch_from_web=fetch_from_web, - ) - for year in range(start.year, end.year + 1) - ] - # get raw data - ts = pd.concat(data).resample("D").mean() - # whittle down - ts = ts[start:end] + data = [] + for year in range(start.year, end.year + 1): + try: + data.append( + load_gsod_daily_temp_data_cached_proxy( + usaf_id, + year, + read_from_cache=read_from_cache, + write_to_cache=write_to_cache, + fetch_from_web=fetch_from_web, + ) + ) + except GSODDataNotAvailableError: + if error_on_missing_years: + raise + pywarnings.warn( + "eeweather: GSOD data not available for {} in {}".format(usaf_id, year) + ) + + if data: + # get raw data + ts = pd.concat(data).resample("D").mean() + + # whittle down + ts = ts[start:end] + else: + ts = pd.Series([], dtype=float, index=pd.DatetimeIndex([], tz=pytz.UTC)) + + # because start and end dates need to fall exactly on days + ts_start = datetime(start.year, start.month, start.day, tzinfo=pytz.UTC) + # add a day if not already exactly on a day, which guarantees + # that ts_start is greater than or equal to start. + if ts_start < start: + ts_start += timedelta(days=1) + ts_end = datetime(end.year, end.month, end.day, tzinfo=pytz.UTC) + + # fill in gaps, covering the full requested range even when no data loaded + ts = ts.reindex(pd.date_range(ts_start, ts_end, freq="D", tz=pytz.UTC)) + for warning in _data_gap_warnings(ts): + pywarnings.warn("eeweather: {}".format(warning.description)) - if len(ts) > 0: - # because start and end dates need.to fall exactly on days - ts_start = datetime(start.year, start.month, start.day, tzinfo=pytz.UTC) - # add a day if not already exactly on a day, which guarantees - # that ts_start is greater than or equal to start. - if ts_start < start: - ts_start += timedelta(days=1) - ts_end = datetime(end.year, end.month, end.day, tzinfo=pytz.UTC) - # fill in gaps - ts = ts.reindex(pd.date_range(ts_start, ts_end, freq="D", tz=pytz.UTC)) return ts @@ -1509,7 +1623,13 @@ def load_isd_hourly_temp_data( ) def load_isd_daily_temp_data( - self, start, end, read_from_cache=True, write_to_cache=True, fetch_from_web=True + self, + start, + end, + read_from_cache=True, + write_to_cache=True, + fetch_from_web=True, + error_on_missing_years=True, ): """Load resampled daily ISD temperature data from start date to end date (inclusive). @@ -1524,9 +1644,12 @@ def load_isd_daily_temp_data( read_from_cache : bool Whether or not to load data from cache. fetch_from_web : bool - Whether or not to fetch data from ftp. + Whether or not to fetch data from the web. write_to_cache : bool Whether or not to write newly loaded data to cache. + error_on_missing_years : bool + Whether to raise when data is unavailable for a year in the range, + or to warn and fill that year with NaN. """ return load_isd_daily_temp_data( self.usaf_id, @@ -1535,10 +1658,17 @@ def load_isd_daily_temp_data( read_from_cache=read_from_cache, write_to_cache=write_to_cache, fetch_from_web=fetch_from_web, + error_on_missing_years=error_on_missing_years, ) def load_gsod_daily_temp_data( - self, start, end, read_from_cache=True, write_to_cache=True, fetch_from_web=True + self, + start, + end, + read_from_cache=True, + write_to_cache=True, + fetch_from_web=True, + error_on_missing_years=True, ): """Load resampled daily GSOD temperature data from start date to end date (inclusive). @@ -1555,7 +1685,10 @@ def load_gsod_daily_temp_data( write_to_cache : bool Whether or not to write newly loaded data to cache. fetch_from_web : bool - Whether or not to fetch data from ftp. + Whether or not to fetch data from the web. + error_on_missing_years : bool + Whether to raise when data is unavailable for a year in the range, + or to warn and fill that year with NaN. """ return load_gsod_daily_temp_data( self.usaf_id, @@ -1564,6 +1697,7 @@ def load_gsod_daily_temp_data( read_from_cache=read_from_cache, write_to_cache=write_to_cache, fetch_from_web=fetch_from_web, + error_on_missing_years=error_on_missing_years, ) def load_tmy3_hourly_temp_data( diff --git a/eeweather/testing.py b/eeweather/testing.py index 1fc2486..dd2d02a 100644 --- a/eeweather/testing.py +++ b/eeweather/testing.py @@ -20,8 +20,8 @@ import datetime import pytz +from importlib.resources import files from io import BytesIO -import pkg_resources import re import tempfile @@ -29,41 +29,37 @@ from eeweather.cache import KeyValueStore + +def _resource_bytes(name): + return files("eeweather.resources").joinpath(name).read_bytes() + + def write_isd_file(bytes_string): - with pkg_resources.resource_stream("eeweather.resources", "ISD.gz") as f: - bytes_string.write(f.read()) + bytes_string.write(_resource_bytes("ISD.gz")) def write_tmy3_file(): - data = pkg_resources.resource_string("eeweather.resources", "722880TYA.CSV") - return data.decode("ascii") + return _resource_bytes("722880TYA.CSV").decode("ascii") def write_cz2010_file(): - data = pkg_resources.resource_string("eeweather.resources", "722880_CZ2010.CSV") - return data.decode("ascii") + return _resource_bytes("722880_CZ2010.CSV").decode("ascii") def write_missing_isd_file(bytes_string): - with pkg_resources.resource_stream("eeweather.resources", "ISD-MISSING.gz") as f: - bytes_string.write(f.read()) + bytes_string.write(_resource_bytes("ISD-MISSING.gz")) def write_nan_isd_file(bytes_string): - with pkg_resources.resource_stream("eeweather.resources", "ISD-NAN.gz") as f: - bytes_string.write(f.read()) + bytes_string.write(_resource_bytes("ISD-NAN.gz")) def write_gsod_file(bytes_string): - with pkg_resources.resource_stream("eeweather.resources", "GSOD.op.gz") as f: - bytes_string.write(f.read()) + bytes_string.write(_resource_bytes("GSOD.op.gz")) def write_missing_gsod_file(bytes_string): - with pkg_resources.resource_stream( - "eeweather.resources", "GSOD-MISSING.op.gz" - ) as f: - bytes_string.write(f.read()) + bytes_string.write(_resource_bytes("GSOD-MISSING.op.gz")) def mock_request_text_tmy3(url): @@ -98,6 +94,7 @@ def read_file_as_bytes(self, filename): write_missing_gsod_file(bytes_string) bytes_string.seek(0) + return bytes_string @@ -116,38 +113,56 @@ def get_store(self): def monkey_patch_make_api_request_return_empty( dataset_type: str, usaf_id: str, wban_id: str, year: int ): - if usaf_id == "722874" and year == 2006 and dataset_type == "GSOD": - return [(datetime.datetime(2006, 1, 4, 0, 0, 0, tzinfo=pytz.UTC), float("nan"))] + single_nan_day = ( + datetime.datetime(2006, 1, 4, 0, 0, 0, tzinfo=pytz.UTC), + float("nan"), + ) + + return [single_nan_day] if usaf_id == "722874" and year == 2006: return [] if usaf_id == "722874" and year == 2005: - return [(datetime.datetime(2005, 1, 1, 0, 0, 0), float("nan"))] + single_naive_nan_day = (datetime.datetime(2005, 1, 1, 0, 0, 0), float("nan")) + + return [single_naive_nan_day] - return _original_make_api_request( + result = _original_make_api_request( dataset_type=dataset_type, usaf_id=usaf_id, wban_id=wban_id, year=year ) + return result + def monkey_patch_make_api_request_return_empty_v2( dataset_type: str, usaf_id: str, wban_id: str, year: int ): - if usaf_id == "722874" and year == 2006: - return [(datetime.datetime(2006, 1, 4, 0, 0, 0, tzinfo=pytz.UTC), float("nan"))] + single_nan_day = ( + datetime.datetime(2006, 1, 4, 0, 0, 0, tzinfo=pytz.UTC), + float("nan"), + ) + + return [single_nan_day] if usaf_id == "722874" and year == 2005: - return [(datetime.datetime(2005, 1, 1, 0, 0, 0), float("nan"))] + single_naive_nan_day = (datetime.datetime(2005, 1, 1, 0, 0, 0), float("nan")) + + return [single_naive_nan_day] if usaf_id == "994035": start_date = datetime.datetime(2013, 1, 1, 0, 0, 0) - return [ + nan_hours = [ (start_date + datetime.timedelta(hours=1) * i, float("nan")) for i in range(8611) ] - return _original_make_api_request( + return nan_hours + + result = _original_make_api_request( dataset_type=dataset_type, usaf_id=usaf_id, wban_id=wban_id, year=year ) + + return result diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..53070ad --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,83 @@ +[build-system] +requires = ["hatchling>=1.27"] +build-backend = "hatchling.build" + +[project] +name = "eeweather" +dynamic = ["version"] +description = "Weather station wrangling for EEmeter" +readme = "README.md" +requires-python = ">=3.10" +license = "Apache-2.0" +license-files = ["LICENSE"] +authors = [{ name = "opendsm", email = "opendsm@lists.lfenergy.org" }] +classifiers = [ + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", +] + +dependencies = [ + "click", + "pandas>=1.0.0", + "pyproj>=1.9.6", + "pytz", + "requests", + "shapely", +] + +[project.optional-dependencies] +dev = [ + "black", + "coverage", + "pytest", + "pytest-cov", + "pytest-xdist", + "syrupy>=5,<6", + "tox", +] + +[project.scripts] +eeweather = "eeweather.cli:cli" + +[project.urls] +Homepage = "https://github.com/opendsm/eeweather" +Documentation = "https://eeweather.readthedocs.io" +Repository = "https://github.com/opendsm/eeweather" +Issues = "https://github.com/opendsm/eeweather/issues" + +[tool.hatch.version] +path = "eeweather/__version__.py" + +[tool.hatch.build.targets.wheel] +packages = ["eeweather"] + +[tool.pytest.ini_options] +# --cov / --cov-report are off by default to keep normal runs fast; coverage +# runs via `tox -e coverage`. +addopts = [ + "-n", "auto", # parallel run (pytest-xdist) + "-vv", # verbose +] +filterwarnings = [ + "error", +] + +[tool.coverage.run] +omit = [ + ".tox/*", + # metadata-db rebuild code; runs against live primary sources, not unit-testable + "eeweather/database.py", +] + +[tool.coverage.report] +exclude_lines = [ + "pragma: no cover", + "if __name__ == .__main__.:", + "raise NotImplementedError", +] +# Conservative floor for `tox -e coverage`. Raise it as test coverage is +# added. The full suite measures 95.3%. +fail_under = 94 diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 6c7d969..0000000 --- a/pytest.ini +++ /dev/null @@ -1,13 +0,0 @@ -[pytest] -addopts = - # run in parallel - requires pytest-xdist - -n auto - - # show coverage - --cov=./ - - # show lines missing coverage - --cov-report term-missing - - # verbose output - -vv diff --git a/setup.py b/setup.py deleted file mode 100644 index f08bbfc..0000000 --- a/setup.py +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" - -Copyright 2018-2023 OpenEEmeter contributors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -""" -# Setup.py inspired by https://github.com/kennethreitz/setup.py - -# Note: To use the 'upload' functionality of this file, you must: -# $ pip install twine - -import io -import os -import sys -from shutil import rmtree - -from setuptools import find_packages, setup, Command - -NAME = "eeweather" -REQUIRED = ["click", "pandas>=1.0.0", "pyproj>=1.9.6", "requests", "shapely", "retry"] - -here = os.path.abspath(os.path.dirname(__file__)) - -# Import the README and use it as the long-description. -with io.open(os.path.join(here, "README.rst"), encoding="utf-8") as f: - long_description = "\n" + f.read() - -# Load the package's __version__.py module as a dictionary. -about = {} -with open(os.path.join(here, NAME, "__version__.py")) as f: - exec(f.read(), about) - - -class UploadCommand(Command): - """Support setup.py upload.""" - - description = "Build and publish the package." - user_options = [] - - @staticmethod - def status(s): - """Prints things in bold.""" - print("\033[1m{0}\033[0m".format(s)) - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - try: - self.status("Removing previous builds…") - rmtree(os.path.join(here, "dist")) - except OSError: - pass - - self.status("Building Source and Wheel (universal) distribution…") - os.system("{0} setup.py sdist bdist_wheel --universal".format(sys.executable)) - - self.status("Uploading the package to PyPi via Twine…") - os.system("twine upload dist/*") - - sys.exit() - - -# Where the magic happens: -setup( - name=NAME, - version=about["__version__"], - description=about["__description__"], - long_description=long_description, - author=about["__author__"], - author_email=about["__author_email__"], - url=about["__url__"], - packages=find_packages(exclude=("tests",)), - entry_points={"console_scripts": ["eeweather=eeweather.cli:cli"]}, - install_requires=REQUIRED, - include_package_data=True, - license=about["__license__"], - classifiers=[ - "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - ], - # $ setup.py publish support. - cmdclass={"upload": UploadCommand}, -) diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..14a80a1 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" + +Copyright 2018-2023 OpenEEmeter contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +""" +import gzip + +from pathlib import Path + +import pytest + + + +FIXTURE_DIR = Path(__file__).parent / "fixtures" + +ACCESS_API_URL = "https://www.ncei.noaa.gov/access/services/data/v1" + + +class MockAccessAPIResponse: + def __init__(self, text): + self.text = text + + def raise_for_status(self): + pass + + +@pytest.fixture +def mock_api_transport(monkeypatch): + """Serve captured NCEI access api payloads for all api requests. + + Fixture files are real responses recorded from the api, named + {dataset}_{station}_{year}.csv.gz. A request with no matching fixture + fails the test; no request reaches the network. + """ + + def mock_get(url, params=None, **kwargs): + assert url == ACCESS_API_URL, "unexpected url: {}".format(url) + name = "{}_{}_{}.csv.gz".format( + params["dataset"], params["stations"], params["startDate"][:4] + ) + path = FIXTURE_DIR / name + if not path.exists(): + raise AssertionError( + "no captured fixture for {}; tests must not hit the network".format( + name + ) + ) + + with gzip.open(path, "rb") as f: + text = f.read().decode() + + return MockAccessAPIResponse(text) + + monkeypatch.setattr("eeweather.access_api.requests.get", mock_get) diff --git a/tests/fixtures/global-hourly_72019300117_2019.csv.gz b/tests/fixtures/global-hourly_72019300117_2019.csv.gz new file mode 100644 index 0000000..cb45a15 Binary files /dev/null and b/tests/fixtures/global-hourly_72019300117_2019.csv.gz differ diff --git a/tests/fixtures/global-hourly_72287493134_1800.csv.gz b/tests/fixtures/global-hourly_72287493134_1800.csv.gz new file mode 100644 index 0000000..60ff10e Binary files /dev/null and b/tests/fixtures/global-hourly_72287493134_1800.csv.gz differ diff --git a/tests/fixtures/global-hourly_72287493134_2005.csv.gz b/tests/fixtures/global-hourly_72287493134_2005.csv.gz new file mode 100644 index 0000000..a0d1030 Binary files /dev/null and b/tests/fixtures/global-hourly_72287493134_2005.csv.gz differ diff --git a/tests/fixtures/global-hourly_72287493134_2006.csv.gz b/tests/fixtures/global-hourly_72287493134_2006.csv.gz new file mode 100644 index 0000000..3c567d3 Binary files /dev/null and b/tests/fixtures/global-hourly_72287493134_2006.csv.gz differ diff --git a/tests/fixtures/global-hourly_72287493134_2007.csv.gz b/tests/fixtures/global-hourly_72287493134_2007.csv.gz new file mode 100644 index 0000000..5a3c56f Binary files /dev/null and b/tests/fixtures/global-hourly_72287493134_2007.csv.gz differ diff --git a/tests/fixtures/global-hourly_72287493134_2025.csv.gz b/tests/fixtures/global-hourly_72287493134_2025.csv.gz new file mode 100644 index 0000000..12d5d21 Binary files /dev/null and b/tests/fixtures/global-hourly_72287493134_2025.csv.gz differ diff --git a/tests/fixtures/global-hourly_72287493134_2050.csv.gz b/tests/fixtures/global-hourly_72287493134_2050.csv.gz new file mode 100644 index 0000000..3fa97ef Binary files /dev/null and b/tests/fixtures/global-hourly_72287493134_2050.csv.gz differ diff --git a/tests/fixtures/global-hourly_72494023234_2025.csv.gz b/tests/fixtures/global-hourly_72494023234_2025.csv.gz new file mode 100644 index 0000000..05ac885 Binary files /dev/null and b/tests/fixtures/global-hourly_72494023234_2025.csv.gz differ diff --git a/tests/fixtures/global-summary-of-the-day_72019300117_2019.csv.gz b/tests/fixtures/global-summary-of-the-day_72019300117_2019.csv.gz new file mode 100644 index 0000000..b20c4c3 Binary files /dev/null and b/tests/fixtures/global-summary-of-the-day_72019300117_2019.csv.gz differ diff --git a/tests/fixtures/global-summary-of-the-day_72287493134_1800.csv.gz b/tests/fixtures/global-summary-of-the-day_72287493134_1800.csv.gz new file mode 100644 index 0000000..80d7e70 Binary files /dev/null and b/tests/fixtures/global-summary-of-the-day_72287493134_1800.csv.gz differ diff --git a/tests/fixtures/global-summary-of-the-day_72287493134_2005.csv.gz b/tests/fixtures/global-summary-of-the-day_72287493134_2005.csv.gz new file mode 100644 index 0000000..3d5862a Binary files /dev/null and b/tests/fixtures/global-summary-of-the-day_72287493134_2005.csv.gz differ diff --git a/tests/fixtures/global-summary-of-the-day_72287493134_2006.csv.gz b/tests/fixtures/global-summary-of-the-day_72287493134_2006.csv.gz new file mode 100644 index 0000000..a0b0a7b Binary files /dev/null and b/tests/fixtures/global-summary-of-the-day_72287493134_2006.csv.gz differ diff --git a/tests/fixtures/global-summary-of-the-day_72287493134_2007.csv.gz b/tests/fixtures/global-summary-of-the-day_72287493134_2007.csv.gz new file mode 100644 index 0000000..d82c4df Binary files /dev/null and b/tests/fixtures/global-summary-of-the-day_72287493134_2007.csv.gz differ diff --git a/tests/fixtures/global-summary-of-the-day_72287493134_2025.csv.gz b/tests/fixtures/global-summary-of-the-day_72287493134_2025.csv.gz new file mode 100644 index 0000000..4191d9f Binary files /dev/null and b/tests/fixtures/global-summary-of-the-day_72287493134_2025.csv.gz differ diff --git a/tests/fixtures/global-summary-of-the-day_72287493134_2050.csv.gz b/tests/fixtures/global-summary-of-the-day_72287493134_2050.csv.gz new file mode 100644 index 0000000..b739853 Binary files /dev/null and b/tests/fixtures/global-summary-of-the-day_72287493134_2050.csv.gz differ diff --git a/tests/fixtures/global-summary-of-the-day_72494023234_2025.csv.gz b/tests/fixtures/global-summary-of-the-day_72494023234_2025.csv.gz new file mode 100644 index 0000000..8f405cb Binary files /dev/null and b/tests/fixtures/global-summary-of-the-day_72494023234_2025.csv.gz differ diff --git a/tests/test_access_api.py b/tests/test_access_api.py new file mode 100644 index 0000000..da64017 --- /dev/null +++ b/tests/test_access_api.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" + +Copyright 2018-2023 OpenEEmeter contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +""" +import gzip + +from pathlib import Path + +import pytest +import requests + +from eeweather.access_api import ( + API_REQUEST_TRIES, + DatasetType, + FileParseResult, + _get_api_request_params, + make_api_request, +) + + + +FIXTURE_DIR = Path(__file__).parent / "fixtures" + + +def _fixture_head(name, n_rows=1): + """Header plus the first n_rows data rows of a captured api payload.""" + with gzip.open(FIXTURE_DIR / name, "rb") as f: + lines = f.read().decode().strip().split("\n") + + return "\n".join(lines[: n_rows + 1]) + "\n" + + +class MockResponse: + def __init__(self, text): + self.text = text + + def raise_for_status(self): + pass + + +def test_file_parse_result_from_isd_file_path(): + result = FileParseResult.from_file_path("/pub/data/noaa/2007/722874-93134-2007.gz") + + assert result.dataset_type == DatasetType.ISD + assert result.usaf_id == "722874" + assert result.wban_id == "93134" + assert result.year == 2007 + + +def test_file_parse_result_from_gsod_file_path(): + result = FileParseResult.from_file_path( + "/pub/data/gsod/2007/722874-93134-2007.op.gz" + ) + + assert result.dataset_type == DatasetType.GSOD + assert result.usaf_id == "722874" + assert result.wban_id == "93134" + assert result.year == 2007 + + +def test_file_parse_result_ambiguous_path_raises(): + with pytest.raises(ValueError, match="ambiguous"): + FileParseResult.from_file_path("/pub/data/gsod/noaa/722874-93134-2007.gz") + + +def test_file_parse_result_unrecognized_path_raises(): + with pytest.raises(ValueError, match="cannot be determined"): + FileParseResult.from_file_path("/pub/data/other/722874-93134-2007.gz") + + +def test_get_api_request_params_unsupported_dataset_raises(): + with pytest.raises(ValueError, match="not supported"): + _get_api_request_params("UNSUPPORTED", "722874", "93134", 2007) + + +def test_make_api_request_retries_then_raises(monkeypatch): + calls = [] + + def failing_get(url, params=None): + calls.append(url) + raise requests.ConnectionError("refused") + + monkeypatch.setattr("eeweather.access_api.requests.get", failing_get) + + with pytest.raises(requests.ConnectionError): + make_api_request(DatasetType.ISD, "722874", "93134", 2007) + + assert len(calls) == API_REQUEST_TRIES + + +def test_make_api_request_succeeds_after_transient_failure(monkeypatch): + # first captured 2007 observation for 722874 is +0150,5 -> 15.0 C + payload = _fixture_head("global-hourly_72287493134_2007.csv.gz") + calls = [] + + def flaky_get(url, params=None): + calls.append(url) + if len(calls) == 1: + raise requests.ConnectionError("refused") + + return MockResponse(payload) + + monkeypatch.setattr("eeweather.access_api.requests.get", flaky_get) + + elements = make_api_request(DatasetType.ISD, "722874", "93134", 2007) + + assert len(calls) == 2 + assert len(elements) == 1 + assert elements[0][1] == pytest.approx(15.0, abs=1e-9) + + +def test_make_api_request_missing_isd_temp_parses_as_nan(monkeypatch): + # 722874's 2025 observations report temperature as missing (+9999,9) + payload = _fixture_head("global-hourly_72287493134_2025.csv.gz") + + def mock_get(url, params=None): + return MockResponse(payload) + + monkeypatch.setattr("eeweather.access_api.requests.get", mock_get) + + elements = make_api_request(DatasetType.ISD, "722874", "93134", 2025) + + assert len(elements) == 1 + assert elements[0][1] != elements[0][1] # NaN + + +def test_make_api_request_gsod_converts_fahrenheit_to_celsius(monkeypatch): + # first captured 2007 GSOD observation for 722874 is 56.0 F -> 13.333 C + payload = _fixture_head("global-summary-of-the-day_72287493134_2007.csv.gz") + + def mock_get(url, params=None): + return MockResponse(payload) + + monkeypatch.setattr("eeweather.access_api.requests.get", mock_get) + + elements = make_api_request(DatasetType.GSOD, "722874", "93134", 2007) + + assert len(elements) == 1 + assert elements[0][1] == pytest.approx((56.0 - 32.0) * 5.0 / 9.0, abs=1e-9) + + +def test_make_api_request_malformed_isd_temp_raises(monkeypatch): + # a captured observation with its scale suffix stripped; valid payloads + # always carry a "value,quality" pair, so a bare value must be rejected + payload = _fixture_head("global-hourly_72287493134_2007.csv.gz").replace( + "+0150,5", "+0150" + ) + + def mock_get(url, params=None): + return MockResponse(payload) + + monkeypatch.setattr("eeweather.access_api.requests.get", mock_get) + + with pytest.raises(ValueError, match="unexpected temp value"): + make_api_request(DatasetType.ISD, "722874", "93134", 2007) diff --git a/tests/test_cache.py b/tests/test_cache.py index 404ee62..ebba018 100644 --- a/tests/test_cache.py +++ b/tests/test_cache.py @@ -18,14 +18,13 @@ """ import tempfile -from eeweather.cache import KeyValueStore, get_datetime_if_exists -from datetime import datetime -from datetime import UTC -import pytz +from eeweather.cache import KeyValueStore +from datetime import datetime, timezone import pytest + @pytest.fixture def s(): return KeyValueStore("sqlite:///{}/cache.db".format(tempfile.mkdtemp())) @@ -46,7 +45,8 @@ def test_key_value_store(s): assert data["b"][1] == "two" assert data["b"][2] == 3.0 dt1 = s.key_updated("a") - assert dt1.date() == datetime.now(UTC).date() + assert dt1.tzinfo is not None + assert dt1.date() == datetime.now(timezone.utc).date() # update key 'a' s.save_json("a", ["updated"]) @@ -73,15 +73,6 @@ def test_key_value_store_clear_single_key(s): assert s.key_exists("b") is False -def test_get_datetime_if_exists(s): - data = None - result = get_datetime_if_exists(data) - assert result == None - - data = [datetime(2018, 1, 1)] - result = get_datetime_if_exists(data) - assert result == pytz.utc.localize(datetime(2018, 1, 1)) - - data = [pytz.utc.localize(datetime(2018, 1, 1))] - result = get_datetime_if_exists(data) - assert result == pytz.utc.localize(datetime(2018, 1, 1)) +def test_key_value_store_rejects_non_sqlite_url(): + with pytest.raises(ValueError, match="sqlite:///"): + KeyValueStore("postgresql://user@host/db") diff --git a/tests/test_cli.py b/tests/test_cli.py index bb0d9f9..94a5a8c 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -30,10 +30,11 @@ ) + def test_eeweather_cli(): runner = CliRunner() - result = runner.invoke(cli) + result = runner.invoke(cli, ["--help"]) assert result.exit_code == 0 assert len(result.output) > 100 diff --git a/tests/test_stations.py b/tests/test_stations.py index ca16790..139786d 100644 --- a/tests/test_stations.py +++ b/tests/test_stations.py @@ -19,7 +19,9 @@ """ from datetime import datetime import pandas as pd +import contextlib import pytest +import sqlite3 import pytz from eeweather import ( @@ -98,22 +100,14 @@ NonUTCTimezoneInfoError, ) from eeweather.testing import ( - MockNOAAFTPConnectionProxy, MockKeyValueStoreProxy, mock_request_text_tmy3, mock_request_text_cz2010, ) import eeweather.testing -from sqlalchemy.orm import Session -@pytest.fixture -def monkeypatch_noaa_ftp(monkeypatch): - monkeypatch.setattr( - "eeweather.connections.noaa_ftp_connection_proxy", MockNOAAFTPConnectionProxy() - ) - @pytest.fixture def monkeypatch_tmy3_request(monkeypatch): @@ -136,7 +130,7 @@ def monkeypatch_key_value_store(monkeypatch): @pytest.fixture -def monkeypatch_make_api_request(monkeypatch): +def monkeypatch_make_api_request(monkeypatch, mock_api_transport): monkeypatch.setattr( "eeweather.access_api.make_api_request", eeweather.testing.monkey_patch_make_api_request_return_empty, @@ -144,13 +138,20 @@ def monkeypatch_make_api_request(monkeypatch): @pytest.fixture -def monkeypatch_make_api_request_v2(monkeypatch): +def monkeypatch_make_api_request_v2(monkeypatch, mock_api_transport): monkeypatch.setattr( "eeweather.access_api.make_api_request", eeweather.testing.monkey_patch_make_api_request_return_empty_v2, ) + +def _backdate_cache_key(store, key, updated): + with contextlib.closing(sqlite3.connect(store._path)) as conn, conn: + conn.execute( + "update items set updated = ? where key = ?", (updated.isoformat(), key) + ) + def test_get_isd_station_metadata(): assert get_isd_station_metadata("722874") == { "ba_climate_zone": "Hot-Dry", @@ -397,27 +398,27 @@ def test_isd_station_get_isd_file_metadata(): # fetch raw -def test_fetch_isd_raw_temp_data(monkeypatch_noaa_ftp): +def test_fetch_isd_raw_temp_data(mock_api_transport): data = fetch_isd_raw_temp_data("722874", 2007) assert round(data.sum()) == pytest.approx(185945, 0.00001) assert data.shape == (11094,) -def test_fetch_gsod_raw_temp_data(monkeypatch_noaa_ftp): +def test_fetch_gsod_raw_temp_data(mock_api_transport): data = fetch_gsod_raw_temp_data("722874", 2007) assert data.sum() == pytest.approx(6509.5, 0.00001) assert data.shape == (365,) # station fetch raw -def test_isd_station_fetch_isd_raw_temp_data(monkeypatch_noaa_ftp): +def test_isd_station_fetch_isd_raw_temp_data(mock_api_transport): station = ISDStation("722874") data = station.fetch_isd_raw_temp_data(2007) assert round(data.sum()) == pytest.approx(185945, 0.00001) assert data.shape == (11094,) -def test_isd_station_fetch_gsod_raw_temp_data(monkeypatch_noaa_ftp): +def test_isd_station_fetch_gsod_raw_temp_data(mock_api_transport): station = ISDStation("722874") data = station.fetch_gsod_raw_temp_data(2007) assert data.sum() == pytest.approx(6509.5, 0.00001) @@ -436,12 +437,12 @@ def test_fetch_gsod_raw_temp_data_invalid_station(): # fetch raw invalid year -def test_fetch_isd_raw_temp_data_invalid_year(monkeypatch_noaa_ftp): +def test_fetch_isd_raw_temp_data_invalid_year(mock_api_transport): with pytest.raises(ISDDataNotAvailableError): fetch_isd_raw_temp_data("722874", 1800) -def test_fetch_gsod_raw_temp_data_invalid_year(monkeypatch_noaa_ftp): +def test_fetch_gsod_raw_temp_data_invalid_year(mock_api_transport): with pytest.raises(GSODDataNotAvailableError): fetch_gsod_raw_temp_data("722874", 1800) @@ -455,19 +456,19 @@ def test_isd_station_fetch_isd_raw_temp_data_all_nan(monkeypatch_make_api_reques # fetch -def test_fetch_isd_hourly_temp_data(monkeypatch_noaa_ftp): +def test_fetch_isd_hourly_temp_data(mock_api_transport): data = fetch_isd_hourly_temp_data("722874", 2007) assert data.sum() == pytest.approx(156160.0355, 0.00001) assert data.shape == (8760,) -def test_fetch_isd_daily_temp_data(monkeypatch_noaa_ftp): +def test_fetch_isd_daily_temp_data(mock_api_transport): data = fetch_isd_daily_temp_data("722874", 2007) assert data.sum() == pytest.approx(6510.002260821784, 0.00001) assert data.shape == (365,) -def test_fetch_gsod_daily_temp_data(monkeypatch_noaa_ftp): +def test_fetch_gsod_daily_temp_data(mock_api_transport): data = fetch_gsod_daily_temp_data("722874", 2007) assert data.sum() == pytest.approx(6509.5, 0.00001) assert data.shape == (365,) @@ -486,21 +487,21 @@ def test_fetch_cz2010_hourly_temp_data(monkeypatch_cz2010_request): # station fetch -def test_isd_station_fetch_isd_hourly_temp_data(monkeypatch_noaa_ftp): +def test_isd_station_fetch_isd_hourly_temp_data(mock_api_transport): station = ISDStation("722874") data = station.fetch_isd_hourly_temp_data(2007) assert data.sum() == pytest.approx(156160.0355, 0.00001) assert data.shape == (8760,) -def test_isd_station_fetch_isd_daily_temp_data(monkeypatch_noaa_ftp): +def test_isd_station_fetch_isd_daily_temp_data(mock_api_transport): station = ISDStation("722874") data = station.fetch_isd_daily_temp_data(2007) assert data.sum() == pytest.approx(6510, 0.00001) assert data.shape == (365,) -def test_isd_station_fetch_gsod_daily_temp_data(monkeypatch_noaa_ftp): +def test_isd_station_fetch_gsod_daily_temp_data(mock_api_transport): station = ISDStation("722874") data = station.fetch_gsod_daily_temp_data(2007) assert data.sum() == pytest.approx(6509.5, 0.00001) @@ -547,7 +548,7 @@ def test_fetch_cz2010_hourly_temp_data_invalid(): fetch_cz2010_hourly_temp_data("INVALID") -def test_fetch_tmy3_hourly_temp_data_not_in_tmy3_list(monkeypatch_noaa_ftp): +def test_fetch_tmy3_hourly_temp_data_not_in_tmy3_list(mock_api_transport): data = fetch_isd_hourly_temp_data("722874", 2007) assert data.sum() == pytest.approx(156160.0355, 0.00001) assert data.shape == (8760,) @@ -651,21 +652,21 @@ def test_isd_station_cached_gsod_daily_temp_data_is_expired_empty( # cache expired false def test_cached_isd_hourly_temp_data_is_expired_false( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): load_isd_hourly_temp_data_cached_proxy("722874", 2007) assert cached_isd_hourly_temp_data_is_expired("722874", 2007) is False def test_cached_isd_daily_temp_data_is_expired_false( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): load_isd_daily_temp_data_cached_proxy("722874", 2007) assert cached_isd_daily_temp_data_is_expired("722874", 2007) is False def test_cached_gsod_daily_temp_data_is_expired_false( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): load_gsod_daily_temp_data_cached_proxy("722874", 2007) assert cached_gsod_daily_temp_data_is_expired("722874", 2007) is False @@ -673,61 +674,43 @@ def test_cached_gsod_daily_temp_data_is_expired_false( # cache expired true def test_cached_isd_hourly_temp_data_is_expired_true( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): load_isd_hourly_temp_data_cached_proxy("722874", 2007) # manually expire key value item key = get_isd_hourly_temp_data_cache_key("722874", 2007) - store = monkeypatch_key_value_store - s = ( - store.items.update() - .where(store.items.c.key == key) - .values(updated=pytz.UTC.localize(datetime(2007, 3, 3))) + _backdate_cache_key( + monkeypatch_key_value_store, key, pytz.UTC.localize(datetime(2007, 3, 3)) ) - with Session(store.eng) as session: - session.execute(s) - session.commit() assert cached_isd_hourly_temp_data_is_expired("722874", 2007) is True def test_cached_isd_daily_temp_data_is_expired_true( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): load_isd_daily_temp_data_cached_proxy("722874", 2007) # manually expire key value item key = get_isd_daily_temp_data_cache_key("722874", 2007) - store = monkeypatch_key_value_store - s = ( - store.items.update() - .where(store.items.c.key == key) - .values(updated=pytz.UTC.localize(datetime(2007, 3, 3))) + _backdate_cache_key( + monkeypatch_key_value_store, key, pytz.UTC.localize(datetime(2007, 3, 3)) ) - with Session(store.eng) as session: - session.execute(s) - session.commit() assert cached_isd_daily_temp_data_is_expired("722874", 2007) is True def test_cached_gsod_daily_temp_data_is_expired_true( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): load_gsod_daily_temp_data_cached_proxy("722874", 2007) # manually expire key value item key = get_gsod_daily_temp_data_cache_key("722874", 2007) - store = monkeypatch_key_value_store - s = ( - store.items.update() - .where(store.items.c.key == key) - .values(updated=pytz.UTC.localize(datetime(2007, 3, 3))) + _backdate_cache_key( + monkeypatch_key_value_store, key, pytz.UTC.localize(datetime(2007, 3, 3)) ) - with Session(store.eng) as session: - session.execute(s) - session.commit() assert cached_gsod_daily_temp_data_is_expired("722874", 2007) is True @@ -791,35 +774,35 @@ def test_isd_station_validate_cz2010_hourly_temp_data_cache_empty( # error on non-existent when relying on cache def test_raise_on_missing_isd_hourly_temp_data_cache_data_no_web_fetch( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): with pytest.raises(ISDDataNotAvailableError): load_isd_hourly_temp_data_cached_proxy("722874", 1907, fetch_from_web=False) def test_raise_on_missing_isd_daily_temp_data_cache_data_no_web_fetch( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): with pytest.raises(ISDDataNotAvailableError): load_isd_daily_temp_data_cached_proxy("722874", 1907, fetch_from_web=False) def test_raise_on_missing_gsod_daily_temp_data_cache_data_no_web_fetch( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): with pytest.raises(GSODDataNotAvailableError): load_gsod_daily_temp_data_cached_proxy("722874", 1907, fetch_from_web=False) def test_raise_on_missing_tmy3_hourly_temp_data_cache_data_no_web_fetch( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): with pytest.raises(TMY3DataNotAvailableError): load_tmy3_hourly_temp_data_cached_proxy("722874", fetch_from_web=False) def test_raise_on_missing_cz2010_hourly_temp_data_cache_data_no_web_fetch( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): with pytest.raises(CZ2010DataNotAvailableError): load_cz2010_hourly_temp_data_cached_proxy("722874", fetch_from_web=False) @@ -827,21 +810,21 @@ def test_raise_on_missing_cz2010_hourly_temp_data_cache_data_no_web_fetch( # validate updated recently def test_validate_isd_hourly_temp_data_cache_updated_recently( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): load_isd_hourly_temp_data_cached_proxy("722874", 2007) assert validate_isd_hourly_temp_data_cache("722874", 2007) is True def test_validate_isd_daily_temp_data_cache_updated_recently( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): load_isd_daily_temp_data_cached_proxy("722874", 2007) assert validate_isd_daily_temp_data_cache("722874", 2007) is True def test_validate_gsod_daily_temp_data_cache_updated_recently( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): load_gsod_daily_temp_data_cached_proxy("722874", 2007) assert validate_gsod_daily_temp_data_cache("722874", 2007) is True @@ -863,63 +846,44 @@ def test_validate_cz2010_hourly_temp_data_cache_updated_recently( # validate expired def test_validate_isd_hourly_temp_data_cache_expired( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): load_isd_hourly_temp_data_cached_proxy("722874", 2007) # manually expire key value item key = get_isd_hourly_temp_data_cache_key("722874", 2007) - store = monkeypatch_key_value_store - s = ( - store.items.update() - .where(store.items.c.key == key) - .values(updated=pytz.UTC.localize(datetime(2007, 3, 3))) + _backdate_cache_key( + monkeypatch_key_value_store, key, pytz.UTC.localize(datetime(2007, 3, 3)) ) - with Session(store.eng) as session: - session.execute(s) - session.commit() assert validate_isd_hourly_temp_data_cache("722874", 2007) is False def test_validate_isd_daily_temp_data_cache_expired( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): load_isd_daily_temp_data_cached_proxy("722874", 2007) # manually expire key value item key = get_isd_daily_temp_data_cache_key("722874", 2007) - store = monkeypatch_key_value_store - s = ( - store.items.update() - .where(store.items.c.key == key) - .values(updated=pytz.UTC.localize(datetime(2007, 3, 3))) + _backdate_cache_key( + monkeypatch_key_value_store, key, pytz.UTC.localize(datetime(2007, 3, 3)) ) - with Session(store.eng) as session: - session.execute(s) - session.commit() assert validate_isd_daily_temp_data_cache("722874", 2007) is False def test_validate_gsod_daily_temp_data_cache_expired( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): load_gsod_daily_temp_data_cached_proxy("722874", 2007) # manually expire key value item key = get_gsod_daily_temp_data_cache_key("722874", 2007) - store = monkeypatch_key_value_store - s = ( - store.items.update() - .where(store.items.c.key == key) - .values(updated=pytz.UTC.localize(datetime(2007, 3, 3))) + _backdate_cache_key( + monkeypatch_key_value_store, key, pytz.UTC.localize(datetime(2007, 3, 3)) ) - with Session(store.eng) as session: - session.execute(s) - session.commit() - assert validate_gsod_daily_temp_data_cache("722874", 2007) is False @@ -1256,7 +1220,7 @@ def test_isd_station_write_read_destroy_cz2010_hourly_temp_data_to_from_cache( # load cached proxy def test_load_isd_hourly_temp_data_cached_proxy( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): # doesn't yet guarantee that all code paths are taken, # except that coverage picks it up either here or elsewhere @@ -1267,7 +1231,7 @@ def test_load_isd_hourly_temp_data_cached_proxy( def test_load_isd_daily_temp_data_cached_proxy( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): # doesn't yet guarantee that all code paths are taken, # except that coverage picks it up either here or elsewhere @@ -1278,7 +1242,7 @@ def test_load_isd_daily_temp_data_cached_proxy( def test_load_gsod_daily_temp_data_cached_proxy( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): # doesn't yet guarantee that all code paths are taken, # except that coverage picks it up either here or elsewhere @@ -1312,7 +1276,7 @@ def test_load_cz2010_hourly_temp_data_cached_proxy( # station load cached proxy def test_isd_station_load_isd_hourly_temp_data_cached_proxy( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): station = ISDStation("722874") @@ -1325,7 +1289,7 @@ def test_isd_station_load_isd_hourly_temp_data_cached_proxy( def test_isd_station_load_isd_daily_temp_data_cached_proxy( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): station = ISDStation("722874") @@ -1338,7 +1302,7 @@ def test_isd_station_load_isd_daily_temp_data_cached_proxy( def test_isd_station_load_gsod_daily_temp_data_cached_proxy( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): station = ISDStation("722874") @@ -1468,14 +1432,14 @@ def test_load_cz2010_hourly_temp_data( end = datetime(2007, 4, 3, tzinfo=pytz.UTC) ts = load_cz2010_hourly_temp_data("722880", start, end) assert ts.index[0] == start - assert pd.notnull(ts[1]) + assert pd.notnull(ts.iloc[1]) assert ts.index[-1] == end assert pd.notnull(ts.iloc[-1]) # station load data between dates def test_isd_station_load_isd_hourly_temp_data( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): station = ISDStation("722874") start = datetime(2007, 3, 3, tzinfo=pytz.UTC) @@ -1486,7 +1450,7 @@ def test_isd_station_load_isd_hourly_temp_data( def test_isd_station_load_isd_daily_temp_data( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): station = ISDStation("722874") start = datetime(2007, 3, 3, tzinfo=pytz.UTC) @@ -1497,7 +1461,7 @@ def test_isd_station_load_isd_daily_temp_data( def test_isd_station_load_gsod_daily_temp_data( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): station = ISDStation("722874") start = datetime(2007, 3, 3, tzinfo=pytz.UTC) @@ -1531,7 +1495,7 @@ def test_isd_station_load_cz2010_hourly_temp_data( # load cached def test_load_cached_isd_hourly_temp_data( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): ts = load_cached_isd_hourly_temp_data("722874") assert ts is None @@ -1547,7 +1511,7 @@ def test_load_cached_isd_hourly_temp_data( def test_load_cached_isd_daily_temp_data( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): ts = load_cached_isd_daily_temp_data("722874") assert ts is None @@ -1563,7 +1527,7 @@ def test_load_cached_isd_daily_temp_data( def test_load_cached_gsod_daily_temp_data( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): ts = load_cached_gsod_daily_temp_data("722874") assert ts is None @@ -1612,7 +1576,7 @@ def test_load_cached_cz2010_hourly_temp_data( # station load cached def test_isd_station_load_cached_isd_hourly_temp_data( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): station = ISDStation("722874") @@ -1630,7 +1594,7 @@ def test_isd_station_load_cached_isd_hourly_temp_data( def test_isd_station_load_cached_isd_daily_temp_data( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): station = ISDStation("722874") @@ -1648,7 +1612,7 @@ def test_isd_station_load_cached_isd_daily_temp_data( def test_isd_station_load_cached_gsod_daily_temp_data( - monkeypatch_noaa_ftp, monkeypatch_key_value_store + mock_api_transport, monkeypatch_key_value_store ): station = ISDStation("722874") @@ -1852,3 +1816,249 @@ def test_isd_station_load_isd_hourly_temp_data_missing_years( assert pd.isnull(ts.iloc[0]) assert ts.index[-1] == end assert pd.notnull(ts.iloc[-1]) + + +# station 720193's 2019 data has a real mid-year outage +def test_load_isd_hourly_temp_data_warns_on_internal_gap( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2019, 1, 1, tzinfo=pytz.UTC) + end = datetime(2019, 12, 31, tzinfo=pytz.UTC) + + ts, warnings = load_isd_hourly_temp_data("720193", start, end) + + assert len(ts) == 8737 + assert int(ts.notna().sum()) == 8106 + assert [w.qualified_name for w in warnings] == ["eeweather.data_gap"] + assert warnings[0].data["max_gap_days"] == pytest.approx(16.125, abs=1e-9) + + +def test_load_gsod_daily_temp_data_warns_on_internal_gap( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2019, 1, 1, tzinfo=pytz.UTC) + end = datetime(2019, 12, 31, tzinfo=pytz.UTC) + + with pytest.warns(UserWarning, match="internal gap of 25 days"): + ts = load_gsod_daily_temp_data("720193", start, end) + + assert len(ts) == 365 + assert int(ts.notna().sum()) == 340 + assert ts.mean() == pytest.approx(12.24902, abs=1e-5) + + +# a trailing gap shorter than a day does not warn: station 724940's last +# 2025 observation is 17 hours before the requested end +def test_load_isd_hourly_temp_data_short_trailing_gap_no_warning( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2025, 6, 1, tzinfo=pytz.UTC) + end = datetime(2025, 8, 28, tzinfo=pytz.UTC) + + ts, warnings = load_isd_hourly_temp_data("724940", start, end) + + assert len(ts) == 2113 + assert int(ts.notna().sum()) == 2096 + assert ts.last_valid_index() == datetime(2025, 8, 27, 7, tzinfo=pytz.UTC) + assert warnings == [] + + +# regression pins on real captured 2007 data +def test_load_isd_hourly_temp_data_2007_regression_values( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2007, 1, 1, tzinfo=pytz.UTC) + end = datetime(2007, 12, 31, tzinfo=pytz.UTC) + + ts, warnings = load_isd_hourly_temp_data("722874", start, end) + + assert len(ts) == 8737 + assert int(ts.notna().sum()) == 8732 + assert ts.mean() == pytest.approx(17.851869, abs=1e-5) + assert ts.first_valid_index() == datetime(2007, 1, 1, tzinfo=pytz.UTC) + assert ts.dropna().iloc[0] == pytest.approx(14.89, abs=1e-5) + assert warnings == [] + + +def test_load_isd_daily_temp_data_2007_regression_values( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2007, 1, 1, tzinfo=pytz.UTC) + end = datetime(2007, 12, 31, tzinfo=pytz.UTC) + + ts = load_isd_daily_temp_data("722874", start, end) + + assert len(ts) == 365 + assert int(ts.notna().sum()) == 365 + assert ts.mean() == pytest.approx(17.835623, abs=1e-5) + assert ts.iloc[0] == pytest.approx(13.222929, abs=1e-5) + + +# truncated data warns: station 724940 ISD data ends 2025-08-27 +def test_load_isd_hourly_temp_data_warns_on_truncated_data( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2025, 6, 1, tzinfo=pytz.UTC) + end = datetime(2025, 10, 1, tzinfo=pytz.UTC) + + ts, warnings = load_isd_hourly_temp_data("724940", start, end) + + assert len(ts) == 2929 + assert int(ts.notna().sum()) == 2096 + assert ts.last_valid_index() == datetime(2025, 8, 27, 7, tzinfo=pytz.UTC) + assert [w.qualified_name for w in warnings] == ["eeweather.data_truncated"] + assert warnings[0].data["last_valid"] == "2025-08-27T07:00:00+00:00" + assert warnings[0].data["requested_end"] == "2025-10-01T00:00:00+00:00" + + +def test_load_gsod_daily_temp_data_warns_on_truncated_data( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2025, 6, 1, tzinfo=pytz.UTC) + end = datetime(2025, 10, 1, tzinfo=pytz.UTC) + + with pytest.warns(UserWarning, match="Data ends 35 days"): + ts = load_gsod_daily_temp_data("724940", start, end) + + assert len(ts) == 123 + assert int(ts.notna().sum()) == 88 + assert ts.last_valid_index() == datetime(2025, 8, 27, tzinfo=pytz.UTC) + + +# all-years-missing behavior +def test_load_isd_hourly_temp_data_missing_year_strict_raises( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2050, 1, 1, tzinfo=pytz.UTC) + end = datetime(2050, 6, 1, tzinfo=pytz.UTC) + + with pytest.raises(ISDDataNotAvailableError): + load_isd_hourly_temp_data("722874", start, end) + + +def test_load_isd_hourly_temp_data_missing_year_tolerant_returns_nan_range( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2050, 1, 1, tzinfo=pytz.UTC) + end = datetime(2050, 6, 1, tzinfo=pytz.UTC) + + ts, warnings = load_isd_hourly_temp_data( + "722874", start, end, error_on_missing_years=False + ) + + assert ts.index[0] == start + assert ts.index[-1] == end + assert ts.isna().all() + assert [w.qualified_name for w in warnings] == [ + "eeweather.isd_data_not_available", + "eeweather.no_data_in_requested_range", + ] + + +def test_load_isd_daily_temp_data_missing_year_strict_raises( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2050, 1, 1, tzinfo=pytz.UTC) + end = datetime(2050, 6, 1, tzinfo=pytz.UTC) + + with pytest.raises(ISDDataNotAvailableError): + load_isd_daily_temp_data("722874", start, end) + + +def test_load_isd_daily_temp_data_missing_year_tolerant_warns_and_fills_nan( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2050, 1, 1, tzinfo=pytz.UTC) + end = datetime(2050, 6, 1, tzinfo=pytz.UTC) + + with pytest.warns(UserWarning) as record: + ts = load_isd_daily_temp_data( + "722874", start, end, error_on_missing_years=False + ) + + messages = [str(w.message) for w in record] + assert any("ISD data not available for 722874 in 2050" in m for m in messages) + assert any("No data was available" in m for m in messages) + + assert ts.index[0] == start + assert ts.index[-1] == end + assert ts.isna().all() + + +def test_load_gsod_daily_temp_data_missing_year_strict_raises( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2050, 1, 1, tzinfo=pytz.UTC) + end = datetime(2050, 6, 1, tzinfo=pytz.UTC) + + with pytest.raises(GSODDataNotAvailableError): + load_gsod_daily_temp_data("722874", start, end) + + +def test_load_gsod_daily_temp_data_missing_year_tolerant_warns_and_fills_nan( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2050, 1, 1, tzinfo=pytz.UTC) + end = datetime(2050, 6, 1, tzinfo=pytz.UTC) + + with pytest.warns(UserWarning) as record: + ts = load_gsod_daily_temp_data( + "722874", start, end, error_on_missing_years=False + ) + + messages = [str(w.message) for w in record] + assert any("GSOD data not available for 722874 in 2050" in m for m in messages) + assert any("No data was available" in m for m in messages) + + assert ts.index[0] == start + assert ts.index[-1] == end + assert ts.isna().all() + + +# a year that exists but contains no valid temperatures: 722874 in 2025 +# reports only daily summaries with missing temperature values +def test_fetch_isd_raw_temp_data_all_nan_year(mock_api_transport): + ts = fetch_isd_raw_temp_data("722874", 2025) + + assert len(ts) == 206 + assert ts.isna().all() + + +def test_load_isd_hourly_temp_data_all_nan_year_warns_no_data( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2025, 1, 1, tzinfo=pytz.UTC) + end = datetime(2025, 6, 1, tzinfo=pytz.UTC) + + ts, warnings = load_isd_hourly_temp_data("722874", start, end) + + assert ts.isna().all() + assert [w.qualified_name for w in warnings] == [ + "eeweather.no_data_in_requested_range" + ] + + +# start not exactly on an hour rounds forward to the next hour +def test_load_isd_hourly_temp_data_start_mid_hour_aligns_forward( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2007, 1, 1, 0, 30, tzinfo=pytz.UTC) + end = datetime(2007, 2, 1, tzinfo=pytz.UTC) + + ts, warnings = load_isd_hourly_temp_data("722874", start, end) + + assert ts.index[0] == datetime(2007, 1, 1, 1, 0, tzinfo=pytz.UTC) + assert ts.index[-1] == end + + +# a sub-hour range contains no aligned hours; returns empty without warning +def test_load_isd_hourly_temp_data_sub_hour_range_returns_empty( + mock_api_transport, monkeypatch_key_value_store +): + start = datetime(2007, 6, 1, 12, 30, tzinfo=pytz.UTC) + end = datetime(2007, 6, 1, 12, 45, tzinfo=pytz.UTC) + + ts, warnings = load_isd_hourly_temp_data("722874", start, end) + + assert len(ts) == 0 + assert warnings == [] diff --git a/tox.ini b/tox.ini index f15748c..88421b4 100644 --- a/tox.ini +++ b/tox.ini @@ -1,10 +1,17 @@ [tox] -envlist = py{35,36,37,310} +envlist = 3.{10, 11, 12, 13, 14} [testenv] -passenv = HOME +package = editable +deps = + pytest + pytest-cov + pytest-xdist + syrupy>=5,<6 commands = - pip install -r requirements.txt - pip install funcsigs pathlib2 - pip install -e . - py.test -n0 {posargs} + pytest tests/ + +[testenv:coverage] +# Runs serially: the tracer can't attach to xdist workers. +commands = + pytest tests/ -p no:xdist --cov=eeweather --cov-report=term-missing --cov-report=xml