diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b07ea1f..ae1c4f3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,10 +24,12 @@ jobs: python-version: ${{ matrix.python-version }} cache: poetry - name: Install dependencies - run: poetry install --no-interaction --no-root --with dev + run: poetry install --no-interaction --no-root --with dev,examples - name: Check code formatting run: poetry run black . - - name: Lint code - run: poetry run pyright + - name: Lint lib code + run: poetry run mypy src --enable-incomplete-feature=Unpack + - name: Lint lib examples + run: poetry run mypy examples --enable-incomplete-feature=Unpack - name: Run tests run: poetry run pytest -n auto diff --git a/CHANGELOG.md b/CHANGELOG.md index d6fad5b..4865741 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added -- +- Added support for `record_error_if` and `record_success_if` ### Changed diff --git a/README.md b/README.md index 3f60790..8b511ad 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ poetry install --with examples Code in this repository is: - formatted using [black](https://black.readthedocs.io/en/stable/). -- contains type definitions (which are linted by [pyright](https://microsoft.github.io/pyright/)) +- contains type definitions (which are linted by [mypy](https://www.mypy-lang.org/)) - tested using [pytest](https://docs.pytest.org/) In order to run these tools locally you have to install them, you can install them using poetry: @@ -176,8 +176,8 @@ After that you can run the tools individually ```sh # Formatting using black poetry run black . -# Lint using pyright -poetry run pyright +# Lint using mypy +poetry run mypy . # Run the tests using pytest poetry run pytest # Run a single test, and clear the cache diff --git a/examples/django_example/mypy.ini b/examples/django_example/mypy.ini new file mode 100644 index 0000000..f5d9ce5 --- /dev/null +++ b/examples/django_example/mypy.ini @@ -0,0 +1,6 @@ +[mypy] +plugins = + mypy_django_plugin.main + +[mypy.plugins.django-stubs] +django_settings_module = "django_example.settings" diff --git a/examples/fastapi-example.py b/examples/fastapi-example.py index 26c0849..bcb3f0c 100644 --- a/examples/fastapi-example.py +++ b/examples/fastapi-example.py @@ -3,6 +3,7 @@ from autometrics import autometrics from fastapi import FastAPI, Response +from fastapi.responses import JSONResponse from prometheus_client import generate_latest app = FastAPI() @@ -44,5 +45,46 @@ async def do_something_async(): return "async world" +def response_is_error(response: Response): + if response.status_code >= 400: + return True + + +@app.get("/not-implemented") +@autometrics(record_error_if=response_is_error) +def not_implemented(): + return JSONResponse( + status_code=501, content={"message": "This endpoint is not implemented"} + ) + + +@app.get("/flowers/{flower_name}") +def flower(flower_name: str): + try: + return JSONResponse(content={"message": get_pretty_flower(flower_name)}) + except NotFoundError as error: + return JSONResponse(status_code=404, content={"message": str(error)}) + + +class NotFoundError(Exception): + pass + + +def is_not_found_error(error: Exception): + return isinstance(error, NotFoundError) + + +@autometrics(record_success_if=is_not_found_error) +def get_pretty_flower(flower_name: str): + """Returns whether the flower is pretty""" + print(f"Getting pretty flower for {flower_name}") + flowers = ["rose", "tulip", "daisy"] + if flower_name not in flowers: + raise NotFoundError( + f"Flower {flower_name} not found. Perhaps you meant one of these: {', '.join(flowers)}?" + ) + return f"A {flower_name} is pretty" + + if __name__ == "__main__": uvicorn.run(app, host="localhost", port=8080) diff --git a/poetry.lock b/poetry.lock index 850fa3c..de9da7d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.0 and should not be changed by hand. [[package]] name = "anyio" @@ -548,6 +548,44 @@ tzdata = {version = "*", markers = "sys_platform == \"win32\""} argon2 = ["argon2-cffi (>=19.1.0)"] bcrypt = ["bcrypt"] +[[package]] +name = "django-stubs" +version = "4.2.3" +description = "Mypy stubs for Django" +optional = false +python-versions = ">=3.8" +files = [ + {file = "django-stubs-4.2.3.tar.gz", hash = "sha256:dadab39b46d9ae8f37a8e879c590f39a9e042b565c03fa0c5a8f754b441b1f23"}, + {file = "django_stubs-4.2.3-py3-none-any.whl", hash = "sha256:e30e2e4927ba14bec587ed2c686404b6b8e473cabe9baca445e7d2e1e0d7b14f"}, +] + +[package.dependencies] +django = "*" +django-stubs-ext = ">=4.2.2" +mypy = ">=1.0.0" +tomli = {version = "*", markers = "python_version < \"3.11\""} +types-pytz = "*" +types-PyYAML = "*" +typing-extensions = "*" + +[package.extras] +compatible-mypy = ["mypy (==1.4.*)"] + +[[package]] +name = "django-stubs-ext" +version = "4.2.2" +description = "Monkey-patching and extensions for django-stubs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "django-stubs-ext-4.2.2.tar.gz", hash = "sha256:c69d1cc46f1c4c3b7894b685a5022c29b2a36c7cfb52e23762eaf357ebfc2c98"}, + {file = "django_stubs_ext-4.2.2-py3-none-any.whl", hash = "sha256:fdacc65a14d2d4b97334b58ff178a5853ec8c8c76cec406e417916ad67536ce4"}, +] + +[package.dependencies] +django = "*" +typing-extensions = "*" + [[package]] name = "docutils" version = "0.19" @@ -607,13 +645,13 @@ all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)" [[package]] name = "flask" -version = "2.3.2" +version = "2.3.3" description = "A simple framework for building complex web applications." optional = false python-versions = ">=3.8" files = [ - {file = "Flask-2.3.2-py3-none-any.whl", hash = "sha256:77fd4e1249d8c9923de34907236b747ced06e5467ecac1a7bb7115ae0e9670b0"}, - {file = "Flask-2.3.2.tar.gz", hash = "sha256:8c2f9abd47a9e8df7f0c3f091ce9497d011dc3b31effcf4c85a6e2b50f4114ef"}, + {file = "flask-2.3.3-py3-none-any.whl", hash = "sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b"}, + {file = "flask-2.3.3.tar.gz", hash = "sha256:09c347a92aa7ff4a8e7f3206795f30d826654baf38b873d0744cd571ca609efc"}, ] [package.dependencies] @@ -622,7 +660,7 @@ click = ">=8.1.3" importlib-metadata = {version = ">=3.6.0", markers = "python_version < \"3.10\""} itsdangerous = ">=2.1.2" Jinja2 = ">=3.1.2" -Werkzeug = ">=2.3.3" +Werkzeug = ">=2.3.7" [package.extras] async = ["asgiref (>=3.2)"] @@ -713,101 +751,119 @@ test = ["cffi (>=1.12.2)", "coverage (>=5.0)", "dnspython (>=1.16.0,<2.0)", "idn [[package]] name = "geventhttpclient" -version = "2.0.9" +version = "2.0.10" description = "http client library for gevent" optional = false python-versions = "*" files = [ - {file = "geventhttpclient-2.0.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f4dcd420c74f68ffc493abdc0964583f762e0f03c9ccd62b8dcfa589f8cabe49"}, - {file = "geventhttpclient-2.0.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5fe8766994434ed6dc807d2e5726e9cec536b5593885b50598fe763908242054"}, - {file = "geventhttpclient-2.0.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c23aacbe40f767d4bfb4215b51302d68f9611f2e730521e65c7239854177c30f"}, - {file = "geventhttpclient-2.0.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f9ead0e6eb8302b394744c8ad7df71b1482e40402ecc208b446dba870bbafa1"}, - {file = "geventhttpclient-2.0.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15393cf588d24bf90b430299733ed161829065d14df99db250b40a83ec7978aa"}, - {file = "geventhttpclient-2.0.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41b35daa9fe8217f295bc162492260daf4d4e1d9e3e8ed1fa2085a003cb5bb86"}, - {file = "geventhttpclient-2.0.9-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0373b1d920cb2c1d65913258e2abe1534f5c6d1e687ed9322ad47858d75fd7d0"}, - {file = "geventhttpclient-2.0.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:344f22ce6cc959e67c32c9992422ee623b2e92da80b7774f939a03a8f66a823b"}, - {file = "geventhttpclient-2.0.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2f467fc073631dd7c13f289ab59e82ae9b181a1faabcc8b23be48a48e8e45ba9"}, - {file = "geventhttpclient-2.0.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:9f1395906e79b7d3db97199625ae9050c1249e2cb8073bb32495c375af351849"}, - {file = "geventhttpclient-2.0.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3c8f035c55f8db9b3a976d813dd20965ecf957e268e420e66b88cba81a66f3ac"}, - {file = "geventhttpclient-2.0.9-cp310-cp310-win32.whl", hash = "sha256:372776cdcad9a34a8635da4002f1614a36269ee02e968750c4fbde6ea83360d7"}, - {file = "geventhttpclient-2.0.9-cp310-cp310-win_amd64.whl", hash = "sha256:9a11b88ce228f91bd47acacb573acbcdf8276b933e2fd7e4f7aa6259c279271e"}, - {file = "geventhttpclient-2.0.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273cde2893c13cbdfcad46e6a0fb906aa3f6b050e712cba0e46cfa59aca4c330"}, - {file = "geventhttpclient-2.0.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba0f8863526a2cf44567fda5981da90278583d3006aef02482a92b7d7e38e610"}, - {file = "geventhttpclient-2.0.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8da5696d055883cef55fe52246ea2a686bae865d4d38900f67c7c3df7d01eaa"}, - {file = "geventhttpclient-2.0.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e25e14c91898217f3a69346c2704e4629634b3429cdff226e716e6d830c402e1"}, - {file = "geventhttpclient-2.0.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46b08a7de94a3db62ebeb41e68097db1e3836eef2e2febccb2d710add8943838"}, - {file = "geventhttpclient-2.0.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e33f23168824338a84e05e47808a48895e78e77c5d2ec353a6e77a0b727057"}, - {file = "geventhttpclient-2.0.9-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f505a7060aeafd7ed94acc8c234690717ed03aa6421580847ade8d4a6d8741c1"}, - {file = "geventhttpclient-2.0.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bc0cd15d51b5817efeef98d6ffe51bebd371c0c81731b239d0c6e81923c3b986"}, - {file = "geventhttpclient-2.0.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9a7e72d38e3a4d4f84c11dbfd74b70e70c3c9099ea7336a6c6227e0628c83a67"}, - {file = "geventhttpclient-2.0.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:62edef5141ea260caa91618b133d8888d9af6767e11a2e972dbb5be0e297ff8e"}, - {file = "geventhttpclient-2.0.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:40cc9acfb7096b8fa3a4c4634dcc0a1cfc6a0a5501c597d1c4a5574fde1bb1be"}, - {file = "geventhttpclient-2.0.9-cp311-cp311-win32.whl", hash = "sha256:44e7de9925356486988f72b239d1608597b6d1462664a7fa7ad5b8704a3f6f4e"}, - {file = "geventhttpclient-2.0.9-cp311-cp311-win_amd64.whl", hash = "sha256:03b3c64fcd16795a5acbdf8588e05a58fde498cd550285cf3ea6e1c6cc28378c"}, - {file = "geventhttpclient-2.0.9-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:be198e668c8573e4cc7fa8e6b71e32a94765c424bc6a8cdd5fc23ab23769864c"}, - {file = "geventhttpclient-2.0.9-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f550e6ceb67a6cac9e42915612a10c0f799666fa309be796db65585690d8262"}, - {file = "geventhttpclient-2.0.9-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5210e91b1a1d9f2bcd414238cae2593b66172098db7bde396ae2fdb8e658eb85"}, - {file = "geventhttpclient-2.0.9-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:97f4c7f57bf24b669bc2e71de725067a4b73f280fc20875fd8c7cee712b754f3"}, - {file = "geventhttpclient-2.0.9-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01869edfc3f9b892dfdd0b3ef102c97dd250725e8364de2e450d9ee2e3bf74db"}, - {file = "geventhttpclient-2.0.9-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a85f9d272af4bc599a54496cb420ee0654c35023d6cd7f2a49c36d5a5d30e375"}, - {file = "geventhttpclient-2.0.9-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:9f78d0bda2583a7f9d87cc987ab9976bf4e85d467af7d8fa39f51bed1918e812"}, - {file = "geventhttpclient-2.0.9-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:2e8013742b22586c25c797d7d7bfb8882b2eed43051f28f7617ea302cf4e5098"}, - {file = "geventhttpclient-2.0.9-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:1eb410b5522ef617923470f036774388c191eda3ae47abf5a175f628cff75928"}, - {file = "geventhttpclient-2.0.9-cp36-cp36m-win32.whl", hash = "sha256:12de78429c420ac3dbfd4e89fbd1d9d2cf9a60c06a82fc39a398f92d5f717c95"}, - {file = "geventhttpclient-2.0.9-cp36-cp36m-win_amd64.whl", hash = "sha256:5eb747774ed72467b3b77913bfe041f0be4a22958dd7538a654bf24107d1b917"}, - {file = "geventhttpclient-2.0.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:36e9c7e4f86db9335123a12b343c2b91d8d7fe4724428ac418bcfcd471248bc9"}, - {file = "geventhttpclient-2.0.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a7d8a7d7ee6b08e44e58e92e47ca4b50edf8ed64b8906bd0a6cbb481aeae69b"}, - {file = "geventhttpclient-2.0.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:186d3e4f549a004f0ae8857db81f05798d48dd9e6cbfa97dfa46f6177883458d"}, - {file = "geventhttpclient-2.0.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c0ed350c0f4598f6d07d6fdc2d3546a1611ebf15fcdc83bc77dea6d22f2ef38"}, - {file = "geventhttpclient-2.0.9-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0c557aeb45a005c72200842fddfb507bbd7f2ec9296059c7ea3977ea226d4e7"}, - {file = "geventhttpclient-2.0.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6c9ea74c83e94ea7c9869e383f93fa20a5fbde9cfb020400cdb75c39e029507a"}, - {file = "geventhttpclient-2.0.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9b072c041993b3242aeccce0d436bcb951f83e83517d5f5c0b9b97efe6ee273e"}, - {file = "geventhttpclient-2.0.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:d17ea1282fef41aa1b43e193869f0b9119fab919fe90092dfa5754fd6a012982"}, - {file = "geventhttpclient-2.0.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4941aa5e45479a6595469754d6395e5d1a76cf555d0d111aa4c128d8f4ebd41b"}, - {file = "geventhttpclient-2.0.9-cp37-cp37m-win32.whl", hash = "sha256:2d36b3a241a4c64a094622c4da67b98141295ab9ba24a79671235bb8735047f5"}, - {file = "geventhttpclient-2.0.9-cp37-cp37m-win_amd64.whl", hash = "sha256:f7a99e0976ac64d21f54be87083b6ec440753db50db36d83b2b2b0b6edaacad7"}, - {file = "geventhttpclient-2.0.9-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f46848b5c6610c671a7258757bf4d34032c56a80ead880e69890d9ef5c1e63a1"}, - {file = "geventhttpclient-2.0.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b671b736468e35e588f24d2219d9f84f3c69c466fdc76ce47774106eb3af2c10"}, - {file = "geventhttpclient-2.0.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b290897e50e0f378d4cabdafffe2f51950d1c820722ee39b37657eda7339a3a8"}, - {file = "geventhttpclient-2.0.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41cad9ddc365edf77cb62a4e3a8168dee9ee37109b410a42c5ec0691403dbe37"}, - {file = "geventhttpclient-2.0.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0b69bc9632827b108aba11d85e7c604290e413486e7dc9ddf471303ceab4381"}, - {file = "geventhttpclient-2.0.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:988121fdd5b8939c4071ce45b26f9e3aa1cb050e3087ee02b28e7c21bcada35c"}, - {file = "geventhttpclient-2.0.9-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db4db1ceaa88d648c43a318af16690fb59f13ad1fc48603e054c563490950034"}, - {file = "geventhttpclient-2.0.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:192be8b440e6512c384cc5be98b3b3e8b39dcae0f7c10aee3c3491f30a20e676"}, - {file = "geventhttpclient-2.0.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ffed7591e612cb80935ed11c1fb0a752aed3f014a48b9404cd0c77182e82335c"}, - {file = "geventhttpclient-2.0.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:c2b06ccac902fb243384da12692be240e7a9ddcd2efedcde2444872546ada83c"}, - {file = "geventhttpclient-2.0.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8257d9538a1d342a2052c0df099a318d7611562a4725985ac652a356c5cd45c9"}, - {file = "geventhttpclient-2.0.9-cp38-cp38-win32.whl", hash = "sha256:ce61c0be828e10dbfac91ed7160f651ecc2fbad44ed1815eaac6e9d41e09a87a"}, - {file = "geventhttpclient-2.0.9-cp38-cp38-win_amd64.whl", hash = "sha256:aa2b47489bd229fce3ab626c370eb8d18fd6116611552de9d8979c37238fc62b"}, - {file = "geventhttpclient-2.0.9-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a16bde611a76ada61c9af9acc20b88d5ee6c025deede2680fde084838a3bfbae"}, - {file = "geventhttpclient-2.0.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:780d04ea934e254af9de90402f29804e6a3455c3bfa44acc1e8ccb65ce5115a9"}, - {file = "geventhttpclient-2.0.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3033399fcbe1fbafbe6ff56afb587725aa993ab549845ebbd8a2206be6082cb"}, - {file = "geventhttpclient-2.0.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d32d3f6f413a6a16ac3bfe4cb53f0935c52f33820d2da21d9929ec6a910519b"}, - {file = "geventhttpclient-2.0.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6684b82fd3719d4823ef2eda1edd5bfbf3154e5c2241db0ed858ffb99f8a4ad9"}, - {file = "geventhttpclient-2.0.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38f5c6cfa9387ad741f0b5033b6de12eeb670870149a50b7a64444c84f8e7167"}, - {file = "geventhttpclient-2.0.9-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d654ae061852c842a75b1a38f42b5523389475fe9015de732a55242f6d221e"}, - {file = "geventhttpclient-2.0.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:491ee724ba4057b076610be20da6345a66c630d82ed52f12014ce8bad5a699ab"}, - {file = "geventhttpclient-2.0.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:eab149b7119ac7a6243cad85173f9f9e9ae004e299358181641dddc39233a2d1"}, - {file = "geventhttpclient-2.0.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f6ad2c5590a68b7e959ab5f4adab78008ba3a661482c1fb56a38eba09744b899"}, - {file = "geventhttpclient-2.0.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47bb3025950cc9bf0fd627b101380cf5b0efbbaa591198b851352b24966931cb"}, - {file = "geventhttpclient-2.0.9-cp39-cp39-win32.whl", hash = "sha256:549756ac0e3cc916d6830f0d6147803a5c93beae96f8504f685e4e841d6ace29"}, - {file = "geventhttpclient-2.0.9-cp39-cp39-win_amd64.whl", hash = "sha256:e3133d3e492c5dfb78f9c0f87e1ede78545e7f4bb4851a063df2321669540004"}, - {file = "geventhttpclient-2.0.9-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3fca4415c9d9282a8b5f4de03661be3b1083b97b3e43a1f4b56cec4b933b9705"}, - {file = "geventhttpclient-2.0.9-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b85ca16b34170787a48ac2c69622bba2f2a3541ee55b442576a12f63181f13e"}, - {file = "geventhttpclient-2.0.9-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:711f3522ce20d2de5abe22cafdeee0896f9f682de7690622510c5f8a859c50d2"}, - {file = "geventhttpclient-2.0.9-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96479cafe8cca4e24a1ba53efe3c3c6cf9f10e8cb0398f4cbcf23b4233e103f2"}, - {file = "geventhttpclient-2.0.9-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d742f4288844ec5dbed2af4396fca8d37b5f4d2730ca31fe3575d67a2910e28f"}, - {file = "geventhttpclient-2.0.9-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:53e929c7920fb7841d4b2cde50ed3fdde803948977a333de33a924a9ccfccd38"}, - {file = "geventhttpclient-2.0.9-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4693365990aa6d5cb104cea80dd831b8032f6a4f77790fa8b837fc25e86f8e5"}, - {file = "geventhttpclient-2.0.9-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99bb292a4f4fa4a23d22e6bf1799530d0cb675dae87d81d77079abe98f71150d"}, - {file = "geventhttpclient-2.0.9-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4533b7023a90cb9766213f70d15bc76bb66b7b441c3976f27e254403a6c738fa"}, - {file = "geventhttpclient-2.0.9-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a9b6341c937d01ba48028a3d605fded6fd2eed692bb1ddc941d2aa3dd317eed9"}, - {file = "geventhttpclient-2.0.9-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a05a3345796accd0a9acb3fc133a0e4cd949d3e63becec34fcb2e8d001dd92fe"}, - {file = "geventhttpclient-2.0.9-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32cc9bd3518aa0772065175aa6eddadff8b05688683940bfd583cb468b518987"}, - {file = "geventhttpclient-2.0.9-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e7185e91b52f6d2cdab849ba24c8ac24b3bd1ad8eb9917e4ed86f4e93f718b1"}, - {file = "geventhttpclient-2.0.9-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62a47451abf94422b3f0efda4f147111f2f4a75f7e55db974cf4b35acaee0131"}, - {file = "geventhttpclient-2.0.9-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:dc75486b0847c185856f981b728a2bbfe09e8a754676e57a8549660157918d2f"}, - {file = "geventhttpclient-2.0.9.tar.gz", hash = "sha256:8abc39d346e923bd6a7b405d38dd01e19146594b6304032f382eda8b0f631513"}, + {file = "geventhttpclient-2.0.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2ba6814f4a31286573f7fd24154bdb9cbe4ae01e754f48d71b1944798bf663"}, + {file = "geventhttpclient-2.0.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c01dfb0de68f219b7a534121caa71481e32574bba7fe547fa37ee47a73a7b224"}, + {file = "geventhttpclient-2.0.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1b2c7e6bb15910a2e86f8da375adfd63ac07587a1c764cedc082b00390bcd76e"}, + {file = "geventhttpclient-2.0.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:022801e2323e3e673e3c7034f6bc5440b4651649df03396eb1b3a86a6aba899d"}, + {file = "geventhttpclient-2.0.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcfc1489e71b010d8ce8857578cdb1b8ba348626807aa9d077fc73c9864e51e1"}, + {file = "geventhttpclient-2.0.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aef527f67653488000218283368e526fa699604e03e98ce4e0e588e89116977d"}, + {file = "geventhttpclient-2.0.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a673a4b6b1839c8491372e43208912040c25a34254c60bf1d084489ddc300ee"}, + {file = "geventhttpclient-2.0.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2ceae04de8bdb4ef1d0ca7724cd9cad77c6611aac3830a24a7f13747e8b748c7"}, + {file = "geventhttpclient-2.0.10-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:dc3effc56065a5c26292ca26127e6fdd0f68429b413e847a8b7bad38972aab53"}, + {file = "geventhttpclient-2.0.10-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:304c1d24d33b19cae53614ffc91c68d1e682d8b60a4d9eefcf87fcd099b1c2f2"}, + {file = "geventhttpclient-2.0.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d39b468aba4dbec358eb0205d41791afc53651eee789566239e544ed6c8b7dbb"}, + {file = "geventhttpclient-2.0.10-cp310-cp310-win32.whl", hash = "sha256:91cd3f680ee413cc83819f0e1f63e49297c550099e85bbee92e73960d3eba041"}, + {file = "geventhttpclient-2.0.10-cp310-cp310-win_amd64.whl", hash = "sha256:9a9c02c44b1e4e6edf929aa7c98b665f4db9cdcd406e4a9b4897f48127a6dd6b"}, + {file = "geventhttpclient-2.0.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cb079f45fdc8e2bf7157ef55727d8c2bb7c95fb4f754dac61d7a9b91da0c5c1a"}, + {file = "geventhttpclient-2.0.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd657ba277f4888b5a4b5da72a587641d6725d1e6ab0dd6875f29ad0a3458ad5"}, + {file = "geventhttpclient-2.0.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fd589226e908a6c2556572ff3b13fe00308849b44dec47bb794de27afa0339de"}, + {file = "geventhttpclient-2.0.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e38a4123ed63935ccaf18054135e50fe4f798744f10d37faa9d2eaddfcff12f"}, + {file = "geventhttpclient-2.0.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9711c629559b1f0be4977a2be79899fb90085a5a1f85ca435ec91d6a5648ff3f"}, + {file = "geventhttpclient-2.0.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7435458eada516d1caf8499a2618db1160e62bbe0c8e4d6f3ab03fc507587dff"}, + {file = "geventhttpclient-2.0.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:446b17f342315d8c63c020732b9ab939a874014c84cf250d66ffd96c877f6d96"}, + {file = "geventhttpclient-2.0.10-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:68279ab30e20f48fbac4371cd5850c77ecc37f24ef656f8c37afd5454576bc57"}, + {file = "geventhttpclient-2.0.10-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0823827d029aed708d6ed577994cdd3b4c1466690be0b7f27f3b459783ab7c6a"}, + {file = "geventhttpclient-2.0.10-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:505722ef30d680c983812795e047dbb2d09dc0f476015e5d3411251bb960e3b1"}, + {file = "geventhttpclient-2.0.10-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8ebf2ce3ca1308ffc9daae1f45860b2f5a3c1a75f6c46b2d12b9a478f7c4f05e"}, + {file = "geventhttpclient-2.0.10-cp311-cp311-win32.whl", hash = "sha256:4ad20f6f03e34e44366e6794a28bd0b35b09e1dca3350bbf0a72c50d64c9c266"}, + {file = "geventhttpclient-2.0.10-cp311-cp311-win_amd64.whl", hash = "sha256:c1883adee9c69374e30f43f7bea85dd4a7b4cc440e3c6ecf975bef04e1f8a972"}, + {file = "geventhttpclient-2.0.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7525bd48fadc93a79d13383cf38a10eed6c9f2f3c65e1f3a8cd4978dfcf023a0"}, + {file = "geventhttpclient-2.0.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c6820591122c4444652238806c0c97f6c0de76d790bab255fd242962c8026654"}, + {file = "geventhttpclient-2.0.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34a06879a2dbc2a78edf8cfcabbcc67a177d0642b0e4490b771b72ebceea4537"}, + {file = "geventhttpclient-2.0.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:441a16eb8743b44c7b6f0acbbdc38d6f407f0763eb859ae0ae6e61427ac86c3e"}, + {file = "geventhttpclient-2.0.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdf3a7a5c6b244c6d55de9d28245f70ee33cca8353355a9b10ea0c2e08ff24a0"}, + {file = "geventhttpclient-2.0.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e65a91c7a4e559d0f60dab4439d15355ade9c30f5c73276bb748b000a062e8f"}, + {file = "geventhttpclient-2.0.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d051f15c3c92140ce142336ae05a76868ce05a86b4e15c5becb5431beaf53a07"}, + {file = "geventhttpclient-2.0.10-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:224d1f34e32d683889f8a92f92ce3a1e4bb2f3f4a3d85b931a8df493dd59e9e7"}, + {file = "geventhttpclient-2.0.10-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:309a35f033766476765a48a9c2712ffb988c3e3d50cd4b98eaa77e34b470af7e"}, + {file = "geventhttpclient-2.0.10-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:d9d09579969cfb244e88bb599ac93549d8c0b56018de1f1ffade4a986951ad1d"}, + {file = "geventhttpclient-2.0.10-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:15ecc1599646755d7e2e5648606c21ace00c3337c2d72d33b4e2de5d66b4ed65"}, + {file = "geventhttpclient-2.0.10-cp312-cp312-win32.whl", hash = "sha256:c99dd907622f28523c3f90b8718643c103ce6519be7128e75730c398fd23d157"}, + {file = "geventhttpclient-2.0.10-cp312-cp312-win_amd64.whl", hash = "sha256:9532ee9066072737fe0eac1714c99792d7007769d529a056bc0c238946f67fdf"}, + {file = "geventhttpclient-2.0.10-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7197223e650b9e07e1b3ddc1b41b8cdc1c2c4b408f392bdf827efa8c0cb6c67b"}, + {file = "geventhttpclient-2.0.10-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:304b9d67c91db96633d89b938b68020d7f787ff962580b1cff819d4218d7eb45"}, + {file = "geventhttpclient-2.0.10-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bdd4aa396f69f4063b7fcddb2c400c9eea933bcce63f3c65fc28a1869c88179c"}, + {file = "geventhttpclient-2.0.10-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8da6f49e65cdcc19fbc37978d9e3e14ba30c949d9a5492e0f96e1e5270f2305"}, + {file = "geventhttpclient-2.0.10-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba65c48a63042deadc8e4f1f5348409d851d6fa06f8a1b5a58fd6fd24e50daaf"}, + {file = "geventhttpclient-2.0.10-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:f3dcbf4a53852498128937e870c4b0ced1ed49b9153c68d12a52a0711652b9cf"}, + {file = "geventhttpclient-2.0.10-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:976e86d63fd1cd3bda4f78ec469b6d1c8dec4259abeb62191464e8dd4d40bb8e"}, + {file = "geventhttpclient-2.0.10-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:05be35bc7d2bd3ad6f0aa5042ae5a0b171ff19ec75ffeae1b4a2698572dd67a4"}, + {file = "geventhttpclient-2.0.10-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b3556a97e1c71d6b323076e6153f3afcf4f2e37ad79c3fe6d5bf006d3c1b5436"}, + {file = "geventhttpclient-2.0.10-cp36-cp36m-win32.whl", hash = "sha256:2b2d801205000f673f879b4edc1064b7dfc1bdd0dc5257bf565e6e7386b818bf"}, + {file = "geventhttpclient-2.0.10-cp36-cp36m-win_amd64.whl", hash = "sha256:7fd672aa9186607ac802b09efd3c835eb808f930a5c3489553dbfcbe78539129"}, + {file = "geventhttpclient-2.0.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:551b147e4c2ea60bfefc4f12dd061bfe84792497a32a369f8dab7f503da5aa05"}, + {file = "geventhttpclient-2.0.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:113c001d339b9e5c209f6f9da9271b0011341c25a4171d142c1d802bc0889ec4"}, + {file = "geventhttpclient-2.0.10-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fcdfdbbbf3c96265aca110433a5ce68e807336fa58bd7ef0651e66032037575"}, + {file = "geventhttpclient-2.0.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:223daf689883680eef2aa1b773a2bd7e6500749615332b0a0949ee11afeeeff9"}, + {file = "geventhttpclient-2.0.10-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a45343be209224de6e525611938a41a4269c36df3b3c1f6e12f99af188d192a4"}, + {file = "geventhttpclient-2.0.10-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c268f7573f2b3cceabdc086abca96a59fb2766acbf60fb349ccbc208b6051e7c"}, + {file = "geventhttpclient-2.0.10-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c8117ef8e405fa05f5ea50fd9eb1d538bb7eeb86dba2849fb25d8296fabb70fc"}, + {file = "geventhttpclient-2.0.10-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:fb70548781b3ba3531ec3572ae6f4cd87f387822c412fff1ee6fe52c2e4b66cf"}, + {file = "geventhttpclient-2.0.10-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b87dcef1ca6eb9127fd60844f1dd77063081335079b498bc1e1cd8e4764b6863"}, + {file = "geventhttpclient-2.0.10-cp37-cp37m-win32.whl", hash = "sha256:8ff70f24183705f2cb63dc132b4dd4e0eec58b8f182fde76f5a205e4608266cd"}, + {file = "geventhttpclient-2.0.10-cp37-cp37m-win_amd64.whl", hash = "sha256:f30d83152339779650a97471f27ef2fb2e6804ce660c96790c0d01c66648483f"}, + {file = "geventhttpclient-2.0.10-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:786e120946a4dc1c7ede5a04943119540a1ccc22227029cdb7988a3d216885b1"}, + {file = "geventhttpclient-2.0.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c27943dff539c4bc19f31ea8bffbb79a215e3b3f72b87686791956af39586ac4"}, + {file = "geventhttpclient-2.0.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a377934706416ef04b92291540b609c7dde004a7ccb3b4e047873af2432d78e4"}, + {file = "geventhttpclient-2.0.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b91c1a73e99ef4542e7098a997d1a4bce08cafb935e24a7b6d02c6da2359c91d"}, + {file = "geventhttpclient-2.0.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80683052062f4cb6f18e7d2b1dba91f9536f7955a12660d599ed64bb4aa56d1e"}, + {file = "geventhttpclient-2.0.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44c06c9882cc50201e5c7fe667eae73a491b6590018aa43c54c79e88c30abdb0"}, + {file = "geventhttpclient-2.0.10-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271834908b41954fedc777478ffdc10050387bb5863805e19301b80e0fd85618"}, + {file = "geventhttpclient-2.0.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f2f48dfd37d341c8433e7a2f76108b3d21614ccf2fbe00051d9dd29b3258efa6"}, + {file = "geventhttpclient-2.0.10-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d6110eb2f685c6dcaff56e9b3b161da2eb432eea15b68cee0f51ec5d28c886ea"}, + {file = "geventhttpclient-2.0.10-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:a9e9c1c080a527dd9047e0421231cdd2394eeb92f94836f4ad7d7fece937ba26"}, + {file = "geventhttpclient-2.0.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fa34492682347420384e49bd7c15886330af685924fc64badefce642867e4856"}, + {file = "geventhttpclient-2.0.10-cp38-cp38-win32.whl", hash = "sha256:ea66408103b4c8954cbd3cc464be0e968a139d073987555a280760fb56fed41f"}, + {file = "geventhttpclient-2.0.10-cp38-cp38-win_amd64.whl", hash = "sha256:ef45b4facbaf7793373a32cab3f3e9460b76eb5f854b066f53b4753eca0efa7d"}, + {file = "geventhttpclient-2.0.10-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75e09f122824d1d4aa3e9e48089a5e6f5c0925c817dfb99a65aeafa173243a27"}, + {file = "geventhttpclient-2.0.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c9b4269873ce14bdd0977ae7b3b29e55ba2dc187b1088665cfe78fc094fc6795"}, + {file = "geventhttpclient-2.0.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:39db24bf426471cf81530675459ea209355032bf73f55a6e111f28853fe7564f"}, + {file = "geventhttpclient-2.0.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf9148ce0072e6f2c644522b38d22d2749367dd599a4b32991ca9fc5feb112c5"}, + {file = "geventhttpclient-2.0.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:452624f7e1b16e27c5df5b4f639a5a45f9372d9d9a8e7d2754f2f034b04d43d3"}, + {file = "geventhttpclient-2.0.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57ecf4d4a09b502d2d4b25bc074b10290d595d80b6ce86294ecdd992cff80fb9"}, + {file = "geventhttpclient-2.0.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e338a3b23d05c7550a6163b8d367de953be25f1d94949d043b325390df72d527"}, + {file = "geventhttpclient-2.0.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6d2b0b87bb933911dadb702df74a7da91a4cdd86b6d75800db8494d7e5709e70"}, + {file = "geventhttpclient-2.0.10-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5396759194bef95b92128dfd8b80d332f809de23193a2529071a519afd6e9250"}, + {file = "geventhttpclient-2.0.10-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c13ba845f042d0807f6024b80c458b22b615028cc4f4ad23bd67c6db9de9969e"}, + {file = "geventhttpclient-2.0.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24b33b88fc7b815139b80736bb46a7f6113abc7edd3d846cd99fc8d8c31d8439"}, + {file = "geventhttpclient-2.0.10-cp39-cp39-win32.whl", hash = "sha256:e545fa59f298f6fc5219403f06819271f77a67216d1352f5cf703f292be05c3e"}, + {file = "geventhttpclient-2.0.10-cp39-cp39-win_amd64.whl", hash = "sha256:216e451ea72fe2372bc72e34f214ef8bc9d62b049d9048f88f81338e1c6008a5"}, + {file = "geventhttpclient-2.0.10-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:71a224032b2da3fe30d75fb57fb9d3e8ff323895e14facd9374e585d5bf52d01"}, + {file = "geventhttpclient-2.0.10-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bed5b6051582bdf39c7ff15051ec0758d1a0ebcb6ff09b6ae600717caf3f379e"}, + {file = "geventhttpclient-2.0.10-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e2e2eed1d821854f9f32f475d258af605a87ce12dc4d93abe61c022bf2bb06e"}, + {file = "geventhttpclient-2.0.10-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2cd1ecc9a389ca54a5e538769c3f35a82478006dc50eb505989d2ff6c3cf518"}, + {file = "geventhttpclient-2.0.10-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:fb7018bfd4f6808d4e3b9cdda2dcb52cc01236a4bb65e18021fb8816996e9cd3"}, + {file = "geventhttpclient-2.0.10-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6df4957678eb05a6ccfbbb96a9490345758620b53fe5653052979df94819765b"}, + {file = "geventhttpclient-2.0.10-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:508bcc82f7259e316f2060025e7ff899acc8032c645e765bb780083e39060c07"}, + {file = "geventhttpclient-2.0.10-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:961dac20f0f4b8cfa4e2eaafe2d20d74448a5a04239135fa1867a9a1bc3fd986"}, + {file = "geventhttpclient-2.0.10-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:826fa6487ba1c1b7186dcdc300c216fd9b8cf34e307335b4cad1769736988ce9"}, + {file = "geventhttpclient-2.0.10-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:b30c9495b43b2f67b6a0102ee3fd497762b6bf972e435e5974fd8d2cb5263235"}, + {file = "geventhttpclient-2.0.10-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e2a9a5e52abc8d3275902c1199ff810264b033e346bcf19da920f9b6de1ea916"}, + {file = "geventhttpclient-2.0.10-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:993b653c7c3d4e0683067b2e324fd749649e87b453205def6a4809dd30498b44"}, + {file = "geventhttpclient-2.0.10-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6aa110a66936c37a8bbc2a51515fc0f7e99404e245ef15af8346fa2f6b4f6698"}, + {file = "geventhttpclient-2.0.10-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ce4699fcadc17786cba0b461ff59d0231277155439b274fa12861f93fa764c8"}, + {file = "geventhttpclient-2.0.10-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:23fedc0bf219cc42f9b3d565953a08a429c09642859b86174535977bb281f1c1"}, + {file = "geventhttpclient-2.0.10-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a9e99fa203a43a8393cf01e5a6433e74524c97bf67e39c4f062c8fff27f49360"}, + {file = "geventhttpclient-2.0.10-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0dfcfdc3a05e2145fe15f8b9cc7dd8b9fcd545dd42d051be0a2a828b8b3cc4a3"}, + {file = "geventhttpclient-2.0.10-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b56abccfea3fe154f29dbc518737c70d63c1f44da4c956e31e9a5ff65074de19"}, + {file = "geventhttpclient-2.0.10-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9f8d335e7e3579608904e001ba9b055d3f30b184db550c32901b3b86af71b92"}, + {file = "geventhttpclient-2.0.10-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:96f1a63f18eb4a66ea9d6ab211d756afe8b6d5c6e80beff298cd7b65a3d710c7"}, + {file = "geventhttpclient-2.0.10.tar.gz", hash = "sha256:b7c97b26511957a36a894ec54651c08890a69e118b69755f8e74bfc37c63391b"}, ] [package.dependencies] @@ -816,6 +872,79 @@ certifi = "*" gevent = ">=0.13" six = "*" +[[package]] +name = "greenlet" +version = "2.0.2" +description = "Lightweight in-process concurrent programming" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" +files = [ + {file = "greenlet-2.0.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d"}, + {file = "greenlet-2.0.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9"}, + {file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"}, + {file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"}, + {file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"}, + {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75209eed723105f9596807495d58d10b3470fa6732dd6756595e89925ce2470"}, + {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a51c9751078733d88e013587b108f1b7a1fb106d402fb390740f002b6f6551a"}, + {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"}, + {file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"}, + {file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"}, + {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:eff4eb9b7eb3e4d0cae3d28c283dc16d9bed6b193c2e1ace3ed86ce48ea8df19"}, + {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5454276c07d27a740c5892f4907c86327b632127dd9abec42ee62e12427ff7e3"}, + {file = "greenlet-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:7cafd1208fdbe93b67c7086876f061f660cfddc44f404279c1585bbf3cdc64c5"}, + {file = "greenlet-2.0.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6"}, + {file = "greenlet-2.0.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43"}, + {file = "greenlet-2.0.2-cp35-cp35m-win32.whl", hash = "sha256:03a8f4f3430c3b3ff8d10a2a86028c660355ab637cee9333d63d66b56f09d52a"}, + {file = "greenlet-2.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4b58adb399c4d61d912c4c331984d60eb66565175cdf4a34792cd9600f21b394"}, + {file = "greenlet-2.0.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:703f18f3fda276b9a916f0934d2fb6d989bf0b4fb5a64825260eb9bfd52d78f0"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:32e5b64b148966d9cccc2c8d35a671409e45f195864560829f395a54226408d3"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0f72c9ddb8cd28532185f54cc1453f2c16fb417a08b53a855c4e6a418edd099"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd021c754b162c0fb55ad5d6b9d960db667faad0fa2ff25bb6e1301b0b6e6a75"}, + {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:3c9b12575734155d0c09d6c3e10dbd81665d5c18e1a7c6597df72fd05990c8cf"}, + {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b9ec052b06a0524f0e35bd8790686a1da006bd911dd1ef7d50b77bfbad74e292"}, + {file = "greenlet-2.0.2-cp36-cp36m-win32.whl", hash = "sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9"}, + {file = "greenlet-2.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9f35ec95538f50292f6d8f2c9c9f8a3c6540bbfec21c9e5b4b751e0a7c20864f"}, + {file = "greenlet-2.0.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:f82d4d717d8ef19188687aa32b8363e96062911e63ba22a0cff7802a8e58e5f1"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73"}, + {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:36abbf031e1c0f79dd5d596bfaf8e921c41df2bdf54ee1eed921ce1f52999a86"}, + {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33"}, + {file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"}, + {file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"}, + {file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acd2162a36d3de67ee896c43effcd5ee3de247eb00354db411feb025aa319857"}, + {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0bf60faf0bc2468089bdc5edd10555bab6e85152191df713e2ab1fcc86382b5a"}, + {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"}, + {file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"}, + {file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"}, + {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c817e84245513926588caf1152e3b559ff794d505555211ca041f032abbb6b"}, + {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8"}, + {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7efde645ca1cc441d6dc4b48c0f7101e8d86b54c8530141b09fd31cef5149ec9"}, + {file = "greenlet-2.0.2-cp39-cp39-win32.whl", hash = "sha256:ea9872c80c132f4663822dd2a08d404073a5a9b5ba6155bea72fb2a79d1093b5"}, + {file = "greenlet-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:db1a39669102a1d8d12b57de2bb7e2ec9066a6f2b3da35ae511ff93b01b5d564"}, + {file = "greenlet-2.0.2.tar.gz", hash = "sha256:e7c8dc13af7db097bed64a051d2dd49e9f0af495c26995c00a9ee842690d34c0"}, +] + +[package.extras] +docs = ["Sphinx", "docutils (<0.18)"] +test = ["objgraph", "psutil"] + [[package]] name = "greenlet" version = "3.0.0a1" @@ -1247,6 +1376,52 @@ files = [ {file = "msgpack-1.0.5.tar.gz", hash = "sha256:c075544284eadc5cddc70f4757331d99dcbc16b2bbd4849d15f8aae4cf36d31c"}, ] +[[package]] +name = "mypy" +version = "1.5.1" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f33592ddf9655a4894aef22d134de7393e95fcbdc2d15c1ab65828eee5c66c70"}, + {file = "mypy-1.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:258b22210a4a258ccd077426c7a181d789d1121aca6db73a83f79372f5569ae0"}, + {file = "mypy-1.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9ec1f695f0c25986e6f7f8778e5ce61659063268836a38c951200c57479cc12"}, + {file = "mypy-1.5.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:abed92d9c8f08643c7d831300b739562b0a6c9fcb028d211134fc9ab20ccad5d"}, + {file = "mypy-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:a156e6390944c265eb56afa67c74c0636f10283429171018446b732f1a05af25"}, + {file = "mypy-1.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6ac9c21bfe7bc9f7f1b6fae441746e6a106e48fc9de530dea29e8cd37a2c0cc4"}, + {file = "mypy-1.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51cb1323064b1099e177098cb939eab2da42fea5d818d40113957ec954fc85f4"}, + {file = "mypy-1.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:596fae69f2bfcb7305808c75c00f81fe2829b6236eadda536f00610ac5ec2243"}, + {file = "mypy-1.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:32cb59609b0534f0bd67faebb6e022fe534bdb0e2ecab4290d683d248be1b275"}, + {file = "mypy-1.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:159aa9acb16086b79bbb0016145034a1a05360626046a929f84579ce1666b315"}, + {file = "mypy-1.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f6b0e77db9ff4fda74de7df13f30016a0a663928d669c9f2c057048ba44f09bb"}, + {file = "mypy-1.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:26f71b535dfc158a71264e6dc805a9f8d2e60b67215ca0bfa26e2e1aa4d4d373"}, + {file = "mypy-1.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fc3a600f749b1008cc75e02b6fb3d4db8dbcca2d733030fe7a3b3502902f161"}, + {file = "mypy-1.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:26fb32e4d4afa205b24bf645eddfbb36a1e17e995c5c99d6d00edb24b693406a"}, + {file = "mypy-1.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:82cb6193de9bbb3844bab4c7cf80e6227d5225cc7625b068a06d005d861ad5f1"}, + {file = "mypy-1.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4a465ea2ca12804d5b34bb056be3a29dc47aea5973b892d0417c6a10a40b2d65"}, + {file = "mypy-1.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9fece120dbb041771a63eb95e4896791386fe287fefb2837258925b8326d6160"}, + {file = "mypy-1.5.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d28ddc3e3dfeab553e743e532fb95b4e6afad51d4706dd22f28e1e5e664828d2"}, + {file = "mypy-1.5.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:57b10c56016adce71fba6bc6e9fd45d8083f74361f629390c556738565af8eeb"}, + {file = "mypy-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:ff0cedc84184115202475bbb46dd99f8dcb87fe24d5d0ddfc0fe6b8575c88d2f"}, + {file = "mypy-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8f772942d372c8cbac575be99f9cc9d9fb3bd95c8bc2de6c01411e2c84ebca8a"}, + {file = "mypy-1.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5d627124700b92b6bbaa99f27cbe615c8ea7b3402960f6372ea7d65faf376c14"}, + {file = "mypy-1.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:361da43c4f5a96173220eb53340ace68cda81845cd88218f8862dfb0adc8cddb"}, + {file = "mypy-1.5.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:330857f9507c24de5c5724235e66858f8364a0693894342485e543f5b07c8693"}, + {file = "mypy-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:c543214ffdd422623e9fedd0869166c2f16affe4ba37463975043ef7d2ea8770"}, + {file = "mypy-1.5.1-py3-none-any.whl", hash = "sha256:f757063a83970d67c444f6e01d9550a7402322af3557ce7630d3c957386fa8f5"}, + {file = "mypy-1.5.1.tar.gz", hash = "sha256:b031b9601f1060bf1281feab89697324726ba0c0bae9d7cd7ab4b690940f0b92"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.1.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +reports = ["lxml"] + [[package]] name = "mypy-extensions" version = "1.0.0" @@ -1258,20 +1433,6 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] -[[package]] -name = "nodeenv" -version = "1.8.0" -description = "Node.js virtual environment builder" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" -files = [ - {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, - {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, -] - -[package.dependencies] -setuptools = "*" - [[package]] name = "opentelemetry-api" version = "1.19.0" @@ -1383,13 +1544,13 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co [[package]] name = "pluggy" -version = "1.2.0" +version = "1.3.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, - {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, ] [package.extras] @@ -1527,24 +1688,6 @@ files = [ [package.dependencies] tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -[[package]] -name = "pyright" -version = "1.1.322" -description = "Command line wrapper for pyright" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pyright-1.1.322-py3-none-any.whl", hash = "sha256:1bcddb55c4fca5d3c86eee71db0e8aad80536527f2084284998c6cbceda10e4e"}, - {file = "pyright-1.1.322.tar.gz", hash = "sha256:c8299d8b5d8c6e6f6ea48a77bf330a6df79e23305d21d25043bba8a23c1e1ed8"}, -] - -[package.dependencies] -nodeenv = ">=1.6.0" - -[package.extras] -all = ["twine (>=3.4.1)"] -dev = ["twine (>=3.4.1)"] - [[package]] name = "pytest" version = "7.4.0" @@ -1872,18 +2015,18 @@ jeepney = ">=0.6" [[package]] name = "setuptools" -version = "68.0.0" +version = "68.1.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, - {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, + {file = "setuptools-68.1.2-py3-none-any.whl", hash = "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b"}, + {file = "setuptools-68.1.2.tar.gz", hash = "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5,<=7.1.2)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] @@ -1975,6 +2118,53 @@ rfc3986 = ">=1.4.0" rich = ">=12.0.0" urllib3 = ">=1.26.0" +[[package]] +name = "types-pytz" +version = "2023.3.0.1" +description = "Typing stubs for pytz" +optional = false +python-versions = "*" +files = [ + {file = "types-pytz-2023.3.0.1.tar.gz", hash = "sha256:1a7b8d4aac70981cfa24478a41eadfcd96a087c986d6f150d77e3ceb3c2bdfab"}, + {file = "types_pytz-2023.3.0.1-py3-none-any.whl", hash = "sha256:65152e872137926bb67a8fe6cc9cfd794365df86650c5d5fdc7b167b0f38892e"}, +] + +[[package]] +name = "types-pyyaml" +version = "6.0.12.11" +description = "Typing stubs for PyYAML" +optional = false +python-versions = "*" +files = [ + {file = "types-PyYAML-6.0.12.11.tar.gz", hash = "sha256:7d340b19ca28cddfdba438ee638cd4084bde213e501a3978738543e27094775b"}, + {file = "types_PyYAML-6.0.12.11-py3-none-any.whl", hash = "sha256:a461508f3096d1d5810ec5ab95d7eeecb651f3a15b71959999988942063bf01d"}, +] + +[[package]] +name = "types-requests" +version = "2.31.0.2" +description = "Typing stubs for requests" +optional = false +python-versions = "*" +files = [ + {file = "types-requests-2.31.0.2.tar.gz", hash = "sha256:6aa3f7faf0ea52d728bb18c0a0d1522d9bfd8c72d26ff6f61bfc3d06a411cf40"}, + {file = "types_requests-2.31.0.2-py3-none-any.whl", hash = "sha256:56d181c85b5925cbc59f4489a57e72a8b2166f18273fd8ba7b6fe0c0b986f12a"}, +] + +[package.dependencies] +types-urllib3 = "*" + +[[package]] +name = "types-urllib3" +version = "1.26.25.14" +description = "Typing stubs for urllib3" +optional = false +python-versions = "*" +files = [ + {file = "types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f"}, + {file = "types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e"}, +] + [[package]] name = "typing-extensions" version = "4.7.1" @@ -2226,4 +2416,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "9249681d17914def1558d7972b79efb7362d2b22381f2da88404ed1f018d5ebc" +content-hash = "b50f133668cffe99e6c147dba74e91b335a7258ce4d0d8028c084c2374567871" diff --git a/pyproject.toml b/pyproject.toml index 33ec34f..018db0e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,11 +20,11 @@ classifiers = [ "Topic :: Software Development :: Build Tools", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Monitoring", + "Typing :: Typed" ] packages = [{ include = "autometrics", from = "src" }] [tool.poetry.dependencies] -opentelemetry-api = "^1.17.0" opentelemetry-exporter-prometheus = "^1.12.0rc1" opentelemetry-sdk = "^1.17.0" prometheus-client = "^0.16.0 || ^0.17.0" @@ -35,12 +35,28 @@ typing-extensions = "^4.5.0" [tool.poetry.group.dev] optional = true +[tool.mypy] +namespace_packages = true +mypy_path = "src" +enable_incomplete_feature = "Unpack" + +# This override is needed because with certain flavors of python and +# mypy you can get the following error: +# opentelemetry/attributes/__init__.py:14: error: invalid syntax +# Which at the time of writing is a line that states ignore types: +# `# type: ignore` +[[tool.mypy.overrides]] +module = [ + "opentelemetry.attributes", +] +follow_imports = "skip" + [tool.poetry.group.dev.dependencies] -pyright = "^1.1.307" pytest = "^7.3.0" pytest-asyncio = "^0.21.0" black = "^23.3.0" pytest-xdist = "^3.3.1" +mypy = "^1.5.1" twine = "4.0.2" [tool.poetry.group.examples] @@ -83,6 +99,13 @@ uvicorn = "0.21.1" webencodings = "0.5.1" zipp = "3.15.0" locust = "^2.15.1" +django-stubs = "4.2.3" + + + +[tool.poetry.group.development.dependencies] +types-requests = "^2.31.0.2" +django-stubs = "^4.2.3" [build-system] requires = ["poetry-core"] diff --git a/src/autometrics/decorator.py b/src/autometrics/decorator.py index 3ab243e..03dfb1d 100644 --- a/src/autometrics/decorator.py +++ b/src/autometrics/decorator.py @@ -4,7 +4,7 @@ from contextvars import ContextVar, Token from functools import wraps -from typing import overload, TypeVar, Callable, Optional, Awaitable +from typing import overload, TypeVar, Callable, Optional, Awaitable, Union, Coroutine from typing_extensions import ParamSpec from .objectives import Objective @@ -15,39 +15,60 @@ append_docs_to_docstring, ) - -P = ParamSpec("P") -T = TypeVar("T") - +Params = ParamSpec("Params") +R = TypeVar("R") +Y = TypeVar("Y") +S = TypeVar("S") caller_module_var: ContextVar[str] = ContextVar("caller.module", default="") caller_function_var: ContextVar[str] = ContextVar("caller.function", default="") -# Bare decorator usage +# Decorator with arguments (where decorated function returns an awaitable) @overload -def autometrics(func: Callable[P, T]) -> Callable[P, T]: +def autometrics( + func: None = None, + *, + objective: Optional[Objective] = None, + track_concurrency: Optional[bool] = False, + record_error_if: Callable[[R], bool], + record_success_if: Optional[Callable[[Exception], bool]] = None, +) -> Union[ + Callable[ + [Callable[Params, Coroutine[Y, S, R]]], Callable[Params, Coroutine[Y, S, R]] + ], + Callable[[Callable[Params, R]], Callable[Params, R]], +]: ... +# Decorator with arguments (where decorated function returns an awaitable) @overload -def autometrics(func: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[T]]: +def autometrics( + func: None = None, + *, + objective: Optional[Objective] = None, + track_concurrency: Optional[bool] = False, + record_success_if: Optional[Callable[[Exception], bool]] = None, +) -> Callable[[Callable[Params, R]], Callable[Params, R]]: ... -# Decorator with arguments +# Using the func parameter +# i.e. using @autometrics() @overload def autometrics( - *, objective: Optional[Objective] = None, track_concurrency: Optional[bool] = False -) -> Callable: + func: Callable[Params, R], +) -> Callable[Params, R]: ... def autometrics( - func: Optional[Callable] = None, - *, - objective: Optional[Objective] = None, - track_concurrency: Optional[bool] = False, + func=None, + objective=None, + track_concurrency=None, + record_error_if=None, + record_success_if=None, ): """Decorator for tracking function calls and duration. Supports synchronous and async functions.""" @@ -100,7 +121,7 @@ def track_result_error( result=Result.ERROR, ) - def sync_decorator(func: Callable[P, T]) -> Callable[P, T]: + def sync_decorator(func: Callable[Params, R]) -> Callable[Params, R]: """Helper for decorating synchronous functions, to track calls and duration.""" module_name = get_module_name(func) @@ -108,7 +129,7 @@ def sync_decorator(func: Callable[P, T]) -> Callable[P, T]: register_function_info(func_name, module_name) @wraps(func) - def sync_wrapper(*args: P.args, **kwds: P.kwargs) -> T: + def sync_wrapper(*args: Params.args, **kwds: Params.kwargs) -> R: start_time = time.time() caller_module = caller_module_var.get() caller_function = caller_function_var.get() @@ -121,23 +142,40 @@ def sync_wrapper(*args: P.args, **kwds: P.kwargs) -> T: if track_concurrency: track_start(module=module_name, function=func_name) result = func(*args, **kwds) - track_result_ok( - start_time, - function=func_name, - module=module_name, - caller_module=caller_module, - caller_function=caller_function, - ) + if record_error_if and record_error_if(result): + track_result_error( + start_time, + function=func_name, + module=module_name, + caller_module=caller_module, + caller_function=caller_function, + ) + else: + track_result_ok( + start_time, + function=func_name, + module=module_name, + caller_module=caller_module, + caller_function=caller_function, + ) except Exception as exception: - result = exception.__class__.__name__ - track_result_error( - start_time, - function=func_name, - module=module_name, - caller_module=caller_module, - caller_function=caller_function, - ) + if record_success_if and record_success_if(exception): + track_result_ok( + start_time, + function=func_name, + module=module_name, + caller_module=caller_module, + caller_function=caller_function, + ) + else: + track_result_error( + start_time, + function=func_name, + module=module_name, + caller_module=caller_module, + caller_function=caller_function, + ) # Reraise exception raise exception @@ -152,7 +190,9 @@ def sync_wrapper(*args: P.args, **kwds: P.kwargs) -> T: sync_wrapper.__doc__ = append_docs_to_docstring(func, func_name, module_name) return sync_wrapper - def async_decorator(func: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[T]]: + def async_decorator( + func: Callable[Params, Awaitable[R]] + ) -> Callable[Params, Awaitable[R]]: """Helper for decorating async functions, to track calls and duration.""" module_name = get_module_name(func) @@ -160,7 +200,7 @@ def async_decorator(func: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[T] register_function_info(func_name, module_name) @wraps(func) - async def async_wrapper(*args: P.args, **kwds: P.kwargs) -> T: + async def async_wrapper(*args: Params.args, **kwds: Params.kwargs) -> R: start_time = time.time() caller_module = caller_module_var.get() caller_function = caller_function_var.get() @@ -173,23 +213,40 @@ async def async_wrapper(*args: P.args, **kwds: P.kwargs) -> T: if track_concurrency: track_start(module=module_name, function=func_name) result = await func(*args, **kwds) - track_result_ok( - start_time, - function=func_name, - module=module_name, - caller_module=caller_module, - caller_function=caller_function, - ) + if record_error_if and record_error_if(result): + track_result_error( + start_time, + function=func_name, + module=module_name, + caller_module=caller_module, + caller_function=caller_function, + ) + else: + track_result_ok( + start_time, + function=func_name, + module=module_name, + caller_module=caller_module, + caller_function=caller_function, + ) except Exception as exception: - result = exception.__class__.__name__ - track_result_error( - start_time, - function=func_name, - module=module_name, - caller_module=caller_module, - caller_function=caller_function, - ) + if record_success_if and record_success_if(exception): + track_result_ok( + start_time, + function=func_name, + module=module_name, + caller_module=caller_module, + caller_function=caller_function, + ) + else: + track_result_error( + start_time, + function=func_name, + module=module_name, + caller_module=caller_module, + caller_function=caller_function, + ) # Reraise exception raise exception @@ -204,7 +261,7 @@ async def async_wrapper(*args: P.args, **kwds: P.kwargs) -> T: async_wrapper.__doc__ = append_docs_to_docstring(func, func_name, module_name) return async_wrapper - def pick_decorator(func: Callable) -> Callable: + def pick_decorator(func): """Pick the correct decorator based on the function type.""" if inspect.iscoroutinefunction(func): return async_decorator(func) diff --git a/src/autometrics/py.typed b/src/autometrics/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/src/autometrics/test_decorator.py b/src/autometrics/test_decorator.py index a1e12f5..281c45e 100644 --- a/src/autometrics/test_decorator.py +++ b/src/autometrics/test_decorator.py @@ -1,14 +1,38 @@ """Test the autometrics decorator.""" import time import asyncio +from typing import Optional, Coroutine from prometheus_client.exposition import generate_latest import pytest +from requests import HTTPError from .decorator import autometrics from .objectives import ObjectiveLatency, Objective, ObjectivePercentile from .tracker import set_tracker, TrackerType from .utils import get_function_name, get_module_name +HTTP_ERROR_TEXT = "This is an http error" +CODE_NOT_SET_TEXT = "status code not set" + + +def basic_http_error_function(status_code: Optional[int] = 404): + """This is a basic function that raises an HTTPError. Unless the status_code parameter is set to None""" + + if status_code is None: + return CODE_NOT_SET_TEXT + + raise HTTPError(HTTP_ERROR_TEXT, response=status_code) + + +async def async_http_error_function(status_code: Optional[int] = 404): + """This is a basic function that raises an HTTPError. Unless the status_code parameter is set to None""" + await asyncio.sleep(0.2) + + if status_code is None: + return CODE_NOT_SET_TEXT + + raise HTTPError(HTTP_ERROR_TEXT, response=status_code) + def basic_function(sleep_duration: float = 0.0): """This is a basic function.""" @@ -24,6 +48,7 @@ def error_function(): async def basic_async_function(sleep_duration: float = 1.0): """This is a basic async function.""" await asyncio.sleep(sleep_duration) + return True @@ -161,8 +186,7 @@ async def test_objectives_async(self): sleep_duration = 0.25 # Test that the function is *still* async after we wrapped it - assert asyncio.iscoroutinefunction(wrapped_function) == True - + assert asyncio.iscoroutinefunction(wrapped_function) is True await wrapped_function(sleep_duration) # get the metrics @@ -212,6 +236,115 @@ def test_exception(self): duration_sum = f"""function_calls_duration_seconds_sum{{function="error_function",module="autometrics.test_decorator",objective_latency_threshold="",objective_name="",objective_percentile="",service_name="autometrics"}}""" assert duration_sum in data + def test_record_success_if(self): + """This is a test that tests exceptions that may or may not be reported as an error""" + + def record_success_if(exception: Exception): + return isinstance(exception, HTTPError) + + def record_error_if(result: str): + return result == CODE_NOT_SET_TEXT + + wrapped_function = autometrics( + record_success_if=record_success_if, record_error_if=record_error_if + )(basic_http_error_function) + + with pytest.raises(HTTPError) as exception: + wrapped_function(status_code=404) + + assert HTTP_ERROR_TEXT in str(exception.value) + assert exception.value.response == 404 + + # get the metrics + blob = generate_latest() + assert blob is not None + data = blob.decode("utf-8") + + total_count = f"""function_calls_total{{caller_function="",caller_module="",function="basic_http_error_function",module="autometrics.test_decorator",objective_name="",objective_percentile="",result="ok",service_name="autometrics"}} 1.0""" + assert total_count in data + + total_count = f"""function_calls_total{{caller_function="",caller_module="",function="basic_http_error_function",module="autometrics.test_decorator",objective_name="",objective_percentile="",result="error",service_name="autometrics"}} 0.0""" + assert total_count in data + + for latency in ObjectiveLatency: + query = f"""function_calls_duration_seconds_bucket{{function="basic_http_error_function",le="{latency.value}",module="autometrics.test_decorator",objective_latency_threshold="",objective_name="",objective_percentile="",service_name="autometrics"}}""" + assert query in data + + duration_count = f"""function_calls_duration_seconds_count{{function="basic_http_error_function",module="autometrics.test_decorator",objective_latency_threshold="",objective_name="",objective_percentile="",service_name="autometrics"}}""" + assert duration_count in data + + duration_sum = f"""function_calls_duration_seconds_sum{{function="basic_http_error_function",module="autometrics.test_decorator",objective_latency_threshold="",objective_name="",objective_percentile="",service_name="autometrics"}}""" + assert duration_sum in data + + # Calling the test function with None should result in no exception but it should still be marked as an error according to the metrics + result = wrapped_function(status_code=None) + assert result == CODE_NOT_SET_TEXT + + # get the metrics + blob = generate_latest() + assert blob is not None + data = blob.decode("utf-8") + + total_count = f"""function_calls_total{{caller_function="",caller_module="",function="basic_http_error_function",module="autometrics.test_decorator",objective_name="",objective_percentile="",result="ok",service_name="autometrics"}} 1.0""" + assert total_count in data + total_count = f"""function_calls_total{{caller_function="",caller_module="",function="basic_http_error_function",module="autometrics.test_decorator",objective_name="",objective_percentile="",result="error",service_name="autometrics"}} 1.0""" + assert total_count in data + + @pytest.mark.asyncio + async def test_async_record_success_or_ok_if(self): + """This is a test that tests exceptions that may or may not be reported as an error""" + + def record_success_if(exception: Exception): + return isinstance(exception, HTTPError) + + def record_error_if(result: str): + return result == CODE_NOT_SET_TEXT + + wrapped_function = autometrics( + record_success_if=record_success_if, record_error_if=record_error_if + )(async_http_error_function) + + with pytest.raises(HTTPError) as exception: + await wrapped_function(status_code=404) + + assert HTTP_ERROR_TEXT in str(exception.value) + assert exception.value.response == 404 + + # get the metrics + blob = generate_latest() + assert blob is not None + data = blob.decode("utf-8") + + total_count = f"""function_calls_total{{caller_function="",caller_module="",function="async_http_error_function",module="autometrics.test_decorator",objective_name="",objective_percentile="",result="ok",service_name="autometrics"}} 1.0""" + assert total_count in data + + total_count = f"""function_calls_total{{caller_function="",caller_module="",function="async_http_error_function",module="autometrics.test_decorator",objective_name="",objective_percentile="",result="error",service_name="autometrics"}} 0.0""" + assert total_count in data + + for latency in ObjectiveLatency: + query = f"""function_calls_duration_seconds_bucket{{function="async_http_error_function",le="{latency.value}",module="autometrics.test_decorator",objective_latency_threshold="",objective_name="",objective_percentile="",service_name="autometrics"}}""" + assert query in data + + duration_count = f"""function_calls_duration_seconds_count{{function="async_http_error_function",module="autometrics.test_decorator",objective_latency_threshold="",objective_name="",objective_percentile="",service_name="autometrics"}}""" + assert duration_count in data + + duration_sum = f"""function_calls_duration_seconds_sum{{function="async_http_error_function",module="autometrics.test_decorator",objective_latency_threshold="",objective_name="",objective_percentile="",service_name="autometrics"}}""" + assert duration_sum in data + + # Calling the test function with None should result in no exception but it should still be marked as an error according to the metrics + result = await wrapped_function(status_code=None) + assert result == CODE_NOT_SET_TEXT + + # get the metrics + blob = generate_latest() + assert blob is not None + data = blob.decode("utf-8") + + total_count = f"""function_calls_total{{caller_function="",caller_module="",function="async_http_error_function",module="autometrics.test_decorator",objective_name="",objective_percentile="",result="ok",service_name="autometrics"}} 1.0""" + assert total_count in data + total_count = f"""function_calls_total{{caller_function="",caller_module="",function="async_http_error_function",module="autometrics.test_decorator",objective_name="",objective_percentile="",result="error",service_name="autometrics"}} 1.0""" + assert total_count in data + @pytest.mark.asyncio async def test_async_exception(self): """This is a test that covers exceptions.""" @@ -219,7 +352,7 @@ async def test_async_exception(self): wrapped_function = autometrics(error_async_function) # Test that the function is *still* async after we wrap it - assert asyncio.iscoroutinefunction(wrapped_function) == True + assert asyncio.iscoroutinefunction(wrapped_function) is True with pytest.raises(RuntimeError) as exception: await wrapped_function() diff --git a/src/autometrics/tracker/test_concurrency.py b/src/autometrics/tracker/test_concurrency.py index 1ff7395..d10703f 100644 --- a/src/autometrics/tracker/test_concurrency.py +++ b/src/autometrics/tracker/test_concurrency.py @@ -2,7 +2,6 @@ import asyncio import pytest - from .tracker import set_tracker, TrackerType from ..decorator import autometrics @@ -10,7 +9,7 @@ @autometrics(track_concurrency=True) -async def sleep(time): +async def sleep(time: float): await asyncio.sleep(time) diff --git a/src/autometrics/tracker/test_format.py b/src/autometrics/tracker/test_format.py index 7f34440..afa006f 100644 --- a/src/autometrics/tracker/test_format.py +++ b/src/autometrics/tracker/test_format.py @@ -3,7 +3,7 @@ from . import TrackerType from ..decorator import autometrics -from .. import init +from ..init import init @pytest.mark.parametrize("tracker", TrackerType) diff --git a/src/autometrics/tracker/test_tracker.py b/src/autometrics/tracker/test_tracker.py index b4689f7..d6b2129 100644 --- a/src/autometrics/tracker/test_tracker.py +++ b/src/autometrics/tracker/test_tracker.py @@ -6,7 +6,7 @@ from .tracker import get_tracker, default_tracker -from .. import init +from ..init import init def test_default_tracker(monkeypatch): diff --git a/src/py.typed b/src/py.typed new file mode 100644 index 0000000..e69de29