From 7480356b9787527c7eab7631f898ce83fb0ebc3f Mon Sep 17 00:00:00 2001 From: Peter Schutt Date: Mon, 16 Jan 2023 15:03:53 +1000 Subject: [PATCH] feature(testing): pytest plugin (#246) Adds an initial pass at a pytest plugin for testing `starlite-saqlalchemy` applications. Includes the following fixtures: * `is_unit_test`: a boolean that distinguishes between unit and integration tests * `_patch_http_close`: an autouse fixture that prevents any globally instantiated http clients being closed between tests * `_patch_sqlalchemy_plugin`: autouse fixture that patches the sqlalchemy plugin `on_shutdown` method for unittests * `_patch_worker`: autouse fixture that patches the worker `on_app_startup` and `stop` methods for unit tests * `app`: fixture that uses a defined import path to inject an application instance. Default path is `app.main:create_app` * `client`: fixture that injects a starlite `TestClient` instance bound to the same app given by the `app` fixture * `cap_logger`: a structlog capturing logger for inspecting log output Closes #106 Closes #232 --- .flake8 | 3 +- .github/workflows/ci.yml | 11 +- docs/testing/pytest_plugin.md | 137 ++ mkdocs.yml | 2 + poetry.lock | 1341 +++++++++-------- pyproject.toml | 12 +- src/pytest_starlite_saqlalchemy/__init__.py | 13 + src/pytest_starlite_saqlalchemy/plugin.py | 139 ++ src/starlite_saqlalchemy/__init__.py | 2 + src/starlite_saqlalchemy/settings.py | 1 - src/starlite_saqlalchemy/sqlalchemy_plugin.py | 3 +- src/starlite_saqlalchemy/testing/__init__.py | 11 + .../testing/controller_test.py | 109 ++ .../generic_mock_repository.py} | 136 +- .../testing/modify_settings.py | 37 + tests.env | 40 - tests/conftest.py | 38 - tests/integration/conftest.py | 58 +- tests/integration/test_authors.py | 3 - tests/integration/test_logging.py | 1 - tests/pytest_plugin/__init__.py | 0 tests/pytest_plugin/conftest.py | 4 + tests/pytest_plugin/test_plugin.py | 174 +++ tests/unit/conftest.py | 47 - tests/unit/test_log.py | 2 - tests/utils/app.py | 16 + tests/utils/controllers.py | 17 +- tox.ini | 9 +- 28 files changed, 1367 insertions(+), 999 deletions(-) create mode 100644 docs/testing/pytest_plugin.md create mode 100644 src/pytest_starlite_saqlalchemy/__init__.py create mode 100644 src/pytest_starlite_saqlalchemy/plugin.py create mode 100644 src/starlite_saqlalchemy/testing/__init__.py create mode 100644 src/starlite_saqlalchemy/testing/controller_test.py rename src/starlite_saqlalchemy/{testing.py => testing/generic_mock_repository.py} (56%) create mode 100644 src/starlite_saqlalchemy/testing/modify_settings.py create mode 100644 tests/pytest_plugin/__init__.py create mode 100644 tests/pytest_plugin/conftest.py create mode 100644 tests/pytest_plugin/test_plugin.py create mode 100644 tests/utils/app.py diff --git a/.flake8 b/.flake8 index 6f3cd761..f7517662 100644 --- a/.flake8 +++ b/.flake8 @@ -6,12 +6,13 @@ type-checking-exempt-modules = from sqlalchemy.orm per-file-ignores = examples/dto/*:T201,TC examples/tests/*:SCS108,PT013 + src/pytest_starlite_saqlalchemy/__init__.py:F401 src/starlite_saqlalchemy/dependencies.py:TC src/starlite_saqlalchemy/health.py:TC src/starlite_saqlalchemy/repository/filters.py:TC src/starlite_saqlalchemy/scripts.py:T201 src/starlite_saqlalchemy/settings.py:TC - src/starlite_saqlalchemy/testing.py:SCS108 + src/starlite_saqlalchemy/testing/controller_test.py:SCS108 src/starlite_saqlalchemy/users/controllers.py:TC tests/*:SCS108,PT013 tests/integration/test_tests.py:TC002,SCS108 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e1b5f8c..d679d5b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,6 @@ on: push: branches: [main] pull_request: - branches: [main] env: FORCE_COLOR: "1" @@ -35,7 +34,7 @@ jobs: with: python-version: ${{env.PYTHON_LATEST}} - name: Install Dependencies - run: python -m pip install --upgrade wheel tox + run: python -m pip install --upgrade wheel tox==4.2.8 - run: python -m tox -e pylint mypy: name: mypy @@ -56,7 +55,7 @@ jobs: with: python-version: ${{env.PYTHON_LATEST}} - name: Install Dependencies - run: python -m pip install --upgrade wheel tox + run: python -m pip install --upgrade wheel tox==4.2.8 - run: python -m tox -e mypy pyright: name: pyright @@ -78,7 +77,7 @@ jobs: with: python-version: ${{env.PYTHON_LATEST}} - name: Install Dependencies - run: python -m pip install --upgrade wheel tox + run: python -m pip install --upgrade wheel tox==4.2.8 - run: python -m tox -e pyright tests: name: tests on ${{matrix.python-version}} @@ -108,7 +107,7 @@ jobs: with: python-version: ${{matrix.python-version}} - name: Install Dependencies - run: python -m pip install --upgrade wheel tox tox-gh-actions + run: python -m pip install --upgrade wheel tox==4.2.8 tox-gh-actions - run: python -m tox - name: Upload Coverage Data uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # @v3.1.1 @@ -133,7 +132,7 @@ jobs: - uses: actions/setup-python@5ccb29d8773c3f3f653e1705f474dfaa8a06a912 #v4.4.0 with: python-version: ${{env.PYTHON_LATEST}} - - run: python -m pip install --upgrade wheel tox + - run: python -m pip install --upgrade wheel tox==4.2.8 - name: Download coverage data uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 # @v3.0.1 with: diff --git a/docs/testing/pytest_plugin.md b/docs/testing/pytest_plugin.md new file mode 100644 index 00000000..bf6bf6d1 --- /dev/null +++ b/docs/testing/pytest_plugin.md @@ -0,0 +1,137 @@ +# Pytest Plugin + +The nature of applications built with the `starlite-saqlalchemy` pattern is that they rely heavily +on connected services. + +Abstraction of [PostgreSQL][2] and [Redis][3] connectivity boilerplate is a nice convenience, +however to successfully patch the application for testing requires deeper knowledge of the +implementation than would be otherwise necessary. + +So, `starlite-saqlalchemy` ships with a selection of [pytest fixtures][1] that are often necessary +when building applications such as these. + +## `app` + +The `app` fixture provides an instance of a `Starlite` application. + +```python +from __future__ import annotations + +from starlite import Starlite + + +def test_app_fixture(app: Starlite) -> None: + assert isinstance(app, Starlite) +``` + +The value of Pytest ini option, `test_app` is used to determine the application to load. + +```toml +# pyproject.toml + +[tool.pytest.ini_options] +test_app = "app.main:create_app" +``` + +If no value is configured for the `test_app` ini option, the default location of +`"app.main:create_app"` is searched. + +The value of the `test_app` ini option can either point to an application factory or `Starlite` +instance. + +If the object found at the import path is not a `Starlite` instance, the fixture assumes it is +an application factory, and will call the object and return the response. + +The value of `test_app` is resolved using the uvicorn `import_from_string()` function, so it +supports the same format as `uvicorn` supports for its `app` and `factory` parameters. + +## `client` + +A `starlite.testing.TestClient` instance, wired to the same application that is produced by the +`app` fixture. + +## `cap_logger` + +The `cap_logger` fixture provides an instance of [`structlog.testing.CapturingLogger`][4]. + +```python +from __future__ import annotations + +from typing import TYPE_CHECKING + +from structlog.testing import CapturedCall + +if TYPE_CHECKING: + from structlog.testing import CapturingLogger + + +def test_app_fixture(cap_logger: CapturingLogger) -> None: + cap_logger.info("hello") + cap_logger.info("hello", when="again") + assert cap_logger.calls == [ + CapturedCall(method_name="info", args=("hello",), kwargs={}), + CapturedCall(method_name="info", args=("hello",), kwargs={"when": "again"}), + ] +``` + +The `cap_logger` fixture will capture any `structlog` calls made by the starlite application or the +SAQ worker, so that they can be inspected as part of tests. + +```python +from __future__ import annotations + +from typing import TYPE_CHECKING + +from httpx import AsyncClient + +if TYPE_CHECKING: + from starlite import Starlite + from structlog.testing import CapturingLogger + + +async def test_health_logging_skipped( + app: Starlite, cap_logger: CapturingLogger +) -> None: + """Test that calls to the health check route are not logged.""" + + async with AsyncClient(app=app, base_url="http://testserver") as client: + response = await client.get("/health") + assert response.status_code == 200 + + assert [] == cap_logger.calls +``` + +## is_unit_test + +The `is_unit_test` fixture returns a `bool` that indicates if the test suite believes it is running +a unit test, or an integration test. + +To determine this, we compare the path of the running test to the value of the Pytest ini option +`unit_test_pattern`, which by default is `"^.*/tests/unit/.*$"`. + +This fixture is used to make fixtures behave differently between unit and integration test contexts. + +## _patch_http_close + +This is an [`autouse` fixture][5], that prevents HTTP clients that are defined in the global scope +from being closed. + +The application is configured to close all instantiated HTTP clients on app shutdown, however when +apps are defined in a global/class scope, a test that runs after the first application shutdown in +the test suite would fail. + +## _patch_sqlalchemy_plugin + +This is an [`autouse` fixture][5], that mocks out the `on_shutdown` method of the SQLAlchemy config +object for unit tests. + +## _patch_worker + +This is an [`autouse` fixture][5], that mocks out the `on_app_startup` and `stop` methods of +`worker.Worker` type for unit tests. + +[1]: https://docs.pytest.org/en/latest/explanation/fixtures.html#about-fixtures +[2]: https://www.postgresql.org/ +[3]: https://redis.io +[4]: https://www.structlog.org/en/stable/api.html#structlog.testing.CapturingLogger +[5]: https://docs.pytest.org/en/6.2.x/fixture.html#autouse-fixtures-fixtures-you-don-t-have-to-request diff --git a/mkdocs.yml b/mkdocs.yml index 763726ef..cc396d14 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -7,6 +7,8 @@ nav: - DTOs: dto.md - Async Worker: async_worker.md - Logging: logging.md + - Testing: + - Pytest Plugin: testing/pytest_plugin.md - Reference: reference/ watch: - src/starlite_saqlalchemy diff --git a/poetry.lock b/poetry.lock index 13aea8b1..ae8e4410 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Poetry and should not be changed by hand. + [[package]] name = "anyio" version = "3.6.2" @@ -5,6 +7,10 @@ description = "High level compatibility layer for multiple asynchronous event lo category = "main" optional = false python-versions = ">=3.6.2" +files = [ + {file = "anyio-3.6.2-py3-none-any.whl", hash = "sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3"}, + {file = "anyio-3.6.2.tar.gz", hash = "sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421"}, +] [package.dependencies] idna = ">=2.8" @@ -22,6 +28,10 @@ description = "Timeout context manager for asyncio programs" category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, + {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, +] [[package]] name = "asyncpg" @@ -30,6 +40,44 @@ description = "An asyncio PostgreSQL driver" category = "main" optional = false python-versions = ">=3.7.0" +files = [ + {file = "asyncpg-0.27.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fca608d199ffed4903dce1bcd97ad0fe8260f405c1c225bdf0002709132171c2"}, + {file = "asyncpg-0.27.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:20b596d8d074f6f695c13ffb8646d0b6bb1ab570ba7b0cfd349b921ff03cfc1e"}, + {file = "asyncpg-0.27.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a6206210c869ebd3f4eb9e89bea132aefb56ff3d1b7dd7e26b102b17e27bbb1"}, + {file = "asyncpg-0.27.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7a94c03386bb95456b12c66026b3a87d1b965f0f1e5733c36e7229f8f137747"}, + {file = "asyncpg-0.27.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bfc3980b4ba6f97138b04f0d32e8af21d6c9fa1f8e6e140c07d15690a0a99279"}, + {file = "asyncpg-0.27.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9654085f2b22f66952124de13a8071b54453ff972c25c59b5ce1173a4283ffd9"}, + {file = "asyncpg-0.27.0-cp310-cp310-win32.whl", hash = "sha256:879c29a75969eb2722f94443752f4720d560d1e748474de54ae8dd230bc4956b"}, + {file = "asyncpg-0.27.0-cp310-cp310-win_amd64.whl", hash = "sha256:ab0f21c4818d46a60ca789ebc92327d6d874d3b7ccff3963f7af0a21dc6cff52"}, + {file = "asyncpg-0.27.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:18f77e8e71e826ba2d0c3ba6764930776719ae2b225ca07e014590545928b576"}, + {file = "asyncpg-0.27.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c2232d4625c558f2aa001942cac1d7952aa9f0dbfc212f63bc754277769e1ef2"}, + {file = "asyncpg-0.27.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a3a4ff43702d39e3c97a8786314123d314e0f0e4dabc8367db5b665c93914de"}, + {file = "asyncpg-0.27.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccddb9419ab4e1c48742457d0c0362dbdaeb9b28e6875115abfe319b29ee225d"}, + {file = "asyncpg-0.27.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:768e0e7c2898d40b16d4ef7a0b44e8150db3dd8995b4652aa1fe2902e92c7df8"}, + {file = "asyncpg-0.27.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:609054a1f47292a905582a1cfcca51a6f3f30ab9d822448693e66fdddde27920"}, + {file = "asyncpg-0.27.0-cp311-cp311-win32.whl", hash = "sha256:8113e17cfe236dc2277ec844ba9b3d5312f61bd2fdae6d3ed1c1cdd75f6cf2d8"}, + {file = "asyncpg-0.27.0-cp311-cp311-win_amd64.whl", hash = "sha256:bb71211414dd1eeb8d31ec529fe77cff04bf53efc783a5f6f0a32d84923f45cf"}, + {file = "asyncpg-0.27.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4750f5cf49ed48a6e49c6e5aed390eee367694636c2dcfaf4a273ca832c5c43c"}, + {file = "asyncpg-0.27.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:eca01eb112a39d31cc4abb93a5aef2a81514c23f70956729f42fb83b11b3483f"}, + {file = "asyncpg-0.27.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5710cb0937f696ce303f5eed6d272e3f057339bb4139378ccecafa9ee923a71c"}, + {file = "asyncpg-0.27.0-cp37-cp37m-win_amd64.whl", hash = "sha256:71cca80a056ebe19ec74b7117b09e650990c3ca535ac1c35234a96f65604192f"}, + {file = "asyncpg-0.27.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4bb366ae34af5b5cabc3ac6a5347dfb6013af38c68af8452f27968d49085ecc0"}, + {file = "asyncpg-0.27.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16ba8ec2e85d586b4a12bcd03e8d29e3d99e832764d6a1d0b8c27dbbe4a2569d"}, + {file = "asyncpg-0.27.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d20dea7b83651d93b1eb2f353511fe7fd554752844523f17ad30115d8b9c8cd6"}, + {file = "asyncpg-0.27.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e56ac8a8237ad4adec97c0cd4728596885f908053ab725e22900b5902e7f8e69"}, + {file = "asyncpg-0.27.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bf21ebf023ec67335258e0f3d3ad7b91bb9507985ba2b2206346de488267cad0"}, + {file = "asyncpg-0.27.0-cp38-cp38-win32.whl", hash = "sha256:69aa1b443a182b13a17ff926ed6627af2d98f62f2fe5890583270cc4073f63bf"}, + {file = "asyncpg-0.27.0-cp38-cp38-win_amd64.whl", hash = "sha256:62932f29cf2433988fcd799770ec64b374a3691e7902ecf85da14d5e0854d1ea"}, + {file = "asyncpg-0.27.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fddcacf695581a8d856654bc4c8cfb73d5c9df26d5f55201722d3e6a699e9629"}, + {file = "asyncpg-0.27.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7d8585707ecc6661d07367d444bbaa846b4e095d84451340da8df55a3757e152"}, + {file = "asyncpg-0.27.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:975a320baf7020339a67315284a4d3bf7460e664e484672bd3e71dbd881bc692"}, + {file = "asyncpg-0.27.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2232ebae9796d4600a7819fc383da78ab51b32a092795f4555575fc934c1c89d"}, + {file = "asyncpg-0.27.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:88b62164738239f62f4af92567b846a8ef7cf8abf53eddd83650603de4d52163"}, + {file = "asyncpg-0.27.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:eb4b2fdf88af4fb1cc569781a8f933d2a73ee82cd720e0cb4edabbaecf2a905b"}, + {file = "asyncpg-0.27.0-cp39-cp39-win32.whl", hash = "sha256:8934577e1ed13f7d2d9cea3cc016cc6f95c19faedea2c2b56a6f94f257cea672"}, + {file = "asyncpg-0.27.0-cp39-cp39-win_amd64.whl", hash = "sha256:1b6499de06fe035cf2fa932ec5617ed3f37d4ebbf663b655922e105a484a6af9"}, + {file = "asyncpg-0.27.0.tar.gz", hash = "sha256:720986d9a4705dd8a40fdf172036f5ae787225036a7eb46e704c45aa8f62c054"}, +] [package.extras] dev = ["Cython (>=0.29.24,<0.30.0)", "Sphinx (>=4.1.2,<4.2.0)", "flake8 (>=5.0.4,<5.1.0)", "pytest (>=6.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "uvloop (>=0.15.3)"] @@ -43,6 +91,10 @@ description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, + {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, +] [[package]] name = "click" @@ -51,6 +103,10 @@ description = "Composable command line interface toolkit" category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, +] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} @@ -62,6 +118,10 @@ description = "Cross-platform colored terminal text." category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] [[package]] name = "croniter" @@ -70,24 +130,33 @@ description = "croniter provides iteration for datetime object with cron like fo category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "croniter-1.3.8-py2.py3-none-any.whl", hash = "sha256:d6ed8386d5f4bbb29419dc1b65c4909c04a2322bd15ec0dc5b2877bfa1b75c7a"}, + {file = "croniter-1.3.8.tar.gz", hash = "sha256:32a5ec04e97ec0837bcdf013767abd2e71cceeefd3c2e14c804098ce51ad6cd9"}, +] [package.dependencies] python-dateutil = "*" [[package]] name = "dnspython" -version = "2.2.1" +version = "2.3.0" description = "DNS toolkit" category = "main" optional = false -python-versions = ">=3.6,<4.0" +python-versions = ">=3.7,<4.0" +files = [ + {file = "dnspython-2.3.0-py3-none-any.whl", hash = "sha256:89141536394f909066cabd112e3e1a37e4e654db00a25308b0f130bc3152eb46"}, + {file = "dnspython-2.3.0.tar.gz", hash = "sha256:224e32b03eb46be70e12ef6d64e0be123a64e621ab4c0822ff6d450d52a540b9"}, +] [package.extras] curio = ["curio (>=1.2,<2.0)", "sniffio (>=1.1,<2.0)"] -dnssec = ["cryptography (>=2.6,<37.0)"] -doh = ["h2 (>=4.1.0)", "httpx (>=0.21.1)", "requests (>=2.23.0,<3.0.0)", "requests-toolbelt (>=0.9.1,<0.10.0)"] +dnssec = ["cryptography (>=2.6,<40.0)"] +doh = ["h2 (>=4.1.0)", "httpx (>=0.21.1)", "requests (>=2.23.0,<3.0.0)", "requests-toolbelt (>=0.9.1,<0.11.0)"] +doq = ["aioquic (>=0.9.20)"] idna = ["idna (>=2.1,<4.0)"] -trio = ["trio (>=0.14,<0.20)"] +trio = ["trio (>=0.14,<0.23)"] wmi = ["wmi (>=1.5.1,<2.0.0)"] [[package]] @@ -97,6 +166,10 @@ description = "A robust email address syntax and deliverability validation libra category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +files = [ + {file = "email_validator-1.3.0-py2.py3-none-any.whl", hash = "sha256:816073f2a7cffef786b29928f58ec16cdac42710a53bb18aa94317e3e145ec5c"}, + {file = "email_validator-1.3.0.tar.gz", hash = "sha256:553a66f8be2ec2dea641ae1d3f29017ab89e9d603d4a25cdaac39eefa283d769"}, +] [package.dependencies] dnspython = ">=1.15.0" @@ -109,6 +182,10 @@ description = "Faker is a Python package that generates fake data for you." category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "Faker-16.4.0-py3-none-any.whl", hash = "sha256:5420467fad3fa582094057754e5e81326cb1f51ab822bf9df96c077cfb35ae49"}, + {file = "Faker-16.4.0.tar.gz", hash = "sha256:dcffdca8ec9a715982bcd5f53ee688dc4784cd112f9910f8f7183773eb3ec276"}, +] [package.dependencies] python-dateutil = ">=2.4" @@ -120,6 +197,24 @@ description = "Ultra-fast query string and url-encoded form-data parsers" category = "main" optional = false python-versions = ">=3.8" +files = [ + {file = "fast_query_parsers-0.3.0-cp38-abi3-macosx_10_7_x86_64.whl", hash = "sha256:e01e9b794d6fad11207341a8e0a7b179f085c9874b3981a77f862a5e44cb241d"}, + {file = "fast_query_parsers-0.3.0-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:f2ffa7f1298db8ff8e013733e32edb77509a468843f5641875386f1df9bdecb4"}, + {file = "fast_query_parsers-0.3.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1becd3a0a06b14c57ee34976bf54d08fc910d4b410170ee5c28ac8d16ef23575"}, + {file = "fast_query_parsers-0.3.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd94f7715b6c1ec57b50e63c22298253648d864c9e78f90a258ebf2c07d13a38"}, + {file = "fast_query_parsers-0.3.0-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:52ef0241bcadc93ef47f650070c5f31f616cd5185a3af95f8b365e1fb135d991"}, + {file = "fast_query_parsers-0.3.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:189eed1007229c1e4a032076d503e92869eebd4a1ebd2498e6bb1b1b0c525708"}, + {file = "fast_query_parsers-0.3.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97d13dcc6cad29c8ef7c6f4bb6240847b476e4eb0445ac7f59d49a11db1644e2"}, + {file = "fast_query_parsers-0.3.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:befa91ff707f77e9948759bafdfe2b743d4b587e3f7767f2b5887b1ffa37f41d"}, + {file = "fast_query_parsers-0.3.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00d3d519cfd020c7a3bd961c9568b6042f853f25e204b8a307ff5b569dee9c38"}, + {file = "fast_query_parsers-0.3.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a659eb2acc0aa44f4cce7a79c4e0c76f14a26026fc13db8f094a29a38cf66248"}, + {file = "fast_query_parsers-0.3.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:e9b277e8281d7fe9b8e9450767cf1c1158ed729d81e03c1dfa2fe2118b22ffe0"}, + {file = "fast_query_parsers-0.3.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:0395ef9cacf49318a0f3caac4fde8a01dd7b7315c14f8a7d084965dedd764868"}, + {file = "fast_query_parsers-0.3.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:47639fc331e668b1be405c4e24af70ad21fc01a6847d2730803346ab9586e788"}, + {file = "fast_query_parsers-0.3.0-cp38-abi3-win32.whl", hash = "sha256:89ee582ab4b331f078eca2fbf51ce82396f749879fc30f20668b85a2896ea165"}, + {file = "fast_query_parsers-0.3.0-cp38-abi3-win_amd64.whl", hash = "sha256:4e9dd270f085a2337fab407d230a252664f952561cb83acece343a5c6a7d8e6b"}, + {file = "fast_query_parsers-0.3.0.tar.gz", hash = "sha256:df972c0b58d0bf51fa43b67d2604ab795984015d47552d02175ebcc685e4852b"}, +] [package.dependencies] maturin = "*" @@ -131,6 +226,68 @@ description = "Lightweight in-process concurrent programming" category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" +files = [ + {file = "greenlet-2.0.1-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:9ed358312e63bf683b9ef22c8e442ef6c5c02973f0c2a939ec1d7b50c974015c"}, + {file = "greenlet-2.0.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4f09b0010e55bec3239278f642a8a506b91034f03a4fb28289a7d448a67f1515"}, + {file = "greenlet-2.0.1-cp27-cp27m-win32.whl", hash = "sha256:1407fe45246632d0ffb7a3f4a520ba4e6051fc2cbd61ba1f806900c27f47706a"}, + {file = "greenlet-2.0.1-cp27-cp27m-win_amd64.whl", hash = "sha256:3001d00eba6bbf084ae60ec7f4bb8ed375748f53aeaefaf2a37d9f0370558524"}, + {file = "greenlet-2.0.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d566b82e92ff2e09dd6342df7e0eb4ff6275a3f08db284888dcd98134dbd4243"}, + {file = "greenlet-2.0.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:0722c9be0797f544a3ed212569ca3fe3d9d1a1b13942d10dd6f0e8601e484d26"}, + {file = "greenlet-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d37990425b4687ade27810e3b1a1c37825d242ebc275066cfee8cb6b8829ccd"}, + {file = "greenlet-2.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be35822f35f99dcc48152c9839d0171a06186f2d71ef76dc57fa556cc9bf6b45"}, + {file = "greenlet-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c140e7eb5ce47249668056edf3b7e9900c6a2e22fb0eaf0513f18a1b2c14e1da"}, + {file = "greenlet-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d21681f09e297a5adaa73060737e3aa1279a13ecdcfcc6ef66c292cb25125b2d"}, + {file = "greenlet-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fb412b7db83fe56847df9c47b6fe3f13911b06339c2aa02dcc09dce8bbf582cd"}, + {file = "greenlet-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c6a08799e9e88052221adca55741bf106ec7ea0710bca635c208b751f0d5b617"}, + {file = "greenlet-2.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e112e03d37987d7b90c1e98ba5e1b59e1645226d78d73282f45b326f7bddcb9"}, + {file = "greenlet-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56961cfca7da2fdd178f95ca407fa330c64f33289e1804b592a77d5593d9bd94"}, + {file = "greenlet-2.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13ba6e8e326e2116c954074c994da14954982ba2795aebb881c07ac5d093a58a"}, + {file = "greenlet-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bf633a50cc93ed17e494015897361010fc08700d92676c87931d3ea464123ce"}, + {file = "greenlet-2.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9f2c221eecb7ead00b8e3ddb913c67f75cba078fd1d326053225a3f59d850d72"}, + {file = "greenlet-2.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:13ebf93c343dd8bd010cd98e617cb4c1c1f352a0cf2524c82d3814154116aa82"}, + {file = "greenlet-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:6f61d71bbc9b4a3de768371b210d906726535d6ca43506737682caa754b956cd"}, + {file = "greenlet-2.0.1-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:2d0bac0385d2b43a7bd1d651621a4e0f1380abc63d6fb1012213a401cbd5bf8f"}, + {file = "greenlet-2.0.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:f6327b6907b4cb72f650a5b7b1be23a2aab395017aa6f1adb13069d66360eb3f"}, + {file = "greenlet-2.0.1-cp35-cp35m-win32.whl", hash = "sha256:81b0ea3715bf6a848d6f7149d25bf018fd24554a4be01fcbbe3fdc78e890b955"}, + {file = "greenlet-2.0.1-cp35-cp35m-win_amd64.whl", hash = "sha256:38255a3f1e8942573b067510f9611fc9e38196077b0c8eb7a8c795e105f9ce77"}, + {file = "greenlet-2.0.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:04957dc96669be041e0c260964cfef4c77287f07c40452e61abe19d647505581"}, + {file = "greenlet-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:4aeaebcd91d9fee9aa768c1b39cb12214b30bf36d2b7370505a9f2165fedd8d9"}, + {file = "greenlet-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:974a39bdb8c90a85982cdb78a103a32e0b1be986d411303064b28a80611f6e51"}, + {file = "greenlet-2.0.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dca09dedf1bd8684767bc736cc20c97c29bc0c04c413e3276e0962cd7aeb148"}, + {file = "greenlet-2.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4c0757db9bd08470ff8277791795e70d0bf035a011a528ee9a5ce9454b6cba2"}, + {file = "greenlet-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:5067920de254f1a2dee8d3d9d7e4e03718e8fd2d2d9db962c8c9fa781ae82a39"}, + {file = "greenlet-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:5a8e05057fab2a365c81abc696cb753da7549d20266e8511eb6c9d9f72fe3e92"}, + {file = "greenlet-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:3d75b8d013086b08e801fbbb896f7d5c9e6ccd44f13a9241d2bf7c0df9eda928"}, + {file = "greenlet-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:097e3dae69321e9100202fc62977f687454cd0ea147d0fd5a766e57450c569fd"}, + {file = "greenlet-2.0.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:cb242fc2cda5a307a7698c93173d3627a2a90d00507bccf5bc228851e8304963"}, + {file = "greenlet-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:72b00a8e7c25dcea5946692a2485b1a0c0661ed93ecfedfa9b6687bd89a24ef5"}, + {file = "greenlet-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5b0ff9878333823226d270417f24f4d06f235cb3e54d1103b71ea537a6a86ce"}, + {file = "greenlet-2.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be9e0fb2ada7e5124f5282d6381903183ecc73ea019568d6d63d33f25b2a9000"}, + {file = "greenlet-2.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b493db84d124805865adc587532ebad30efa68f79ad68f11b336e0a51ec86c2"}, + {file = "greenlet-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0459d94f73265744fee4c2d5ec44c6f34aa8a31017e6e9de770f7bcf29710be9"}, + {file = "greenlet-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a20d33124935d27b80e6fdacbd34205732660e0a1d35d8b10b3328179a2b51a1"}, + {file = "greenlet-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:ea688d11707d30e212e0110a1aac7f7f3f542a259235d396f88be68b649e47d1"}, + {file = "greenlet-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:afe07421c969e259e9403c3bb658968702bc3b78ec0b6fde3ae1e73440529c23"}, + {file = "greenlet-2.0.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:cd4ccc364cf75d1422e66e247e52a93da6a9b73cefa8cad696f3cbbb75af179d"}, + {file = "greenlet-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4c8b1c43e75c42a6cafcc71defa9e01ead39ae80bd733a2608b297412beede68"}, + {file = "greenlet-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:659f167f419a4609bc0516fb18ea69ed39dbb25594934bd2dd4d0401660e8a1e"}, + {file = "greenlet-2.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:356e4519d4dfa766d50ecc498544b44c0249b6de66426041d7f8b751de4d6b48"}, + {file = "greenlet-2.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:811e1d37d60b47cb8126e0a929b58c046251f28117cb16fcd371eed61f66b764"}, + {file = "greenlet-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d38ffd0e81ba8ef347d2be0772e899c289b59ff150ebbbbe05dc61b1246eb4e0"}, + {file = "greenlet-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0109af1138afbfb8ae647e31a2b1ab030f58b21dd8528c27beaeb0093b7938a9"}, + {file = "greenlet-2.0.1-cp38-cp38-win32.whl", hash = "sha256:88c8d517e78acdf7df8a2134a3c4b964415b575d2840a2746ddb1cc6175f8608"}, + {file = "greenlet-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:d6ee1aa7ab36475035eb48c01efae87d37936a8173fc4d7b10bb02c2d75dd8f6"}, + {file = "greenlet-2.0.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:b1992ba9d4780d9af9726bbcef6a1db12d9ab1ccc35e5773685a24b7fb2758eb"}, + {file = "greenlet-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:b5e83e4de81dcc9425598d9469a624826a0b1211380ac444c7c791d4a2137c19"}, + {file = "greenlet-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:505138d4fa69462447a562a7c2ef723c6025ba12ac04478bc1ce2fcc279a2db5"}, + {file = "greenlet-2.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cce1e90dd302f45716a7715517c6aa0468af0bf38e814ad4eab58e88fc09f7f7"}, + {file = "greenlet-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e9744c657d896c7b580455e739899e492a4a452e2dd4d2b3e459f6b244a638d"}, + {file = "greenlet-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:662e8f7cad915ba75d8017b3e601afc01ef20deeeabf281bd00369de196d7726"}, + {file = "greenlet-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:41b825d65f31e394b523c84db84f9383a2f7eefc13d987f308f4663794d2687e"}, + {file = "greenlet-2.0.1-cp39-cp39-win32.whl", hash = "sha256:db38f80540083ea33bdab614a9d28bcec4b54daa5aff1668d7827a9fc769ae0a"}, + {file = "greenlet-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b23d2a46d53210b498e5b701a1913697671988f4bf8e10f935433f6e7c332fb6"}, + {file = "greenlet-2.0.1.tar.gz", hash = "sha256:42e602564460da0e8ee67cb6d7236363ee5e131aa15943b6670e44e5c2ed0f67"}, +] [package.extras] docs = ["Sphinx", "docutils (<0.18)"] @@ -143,6 +300,10 @@ description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] [[package]] name = "hiredis" @@ -151,6 +312,97 @@ description = "Python wrapper for hiredis" category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "hiredis-2.1.1-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:f15e48545dadf3760220821d2f3c850e0c67bbc66aad2776c9d716e6216b5103"}, + {file = "hiredis-2.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b3a437e3af246dd06d116f1615cdf4e620e639dfcc923fe3045e00f6a967fc27"}, + {file = "hiredis-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b61732d75e2222a3b0060b97395df78693d5c3487fe4a5d0b75f6ac1affc68b9"}, + {file = "hiredis-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:170c2080966721b42c5a8726e91c5fc271300a4ac9ddf8a5b79856cfd47553e1"}, + {file = "hiredis-2.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d2d6e4caaffaf42faf14cfdf20b1d6fff6b557137b44e9569ea6f1877e6f375d"}, + {file = "hiredis-2.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d64b2d90302f0dd9e9ba43e89f8640f35b6d5968668da82ba2d2652b2cc3c3d2"}, + {file = "hiredis-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61fd1c55efb48ba734628f096e7a50baf0df3f18e91183face5c07fba3b4beb7"}, + {file = "hiredis-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfc5e923828714f314737e7f856b3dccf8805e5679fe23f07241b397cd785f6c"}, + {file = "hiredis-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ef2aa0485735c8608a92964e52ab9025ceb6003776184a1eb5d1701742cc910b"}, + {file = "hiredis-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2d39193900a03b900a25d474b9f787434f05a282b402f063d4ca02c62d61bdb9"}, + {file = "hiredis-2.1.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:4b51f5eb47e61c6b82cb044a1815903a77a4f840fa050fd2ff40d617c102d16c"}, + {file = "hiredis-2.1.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:d9145d011b74bef972b485a09f391babaa101626dbb54afc2313d5682a746593"}, + {file = "hiredis-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6f45509b43d720d64837c1211fcdea42acd48e71539b7152d74c16413ceea080"}, + {file = "hiredis-2.1.1-cp310-cp310-win32.whl", hash = "sha256:3a284bbf6503cd6ac1183b3542fe853a8be47fb52a631224f6dda46ba229d572"}, + {file = "hiredis-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:f60fad285db733b2badba43f7036a1241cb3e19c17260348f3ff702e6eaa4980"}, + {file = "hiredis-2.1.1-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:69c20816ac2af11701caf10e5b027fd33c6e8dfe7806ab71bc5191aa2a6d50f9"}, + {file = "hiredis-2.1.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:cd43dbaa73322a0c125122114cbc2c37141353b971751d05798f3b9780091e90"}, + {file = "hiredis-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c9632cd480fbc09c14622038a9a5f2f21ef6ce35892e9fa4df8d3308d3f2cedf"}, + {file = "hiredis-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:252d4a254f1566012b94e35cba577a001d3a732fa91e824d2076233222232cf9"}, + {file = "hiredis-2.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b901e68f3a6da279388e5dbe8d3bc562dd6dd3ff8a4b90e4f62e94de36461777"}, + {file = "hiredis-2.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f45f296998043345ecfc4f69a51fa4f3e80ca3659864df80b459095580968a6"}, + {file = "hiredis-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79f2acf237428dd61faa5b49247999ff68f45b3552c57303fcfabd2002eab249"}, + {file = "hiredis-2.1.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82bc6f5b92c9fcd5b5d6506000dd433006b126b193932c52a9bcc10dcc10e4fc"}, + {file = "hiredis-2.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:19843e4505069085301c3126c91b4e48970070fb242d7c617fb6777e83b55541"}, + {file = "hiredis-2.1.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c7336fddae533cbe786360d7a0316c71fe96313872c06cde20a969765202ab04"}, + {file = "hiredis-2.1.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:90b4355779970e121c219def3e35533ec2b24773a26fc4aa0f8271dd262fa2f2"}, + {file = "hiredis-2.1.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4beaac5047317a73b27cf15b4f4e0d2abaafa8378e1a6ed4cf9ff420d8f88aba"}, + {file = "hiredis-2.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7e25dc06e02689a45a49fa5e2f48bdfdbc11c5b52bef792a8cb37e0b82a7b0ae"}, + {file = "hiredis-2.1.1-cp311-cp311-win32.whl", hash = "sha256:f8b3233c1de155743ef34b0cae494e33befed5e0adba77762f5d8a8e417c5015"}, + {file = "hiredis-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:4ced076af04e28761d486501c58259247c1882fd19c7f94c18a257d143248eee"}, + {file = "hiredis-2.1.1-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:f4300e063045e11ee79b79a7c9426813ab8d97e340b15843374093225dde407d"}, + {file = "hiredis-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b04b6c04fe13e1e30ba6f9340d3d0fb776a7e52611d11809fb59341871e050e5"}, + {file = "hiredis-2.1.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:436dcbbe3104737e8b4e2d63a019a764d107d72d6b6ee3cd107097c1c263fd1e"}, + {file = "hiredis-2.1.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:11801d9e96f39286ab558c6db940c39fc00150450ae1007d18b35437d2f79ad7"}, + {file = "hiredis-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7d8d0ca7b4f6136f8a29845d31cfbc3f562cbe71f26da6fca55aa4977e45a18"}, + {file = "hiredis-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c040af9eb9b12602b4b714b90a1c2ac1109e939498d47b0748ec33e7a948747"}, + {file = "hiredis-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f448146b86a8693dda5f02bb4cb2ef65c894db2cf743e7bf351978354ce685e3"}, + {file = "hiredis-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:649c5a1f0952af50f008f0bbec5f0b1e519150220c0a71ef80541a0c128d0c13"}, + {file = "hiredis-2.1.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b8e7415b0952b0dd6df3aa2d37b5191c85e54d6a0ac1449ddb1e9039bbb39fa5"}, + {file = "hiredis-2.1.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:38c1a56a30b953e3543662f950f498cfb17afed214b27f4fc497728fb623e0c9"}, + {file = "hiredis-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6050b519fb3b62d68a28a1941ae9dc5122e8820fef2b8e20a65cb3c1577332a0"}, + {file = "hiredis-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:96add2a205efffe5e19a256a50be0ed78fcb5e9503242c65f57928e95cf4c901"}, + {file = "hiredis-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:8ceb101095f8cce9ac672ed7244b002d83ea97af7f27bb73f2fbe7fe8e8f03c7"}, + {file = "hiredis-2.1.1-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:9f068136e5119f2ba939ecd45c47b4e3cf6dd7ca9a65b6078c838029c5c1f564"}, + {file = "hiredis-2.1.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:8a42e246a03086ae1430f789e37d7192113db347417932745c4700d8999f853a"}, + {file = "hiredis-2.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5359811bfdb10fca234cba4629e555a1cde6c8136025395421f486ce43129ae3"}, + {file = "hiredis-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d304746e2163d3d2cbc4c08925539e00d2bb3edc9e79fce531b5468d4e264d15"}, + {file = "hiredis-2.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4fe297a52a8fc1204eef646bebf616263509d089d472e25742913924b1449099"}, + {file = "hiredis-2.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:637e563d5cbf79d8b04224f99cfce8001146647e7ce198f0b032e32e62079e3c"}, + {file = "hiredis-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39b61340ff2dcd99d5ded0ca5fc33c878d89a1426e2f7b6dbc7c7381e330bc8a"}, + {file = "hiredis-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66eaf6d5ea5207177ba8ffb9ee479eea743292267caf1d6b89b51cf9d5885d23"}, + {file = "hiredis-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4d2d0e458c32cdafd9a0f0b0aaeb61b169583d074287721eee740b730b7654bd"}, + {file = "hiredis-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8a92781e466f2f1f9d38720d8920cb094bc0d59f88219591bc12b1c12c9d471c"}, + {file = "hiredis-2.1.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:5560b09304ebaac5323a7402f5090f2a8559843200014f5adf1ff7517dd3805b"}, + {file = "hiredis-2.1.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4732a0bf877bbd69d4d1b38a3db2160252acb31894a48f324fd54f742f6b2123"}, + {file = "hiredis-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b5bd33ac8a572e2aa94b489dec35b0c00ca554b27e56ad19953e0bf2cbcf3ad8"}, + {file = "hiredis-2.1.1-cp38-cp38-win32.whl", hash = "sha256:07e86649773e486a21e170d1396217e15833776d9e8f4a7121c28a1d37e032c9"}, + {file = "hiredis-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:b964d81db8f11a99552621acd24c97381a0fd401a57187ce9f8cb9a53f4b6f4e"}, + {file = "hiredis-2.1.1-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:27e89e7befc785a273cccb105840db54b7f93005adf4e68c516d57b19ea2aac2"}, + {file = "hiredis-2.1.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ea6f0f98e1721741b5bc3167a495a9f16459fe67648054be05365a67e67c29ba"}, + {file = "hiredis-2.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:40c34aeecccb9474999839299c9d2d5ff46a62ed47c58645b7965f48944abd74"}, + {file = "hiredis-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65927e75da4265ec88d06cbdab20113a9e69bbac3aea1ec053d4d940f1c88fc8"}, + {file = "hiredis-2.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:72cab67bcceb2e998da2f28aad9ec7b1a5ece5888f7ac3d3723cccba62338703"}, + {file = "hiredis-2.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d67429ff99231137491d8c3daa097c767a9c273bb03ac412ed8f6acb89e2e52f"}, + {file = "hiredis-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c596bce5e9dd379c68c17208716da2767bb6f6f2a71d748f9e4c247ced31e6"}, + {file = "hiredis-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e0aab2d6e60aa9f9e14c83396b4a58fb4aded712806486c79189bcae4a175ac"}, + {file = "hiredis-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:17deb7d218a5ae9f05d2b19d51936231546973303747924fc17a2869aef0029a"}, + {file = "hiredis-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d3d60e2af4ce93d6e45a50a9b5795156a8725495e411c7987a2f81ab14e99665"}, + {file = "hiredis-2.1.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:fbc960cd91e55e2281e1a330e7d1c4970b6a05567dd973c96e412b4d012e17c6"}, + {file = "hiredis-2.1.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0ae718e9db4b622072ff73d38bc9cd7711edfedc8a1e08efe25a6c8170446da4"}, + {file = "hiredis-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e51e3fa176fecd19660f898c4238232e8ca0f5709e6451a664c996f9aec1b8e1"}, + {file = "hiredis-2.1.1-cp39-cp39-win32.whl", hash = "sha256:0258bb84b4a1e015f14f891d91957042fa88f6f4e86cc0808d735ebbc1e3fc88"}, + {file = "hiredis-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:c5a47c964c58c044a323336a798d8729722e09865d7e087eb3512df6146b39a8"}, + {file = "hiredis-2.1.1-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:8de0334c212e069d49952e476e16c6b42ba9677cc1e2d2f4588bd9a39489a3ab"}, + {file = "hiredis-2.1.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:653e33f69202c00eca35416ee23091447ad1e9f9a556cc2b715b2befcfc31b3c"}, + {file = "hiredis-2.1.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f14cccf931c859ba3169d766e892a3673a79649ec2ceca7ba95ea376b23fd222"}, + {file = "hiredis-2.1.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86c56359fd7aca6a9ca41af91636aef15d5ad6d19e631ebd662f233c79f7e100"}, + {file = "hiredis-2.1.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:c2b197e3613c3aef3933b2c6eb095bd4be9c84022aea52057697b709b400c4bc"}, + {file = "hiredis-2.1.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ec060d6db9576f6723b5290448aea67160608556b5506eb947997d9d1ca6f7b7"}, + {file = "hiredis-2.1.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8781f5b91d75abef529a33cf3509ba5fe540d2814de0c4602f0f5ba6f1669739"}, + {file = "hiredis-2.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9bd6b934794bea92a15b10ac35889df63b28d2abf9d020a7c87c05dd9c6e1edd"}, + {file = "hiredis-2.1.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf6d85c1ffb4ec4a859b2f31cd8845e633f91ed971a3cce6f59a722dcc361b8c"}, + {file = "hiredis-2.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:bbf80c686e3f63d40b0ab42d3605d3b6d415c368a5d8a9764a314ebda6138650"}, + {file = "hiredis-2.1.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c1d85dfdf37a8df0e0174fc0c762b485b80a2fc7ce9592ae109aaf4a5d45ba9a"}, + {file = "hiredis-2.1.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:816b9ea96e7cc2496a1ac9c4a76db670827c1e31045cc377c66e64a20bb4b3ff"}, + {file = "hiredis-2.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db59afa0edf194bea782e4686bfc496fc1cea2e24f310d769641e343d14cc929"}, + {file = "hiredis-2.1.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c7a7e4ccec7164cdf2a9bbedc0e7430492eb56d9355a41377f40058c481bccc"}, + {file = "hiredis-2.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:646f150fa73f9cbc69419e34a1aae318c9f39bd9640760aa46624b2815da0c2d"}, + {file = "hiredis-2.1.1.tar.gz", hash = "sha256:21751e4b7737aaf7261a068758b22f7670155099592b28d8dde340bf6874313d"}, +] [[package]] name = "httpcore" @@ -159,6 +411,10 @@ description = "A minimal low-level HTTP client." category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "httpcore-0.16.3-py3-none-any.whl", hash = "sha256:da1fb708784a938aa084bde4feb8317056c55037247c787bd7e19eb2c2949dc0"}, + {file = "httpcore-0.16.3.tar.gz", hash = "sha256:c5d6f04e2fc530f39e0c077e6a30caa53f1451096120f1f38b954afd0b17c0cb"}, +] [package.dependencies] anyio = ">=3.0,<5.0" @@ -177,6 +433,10 @@ description = "The next generation HTTP client." category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "httpx-0.23.3-py3-none-any.whl", hash = "sha256:a211fcce9b1254ea24f0cd6af9869b3d29aba40154e947d2a07bb499b3e310d6"}, + {file = "httpx-0.23.3.tar.gz", hash = "sha256:9818458eb565bb54898ccb9b8b251a28785dd4a55afbc23d0eb410754fe7d0f9"}, +] [package.dependencies] certifi = "*" @@ -197,6 +457,10 @@ description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false python-versions = ">=3.5" +files = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] [[package]] name = "jinja2" @@ -205,6 +469,10 @@ description = "A very fast and expressive template engine." category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, +] [package.dependencies] MarkupSafe = ">=2.0" @@ -219,6 +487,10 @@ description = "A super-fast templating language that borrows the best ideas from category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "Mako-1.2.4-py3-none-any.whl", hash = "sha256:c97c79c018b9165ac9922ae4f32da095ffd3c4e6872b45eded42926deea46818"}, + {file = "Mako-1.2.4.tar.gz", hash = "sha256:d60a3903dc3bb01a18ad6a89cdbe2e4eadc69c0bc8ef1e3773ba53d44c3f7a34"}, +] [package.dependencies] MarkupSafe = ">=0.9.2" @@ -235,642 +507,7 @@ description = "Safely add untrusted strings to HTML/XML markup." category = "main" optional = false python-versions = ">=3.7" - -[[package]] -name = "maturin" -version = "0.14.10" -description = "Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} - -[package.extras] -patchelf = ["patchelf"] -zig = ["ziglang (>=0.10.0,<0.11.0)"] - -[[package]] -name = "msgspec" -version = "0.12.0" -description = "A fast and friendly JSON/MessagePack library, with optional schema validation" -category = "main" -optional = false -python-versions = ">=3.8" - -[[package]] -name = "multidict" -version = "6.0.4" -description = "multidict implementation" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "packaging" -version = "23.0" -description = "Core utilities for Python packages" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "pydantic" -version = "1.10.4" -description = "Data validation and settings management using python type hints" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -typing-extensions = ">=4.2.0" - -[package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] - -[[package]] -name = "pydantic-factories" -version = "1.17.0" -description = "Mock data generation for pydantic based models and python dataclasses" -category = "main" -optional = false -python-versions = ">=3.8,<4.0" - -[package.dependencies] -faker = "*" -pydantic = ">=1.10.0" -typing-extensions = "*" - -[[package]] -name = "pydantic-openapi-schema" -version = "1.5.0" -description = "OpenAPI Schema using pydantic. Forked for Starlite-API from 'openapi-schema-pydantic'." -category = "main" -optional = false -python-versions = ">=3.8" - -[package.dependencies] -email-validator = "*" -pydantic = ">=1.10.0" - -[[package]] -name = "python-dateutil" -version = "2.8.2" -description = "Extensions to the standard Python datetime module" -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "python-dotenv" -version = "0.21.0" -description = "Read key-value pairs from a .env file and set them as environment variables" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -cli = ["click (>=5.0)"] - -[[package]] -name = "pyyaml" -version = "6.0" -description = "YAML parser and emitter for Python" -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "redis" -version = "4.3.5" -description = "Python client for Redis database and key-value store" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -async-timeout = ">=4.0.2" -packaging = ">=20.4" - -[package.extras] -hiredis = ["hiredis (>=1.0.0)"] -ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] - -[[package]] -name = "rfc3986" -version = "1.5.0" -description = "Validating URI References per RFC 3986" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} - -[package.extras] -idna2008 = ["idna"] - -[[package]] -name = "saq" -version = "0.9.2" -description = "Distributed Python job queue with asyncio and redis" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -croniter = ">=0.3.18" -redis = ">=4.2,<4.4" - -[package.extras] -dev = ["black", "mypy", "pylint", "types-croniter", "types-redis", "types-setuptools"] -hiredis = ["redis[hiredis] (>=4.2.0)"] -web = ["aiohttp", "aiohttp-basicauth"] - -[[package]] -name = "sentry-sdk" -version = "1.13.0" -description = "Python client for Sentry (https://sentry.io)" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -certifi = "*" -urllib3 = {version = ">=1.26.11", markers = "python_version >= \"3.6\""} - -[package.extras] -aiohttp = ["aiohttp (>=3.5)"] -beam = ["apache-beam (>=2.12)"] -bottle = ["bottle (>=0.12.13)"] -celery = ["celery (>=3)"] -chalice = ["chalice (>=1.16.0)"] -django = ["django (>=1.8)"] -falcon = ["falcon (>=1.4)"] -fastapi = ["fastapi (>=0.79.0)"] -flask = ["blinker (>=1.1)", "flask (>=0.11)"] -httpx = ["httpx (>=0.16.0)"] -opentelemetry = ["opentelemetry-distro (>=0.350b0)"] -pure-eval = ["asttokens", "executing", "pure-eval"] -pymongo = ["pymongo (>=3.1)"] -pyspark = ["pyspark (>=2.4.4)"] -quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] -rq = ["rq (>=0.6)"] -sanic = ["sanic (>=0.8)"] -sqlalchemy = ["sqlalchemy (>=1.2)"] -starlette = ["starlette (>=0.19.1)"] -starlite = ["starlite (>=1.48)"] -tornado = ["tornado (>=5)"] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" - -[[package]] -name = "sniffio" -version = "1.3.0" -description = "Sniff out which async library your code is running under" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "sqlalchemy" -version = "2.0.0rc2" -description = "Database Abstraction Library" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} -typing-extensions = ">=4.2.0" - -[package.extras] -aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] -aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing-extensions (!=3.10.0.1)"] -asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"] -mssql = ["pyodbc"] -mssql-pymssql = ["pymssql"] -mssql-pyodbc = ["pyodbc"] -mypy = ["mypy (>=0.910)"] -mysql = ["mysqlclient (>=1.4.0)"] -mysql-connector = ["mysql-connector-python"] -oracle = ["cx-oracle (>=7)"] -oracle-oracledb = ["oracledb (>=1.0.1)"] -postgresql = ["psycopg2 (>=2.7)"] -postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql-pg8000 = ["pg8000 (>=1.29.1)"] -postgresql-psycopg = ["psycopg (>=3.0.7)"] -postgresql-psycopg2binary = ["psycopg2-binary"] -postgresql-psycopg2cffi = ["psycopg2cffi"] -pymysql = ["pymysql"] -sqlcipher = ["sqlcipher3-binary"] - -[[package]] -name = "starlite" -version = "1.48.1" -description = "Performant, light and flexible ASGI API Framework" -category = "main" -optional = false -python-versions = ">=3.8,<4.0" - -[package.dependencies] -anyio = ">=3" -fast-query-parsers = "*" -httpx = ">=0.22" -jinja2 = ">=3.1.2" -mako = ">=1.2.4" -msgspec = ">=0.11.0" -multidict = ">=6.0.2" -pydantic = "*" -pydantic-factories = "*" -pydantic-openapi-schema = ">=1.5.0" -pyyaml = "*" -typing-extensions = "*" - -[package.extras] -brotli = ["brotli"] -cli = ["click (>=8.1.3)", "rich (>=12.6.0)"] -cryptography = ["cryptography"] -full = ["aiomcache", "brotli", "click (>=8.1.3)", "cryptography", "opentelemetry-instrumentation-asgi", "picologging", "python-jose", "redis[hiredis]", "rich (>=12.6.0)", "structlog"] -jwt = ["cryptography", "python-jose"] -memcached = ["aiomcache"] -opentelemetry = ["opentelemetry-instrumentation-asgi"] -picologging = ["picologging"] -redis = ["redis[hiredis]"] -standard = ["click (>=8.1.3)", "picologging", "rich (>=12.6.0)"] -structlog = ["structlog"] - -[[package]] -name = "structlog" -version = "22.3.0" -description = "Structured Logging for Python" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -dev = ["structlog[docs,tests,typing]"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "twisted"] -tests = ["coverage[toml]", "freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] -typing = ["mypy", "rich", "twisted"] - -[[package]] -name = "tenacity" -version = "8.1.0" -description = "Retry code until it succeeds" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.extras] -doc = ["reno", "sphinx", "tornado (>=4.5)"] - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "typing-extensions" -version = "4.4.0" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "urllib3" -version = "1.26.14" -description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" - -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] - -[[package]] -name = "uvicorn" -version = "0.20.0" -description = "The lightning-fast ASGI server." -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -click = ">=7.0" -h11 = ">=0.8" - -[package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] - -[[package]] -name = "uvloop" -version = "0.17.0" -description = "Fast implementation of asyncio event loop on top of libuv" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -dev = ["Cython (>=0.29.32,<0.30.0)", "Sphinx (>=4.1.2,<4.2.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=22.0.0,<22.1.0)", "pycodestyle (>=2.7.0,<2.8.0)", "pytest (>=3.6.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -test = ["Cython (>=0.29.32,<0.30.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=22.0.0,<22.1.0)", "pycodestyle (>=2.7.0,<2.8.0)"] - -[metadata] -lock-version = "1.1" -python-versions = "^3.10" -content-hash = "02b7b504018c2c2e6633f8028b22dc996e837ba7f1b2a6ae6b879382b9c9d2d0" - -[metadata.files] -anyio = [ - {file = "anyio-3.6.2-py3-none-any.whl", hash = "sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3"}, - {file = "anyio-3.6.2.tar.gz", hash = "sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421"}, -] -async-timeout = [ - {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, - {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, -] -asyncpg = [ - {file = "asyncpg-0.27.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fca608d199ffed4903dce1bcd97ad0fe8260f405c1c225bdf0002709132171c2"}, - {file = "asyncpg-0.27.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:20b596d8d074f6f695c13ffb8646d0b6bb1ab570ba7b0cfd349b921ff03cfc1e"}, - {file = "asyncpg-0.27.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a6206210c869ebd3f4eb9e89bea132aefb56ff3d1b7dd7e26b102b17e27bbb1"}, - {file = "asyncpg-0.27.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7a94c03386bb95456b12c66026b3a87d1b965f0f1e5733c36e7229f8f137747"}, - {file = "asyncpg-0.27.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bfc3980b4ba6f97138b04f0d32e8af21d6c9fa1f8e6e140c07d15690a0a99279"}, - {file = "asyncpg-0.27.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9654085f2b22f66952124de13a8071b54453ff972c25c59b5ce1173a4283ffd9"}, - {file = "asyncpg-0.27.0-cp310-cp310-win32.whl", hash = "sha256:879c29a75969eb2722f94443752f4720d560d1e748474de54ae8dd230bc4956b"}, - {file = "asyncpg-0.27.0-cp310-cp310-win_amd64.whl", hash = "sha256:ab0f21c4818d46a60ca789ebc92327d6d874d3b7ccff3963f7af0a21dc6cff52"}, - {file = "asyncpg-0.27.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:18f77e8e71e826ba2d0c3ba6764930776719ae2b225ca07e014590545928b576"}, - {file = "asyncpg-0.27.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c2232d4625c558f2aa001942cac1d7952aa9f0dbfc212f63bc754277769e1ef2"}, - {file = "asyncpg-0.27.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a3a4ff43702d39e3c97a8786314123d314e0f0e4dabc8367db5b665c93914de"}, - {file = "asyncpg-0.27.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccddb9419ab4e1c48742457d0c0362dbdaeb9b28e6875115abfe319b29ee225d"}, - {file = "asyncpg-0.27.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:768e0e7c2898d40b16d4ef7a0b44e8150db3dd8995b4652aa1fe2902e92c7df8"}, - {file = "asyncpg-0.27.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:609054a1f47292a905582a1cfcca51a6f3f30ab9d822448693e66fdddde27920"}, - {file = "asyncpg-0.27.0-cp311-cp311-win32.whl", hash = "sha256:8113e17cfe236dc2277ec844ba9b3d5312f61bd2fdae6d3ed1c1cdd75f6cf2d8"}, - {file = "asyncpg-0.27.0-cp311-cp311-win_amd64.whl", hash = "sha256:bb71211414dd1eeb8d31ec529fe77cff04bf53efc783a5f6f0a32d84923f45cf"}, - {file = "asyncpg-0.27.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4750f5cf49ed48a6e49c6e5aed390eee367694636c2dcfaf4a273ca832c5c43c"}, - {file = "asyncpg-0.27.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:eca01eb112a39d31cc4abb93a5aef2a81514c23f70956729f42fb83b11b3483f"}, - {file = "asyncpg-0.27.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5710cb0937f696ce303f5eed6d272e3f057339bb4139378ccecafa9ee923a71c"}, - {file = "asyncpg-0.27.0-cp37-cp37m-win_amd64.whl", hash = "sha256:71cca80a056ebe19ec74b7117b09e650990c3ca535ac1c35234a96f65604192f"}, - {file = "asyncpg-0.27.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4bb366ae34af5b5cabc3ac6a5347dfb6013af38c68af8452f27968d49085ecc0"}, - {file = "asyncpg-0.27.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16ba8ec2e85d586b4a12bcd03e8d29e3d99e832764d6a1d0b8c27dbbe4a2569d"}, - {file = "asyncpg-0.27.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d20dea7b83651d93b1eb2f353511fe7fd554752844523f17ad30115d8b9c8cd6"}, - {file = "asyncpg-0.27.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e56ac8a8237ad4adec97c0cd4728596885f908053ab725e22900b5902e7f8e69"}, - {file = "asyncpg-0.27.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bf21ebf023ec67335258e0f3d3ad7b91bb9507985ba2b2206346de488267cad0"}, - {file = "asyncpg-0.27.0-cp38-cp38-win32.whl", hash = "sha256:69aa1b443a182b13a17ff926ed6627af2d98f62f2fe5890583270cc4073f63bf"}, - {file = "asyncpg-0.27.0-cp38-cp38-win_amd64.whl", hash = "sha256:62932f29cf2433988fcd799770ec64b374a3691e7902ecf85da14d5e0854d1ea"}, - {file = "asyncpg-0.27.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fddcacf695581a8d856654bc4c8cfb73d5c9df26d5f55201722d3e6a699e9629"}, - {file = "asyncpg-0.27.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7d8585707ecc6661d07367d444bbaa846b4e095d84451340da8df55a3757e152"}, - {file = "asyncpg-0.27.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:975a320baf7020339a67315284a4d3bf7460e664e484672bd3e71dbd881bc692"}, - {file = "asyncpg-0.27.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2232ebae9796d4600a7819fc383da78ab51b32a092795f4555575fc934c1c89d"}, - {file = "asyncpg-0.27.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:88b62164738239f62f4af92567b846a8ef7cf8abf53eddd83650603de4d52163"}, - {file = "asyncpg-0.27.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:eb4b2fdf88af4fb1cc569781a8f933d2a73ee82cd720e0cb4edabbaecf2a905b"}, - {file = "asyncpg-0.27.0-cp39-cp39-win32.whl", hash = "sha256:8934577e1ed13f7d2d9cea3cc016cc6f95c19faedea2c2b56a6f94f257cea672"}, - {file = "asyncpg-0.27.0-cp39-cp39-win_amd64.whl", hash = "sha256:1b6499de06fe035cf2fa932ec5617ed3f37d4ebbf663b655922e105a484a6af9"}, - {file = "asyncpg-0.27.0.tar.gz", hash = "sha256:720986d9a4705dd8a40fdf172036f5ae787225036a7eb46e704c45aa8f62c054"}, -] -certifi = [ - {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, - {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, -] -click = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, -] -colorama = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] -croniter = [ - {file = "croniter-1.3.8-py2.py3-none-any.whl", hash = "sha256:d6ed8386d5f4bbb29419dc1b65c4909c04a2322bd15ec0dc5b2877bfa1b75c7a"}, - {file = "croniter-1.3.8.tar.gz", hash = "sha256:32a5ec04e97ec0837bcdf013767abd2e71cceeefd3c2e14c804098ce51ad6cd9"}, -] -dnspython = [ - {file = "dnspython-2.2.1-py3-none-any.whl", hash = "sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f"}, - {file = "dnspython-2.2.1.tar.gz", hash = "sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e"}, -] -email-validator = [ - {file = "email_validator-1.3.0-py2.py3-none-any.whl", hash = "sha256:816073f2a7cffef786b29928f58ec16cdac42710a53bb18aa94317e3e145ec5c"}, - {file = "email_validator-1.3.0.tar.gz", hash = "sha256:553a66f8be2ec2dea641ae1d3f29017ab89e9d603d4a25cdaac39eefa283d769"}, -] -faker = [ - {file = "Faker-16.4.0-py3-none-any.whl", hash = "sha256:5420467fad3fa582094057754e5e81326cb1f51ab822bf9df96c077cfb35ae49"}, - {file = "Faker-16.4.0.tar.gz", hash = "sha256:dcffdca8ec9a715982bcd5f53ee688dc4784cd112f9910f8f7183773eb3ec276"}, -] -fast-query-parsers = [ - {file = "fast_query_parsers-0.3.0-cp38-abi3-macosx_10_7_x86_64.whl", hash = "sha256:e01e9b794d6fad11207341a8e0a7b179f085c9874b3981a77f862a5e44cb241d"}, - {file = "fast_query_parsers-0.3.0-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:f2ffa7f1298db8ff8e013733e32edb77509a468843f5641875386f1df9bdecb4"}, - {file = "fast_query_parsers-0.3.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1becd3a0a06b14c57ee34976bf54d08fc910d4b410170ee5c28ac8d16ef23575"}, - {file = "fast_query_parsers-0.3.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd94f7715b6c1ec57b50e63c22298253648d864c9e78f90a258ebf2c07d13a38"}, - {file = "fast_query_parsers-0.3.0-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:52ef0241bcadc93ef47f650070c5f31f616cd5185a3af95f8b365e1fb135d991"}, - {file = "fast_query_parsers-0.3.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:189eed1007229c1e4a032076d503e92869eebd4a1ebd2498e6bb1b1b0c525708"}, - {file = "fast_query_parsers-0.3.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97d13dcc6cad29c8ef7c6f4bb6240847b476e4eb0445ac7f59d49a11db1644e2"}, - {file = "fast_query_parsers-0.3.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:befa91ff707f77e9948759bafdfe2b743d4b587e3f7767f2b5887b1ffa37f41d"}, - {file = "fast_query_parsers-0.3.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00d3d519cfd020c7a3bd961c9568b6042f853f25e204b8a307ff5b569dee9c38"}, - {file = "fast_query_parsers-0.3.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a659eb2acc0aa44f4cce7a79c4e0c76f14a26026fc13db8f094a29a38cf66248"}, - {file = "fast_query_parsers-0.3.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:e9b277e8281d7fe9b8e9450767cf1c1158ed729d81e03c1dfa2fe2118b22ffe0"}, - {file = "fast_query_parsers-0.3.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:0395ef9cacf49318a0f3caac4fde8a01dd7b7315c14f8a7d084965dedd764868"}, - {file = "fast_query_parsers-0.3.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:47639fc331e668b1be405c4e24af70ad21fc01a6847d2730803346ab9586e788"}, - {file = "fast_query_parsers-0.3.0-cp38-abi3-win32.whl", hash = "sha256:89ee582ab4b331f078eca2fbf51ce82396f749879fc30f20668b85a2896ea165"}, - {file = "fast_query_parsers-0.3.0-cp38-abi3-win_amd64.whl", hash = "sha256:4e9dd270f085a2337fab407d230a252664f952561cb83acece343a5c6a7d8e6b"}, - {file = "fast_query_parsers-0.3.0.tar.gz", hash = "sha256:df972c0b58d0bf51fa43b67d2604ab795984015d47552d02175ebcc685e4852b"}, -] -greenlet = [ - {file = "greenlet-2.0.1-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:9ed358312e63bf683b9ef22c8e442ef6c5c02973f0c2a939ec1d7b50c974015c"}, - {file = "greenlet-2.0.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4f09b0010e55bec3239278f642a8a506b91034f03a4fb28289a7d448a67f1515"}, - {file = "greenlet-2.0.1-cp27-cp27m-win32.whl", hash = "sha256:1407fe45246632d0ffb7a3f4a520ba4e6051fc2cbd61ba1f806900c27f47706a"}, - {file = "greenlet-2.0.1-cp27-cp27m-win_amd64.whl", hash = "sha256:3001d00eba6bbf084ae60ec7f4bb8ed375748f53aeaefaf2a37d9f0370558524"}, - {file = "greenlet-2.0.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d566b82e92ff2e09dd6342df7e0eb4ff6275a3f08db284888dcd98134dbd4243"}, - {file = "greenlet-2.0.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:0722c9be0797f544a3ed212569ca3fe3d9d1a1b13942d10dd6f0e8601e484d26"}, - {file = "greenlet-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d37990425b4687ade27810e3b1a1c37825d242ebc275066cfee8cb6b8829ccd"}, - {file = "greenlet-2.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be35822f35f99dcc48152c9839d0171a06186f2d71ef76dc57fa556cc9bf6b45"}, - {file = "greenlet-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c140e7eb5ce47249668056edf3b7e9900c6a2e22fb0eaf0513f18a1b2c14e1da"}, - {file = "greenlet-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d21681f09e297a5adaa73060737e3aa1279a13ecdcfcc6ef66c292cb25125b2d"}, - {file = "greenlet-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fb412b7db83fe56847df9c47b6fe3f13911b06339c2aa02dcc09dce8bbf582cd"}, - {file = "greenlet-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c6a08799e9e88052221adca55741bf106ec7ea0710bca635c208b751f0d5b617"}, - {file = "greenlet-2.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e112e03d37987d7b90c1e98ba5e1b59e1645226d78d73282f45b326f7bddcb9"}, - {file = "greenlet-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56961cfca7da2fdd178f95ca407fa330c64f33289e1804b592a77d5593d9bd94"}, - {file = "greenlet-2.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13ba6e8e326e2116c954074c994da14954982ba2795aebb881c07ac5d093a58a"}, - {file = "greenlet-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bf633a50cc93ed17e494015897361010fc08700d92676c87931d3ea464123ce"}, - {file = "greenlet-2.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9f2c221eecb7ead00b8e3ddb913c67f75cba078fd1d326053225a3f59d850d72"}, - {file = "greenlet-2.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:13ebf93c343dd8bd010cd98e617cb4c1c1f352a0cf2524c82d3814154116aa82"}, - {file = "greenlet-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:6f61d71bbc9b4a3de768371b210d906726535d6ca43506737682caa754b956cd"}, - {file = "greenlet-2.0.1-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:2d0bac0385d2b43a7bd1d651621a4e0f1380abc63d6fb1012213a401cbd5bf8f"}, - {file = "greenlet-2.0.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:f6327b6907b4cb72f650a5b7b1be23a2aab395017aa6f1adb13069d66360eb3f"}, - {file = "greenlet-2.0.1-cp35-cp35m-win32.whl", hash = "sha256:81b0ea3715bf6a848d6f7149d25bf018fd24554a4be01fcbbe3fdc78e890b955"}, - {file = "greenlet-2.0.1-cp35-cp35m-win_amd64.whl", hash = "sha256:38255a3f1e8942573b067510f9611fc9e38196077b0c8eb7a8c795e105f9ce77"}, - {file = "greenlet-2.0.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:04957dc96669be041e0c260964cfef4c77287f07c40452e61abe19d647505581"}, - {file = "greenlet-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:4aeaebcd91d9fee9aa768c1b39cb12214b30bf36d2b7370505a9f2165fedd8d9"}, - {file = "greenlet-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:974a39bdb8c90a85982cdb78a103a32e0b1be986d411303064b28a80611f6e51"}, - {file = "greenlet-2.0.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dca09dedf1bd8684767bc736cc20c97c29bc0c04c413e3276e0962cd7aeb148"}, - {file = "greenlet-2.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4c0757db9bd08470ff8277791795e70d0bf035a011a528ee9a5ce9454b6cba2"}, - {file = "greenlet-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:5067920de254f1a2dee8d3d9d7e4e03718e8fd2d2d9db962c8c9fa781ae82a39"}, - {file = "greenlet-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:5a8e05057fab2a365c81abc696cb753da7549d20266e8511eb6c9d9f72fe3e92"}, - {file = "greenlet-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:3d75b8d013086b08e801fbbb896f7d5c9e6ccd44f13a9241d2bf7c0df9eda928"}, - {file = "greenlet-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:097e3dae69321e9100202fc62977f687454cd0ea147d0fd5a766e57450c569fd"}, - {file = "greenlet-2.0.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:cb242fc2cda5a307a7698c93173d3627a2a90d00507bccf5bc228851e8304963"}, - {file = "greenlet-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:72b00a8e7c25dcea5946692a2485b1a0c0661ed93ecfedfa9b6687bd89a24ef5"}, - {file = "greenlet-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5b0ff9878333823226d270417f24f4d06f235cb3e54d1103b71ea537a6a86ce"}, - {file = "greenlet-2.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be9e0fb2ada7e5124f5282d6381903183ecc73ea019568d6d63d33f25b2a9000"}, - {file = "greenlet-2.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b493db84d124805865adc587532ebad30efa68f79ad68f11b336e0a51ec86c2"}, - {file = "greenlet-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0459d94f73265744fee4c2d5ec44c6f34aa8a31017e6e9de770f7bcf29710be9"}, - {file = "greenlet-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a20d33124935d27b80e6fdacbd34205732660e0a1d35d8b10b3328179a2b51a1"}, - {file = "greenlet-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:ea688d11707d30e212e0110a1aac7f7f3f542a259235d396f88be68b649e47d1"}, - {file = "greenlet-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:afe07421c969e259e9403c3bb658968702bc3b78ec0b6fde3ae1e73440529c23"}, - {file = "greenlet-2.0.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:cd4ccc364cf75d1422e66e247e52a93da6a9b73cefa8cad696f3cbbb75af179d"}, - {file = "greenlet-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4c8b1c43e75c42a6cafcc71defa9e01ead39ae80bd733a2608b297412beede68"}, - {file = "greenlet-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:659f167f419a4609bc0516fb18ea69ed39dbb25594934bd2dd4d0401660e8a1e"}, - {file = "greenlet-2.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:356e4519d4dfa766d50ecc498544b44c0249b6de66426041d7f8b751de4d6b48"}, - {file = "greenlet-2.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:811e1d37d60b47cb8126e0a929b58c046251f28117cb16fcd371eed61f66b764"}, - {file = "greenlet-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d38ffd0e81ba8ef347d2be0772e899c289b59ff150ebbbbe05dc61b1246eb4e0"}, - {file = "greenlet-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0109af1138afbfb8ae647e31a2b1ab030f58b21dd8528c27beaeb0093b7938a9"}, - {file = "greenlet-2.0.1-cp38-cp38-win32.whl", hash = "sha256:88c8d517e78acdf7df8a2134a3c4b964415b575d2840a2746ddb1cc6175f8608"}, - {file = "greenlet-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:d6ee1aa7ab36475035eb48c01efae87d37936a8173fc4d7b10bb02c2d75dd8f6"}, - {file = "greenlet-2.0.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:b1992ba9d4780d9af9726bbcef6a1db12d9ab1ccc35e5773685a24b7fb2758eb"}, - {file = "greenlet-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:b5e83e4de81dcc9425598d9469a624826a0b1211380ac444c7c791d4a2137c19"}, - {file = "greenlet-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:505138d4fa69462447a562a7c2ef723c6025ba12ac04478bc1ce2fcc279a2db5"}, - {file = "greenlet-2.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cce1e90dd302f45716a7715517c6aa0468af0bf38e814ad4eab58e88fc09f7f7"}, - {file = "greenlet-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e9744c657d896c7b580455e739899e492a4a452e2dd4d2b3e459f6b244a638d"}, - {file = "greenlet-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:662e8f7cad915ba75d8017b3e601afc01ef20deeeabf281bd00369de196d7726"}, - {file = "greenlet-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:41b825d65f31e394b523c84db84f9383a2f7eefc13d987f308f4663794d2687e"}, - {file = "greenlet-2.0.1-cp39-cp39-win32.whl", hash = "sha256:db38f80540083ea33bdab614a9d28bcec4b54daa5aff1668d7827a9fc769ae0a"}, - {file = "greenlet-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b23d2a46d53210b498e5b701a1913697671988f4bf8e10f935433f6e7c332fb6"}, - {file = "greenlet-2.0.1.tar.gz", hash = "sha256:42e602564460da0e8ee67cb6d7236363ee5e131aa15943b6670e44e5c2ed0f67"}, -] -h11 = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, -] -hiredis = [ - {file = "hiredis-2.1.1-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:f15e48545dadf3760220821d2f3c850e0c67bbc66aad2776c9d716e6216b5103"}, - {file = "hiredis-2.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b3a437e3af246dd06d116f1615cdf4e620e639dfcc923fe3045e00f6a967fc27"}, - {file = "hiredis-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b61732d75e2222a3b0060b97395df78693d5c3487fe4a5d0b75f6ac1affc68b9"}, - {file = "hiredis-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:170c2080966721b42c5a8726e91c5fc271300a4ac9ddf8a5b79856cfd47553e1"}, - {file = "hiredis-2.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d2d6e4caaffaf42faf14cfdf20b1d6fff6b557137b44e9569ea6f1877e6f375d"}, - {file = "hiredis-2.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d64b2d90302f0dd9e9ba43e89f8640f35b6d5968668da82ba2d2652b2cc3c3d2"}, - {file = "hiredis-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61fd1c55efb48ba734628f096e7a50baf0df3f18e91183face5c07fba3b4beb7"}, - {file = "hiredis-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfc5e923828714f314737e7f856b3dccf8805e5679fe23f07241b397cd785f6c"}, - {file = "hiredis-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ef2aa0485735c8608a92964e52ab9025ceb6003776184a1eb5d1701742cc910b"}, - {file = "hiredis-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2d39193900a03b900a25d474b9f787434f05a282b402f063d4ca02c62d61bdb9"}, - {file = "hiredis-2.1.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:4b51f5eb47e61c6b82cb044a1815903a77a4f840fa050fd2ff40d617c102d16c"}, - {file = "hiredis-2.1.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:d9145d011b74bef972b485a09f391babaa101626dbb54afc2313d5682a746593"}, - {file = "hiredis-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6f45509b43d720d64837c1211fcdea42acd48e71539b7152d74c16413ceea080"}, - {file = "hiredis-2.1.1-cp310-cp310-win32.whl", hash = "sha256:3a284bbf6503cd6ac1183b3542fe853a8be47fb52a631224f6dda46ba229d572"}, - {file = "hiredis-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:f60fad285db733b2badba43f7036a1241cb3e19c17260348f3ff702e6eaa4980"}, - {file = "hiredis-2.1.1-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:69c20816ac2af11701caf10e5b027fd33c6e8dfe7806ab71bc5191aa2a6d50f9"}, - {file = "hiredis-2.1.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:cd43dbaa73322a0c125122114cbc2c37141353b971751d05798f3b9780091e90"}, - {file = "hiredis-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c9632cd480fbc09c14622038a9a5f2f21ef6ce35892e9fa4df8d3308d3f2cedf"}, - {file = "hiredis-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:252d4a254f1566012b94e35cba577a001d3a732fa91e824d2076233222232cf9"}, - {file = "hiredis-2.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b901e68f3a6da279388e5dbe8d3bc562dd6dd3ff8a4b90e4f62e94de36461777"}, - {file = "hiredis-2.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f45f296998043345ecfc4f69a51fa4f3e80ca3659864df80b459095580968a6"}, - {file = "hiredis-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79f2acf237428dd61faa5b49247999ff68f45b3552c57303fcfabd2002eab249"}, - {file = "hiredis-2.1.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82bc6f5b92c9fcd5b5d6506000dd433006b126b193932c52a9bcc10dcc10e4fc"}, - {file = "hiredis-2.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:19843e4505069085301c3126c91b4e48970070fb242d7c617fb6777e83b55541"}, - {file = "hiredis-2.1.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c7336fddae533cbe786360d7a0316c71fe96313872c06cde20a969765202ab04"}, - {file = "hiredis-2.1.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:90b4355779970e121c219def3e35533ec2b24773a26fc4aa0f8271dd262fa2f2"}, - {file = "hiredis-2.1.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4beaac5047317a73b27cf15b4f4e0d2abaafa8378e1a6ed4cf9ff420d8f88aba"}, - {file = "hiredis-2.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7e25dc06e02689a45a49fa5e2f48bdfdbc11c5b52bef792a8cb37e0b82a7b0ae"}, - {file = "hiredis-2.1.1-cp311-cp311-win32.whl", hash = "sha256:f8b3233c1de155743ef34b0cae494e33befed5e0adba77762f5d8a8e417c5015"}, - {file = "hiredis-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:4ced076af04e28761d486501c58259247c1882fd19c7f94c18a257d143248eee"}, - {file = "hiredis-2.1.1-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:f4300e063045e11ee79b79a7c9426813ab8d97e340b15843374093225dde407d"}, - {file = "hiredis-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b04b6c04fe13e1e30ba6f9340d3d0fb776a7e52611d11809fb59341871e050e5"}, - {file = "hiredis-2.1.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:436dcbbe3104737e8b4e2d63a019a764d107d72d6b6ee3cd107097c1c263fd1e"}, - {file = "hiredis-2.1.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:11801d9e96f39286ab558c6db940c39fc00150450ae1007d18b35437d2f79ad7"}, - {file = "hiredis-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7d8d0ca7b4f6136f8a29845d31cfbc3f562cbe71f26da6fca55aa4977e45a18"}, - {file = "hiredis-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c040af9eb9b12602b4b714b90a1c2ac1109e939498d47b0748ec33e7a948747"}, - {file = "hiredis-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f448146b86a8693dda5f02bb4cb2ef65c894db2cf743e7bf351978354ce685e3"}, - {file = "hiredis-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:649c5a1f0952af50f008f0bbec5f0b1e519150220c0a71ef80541a0c128d0c13"}, - {file = "hiredis-2.1.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b8e7415b0952b0dd6df3aa2d37b5191c85e54d6a0ac1449ddb1e9039bbb39fa5"}, - {file = "hiredis-2.1.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:38c1a56a30b953e3543662f950f498cfb17afed214b27f4fc497728fb623e0c9"}, - {file = "hiredis-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6050b519fb3b62d68a28a1941ae9dc5122e8820fef2b8e20a65cb3c1577332a0"}, - {file = "hiredis-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:96add2a205efffe5e19a256a50be0ed78fcb5e9503242c65f57928e95cf4c901"}, - {file = "hiredis-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:8ceb101095f8cce9ac672ed7244b002d83ea97af7f27bb73f2fbe7fe8e8f03c7"}, - {file = "hiredis-2.1.1-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:9f068136e5119f2ba939ecd45c47b4e3cf6dd7ca9a65b6078c838029c5c1f564"}, - {file = "hiredis-2.1.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:8a42e246a03086ae1430f789e37d7192113db347417932745c4700d8999f853a"}, - {file = "hiredis-2.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5359811bfdb10fca234cba4629e555a1cde6c8136025395421f486ce43129ae3"}, - {file = "hiredis-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d304746e2163d3d2cbc4c08925539e00d2bb3edc9e79fce531b5468d4e264d15"}, - {file = "hiredis-2.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4fe297a52a8fc1204eef646bebf616263509d089d472e25742913924b1449099"}, - {file = "hiredis-2.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:637e563d5cbf79d8b04224f99cfce8001146647e7ce198f0b032e32e62079e3c"}, - {file = "hiredis-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39b61340ff2dcd99d5ded0ca5fc33c878d89a1426e2f7b6dbc7c7381e330bc8a"}, - {file = "hiredis-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66eaf6d5ea5207177ba8ffb9ee479eea743292267caf1d6b89b51cf9d5885d23"}, - {file = "hiredis-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4d2d0e458c32cdafd9a0f0b0aaeb61b169583d074287721eee740b730b7654bd"}, - {file = "hiredis-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8a92781e466f2f1f9d38720d8920cb094bc0d59f88219591bc12b1c12c9d471c"}, - {file = "hiredis-2.1.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:5560b09304ebaac5323a7402f5090f2a8559843200014f5adf1ff7517dd3805b"}, - {file = "hiredis-2.1.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4732a0bf877bbd69d4d1b38a3db2160252acb31894a48f324fd54f742f6b2123"}, - {file = "hiredis-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b5bd33ac8a572e2aa94b489dec35b0c00ca554b27e56ad19953e0bf2cbcf3ad8"}, - {file = "hiredis-2.1.1-cp38-cp38-win32.whl", hash = "sha256:07e86649773e486a21e170d1396217e15833776d9e8f4a7121c28a1d37e032c9"}, - {file = "hiredis-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:b964d81db8f11a99552621acd24c97381a0fd401a57187ce9f8cb9a53f4b6f4e"}, - {file = "hiredis-2.1.1-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:27e89e7befc785a273cccb105840db54b7f93005adf4e68c516d57b19ea2aac2"}, - {file = "hiredis-2.1.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ea6f0f98e1721741b5bc3167a495a9f16459fe67648054be05365a67e67c29ba"}, - {file = "hiredis-2.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:40c34aeecccb9474999839299c9d2d5ff46a62ed47c58645b7965f48944abd74"}, - {file = "hiredis-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65927e75da4265ec88d06cbdab20113a9e69bbac3aea1ec053d4d940f1c88fc8"}, - {file = "hiredis-2.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:72cab67bcceb2e998da2f28aad9ec7b1a5ece5888f7ac3d3723cccba62338703"}, - {file = "hiredis-2.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d67429ff99231137491d8c3daa097c767a9c273bb03ac412ed8f6acb89e2e52f"}, - {file = "hiredis-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c596bce5e9dd379c68c17208716da2767bb6f6f2a71d748f9e4c247ced31e6"}, - {file = "hiredis-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e0aab2d6e60aa9f9e14c83396b4a58fb4aded712806486c79189bcae4a175ac"}, - {file = "hiredis-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:17deb7d218a5ae9f05d2b19d51936231546973303747924fc17a2869aef0029a"}, - {file = "hiredis-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d3d60e2af4ce93d6e45a50a9b5795156a8725495e411c7987a2f81ab14e99665"}, - {file = "hiredis-2.1.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:fbc960cd91e55e2281e1a330e7d1c4970b6a05567dd973c96e412b4d012e17c6"}, - {file = "hiredis-2.1.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0ae718e9db4b622072ff73d38bc9cd7711edfedc8a1e08efe25a6c8170446da4"}, - {file = "hiredis-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e51e3fa176fecd19660f898c4238232e8ca0f5709e6451a664c996f9aec1b8e1"}, - {file = "hiredis-2.1.1-cp39-cp39-win32.whl", hash = "sha256:0258bb84b4a1e015f14f891d91957042fa88f6f4e86cc0808d735ebbc1e3fc88"}, - {file = "hiredis-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:c5a47c964c58c044a323336a798d8729722e09865d7e087eb3512df6146b39a8"}, - {file = "hiredis-2.1.1-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:8de0334c212e069d49952e476e16c6b42ba9677cc1e2d2f4588bd9a39489a3ab"}, - {file = "hiredis-2.1.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:653e33f69202c00eca35416ee23091447ad1e9f9a556cc2b715b2befcfc31b3c"}, - {file = "hiredis-2.1.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f14cccf931c859ba3169d766e892a3673a79649ec2ceca7ba95ea376b23fd222"}, - {file = "hiredis-2.1.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86c56359fd7aca6a9ca41af91636aef15d5ad6d19e631ebd662f233c79f7e100"}, - {file = "hiredis-2.1.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:c2b197e3613c3aef3933b2c6eb095bd4be9c84022aea52057697b709b400c4bc"}, - {file = "hiredis-2.1.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ec060d6db9576f6723b5290448aea67160608556b5506eb947997d9d1ca6f7b7"}, - {file = "hiredis-2.1.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8781f5b91d75abef529a33cf3509ba5fe540d2814de0c4602f0f5ba6f1669739"}, - {file = "hiredis-2.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9bd6b934794bea92a15b10ac35889df63b28d2abf9d020a7c87c05dd9c6e1edd"}, - {file = "hiredis-2.1.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf6d85c1ffb4ec4a859b2f31cd8845e633f91ed971a3cce6f59a722dcc361b8c"}, - {file = "hiredis-2.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:bbf80c686e3f63d40b0ab42d3605d3b6d415c368a5d8a9764a314ebda6138650"}, - {file = "hiredis-2.1.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c1d85dfdf37a8df0e0174fc0c762b485b80a2fc7ce9592ae109aaf4a5d45ba9a"}, - {file = "hiredis-2.1.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:816b9ea96e7cc2496a1ac9c4a76db670827c1e31045cc377c66e64a20bb4b3ff"}, - {file = "hiredis-2.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db59afa0edf194bea782e4686bfc496fc1cea2e24f310d769641e343d14cc929"}, - {file = "hiredis-2.1.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c7a7e4ccec7164cdf2a9bbedc0e7430492eb56d9355a41377f40058c481bccc"}, - {file = "hiredis-2.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:646f150fa73f9cbc69419e34a1aae318c9f39bd9640760aa46624b2815da0c2d"}, - {file = "hiredis-2.1.1.tar.gz", hash = "sha256:21751e4b7737aaf7261a068758b22f7670155099592b28d8dde340bf6874313d"}, -] -httpcore = [ - {file = "httpcore-0.16.3-py3-none-any.whl", hash = "sha256:da1fb708784a938aa084bde4feb8317056c55037247c787bd7e19eb2c2949dc0"}, - {file = "httpcore-0.16.3.tar.gz", hash = "sha256:c5d6f04e2fc530f39e0c077e6a30caa53f1451096120f1f38b954afd0b17c0cb"}, -] -httpx = [ - {file = "httpx-0.23.3-py3-none-any.whl", hash = "sha256:a211fcce9b1254ea24f0cd6af9869b3d29aba40154e947d2a07bb499b3e310d6"}, - {file = "httpx-0.23.3.tar.gz", hash = "sha256:9818458eb565bb54898ccb9b8b251a28785dd4a55afbc23d0eb410754fe7d0f9"}, -] -idna = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, -] -jinja2 = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, -] -mako = [ - {file = "Mako-1.2.4-py3-none-any.whl", hash = "sha256:c97c79c018b9165ac9922ae4f32da095ffd3c4e6872b45eded42926deea46818"}, - {file = "Mako-1.2.4.tar.gz", hash = "sha256:d60a3903dc3bb01a18ad6a89cdbe2e4eadc69c0bc8ef1e3773ba53d44c3f7a34"}, -] -markupsafe = [ +files = [ {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, @@ -912,7 +549,15 @@ markupsafe = [ {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, ] -maturin = [ + +[[package]] +name = "maturin" +version = "0.14.10" +description = "Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "maturin-0.14.10-py3-none-linux_armv6l.whl", hash = "sha256:ec8269c02cc435893308dfd50f57f14fb1be3554e4e61c5bf49b97363b289775"}, {file = "maturin-0.14.10-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:e9c19dc0a28109280f7d091ca7b78e25f3fc340fcfac92801829a21198fa20eb"}, {file = "maturin-0.14.10-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:cf950ebfe449a97617b91d75e09766509e21a389ce3f7b6ef15130ad8a95430a"}, @@ -927,7 +572,22 @@ maturin = [ {file = "maturin-0.14.10-py3-none-win_arm64.whl", hash = "sha256:6cc9afb89f28bd591b62f8f3c29736c81c322cffe88f9ab8eb1749377bbc3521"}, {file = "maturin-0.14.10.tar.gz", hash = "sha256:895c48cbe56ae994c2a1eeeef19475ca4819aa4c6412af727a63a772e8ef2d87"}, ] -msgspec = [ + +[package.dependencies] +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} + +[package.extras] +patchelf = ["patchelf"] +zig = ["ziglang (>=0.10.0,<0.11.0)"] + +[[package]] +name = "msgspec" +version = "0.12.0" +description = "A fast and friendly JSON/MessagePack library, with optional schema validation" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ {file = "msgspec-0.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3b3b193fc6e5399040f2c657f2fe77962b8d39bddb9923d4e4850e2e8111ef83"}, {file = "msgspec-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b90c8aa5b029f8fb8f9a4e71429cb37b4110382731058f7c4dfa125a005c459"}, {file = "msgspec-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78cbcabfa413edc281f0f9bb652b42a3092cb289c31dc4489e7d896e615581fb"}, @@ -958,7 +618,15 @@ msgspec = [ {file = "msgspec-0.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:cc7f0555b4cb8c74cca6d13040b3fd9e7adafc0fff273203a13064453c28d32f"}, {file = "msgspec-0.12.0.tar.gz", hash = "sha256:d8fe529a2414a1a5d3ccb1e875b164cc4f56614750c7b27c85006808f5658489"}, ] -multidict = [ + +[[package]] +name = "multidict" +version = "6.0.4" +description = "multidict implementation" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"}, {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"}, {file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"}, @@ -1034,11 +702,27 @@ multidict = [ {file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"}, {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, ] -packaging = [ + +[[package]] +name = "packaging" +version = "23.0" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, ] -pydantic = [ + +[[package]] +name = "pydantic" +version = "1.10.4" +description = "Data validation and settings management using python type hints" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "pydantic-1.10.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5635de53e6686fe7a44b5cf25fcc419a0d5e5c1a1efe73d49d48fe7586db854"}, {file = "pydantic-1.10.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6dc1cc241440ed7ca9ab59d9929075445da6b7c94ced281b3dd4cfe6c8cff817"}, {file = "pydantic-1.10.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51bdeb10d2db0f288e71d49c9cefa609bca271720ecd0c58009bd7504a0c464c"}, @@ -1076,23 +760,85 @@ pydantic = [ {file = "pydantic-1.10.4-py3-none-any.whl", hash = "sha256:4948f264678c703f3877d1c8877c4e3b2e12e549c57795107f08cf70c6ec7774"}, {file = "pydantic-1.10.4.tar.gz", hash = "sha256:b9a3859f24eb4e097502a3be1fb4b2abb79b6103dd9e2e0edb70613a4459a648"}, ] -pydantic-factories = [ - {file = "pydantic_factories-1.17.0-py3-none-any.whl", hash = "sha256:11c267ccbb7d54b1b456f68060f31472a5e53151314679e6f9367962b4d3a6f8"}, - {file = "pydantic_factories-1.17.0.tar.gz", hash = "sha256:f6b2cdf715f8c3e4a84e2851c0fb493af2009398159594c000192a38ce192129"}, + +[package.dependencies] +typing-extensions = ">=4.2.0" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] + +[[package]] +name = "pydantic-factories" +version = "1.17.1" +description = "Mock data generation for pydantic based models and python dataclasses" +category = "main" +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "pydantic_factories-1.17.1-py3-none-any.whl", hash = "sha256:05c0b143540f54d9dd9d0d500b7b146ff29e0c1cd4bb5f2ed99c60842ff1d5e6"}, + {file = "pydantic_factories-1.17.1.tar.gz", hash = "sha256:85848136cd768894dc5b6e3ffaf49753c7627c545ef05ff096ff616071cd59ff"}, ] -pydantic-openapi-schema = [ + +[package.dependencies] +faker = "*" +pydantic = ">=1.10.0" +typing-extensions = "*" + +[[package]] +name = "pydantic-openapi-schema" +version = "1.5.0" +description = "OpenAPI Schema using pydantic. Forked for Starlite-API from 'openapi-schema-pydantic'." +category = "main" +optional = false +python-versions = ">=3.8" +files = [ {file = "pydantic_openapi_schema-1.5.0-py3-none-any.whl", hash = "sha256:0b60d105a2665287fbf8ee85602919a3558e07cf34261e64fa8f4d2281a3bad0"}, {file = "pydantic_openapi_schema-1.5.0.tar.gz", hash = "sha256:50bf6ee00fc0dcd1c87b96f30c3273e3bebcc12f23f30c31e5af5ec2e3275c87"}, ] -python-dateutil = [ + +[package.dependencies] +email-validator = "*" +pydantic = ">=1.10.0" + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] -python-dotenv = [ + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-dotenv" +version = "0.21.0" +description = "Read key-value pairs from a .env file and set them as environment variables" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "python-dotenv-0.21.0.tar.gz", hash = "sha256:b77d08274639e3d34145dfa6c7008e66df0f04b7be7a75fd0d5292c191d79045"}, {file = "python_dotenv-0.21.0-py3-none-any.whl", hash = "sha256:1684eb44636dd462b66c3ee016599815514527ad99965de77f43e0944634a7e5"}, ] -pyyaml = [ + +[package.extras] +cli = ["click (>=5.0)"] + +[[package]] +name = "pyyaml" +version = "6.0" +description = "YAML parser and emitter for Python" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, @@ -1134,31 +880,137 @@ pyyaml = [ {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, ] -redis = [ + +[[package]] +name = "redis" +version = "4.3.5" +description = "Python client for Redis database and key-value store" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ {file = "redis-4.3.5-py3-none-any.whl", hash = "sha256:46652271dc7525cd5a9667e5b0ca983c848c75b2b8f7425403395bb8379dcf25"}, {file = "redis-4.3.5.tar.gz", hash = "sha256:30c07511627a4c5c4d970e060000772f323174f75e745a26938319817ead7a12"}, ] -rfc3986 = [ + +[package.dependencies] +async-timeout = ">=4.0.2" +packaging = ">=20.4" + +[package.extras] +hiredis = ["hiredis (>=1.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] + +[[package]] +name = "rfc3986" +version = "1.5.0" +description = "Validating URI References per RFC 3986" +category = "main" +optional = false +python-versions = "*" +files = [ {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, ] -saq = [ + +[package.dependencies] +idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} + +[package.extras] +idna2008 = ["idna"] + +[[package]] +name = "saq" +version = "0.9.2" +description = "Distributed Python job queue with asyncio and redis" +category = "main" +optional = false +python-versions = "*" +files = [ {file = "saq-0.9.2-py3-none-any.whl", hash = "sha256:9ae0636f8ffe92fa5a9ee68a92828a562d5f0f241762ddf9744df694e33a4ab5"}, {file = "saq-0.9.2.tar.gz", hash = "sha256:d0ad2994e7ae11337dc6481e7065399aa02f3d8923b1d9fdde1e02697de8d976"}, ] -sentry-sdk = [ + +[package.dependencies] +croniter = ">=0.3.18" +redis = ">=4.2,<4.4" + +[package.extras] +dev = ["black", "mypy", "pylint", "types-croniter", "types-redis", "types-setuptools"] +hiredis = ["redis[hiredis] (>=4.2.0)"] +web = ["aiohttp", "aiohttp-basicauth"] + +[[package]] +name = "sentry-sdk" +version = "1.13.0" +description = "Python client for Sentry (https://sentry.io)" +category = "main" +optional = false +python-versions = "*" +files = [ {file = "sentry-sdk-1.13.0.tar.gz", hash = "sha256:72da0766c3069a3941eadbdfa0996f83f5a33e55902a19ba399557cfee1dddcc"}, {file = "sentry_sdk-1.13.0-py2.py3-none-any.whl", hash = "sha256:b7ff6318183e551145b5c4766eb65b59ad5b63ff234dffddc5fb50340cad6729"}, ] -six = [ + +[package.dependencies] +certifi = "*" +urllib3 = {version = ">=1.26.11", markers = "python_version >= \"3.6\""} + +[package.extras] +aiohttp = ["aiohttp (>=3.5)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +chalice = ["chalice (>=1.16.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +fastapi = ["fastapi (>=0.79.0)"] +flask = ["blinker (>=1.1)", "flask (>=0.11)"] +httpx = ["httpx (>=0.16.0)"] +opentelemetry = ["opentelemetry-distro (>=0.350b0)"] +pure-eval = ["asttokens", "executing", "pure-eval"] +pymongo = ["pymongo (>=3.1)"] +pyspark = ["pyspark (>=2.4.4)"] +quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +starlette = ["starlette (>=0.19.1)"] +starlite = ["starlite (>=1.48)"] +tornado = ["tornado (>=5)"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] -sniffio = [ + +[[package]] +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, ] -sqlalchemy = [ + +[[package]] +name = "sqlalchemy" +version = "2.0.0rc2" +description = "Database Abstraction Library" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "SQLAlchemy-2.0.0rc2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:19486279fe24297bf0743c1563735e7cab1f439f36acf165bd8e1be699fb3fcb"}, {file = "SQLAlchemy-2.0.0rc2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fdb8aeea859346dc38881ef74843e3bd7bbe743357746190feaeef17d0307586"}, {file = "SQLAlchemy-2.0.0rc2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:102d7a5526ede7b727db59cbaaabc5abc7033e9951b179372163e7d75d7bb7b2"}, @@ -1201,35 +1053,174 @@ sqlalchemy = [ {file = "SQLAlchemy-2.0.0rc2-py3-none-any.whl", hash = "sha256:39c7aaa77d4a70c2115f9ef7e7fe3ab79649e5e1370b29f21f17702c1512d43a"}, {file = "SQLAlchemy-2.0.0rc2.tar.gz", hash = "sha256:b48e3eb80334c9b444ef1b857260942739e2174c55458790be518c2033355a4b"}, ] -starlite = [ - {file = "starlite-1.48.1-py3-none-any.whl", hash = "sha256:d2a37240b54199f1fa7ba2d3d2079124ee494f9f81722eec2cf04cccf4abfb8b"}, - {file = "starlite-1.48.1.tar.gz", hash = "sha256:2a79e219d8f6498f2b9cad284615b58186c2043010dee70cefb62b930528efed"}, + +[package.dependencies] +greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} +typing-extensions = ">=4.2.0" + +[package.extras] +aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] +aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing-extensions (!=3.10.0.1)"] +asyncio = ["greenlet (!=0.4.17)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"] +mssql = ["pyodbc"] +mssql-pymssql = ["pymssql"] +mssql-pyodbc = ["pyodbc"] +mypy = ["mypy (>=0.910)"] +mysql = ["mysqlclient (>=1.4.0)"] +mysql-connector = ["mysql-connector-python"] +oracle = ["cx-oracle (>=7)"] +oracle-oracledb = ["oracledb (>=1.0.1)"] +postgresql = ["psycopg2 (>=2.7)"] +postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql-pg8000 = ["pg8000 (>=1.29.1)"] +postgresql-psycopg = ["psycopg (>=3.0.7)"] +postgresql-psycopg2binary = ["psycopg2-binary"] +postgresql-psycopg2cffi = ["psycopg2cffi"] +pymysql = ["pymysql"] +sqlcipher = ["sqlcipher3-binary"] + +[[package]] +name = "starlite" +version = "1.49.0" +description = "Performant, light and flexible ASGI API Framework" +category = "main" +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "starlite-1.49.0-py3-none-any.whl", hash = "sha256:97748c7915706f5888f6eb245a4305f7c50f3fdb5bc09785421ee5677513cee9"}, + {file = "starlite-1.49.0.tar.gz", hash = "sha256:216c84745617070b766d0e759016a13fcfb467f75b54c8735a0b1e78625363bf"}, ] -structlog = [ + +[package.dependencies] +anyio = ">=3" +fast-query-parsers = "*" +httpx = ">=0.22" +jinja2 = ">=3.1.2" +mako = ">=1.2.4" +msgspec = ">=0.11.0" +multidict = ">=6.0.2" +pydantic = "*" +pydantic-factories = "*" +pydantic-openapi-schema = ">=1.5.0" +pyyaml = "*" +typing-extensions = "*" + +[package.extras] +brotli = ["brotli"] +cli = ["click", "jsbeautifier", "rich (>=13.0.0)"] +cryptography = ["cryptography"] +full = ["aiomcache", "brotli", "click", "cryptography", "opentelemetry-instrumentation-asgi", "picologging", "python-jose", "redis[hiredis]", "rich (>=13.0.0)", "structlog"] +jwt = ["cryptography", "python-jose"] +memcached = ["aiomcache"] +opentelemetry = ["opentelemetry-instrumentation-asgi"] +picologging = ["picologging"] +redis = ["redis[hiredis]"] +standard = ["click", "jsbeautifier", "picologging", "rich (>=13.0.0)"] +structlog = ["structlog"] + +[[package]] +name = "structlog" +version = "22.3.0" +description = "Structured Logging for Python" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "structlog-22.3.0-py3-none-any.whl", hash = "sha256:b403f344f902b220648fa9f286a23c0cc5439a5844d271fec40562dbadbc70ad"}, {file = "structlog-22.3.0.tar.gz", hash = "sha256:e7509391f215e4afb88b1b80fa3ea074be57a5a17d794bd436a5c949da023333"}, ] -tenacity = [ + +[package.extras] +dev = ["structlog[docs,tests,typing]"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "twisted"] +tests = ["coverage[toml]", "freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] +typing = ["mypy", "rich", "twisted"] + +[[package]] +name = "tenacity" +version = "8.1.0" +description = "Retry code until it succeeds" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ {file = "tenacity-8.1.0-py3-none-any.whl", hash = "sha256:35525cd47f82830069f0d6b73f7eb83bc5b73ee2fff0437952cedf98b27653ac"}, {file = "tenacity-8.1.0.tar.gz", hash = "sha256:e48c437fdf9340f5666b92cd7990e96bc5fc955e1298baf4a907e3972067a445"}, ] -tomli = [ + +[package.extras] +doc = ["reno", "sphinx", "tornado (>=4.5)"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -typing-extensions = [ + +[[package]] +name = "typing-extensions" +version = "4.4.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, ] -urllib3 = [ + +[[package]] +name = "urllib3" +version = "1.26.14" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ {file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"}, {file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"}, ] -uvicorn = [ + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "uvicorn" +version = "0.20.0" +description = "The lightning-fast ASGI server." +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "uvicorn-0.20.0-py3-none-any.whl", hash = "sha256:c3ed1598a5668208723f2bb49336f4509424ad198d6ab2615b7783db58d919fd"}, {file = "uvicorn-0.20.0.tar.gz", hash = "sha256:a4e12017b940247f836bc90b72e725d7dfd0c8ed1c51eb365f5ba30d9f5127d8"}, ] -uvloop = [ + +[package.dependencies] +click = ">=7.0" +h11 = ">=0.8" + +[package.extras] +standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] + +[[package]] +name = "uvloop" +version = "0.17.0" +description = "Fast implementation of asyncio event loop on top of libuv" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "uvloop-0.17.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce9f61938d7155f79d3cb2ffa663147d4a76d16e08f65e2c66b77bd41b356718"}, {file = "uvloop-0.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:68532f4349fd3900b839f588972b3392ee56042e440dd5873dfbbcd2cc67617c"}, {file = "uvloop-0.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0949caf774b9fcefc7c5756bacbbbd3fc4c05a6b7eebc7c7ad6f825b23998d6d"}, @@ -1261,3 +1252,13 @@ uvloop = [ {file = "uvloop-0.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:30babd84706115626ea78ea5dbc7dd8d0d01a2e9f9b306d24ca4ed5796c66ded"}, {file = "uvloop-0.17.0.tar.gz", hash = "sha256:0ddf6baf9cf11a1a22c71487f39f15b2cf78eb5bde7e5b45fbb99e8a9d91b9e1"}, ] + +[package.extras] +dev = ["Cython (>=0.29.32,<0.30.0)", "Sphinx (>=4.1.2,<4.2.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=22.0.0,<22.1.0)", "pycodestyle (>=2.7.0,<2.8.0)", "pytest (>=3.6.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +test = ["Cython (>=0.29.32,<0.30.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=22.0.0,<22.1.0)", "pycodestyle (>=2.7.0,<2.8.0)"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "02b7b504018c2c2e6633f8028b22dc996e837ba7f1b2a6ae6b879382b9c9d2d0" diff --git a/pyproject.toml b/pyproject.toml index b1c0b34f..28e08147 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,11 +12,11 @@ ignore-words-list = "alog" branch = true omit = ["*/starlite_saqlalchemy/scripts.py", "*/starlite_saqlalchemy/lifespan.py", "tests/*"] relative_files = true -source_pkgs = ["starlite_saqlalchemy"] +source_pkgs = ["starlite_saqlalchemy", "pytest_starlite_saqlalchemy"] [tool.coverage.paths] source = ["src", "*/site-packages"] -others = [".", "*/starlite_saqlalchemy"] +others = [".", "*/starlite_saqlalchemy", "*/pytest_starlite_saqlalchemy"] [tool.coverage.report] show_missing = true @@ -48,9 +48,11 @@ classifiers = [ "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development", "Topic :: System :: Installation/Setup", + "Framework :: Pytest", ] packages = [ - { include = "starlite_saqlalchemy", from = "src" } + { include = "starlite_saqlalchemy", from = "src" }, + { include = "pytest_starlite_saqlalchemy", from = "src" } ] [tool.poetry.dependencies] @@ -71,6 +73,9 @@ tenacity = "*" uvicorn = "*" uvloop = "*" +[tool.poetry.plugins."pytest11"] +pytest_starlite_saqlalchemy = "pytest_starlite_saqlalchemy" + [tool.poetry.urls] GitHub = "https://github.com/topsport-com-au" Bugs = "https://github.com/topsport-com-au/starlite-saqlalchemy/issues" @@ -88,6 +93,7 @@ addopts = ["-ra", "--strict-config"] asyncio_mode = "auto" env_files = ["tests.env"] testpaths = ["tests/unit"] +test_app = "tests.utils.app:create_app" [tool.pylint.main] disable = [ diff --git a/src/pytest_starlite_saqlalchemy/__init__.py b/src/pytest_starlite_saqlalchemy/__init__.py new file mode 100644 index 00000000..f89939e8 --- /dev/null +++ b/src/pytest_starlite_saqlalchemy/__init__.py @@ -0,0 +1,13 @@ +"""Pytest plugin to support testing starlite-saqlalchemy applications.""" +from __future__ import annotations + +from .plugin import ( + _patch_http_close, + _patch_sqlalchemy_plugin, + _patch_worker, + fx_app, + fx_cap_logger, + fx_client, + fx_is_unit_test, + pytest_addoption, +) diff --git a/src/pytest_starlite_saqlalchemy/plugin.py b/src/pytest_starlite_saqlalchemy/plugin.py new file mode 100644 index 00000000..048351c2 --- /dev/null +++ b/src/pytest_starlite_saqlalchemy/plugin.py @@ -0,0 +1,139 @@ +"""Pytest plugin to support testing starlite-saqlalchemy applications.""" +# pylint: disable=import-outside-toplevel +from __future__ import annotations + +import re +from typing import TYPE_CHECKING +from unittest.mock import MagicMock + +import pytest +from starlite import Starlite, TestClient +from structlog.contextvars import clear_contextvars +from structlog.testing import CapturingLogger +from uvicorn.importer import ImportFromStringError, import_from_string + +if TYPE_CHECKING: + from collections.abc import Generator + + from pytest import Config, FixtureRequest, MonkeyPatch, Parser + +__all__ = ( + "_patch_http_close", + "_patch_sqlalchemy_plugin", + "_patch_worker", + "fx_app", + "fx_cap_logger", + "fx_client", + "fx_is_unit_test", + "pytest_addoption", +) + + +def pytest_addoption(parser: Parser) -> None: + """Adds Pytest ini config variables for the plugin.""" + parser.addini( + "test_app", + "Path to application instance, or callable that returns an application instance.", + type="string", + default="app.main:create_app", + ) + parser.addini( + "unit_test_pattern", + ( + "Regex used to identify if a test is running as part of a unit or integration test " + "suite. The pattern is matched against the path of each test function and affects the " + "behavior of fixtures that are shared between unit and integration tests." + ), + type="string", + default=r"^.*/tests/unit/.*$", + ) + + +@pytest.fixture(name="is_unit_test") +def fx_is_unit_test(request: FixtureRequest) -> bool: + """Uses the ini option `unit_test_pattern` to determine if the test is part + of unit or integration tests.""" + unittest_pattern: str = request.config.getini("unit_test_pattern") # pyright:ignore + return bool(re.search(unittest_pattern, str(request.path))) + + +@pytest.fixture(autouse=True) +def _patch_http_close(monkeypatch: MonkeyPatch) -> None: + """We don't want global http clients to get closed between tests.""" + import starlite_saqlalchemy + + monkeypatch.setattr(starlite_saqlalchemy.http, "clients", set()) + + +@pytest.fixture(autouse=True) +def _patch_sqlalchemy_plugin(is_unit_test: bool, monkeypatch: MonkeyPatch) -> None: + if is_unit_test: + from starlite_saqlalchemy import sqlalchemy_plugin + + monkeypatch.setattr( + sqlalchemy_plugin.SQLAlchemyConfig, # type:ignore[attr-defined] + "on_shutdown", + MagicMock(), + ) + + +@pytest.fixture(autouse=True) +def _patch_worker(is_unit_test: bool, monkeypatch: MonkeyPatch) -> None: + """We don't want the worker to start for unittests.""" + if is_unit_test: + from starlite_saqlalchemy import worker + + monkeypatch.setattr(worker.Worker, "on_app_startup", MagicMock()) + monkeypatch.setattr(worker.Worker, "stop", MagicMock()) + + +@pytest.fixture(name="app") +def fx_app(pytestconfig: Config, monkeypatch: MonkeyPatch) -> Starlite: + """ + Returns: + An application instance, configured via plugin. + """ + test_app_str = pytestconfig.getini("test_app") + + try: + app_or_callable = import_from_string(test_app_str) + except (ImportFromStringError, ModuleNotFoundError): + from starlite_saqlalchemy.init_plugin import ConfigureApp + + app = Starlite(route_handlers=[], on_app_init=[ConfigureApp()], openapi_config=None) + else: + if isinstance(app_or_callable, Starlite): + app = app_or_callable + else: + app = app_or_callable() + + monkeypatch.setattr(app, "before_startup", []) + return app + + +@pytest.fixture(name="client") +def fx_client(app: Starlite) -> Generator[TestClient, None, None]: + """Test client fixture for making calls on the global app instance.""" + with TestClient(app=app) as client: + yield client + + +@pytest.fixture(name="cap_logger") +def fx_cap_logger(monkeypatch: MonkeyPatch) -> CapturingLogger: + """Used to monkeypatch the app logger, so we can inspect output.""" + import starlite_saqlalchemy + + starlite_saqlalchemy.log.configure( + starlite_saqlalchemy.log.default_processors # type:ignore[arg-type] + ) + # clear context for every test + clear_contextvars() + # pylint: disable=protected-access + logger = starlite_saqlalchemy.log.controller.LOGGER.bind() + logger._logger = CapturingLogger() + # drop rendering processor to get a dict, not bytes + # noinspection PyProtectedMember + logger._processors = starlite_saqlalchemy.log.default_processors[:-1] + monkeypatch.setattr(starlite_saqlalchemy.log.controller, "LOGGER", logger) + monkeypatch.setattr(starlite_saqlalchemy.log.worker, "LOGGER", logger) + return logger._logger diff --git a/src/starlite_saqlalchemy/__init__.py b/src/starlite_saqlalchemy/__init__.py index 044ce55f..53496bfe 100644 --- a/src/starlite_saqlalchemy/__init__.py +++ b/src/starlite_saqlalchemy/__init__.py @@ -29,6 +29,7 @@ def example_handler() -> dict: dto, exceptions, health, + http, log, openapi, redis, @@ -51,6 +52,7 @@ def example_handler() -> dict: "dto", "exceptions", "health", + "http", "log", "openapi", "redis", diff --git a/src/starlite_saqlalchemy/settings.py b/src/starlite_saqlalchemy/settings.py index f14f4630..ca803ba6 100644 --- a/src/starlite_saqlalchemy/settings.py +++ b/src/starlite_saqlalchemy/settings.py @@ -113,7 +113,6 @@ class Config: REQUEST_FIELDS: list[RequestExtractorField] = [ "path", "method", - "content_type", "headers", "cookies", "query", diff --git a/src/starlite_saqlalchemy/sqlalchemy_plugin.py b/src/starlite_saqlalchemy/sqlalchemy_plugin.py index 821b26b8..40626a74 100644 --- a/src/starlite_saqlalchemy/sqlalchemy_plugin.py +++ b/src/starlite_saqlalchemy/sqlalchemy_plugin.py @@ -19,7 +19,7 @@ from starlite.datastructures.state import State from starlite.types import Message, Scope -__all__ = ["config", "plugin"] +__all__ = ["SQLAlchemyHealthCheck", "config", "plugin"] async def before_send_handler(message: "Message", _: "State", scope: "Scope") -> None: @@ -49,6 +49,7 @@ class SQLAlchemyHealthCheck(AbstractHealthCheck): name: str = "db" def __init__(self) -> None: + """Health check with database check.""" self.engine = create_async_engine( settings.db.URL, logging_name="starlite_saqlalchemy.health" ) diff --git a/src/starlite_saqlalchemy/testing/__init__.py b/src/starlite_saqlalchemy/testing/__init__.py new file mode 100644 index 00000000..8d75d555 --- /dev/null +++ b/src/starlite_saqlalchemy/testing/__init__.py @@ -0,0 +1,11 @@ +"""Application testing support.""" + +from .controller_test import ControllerTest +from .generic_mock_repository import GenericMockRepository +from .modify_settings import modify_settings + +__all__ = ( + "ControllerTest", + "GenericMockRepository", + "modify_settings", +) diff --git a/src/starlite_saqlalchemy/testing/controller_test.py b/src/starlite_saqlalchemy/testing/controller_test.py new file mode 100644 index 00000000..c964dde2 --- /dev/null +++ b/src/starlite_saqlalchemy/testing/controller_test.py @@ -0,0 +1,109 @@ +"""Automated controller testing.""" +from __future__ import annotations + +import random +from typing import TYPE_CHECKING + +from starlite.status_codes import HTTP_200_OK, HTTP_201_CREATED + +if TYPE_CHECKING: + from collections.abc import Sequence + from typing import Any + + from pytest import MonkeyPatch + from starlite.testing import TestClient + + from starlite_saqlalchemy.db import orm + from starlite_saqlalchemy.service import Service + + +class ControllerTest: + """Standard controller testing utility.""" + + def __init__( + self, + client: TestClient, + base_path: str, + collection: Sequence[orm.Base], + raw_collection: Sequence[dict[str, Any]], + service_type: type[Service], + monkeypatch: MonkeyPatch, + collection_filters: dict[str, Any] | None = None, + ) -> None: + """Perform standard tests of controllers. + + Args: + client: Test client instance. + base_path: Path for POST and collection GET requests. + collection: Collection of domain objects. + raw_collection: Collection of raw representations of domain objects. + service_type: The domain Service object type. + monkeypatch: Pytest's monkeypatch. + collection_filters: Collection filters for GET collection request. + """ + self.client = client + self.base_path = base_path + self.collection = collection + self.raw_collection = raw_collection + self.service_type = service_type + self.monkeypatch = monkeypatch + self.collection_filters = collection_filters + + def _get_random_member(self) -> Any: + return random.choice(self.collection) + + def _get_raw_for_member(self, member: Any) -> dict[str, Any]: + return [item for item in self.raw_collection if item["id"] == str(member.id)][0] + + def test_get_collection(self, with_filters: bool = False) -> None: + """Test collection endpoint get request.""" + + async def _list(*_: Any, **__: Any) -> list[Any]: + return list(self.collection) + + self.monkeypatch.setattr(self.service_type, "list", _list) + + resp = self.client.get( + self.base_path, params=self.collection_filters if with_filters else None + ) + + assert resp.status_code == HTTP_200_OK + assert resp.json() == self.raw_collection + + def test_member_request(self, method: str, service_method: str, exp_status: int) -> None: + """Test member endpoint request.""" + member = self._get_random_member() + raw = self._get_raw_for_member(member) + + async def _method(*_: Any, **__: Any) -> Any: + return member + + self.monkeypatch.setattr(self.service_type, service_method, _method) + + if method.lower() == "post": + url = self.base_path + else: + url = f"{self.base_path}/{member.id}" + + request_kw: dict[str, Any] = {} + if method.lower() in ("put", "post"): + request_kw["json"] = raw + + resp = self.client.request(method, url, **request_kw) + + assert resp.status_code == exp_status + assert resp.json() == raw + + def run(self) -> None: + """Run the tests.""" + # test the collection route with and without filters for branch coverage. + self.test_get_collection() + if self.collection_filters: + self.test_get_collection(with_filters=True) + for method, service_method, status in [ + ("GET", "get", HTTP_200_OK), + ("PUT", "update", HTTP_200_OK), + ("POST", "create", HTTP_201_CREATED), + ("DELETE", "delete", HTTP_200_OK), + ]: + self.test_member_request(method, service_method, status) diff --git a/src/starlite_saqlalchemy/testing.py b/src/starlite_saqlalchemy/testing/generic_mock_repository.py similarity index 56% rename from src/starlite_saqlalchemy/testing.py rename to src/starlite_saqlalchemy/testing/generic_mock_repository.py index 3f341641..9342b5ea 100644 --- a/src/starlite_saqlalchemy/testing.py +++ b/src/starlite_saqlalchemy/testing/generic_mock_repository.py @@ -4,66 +4,24 @@ """ from __future__ import annotations -import random -from contextlib import contextmanager from datetime import datetime from typing import TYPE_CHECKING, Generic, TypeVar from uuid import uuid4 -from starlite.status_codes import HTTP_200_OK, HTTP_201_CREATED - from starlite_saqlalchemy.db import orm from starlite_saqlalchemy.exceptions import ConflictError, StarliteSaqlalchemyError from starlite_saqlalchemy.repository.abc import AbstractRepository if TYPE_CHECKING: - from collections.abc import ( - Callable, - Generator, - Hashable, - Iterable, - MutableMapping, - Sequence, - ) + from collections.abc import Callable, Hashable, Iterable, MutableMapping from typing import Any - from pydantic import BaseSettings - from pytest import MonkeyPatch - from starlite.testing import TestClient - from starlite_saqlalchemy.repository.types import FilterTypes - from starlite_saqlalchemy.service import Service ModelT = TypeVar("ModelT", bound=orm.Base) MockRepoT = TypeVar("MockRepoT", bound="GenericMockRepository") -@contextmanager -def modify_settings(*update: tuple[BaseSettings, dict[str, Any]]) -> Generator[None, None, None]: - """Context manager that modify the desired settings and restore them on - exit. - - >>> assert settings.app.ENVIRONMENT = "local" - >>> with modify_settings((settings.app, {"ENVIRONMENT": "prod"})): - >>> assert settings.app.ENVIRONMENT == "prod" - >>> assert settings.app.ENVIRONMENT == "local" - """ - old_settings: list[tuple[BaseSettings, dict[str, Any]]] = [] - try: - for model, new_values in update: - old_values = {} - for field, value in model.dict().items(): - if field in new_values: - old_values[field] = value - setattr(model, field, new_values[field]) - old_settings.append((model, old_values)) - yield - finally: - for model, old_values in old_settings: - for field, old_val in old_values.items(): - setattr(model, field, old_val) - - class GenericMockRepository(AbstractRepository[ModelT], Generic[ModelT]): """A repository implementation for tests. @@ -228,95 +186,3 @@ def seed_collection(cls, instances: Iterable[ModelT]) -> None: def clear_collection(cls) -> None: """Empty the collection for repository type.""" cls.collection = {} - - -class ControllerTest: - """Standard controller testing utility.""" - - def __init__( - self, - client: TestClient, - base_path: str, - collection: Sequence[orm.Base], - raw_collection: Sequence[dict[str, Any]], - service_type: type[Service], - monkeypatch: MonkeyPatch, - collection_filters: dict[str, Any] | None = None, - ) -> None: - """Perform standard tests of controllers. - - Args: - client: Test client instance. - base_path: Path for POST and collection GET requests. - collection: Collection of domain objects. - raw_collection: Collection of raw representations of domain objects. - service_type: The domain Service object type. - monkeypatch: Pytest's monkeypatch. - collection_filters: Collection filters for GET collection request. - """ - self.client = client - self.base_path = base_path - self.collection = collection - self.raw_collection = raw_collection - self.service_type = service_type - self.monkeypatch = monkeypatch - self.collection_filters = collection_filters - - def _get_random_member(self) -> Any: - return random.choice(self.collection) - - def _get_raw_for_member(self, member: Any) -> dict[str, Any]: - return [item for item in self.raw_collection if item["id"] == str(member.id)][0] - - def test_get_collection(self, with_filters: bool = False) -> None: - """Test collection endpoint get request.""" - - async def _list(*_: Any, **__: Any) -> list[Any]: - return list(self.collection) - - self.monkeypatch.setattr(self.service_type, "list", _list) - - resp = self.client.get( - self.base_path, params=self.collection_filters if with_filters else None - ) - - assert resp.status_code == HTTP_200_OK - assert resp.json() == self.raw_collection - - def test_member_request(self, method: str, service_method: str, exp_status: int) -> None: - """Test member endpoint request.""" - member = self._get_random_member() - raw = self._get_raw_for_member(member) - - async def _method(*_: Any, **__: Any) -> Any: - return member - - self.monkeypatch.setattr(self.service_type, service_method, _method) - - if method.lower() == "post": - url = self.base_path - else: - url = f"{self.base_path}/{member.id}" - - request_kw: dict[str, Any] = {} - if method.lower() in ("put", "post"): - request_kw["json"] = raw - - resp = self.client.request(method, url, **request_kw) - - assert resp.status_code == exp_status - assert resp.json() == raw - - def run(self) -> None: - """Run the tests.""" - # test the collection route with and without filters for branch coverage. - self.test_get_collection() - if self.collection_filters: - self.test_get_collection(with_filters=True) - for method, service_method, status in [ - ("GET", "get", HTTP_200_OK), - ("PUT", "update", HTTP_200_OK), - ("POST", "create", HTTP_201_CREATED), - ("DELETE", "delete", HTTP_200_OK), - ]: - self.test_member_request(method, service_method, status) diff --git a/src/starlite_saqlalchemy/testing/modify_settings.py b/src/starlite_saqlalchemy/testing/modify_settings.py new file mode 100644 index 00000000..95c4b8be --- /dev/null +++ b/src/starlite_saqlalchemy/testing/modify_settings.py @@ -0,0 +1,37 @@ +"""A context manager to support patching application settings.""" +from __future__ import annotations + +from contextlib import contextmanager +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Generator + from typing import Any + + from pydantic import BaseSettings + + +@contextmanager +def modify_settings(*update: tuple[BaseSettings, dict[str, Any]]) -> Generator[None, None, None]: + """Context manager that modify the desired settings and restore them on + exit. + + >>> assert settings.app.ENVIRONMENT = "local" + >>> with modify_settings((settings.app, {"ENVIRONMENT": "prod"})): + >>> assert settings.app.ENVIRONMENT == "prod" + >>> assert settings.app.ENVIRONMENT == "local" + """ + old_settings: list[tuple[BaseSettings, dict[str, Any]]] = [] + try: + for model, new_values in update: + old_values = {} + for field, value in model.dict().items(): + if field in new_values: + old_values[field] = value + setattr(model, field, new_values[field]) + old_settings.append((model, old_values)) + yield + finally: + for model, old_values in old_settings: + for field, old_val in old_values.items(): + setattr(model, field, old_val) diff --git a/tests.env b/tests.env index 774c73dd..e5a31403 100644 --- a/tests.env +++ b/tests.env @@ -1,43 +1,3 @@ # App -BUILD_NUMBER= -DEBUG=true ENVIRONMENT=test NAME=my-starlite-app - -# API -API_CACHE_EXPIRATION=60 -API_DEFAULT_PAGINATION_LIMIT=100 -API_HEALTH_PATH=/health -API_DB_SESSION_DEPENDENCY_KEY=db_session - -# OpenAPI -OPENAPI_CONTACT_EMAIL=some_human@email.com -OPENAPI_CONTACT_NAME="Some Human" -OPENAPI_TITLE="My Starlite App" -OPENAPI_VERSION=1.0.0 - -# Sentry -SENTRY_DSN= -SENTRY_TRACES_SAMPLE_RATE=0.0001 - -# Redis -REDIS_URL=redis://cache.local:6379/0 - -# Database -DB_ECHO=false -DB_ECHO_POOL=false -DB_POOL_DISABLE=false -DB_POOL_MAX_OVERFLOW=10 -DB_POOL_SIZE=5 -DB_POOL_TIMEOUT=30 -DB_URL=postgresql+asyncpg://postgres:mysecretpassword@pg.db.local:5432/db - -# Log -LOG_EXCLUDE_PATHS="\A(?!x)x" -LOG_OBFUSCATE_COOKIES=["session"] -LOG_OBFUSCATE_HEADERS=["Authorization", "X-API-KEY"] -LOG_REQUEST_FIELDS=["path","method","content_type","headers","cookies","query","path_params","body"] -LOG_RESPONSE_FIELDS=["status_code","cookies","headers","body"] -LOG_HTTP_EVENT="HTTP" -LOG_WORKER_EVENT="Worker" -LOG_LEVEL=20 diff --git a/tests/conftest.py b/tests/conftest.py index fa2db5ed..761a66f5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,12 +8,7 @@ import pytest from asyncpg.pgproto import pgproto -from starlite import Starlite -from structlog.contextvars import clear_contextvars -from structlog.testing import CapturingLogger -import starlite_saqlalchemy -from starlite_saqlalchemy import ConfigureApp, log from tests.utils.domain import authors, books if TYPE_CHECKING: @@ -25,39 +20,6 @@ from pytest import MonkeyPatch -@pytest.fixture(name="cap_logger") -def fx_capturing_logger(monkeypatch: MonkeyPatch) -> CapturingLogger: - """Used to monkeypatch the app logger, so we can inspect output.""" - cap_logger = CapturingLogger() - starlite_saqlalchemy.log.configure( - starlite_saqlalchemy.log.default_processors # type:ignore[arg-type] - ) - # clear context for every test - clear_contextvars() - # pylint: disable=protected-access - logger = starlite_saqlalchemy.log.controller.LOGGER.bind() - logger._logger = cap_logger - # drop rendering processor to get a dict, not bytes - # noinspection PyProtectedMember - logger._processors = log.default_processors[:-1] - monkeypatch.setattr(starlite_saqlalchemy.log.controller, "LOGGER", logger) - monkeypatch.setattr(starlite_saqlalchemy.log.worker, "LOGGER", logger) - return cap_logger - - -@pytest.fixture(name="app") -def fx_app() -> Starlite: - """Always use this `app` fixture and never do `from app.main import app` - inside a test module. We need to delay import of the `app.main` module - until as late as possible to ensure we can mock everything necessary before - the application instance is constructed. - - Returns: - The application instance. - """ - return Starlite(route_handlers=[], on_app_init=[ConfigureApp()], openapi_config=None) - - @pytest.fixture(name="raw_authors") def fx_raw_authors() -> list[dict[str, Any]]: """Unstructured author representations.""" diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index f960b52a..ad1d9ece 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -1,9 +1,9 @@ """Config for integration tests.""" -# pylint: disable=redefined-outer-name from __future__ import annotations import asyncio import timeit +from asyncio import AbstractEventLoop, get_event_loop_policy from pathlib import Path from typing import TYPE_CHECKING @@ -16,15 +16,13 @@ from sqlalchemy.engine import URL from sqlalchemy.ext.asyncio import AsyncEngine, async_sessionmaker, create_async_engine from sqlalchemy.pool import NullPool -from starlite import Provide, Router from starlite_saqlalchemy import db, sqlalchemy_plugin, worker from starlite_saqlalchemy.health import AppHealthCheck, HealthController from starlite_saqlalchemy.sqlalchemy_plugin import SQLAlchemyHealthCheck -from tests.utils import controllers if TYPE_CHECKING: - from collections import abc + from collections.abc import AsyncIterator, Awaitable, Callable, Iterator from typing import Any from pytest_docker.plugin import Services # type:ignore[import] @@ -37,10 +35,10 @@ @pytest.fixture(scope="session") -def event_loop() -> abc.Iterator[asyncio.AbstractEventLoop]: +def event_loop() -> Iterator[AbstractEventLoop]: """Need the event loop scoped to the session so that we can use it to check containers are ready in session scoped containers fixture.""" - policy = asyncio.get_event_loop_policy() + policy = get_event_loop_policy() loop = policy.new_event_loop() yield loop loop.close() @@ -56,7 +54,7 @@ def docker_compose_file() -> Path: async def wait_until_responsive( - check: abc.Callable[..., abc.Awaitable], timeout: float, pause: float, **kwargs: Any + check: Callable[..., Awaitable], timeout: float, pause: float, **kwargs: Any ) -> None: """Wait until a service is responsive. @@ -130,8 +128,8 @@ async def _containers( await wait_until_responsive(timeout=30.0, pause=0.1, check=redis_responsive, host=docker_ip) -@pytest.fixture() -async def redis(docker_ip: str) -> Redis: +@pytest.fixture(name="redis") +async def fx_redis(docker_ip: str) -> Redis: """ Args: @@ -143,8 +141,8 @@ async def redis(docker_ip: str) -> Redis: return Redis(host=docker_ip, port=6397) -@pytest.fixture() -async def engine(docker_ip: str) -> AsyncEngine: +@pytest.fixture(name="engine") +async def fx_engine(docker_ip: str) -> AsyncEngine: """Postgresql instance for end-to-end testing. Args: @@ -169,7 +167,7 @@ async def engine(docker_ip: str) -> AsyncEngine: @pytest.fixture(autouse=True) -async def _seed_db(engine: AsyncEngine, authors: list[Author]) -> abc.AsyncIterator[None]: +async def _seed_db(engine: AsyncEngine, authors: list[Author]) -> AsyncIterator[None]: """Populate test database with. Args: @@ -207,42 +205,8 @@ def _patch_redis(app: Starlite, redis: Redis, monkeypatch: pytest.MonkeyPatch) - monkeypatch.setattr(worker.queue, "redis", redis) -@pytest.fixture() -def router() -> Router: - """ - Returns: - This is a router with controllers added for testing against the test domain. - """ - return Router( - path="/authors", - route_handlers=[ - controllers.get_authors, - controllers.create_author, - controllers.get_author, - controllers.update_author, - controllers.delete_author, - ], - dependencies={"service": Provide(controllers.provides_service)}, - tags=["Authors"], - ) - - -@pytest.fixture() -def app(app: Starlite, router: Router) -> Starlite: - """ - Args: - app: App from outermost conftest.py - router: Router with controllers for tests. - - Returns: - App with router attached for integration tests. - """ - app.register(router) - return app - - @pytest.fixture(name="client") -async def fx_client(app: Starlite) -> abc.AsyncIterator[AsyncClient]: +async def fx_client(app: Starlite) -> AsyncIterator[AsyncClient]: """Async client that calls requests on the app. We need to use `httpx.AsyncClient` here, as `starlite.TestClient` creates its own event loop to diff --git a/tests/integration/test_authors.py b/tests/integration/test_authors.py index 8efd2f91..5cbe659d 100644 --- a/tests/integration/test_authors.py +++ b/tests/integration/test_authors.py @@ -3,13 +3,10 @@ from typing import TYPE_CHECKING -import pytest - if TYPE_CHECKING: from httpx import AsyncClient -@pytest.mark.xfail() async def test_update_author(client: AsyncClient) -> None: """Integration test for PUT route.""" response = await client.put( diff --git a/tests/integration/test_logging.py b/tests/integration/test_logging.py index 7ec09c88..a3fe8678 100644 --- a/tests/integration/test_logging.py +++ b/tests/integration/test_logging.py @@ -48,7 +48,6 @@ async def test_logging(app: "Starlite", cap_logger: CapturingLogger) -> None: "request": { "path": "/authors/97108ac1-ffcb-411d-8b1e-d9183399f63b", "method": "PUT", - "content_type": ("application/json", {}), "headers": { "host": "testserver", "accept": "*/*", diff --git a/tests/pytest_plugin/__init__.py b/tests/pytest_plugin/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/pytest_plugin/conftest.py b/tests/pytest_plugin/conftest.py new file mode 100644 index 00000000..0172cf77 --- /dev/null +++ b/tests/pytest_plugin/conftest.py @@ -0,0 +1,4 @@ +"""Enable the `pytester` fixture for the plugin tests.""" +from __future__ import annotations + +pytest_plugins = ["pytester"] diff --git a/tests/pytest_plugin/test_plugin.py b/tests/pytest_plugin/test_plugin.py new file mode 100644 index 00000000..75d00c93 --- /dev/null +++ b/tests/pytest_plugin/test_plugin.py @@ -0,0 +1,174 @@ +"""Test suite for pytest plugin.""" +from __future__ import annotations + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pytest import Pytester + + +def test_pytest_addoption(pytester: Pytester) -> None: + """Test ini options added.""" + pytester.makepyfile( + """ + from pytest import Parser + from pytest_starlite_saqlalchemy import pytest_addoption + + def test_pytest_addoption() -> None: + parser = Parser() + pytest_addoption(parser) + assert parser._ininames == ["test_app", "unit_test_pattern"] + """ + ) + result = pytester.runpytest() + result.assert_outcomes(passed=1) + + +def test_is_unit_test_true(pytester: Pytester) -> None: + """Test is_unit_test fixture True conditions.""" + pytester.makepyprojecttoml( + f""" + [tool.pytest.ini_options] + unit_test_pattern = "^{pytester.path}/test_is_unit_test_true.py$" + """ + ) + pytester.makepyfile( + """ + from unittest.mock import MagicMock + from starlite_saqlalchemy.sqlalchemy_plugin import SQLAlchemyConfig + from starlite_saqlalchemy.worker import Worker + + def test_is_unit_test_true(is_unit_test: bool) -> None: + assert is_unit_test is True + + def test_patch_sqlalchemy_plugin() -> None: + assert isinstance(SQLAlchemyConfig.on_shutdown, MagicMock) + + def test_patch_worker() -> None: + assert isinstance(Worker.on_app_startup, MagicMock) + assert isinstance(Worker.stop, MagicMock) + """ + ) + result = pytester.runpytest() + result.assert_outcomes(passed=3) + + +def test_is_unit_test_false(pytester: Pytester) -> None: + """Unit is_unit_test fixture False conditions.""" + pytester.makepyprojecttoml( + """ + [tool.pytest.ini_options] + unit_test_pattern = "^definitely/not/the/path/to/test_is_unit_test_false.py$" + """ + ) + pytester.makepyfile( + """ + from unittest.mock import MagicMock + from starlite_saqlalchemy.sqlalchemy_plugin import SQLAlchemyConfig + from starlite_saqlalchemy.worker import Worker + + def test_is_unit_test_false(is_unit_test: bool) -> None: + assert is_unit_test is False + + def test_patch_sqlalchemy_plugin() -> None: + assert not isinstance(SQLAlchemyConfig.on_shutdown, MagicMock) + + def test_patch_worker() -> None: + assert not isinstance(Worker.on_app_startup, MagicMock) + assert not isinstance(Worker.stop, MagicMock) + """ + ) + result = pytester.runpytest() + result.assert_outcomes(passed=3) + + +def test_patch_http_close(pytester: Pytester) -> None: + """Test that http clients won't be closed in-between tests.""" + pytester.makepyfile( + """ + import starlite_saqlalchemy + + client = starlite_saqlalchemy.http.Client("https://somewhere.com") + assert starlite_saqlalchemy.http.clients + + def test_patch_http_close(is_unit_test: bool) -> None: + assert not starlite_saqlalchemy.http.clients + """ + ) + result = pytester.runpytest() + result.assert_outcomes(passed=1) + + +def test_app_fixture_if_app_factory(pytester: Pytester) -> None: + """Test that the app fixture returns an instance retrieved from a + factory.""" + pytester.makepyprojecttoml( + """ + [tool.pytest.ini_options] + test_app = "tests.utils.app:create_app" + """ + ) + pytester.makepyfile( + """ + from starlite import Starlite + + def test_app(app): + assert isinstance(app, Starlite) + assert "/authors" in app.route_handler_method_map + """ + ) + result = pytester.runpytest() + result.assert_outcomes(passed=1) + + +def test_app_fixture_if_app_instance(pytester: Pytester) -> None: + """Test that the app fixture returns the an instance if the path points to + one.""" + pytester.syspathinsert() + pytester.makepyfile( + test_app=""" + from tests.utils.app import create_app + + app = create_app() + """ + ) + pytester.makepyprojecttoml( + """ + [tool.pytest.ini_options] + test_app = "test_app:app" + """ + ) + pytester.makepyfile( + """ + from starlite import Starlite + + def test_app(app): + assert isinstance(app, Starlite) + assert "/authors" in app.route_handler_method_map + """ + ) + result = pytester.runpytest() + result.assert_outcomes(passed=1) + + +def test_app_fixture_if_test_app_path_does_not_exist(pytester: Pytester) -> None: + """Tests that the app fixture falls back to a new app instance if the + configured path is not found.""" + pytester.makepyprojecttoml( + """ + [tool.pytest.ini_options] + test_app = "definitely.not.the.path.to.app:app" + """ + ) + pytester.makepyfile( + """ + from starlite import Starlite + + def test_app(app): + assert isinstance(app, Starlite) + # the app that is created should not have any handlers attached. + assert app.route_handler_method_map.keys() == {"/health"} + """ + ) + result = pytester.runpytest() + result.assert_outcomes(passed=1) diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 386f6eab..16871add 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -2,15 +2,12 @@ from __future__ import annotations from typing import TYPE_CHECKING -from unittest.mock import MagicMock import pytest from saq.job import Job from starlite.datastructures import State from starlite.enums import ScopeType -from starlite.testing import TestClient -from starlite_saqlalchemy import sqlalchemy_plugin, worker from starlite_saqlalchemy.testing import GenericMockRepository from tests.utils.domain.authors import Author from tests.utils.domain.authors import Service as AuthorService @@ -20,34 +17,11 @@ from ..utils import controllers if TYPE_CHECKING: - from collections import abc - from pytest import MonkeyPatch from starlite import Starlite from starlite.types import HTTPResponseBodyEvent, HTTPResponseStartEvent, HTTPScope -@pytest.fixture(scope="session", autouse=True) -def _patch_sqlalchemy_plugin() -> abc.Iterator: - monkeypatch = pytest.MonkeyPatch() - monkeypatch.setattr( - sqlalchemy_plugin.SQLAlchemyConfig, # type:ignore[attr-defined] - "on_shutdown", - MagicMock(), - ) - yield - monkeypatch.undo() - - -@pytest.fixture(scope="session", autouse=True) -def _patch_worker() -> abc.Iterator: - monkeypatch = pytest.MonkeyPatch() - monkeypatch.setattr(worker.Worker, "on_app_startup", MagicMock()) - monkeypatch.setattr(worker.Worker, "stop", MagicMock()) - yield - monkeypatch.undo() - - @pytest.fixture(name="author_repository_type") def fx_author_repository_type( authors: list[Author], monkeypatch: pytest.MonkeyPatch @@ -92,27 +66,6 @@ def fx_book_repository( return book_repository_type() -@pytest.fixture(name="app") -def fx_app(app: Starlite, monkeypatch: MonkeyPatch) -> Starlite: - """Remove service readiness checks for unit tests.""" - monkeypatch.setattr(app, "before_startup", []) - return app - - -@pytest.fixture(name="client") -def fx_client(app: Starlite) -> abc.Iterator[TestClient]: - """Client instance attached to app. - - Args: - app: The app for testing. - - Returns: - Test client instance. - """ - with TestClient(app=app) as client_: - yield client_ - - @pytest.fixture() def http_response_start() -> HTTPResponseStartEvent: """ASGI message for start of response.""" diff --git a/tests/unit/test_log.py b/tests/unit/test_log.py index 0373b16a..f10ce12b 100644 --- a/tests/unit/test_log.py +++ b/tests/unit/test_log.py @@ -292,7 +292,6 @@ async def test_before_send_handler_extract_request_data( assert data == { "path": "/", "method": "POST", - "content_type": ("application/json", {}), "headers": {"content-length": "10", "content-type": "application/json"}, "cookies": {}, "query": b"", @@ -436,7 +435,6 @@ def test_handler() -> str: assert "exception" not in call.kwargs -@pytest.mark.xfail(reason="starlite is returning 500 for invalid payloads as of v1.48.1") async def test_log_request_with_invalid_json_payload(client: TestClient[Starlite]) -> None: """Test logs emitted with invalid client payload. diff --git a/tests/utils/app.py b/tests/utils/app.py new file mode 100644 index 00000000..f821df42 --- /dev/null +++ b/tests/utils/app.py @@ -0,0 +1,16 @@ +"""Test application.""" +from __future__ import annotations + +from starlite import Starlite + +from starlite_saqlalchemy import ConfigureApp + +from . import controllers + + +def create_app() -> Starlite: + """App for our test domain.""" + return Starlite( + route_handlers=[controllers.create_router()], + on_app_init=[ConfigureApp()], + ) diff --git a/tests/utils/controllers.py b/tests/utils/controllers.py index d2898450..7f456178 100644 --- a/tests/utils/controllers.py +++ b/tests/utils/controllers.py @@ -4,7 +4,7 @@ from uuid import UUID from sqlalchemy.ext.asyncio import AsyncSession -from starlite import Dependency, delete, get, post, put +from starlite import Dependency, Provide, Router, delete, get, post, put from starlite.status_codes import HTTP_200_OK from starlite_saqlalchemy.repository.types import FilterTypes @@ -49,3 +49,18 @@ async def update_author(data: WriteDTO, service: Service, author_id: UUID) -> Re async def delete_author(service: Service, author_id: UUID) -> ReadDTO: """Delete Author by ID.""" return ReadDTO.from_orm(await service.delete(author_id)) + + +def create_router() -> Router: + """Create a router for our test domain controllers.""" + return Router( + path="/authors", + route_handlers=[ + create_author, + delete_author, + get_author, + get_authors, + update_author, + ], + dependencies={"service": Provide(provides_service)}, + ) diff --git a/tox.ini b/tox.ini index a70b4aa5..630c9bff 100644 --- a/tox.ini +++ b/tox.ini @@ -1,10 +1,10 @@ [gh-actions] python = 3.10: py310 - 3.11: py311,integration + 3.11: py311,pytest-plugin,integration [tox] -envlist = pylint,mypy,pyright,py310,py311,integration,coverage +envlist = pylint,mypy,pyright,py310,py311,pytest-plugin,integration,coverage isolated_build = true [testenv] @@ -14,8 +14,11 @@ deps = commands = coverage run -p -m pytest {posargs} +[testenv:pytest-plugin] +commands = coverage run -p -m pytest tests/pytest_plugin {posargs} + [testenv:coverage] -depends = py310,py311 +depends = py310,py311,pytest-plugin basepython = python3.11 commands = coverage combine