mirror of
https://github.com/ijaric/voice_assistant.git
synced 2025-05-24 14:33:26 +00:00
Merge branch 'main' into handler_orchestrator
This commit is contained in:
commit
6fd3daa6ed
12
.github/workflows/check-pr.yaml
vendored
12
.github/workflows/check-pr.yaml
vendored
|
@ -99,6 +99,18 @@ jobs:
|
||||||
make lint
|
make lint
|
||||||
|
|
||||||
- name: Test Package
|
- name: Test Package
|
||||||
|
env:
|
||||||
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||||
|
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
|
||||||
|
JWT_SECRET_KEY: ${{ secrets.JWT_SECRET_KEY }}
|
||||||
|
POSTGRES_DRIVER: ${{ vars.POSTGRES_DRIVER }}
|
||||||
|
POSTGRES_HOST: ${{ vars.POSTGRES_HOST }}
|
||||||
|
POSTGRES_PORT: ${{ vars.POSTGRES_PORT }}
|
||||||
|
POSTGRES_USER: ${{ vars.POSTGRES_USER }}
|
||||||
|
NGINX_PORT: ${{ vars.NGINX_PORT }}
|
||||||
|
API_HOST: ${{ vars.API_HOST }}
|
||||||
|
API_PORT: ${{ vars.API_PORT }}
|
||||||
|
APP_RELOAD: ${{ vars.APP_RELOAD }}
|
||||||
working-directory: src/${{ matrix.package }}
|
working-directory: src/${{ matrix.package }}
|
||||||
run: |
|
run: |
|
||||||
make ci-test
|
make ci-test
|
||||||
|
|
|
@ -15,6 +15,10 @@ NGINX_PORT=80
|
||||||
API_HOST=0.0.0.0
|
API_HOST=0.0.0.0
|
||||||
API_PORT=8000
|
API_PORT=8000
|
||||||
|
|
||||||
|
TEST_API_PROTOCOL=http
|
||||||
|
TEST_API_HOST=api
|
||||||
|
TEST_API_PORT=8000
|
||||||
|
|
||||||
JWT_SECRET_KEY=v9LctjUWwol4XbvczPiLFMDtZ8aal7mm
|
JWT_SECRET_KEY=v9LctjUWwol4XbvczPiLFMDtZ8aal7mm
|
||||||
JWT_ALGORITHM=HS256
|
JWT_ALGORITHM=HS256
|
||||||
|
|
||||||
|
|
18
src/assistant/Dockerfile.tests
Normal file
18
src/assistant/Dockerfile.tests
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
FROM python:3.11
|
||||||
|
|
||||||
|
RUN apt-get update
|
||||||
|
|
||||||
|
WORKDIR /opt/app
|
||||||
|
|
||||||
|
COPY pyproject.toml ./
|
||||||
|
COPY poetry.lock ./
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& pip install poetry \
|
||||||
|
&& poetry config virtualenvs.create false \
|
||||||
|
&& poetry install --no-dev
|
||||||
|
|
||||||
|
COPY tests tests
|
||||||
|
COPY lib lib
|
||||||
|
|
||||||
|
CMD ["pytest"]
|
|
@ -1,3 +1,3 @@
|
||||||
include ../../common_makefile.mk
|
include ../../common_makefile.mk
|
||||||
|
|
||||||
PROJECT_FOLDERS = bin lib tests
|
PROJECT_FOLDERS = bin lib tests
|
||||||
|
|
56
src/assistant/docker-compose.tests.yml
Normal file
56
src/assistant/docker-compose.tests.yml
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:15.2
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
POSTGRES_DB: ${POSTGRES_NAME}
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
expose:
|
||||||
|
- "${POSTGRES_PORT}"
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data/
|
||||||
|
networks:
|
||||||
|
- backend_network
|
||||||
|
|
||||||
|
api:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
container_name: api
|
||||||
|
image: fastapi_app
|
||||||
|
restart: always
|
||||||
|
entrypoint: ["/opt/app/entrypoint.sh"]
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
expose:
|
||||||
|
- "${API_PORT}"
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
networks:
|
||||||
|
- backend_network
|
||||||
|
- api_network
|
||||||
|
|
||||||
|
tests:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: "Dockerfile.tests"
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
- api
|
||||||
|
networks:
|
||||||
|
- api_network
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
api_network:
|
||||||
|
driver: bridge
|
||||||
|
backend_network:
|
||||||
|
driver: bridge
|
19
src/assistant/poetry.lock
generated
19
src/assistant/poetry.lock
generated
|
@ -1517,6 +1517,24 @@ pluggy = ">=0.12,<2.0"
|
||||||
[package.extras]
|
[package.extras]
|
||||||
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest-asyncio"
|
||||||
|
version = "0.21.1"
|
||||||
|
description = "Pytest support for asyncio"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "pytest-asyncio-0.21.1.tar.gz", hash = "sha256:40a7eae6dded22c7b604986855ea48400ab15b069ae38116e8c01238e9eeb64d"},
|
||||||
|
{file = "pytest_asyncio-0.21.1-py3-none-any.whl", hash = "sha256:8666c1c8ac02631d7c51ba282e0c69a8a452b211ffedf2599099845da5c5c37b"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pytest = ">=7.0.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"]
|
||||||
|
testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-dotenv"
|
name = "python-dotenv"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -2075,4 +2093,5 @@ multidict = ">=4.0"
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.11"
|
python-versions = "^3.11"
|
||||||
|
|
||||||
content-hash = "ade2df30f7b3d75ae8e8d70003c167ceb00b57ccbce17dcff7c971186106aef5"
|
content-hash = "ade2df30f7b3d75ae8e8d70003c167ceb00b57ccbce17dcff7c971186106aef5"
|
||||||
|
|
|
@ -26,11 +26,14 @@ dill = "^0.3.7"
|
||||||
fastapi = "0.103.1"
|
fastapi = "0.103.1"
|
||||||
greenlet = "^2.0.2"
|
greenlet = "^2.0.2"
|
||||||
httpx = "^0.25.0"
|
httpx = "^0.25.0"
|
||||||
|
multidict = "^6.0.4"
|
||||||
openai = "^0.28.1"
|
openai = "^0.28.1"
|
||||||
orjson = "3.9.7"
|
orjson = "3.9.7"
|
||||||
psycopg2-binary = "^2.9.9"
|
psycopg2-binary = "^2.9.9"
|
||||||
pydantic = {extras = ["email"], version = "^2.3.0"}
|
pydantic = {extras = ["email"], version = "^2.3.0"}
|
||||||
pydantic-settings = "^2.0.3"
|
pydantic-settings = "^2.0.3"
|
||||||
|
pytest = "^7.4.2"
|
||||||
|
pytest-asyncio = "^0.21.1"
|
||||||
python = "^3.11"
|
python = "^3.11"
|
||||||
python-jose = "^3.3.0"
|
python-jose = "^3.3.0"
|
||||||
python-magic = "^0.4.27"
|
python-magic = "^0.4.27"
|
||||||
|
@ -91,6 +94,7 @@ variable-rgx = "^_{0,2}[a-z][a-z0-9_]*$"
|
||||||
|
|
||||||
[tool.pyright]
|
[tool.pyright]
|
||||||
exclude = [
|
exclude = [
|
||||||
|
".pytest_cache",
|
||||||
".venv"
|
".venv"
|
||||||
]
|
]
|
||||||
pythonPlatform = "All"
|
pythonPlatform = "All"
|
||||||
|
|
70
src/assistant/tests/conftest.py
Normal file
70
src/assistant/tests/conftest.py
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import asyncio
|
||||||
|
import typing
|
||||||
|
|
||||||
|
import fastapi
|
||||||
|
import httpx
|
||||||
|
import pytest_asyncio
|
||||||
|
|
||||||
|
import lib.app as lib_app
|
||||||
|
import tests.core.settings as tests_core_settings
|
||||||
|
import tests.functional.models as functional_models
|
||||||
|
|
||||||
|
|
||||||
|
@pytest_asyncio.fixture # type: ignore[reportUntypedFunctionDecorator]
|
||||||
|
async def http_client(
|
||||||
|
base_url: str = tests_core_settings.tests_settings.api.get_api_url,
|
||||||
|
) -> typing.AsyncGenerator[httpx.AsyncClient, typing.Any]:
|
||||||
|
session = httpx.AsyncClient(base_url=base_url)
|
||||||
|
yield session
|
||||||
|
await session.aclose()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest_asyncio.fixture # type: ignore[reportUntypedFunctionDecorator]
|
||||||
|
async def make_request(http_client: httpx.AsyncClient):
|
||||||
|
async def inner(
|
||||||
|
api_method: str = "",
|
||||||
|
method: functional_models.MethodsEnum = functional_models.MethodsEnum.GET,
|
||||||
|
headers: dict[str, str] = tests_core_settings.tests_settings.api.headers,
|
||||||
|
body: dict[str, typing.Any] | None = None,
|
||||||
|
jwt_token: str | None = None,
|
||||||
|
) -> functional_models.HTTPResponse:
|
||||||
|
if jwt_token is not None:
|
||||||
|
headers["Authorization"] = f"Bearer {jwt_token}"
|
||||||
|
|
||||||
|
client_params = {"json": body, "headers": headers}
|
||||||
|
if method == functional_models.MethodsEnum.GET:
|
||||||
|
del client_params["json"]
|
||||||
|
|
||||||
|
response = await getattr(http_client, method.value)(api_method, **client_params)
|
||||||
|
return functional_models.HTTPResponse(
|
||||||
|
body=response.json(),
|
||||||
|
headers=response.headers,
|
||||||
|
status_code=response.status_code,
|
||||||
|
)
|
||||||
|
|
||||||
|
return inner
|
||||||
|
|
||||||
|
|
||||||
|
@pytest_asyncio.fixture(scope="session") # type: ignore[reportUntypedFunctionDecorator]
|
||||||
|
def app() -> fastapi.FastAPI:
|
||||||
|
settings = lib_app.Settings()
|
||||||
|
application = lib_app.Application.from_settings(settings)
|
||||||
|
fastapi_app = application._fastapi_app # type: ignore[reportPrivateUsage]
|
||||||
|
return fastapi_app
|
||||||
|
|
||||||
|
|
||||||
|
@pytest_asyncio.fixture # type: ignore[reportUntypedFunctionDecorator]
|
||||||
|
async def app_http_client(
|
||||||
|
app: fastapi.FastAPI,
|
||||||
|
base_url: str = tests_core_settings.tests_settings.api.get_api_url,
|
||||||
|
) -> typing.AsyncGenerator[httpx.AsyncClient, typing.Any]:
|
||||||
|
session = httpx.AsyncClient(app=app, base_url=base_url)
|
||||||
|
yield session
|
||||||
|
await session.aclose()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest_asyncio.fixture(scope="session") # type: ignore[reportUntypedFunctionDecorator]
|
||||||
|
def event_loop():
|
||||||
|
loop = asyncio.get_event_loop_policy().new_event_loop()
|
||||||
|
yield loop
|
||||||
|
loop.close()
|
5
src/assistant/tests/core/__init__.py
Normal file
5
src/assistant/tests/core/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from .settings import *
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"tests_settings",
|
||||||
|
]
|
17
src/assistant/tests/core/settings.py
Normal file
17
src/assistant/tests/core/settings.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import pydantic
|
||||||
|
import pydantic_settings
|
||||||
|
|
||||||
|
import tests.core.split_settings as app_split_settings
|
||||||
|
|
||||||
|
|
||||||
|
class TestsSettings(pydantic_settings.BaseSettings):
|
||||||
|
api: app_split_settings.ApiSettings = pydantic.Field(default_factory=lambda: app_split_settings.ApiSettings())
|
||||||
|
postgres: app_split_settings.PostgresSettings = pydantic.Field(
|
||||||
|
default_factory=lambda: app_split_settings.PostgresSettings()
|
||||||
|
)
|
||||||
|
project: app_split_settings.ProjectSettings = pydantic.Field(
|
||||||
|
default_factory=lambda: app_split_settings.ProjectSettings()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
tests_settings = TestsSettings()
|
9
src/assistant/tests/core/split_settings/__init__.py
Normal file
9
src/assistant/tests/core/split_settings/__init__.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
from .api import *
|
||||||
|
from .postgres import *
|
||||||
|
from .project import *
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"ApiSettings",
|
||||||
|
"PostgresSettings",
|
||||||
|
"ProjectSettings",
|
||||||
|
]
|
23
src/assistant/tests/core/split_settings/api.py
Normal file
23
src/assistant/tests/core/split_settings/api.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import pydantic
|
||||||
|
import pydantic_settings
|
||||||
|
|
||||||
|
import lib.app.split_settings.utils as app_split_settings_utils
|
||||||
|
|
||||||
|
|
||||||
|
class ApiSettings(pydantic_settings.BaseSettings):
|
||||||
|
model_config = pydantic_settings.SettingsConfigDict(
|
||||||
|
env_file=app_split_settings_utils.ENV_PATH,
|
||||||
|
env_prefix="TEST_API_",
|
||||||
|
env_file_encoding="utf-8",
|
||||||
|
extra="ignore",
|
||||||
|
)
|
||||||
|
|
||||||
|
protocol: str = "http"
|
||||||
|
host: str = "0.0.0.0"
|
||||||
|
port: int = 8000
|
||||||
|
headers: dict[str, str] = {"Content-Type": "application/json"}
|
||||||
|
|
||||||
|
@pydantic.computed_field
|
||||||
|
@property
|
||||||
|
def get_api_url(self) -> str:
|
||||||
|
return f"{self.protocol}://{self.host}:{self.port}/api/v1"
|
42
src/assistant/tests/core/split_settings/postgres.py
Normal file
42
src/assistant/tests/core/split_settings/postgres.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import pydantic
|
||||||
|
import pydantic_settings
|
||||||
|
|
||||||
|
import lib.app.split_settings.utils as app_split_settings_utils
|
||||||
|
|
||||||
|
|
||||||
|
class PostgresSettings(pydantic_settings.BaseSettings):
|
||||||
|
model_config = pydantic_settings.SettingsConfigDict(
|
||||||
|
env_file=app_split_settings_utils.ENV_PATH,
|
||||||
|
env_prefix="POSTGRES_",
|
||||||
|
env_file_encoding="utf-8",
|
||||||
|
extra="ignore",
|
||||||
|
)
|
||||||
|
|
||||||
|
name: str = "test_database_name"
|
||||||
|
host: str = "localhost"
|
||||||
|
port: int = 5432
|
||||||
|
user: str = "app"
|
||||||
|
password: pydantic.SecretStr = pydantic.Field(
|
||||||
|
default=...,
|
||||||
|
validation_alias=pydantic.AliasChoices("password", "postgres_password"),
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def db_uri_async(self) -> str:
|
||||||
|
db_uri: str = "postgresql+asyncpg://{pg_user}:{pg_pass}@{pg_host}/{pg_dbname}".format(
|
||||||
|
pg_user=self.user,
|
||||||
|
pg_pass=self.password.get_secret_value(),
|
||||||
|
pg_host=self.host,
|
||||||
|
pg_dbname=self.name,
|
||||||
|
)
|
||||||
|
return db_uri
|
||||||
|
|
||||||
|
@property
|
||||||
|
def db_uri_sync(self) -> str:
|
||||||
|
db_uri: str = "postgresql://{pg_user}:{pg_pass}@{pg_host}/{pg_dbname}".format(
|
||||||
|
pg_user=self.user,
|
||||||
|
pg_pass=self.password.get_secret_value(),
|
||||||
|
pg_host=self.host,
|
||||||
|
pg_dbname=self.name,
|
||||||
|
)
|
||||||
|
return db_uri
|
15
src/assistant/tests/core/split_settings/project.py
Normal file
15
src/assistant/tests/core/split_settings/project.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import pydantic
|
||||||
|
import pydantic_settings
|
||||||
|
|
||||||
|
import lib.app.split_settings.utils as app_split_settings_utils
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectSettings(pydantic_settings.BaseSettings):
|
||||||
|
model_config = pydantic_settings.SettingsConfigDict(
|
||||||
|
env_file=app_split_settings_utils.ENV_PATH,
|
||||||
|
env_file_encoding="utf-8",
|
||||||
|
extra="ignore",
|
||||||
|
)
|
||||||
|
|
||||||
|
debug: bool = False
|
||||||
|
jwt_secret_key: pydantic.SecretStr = pydantic.Field(default=..., validation_alias="jwt_secret_key")
|
4
src/assistant/tests/core/split_settings/utils.py
Normal file
4
src/assistant/tests/core/split_settings/utils.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
BASE_PATH = pathlib.Path(__file__).parent.parent.parent.parent.parent.resolve()
|
||||||
|
ENV_PATH = BASE_PATH / ".env"
|
0
src/assistant/tests/functional/__init__.py
Normal file
0
src/assistant/tests/functional/__init__.py
Normal file
7
src/assistant/tests/functional/models/__init__.py
Normal file
7
src/assistant/tests/functional/models/__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from .http import *
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"HTTPResponse",
|
||||||
|
"MakeResponseCallableType",
|
||||||
|
"MethodsEnum",
|
||||||
|
]
|
35
src/assistant/tests/functional/models/http.py
Normal file
35
src/assistant/tests/functional/models/http.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import dataclasses
|
||||||
|
import enum
|
||||||
|
import typing
|
||||||
|
|
||||||
|
import multidict
|
||||||
|
|
||||||
|
import tests.core.settings as functional_settings
|
||||||
|
|
||||||
|
|
||||||
|
class MethodsEnum(enum.Enum):
|
||||||
|
GET = "get"
|
||||||
|
POST = "post"
|
||||||
|
PUT = "put"
|
||||||
|
DELETE = "delete"
|
||||||
|
PATCH = "patch"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class HTTPResponse:
|
||||||
|
body: dict[str, typing.Any] | str
|
||||||
|
headers: multidict.CIMultiDictProxy[str]
|
||||||
|
status_code: int
|
||||||
|
|
||||||
|
|
||||||
|
class MakeResponseCallableType(typing.Protocol):
|
||||||
|
async def __call__(
|
||||||
|
self,
|
||||||
|
api_method: str = "",
|
||||||
|
url: str = functional_settings.tests_settings.api.get_api_url,
|
||||||
|
method: MethodsEnum = MethodsEnum.GET,
|
||||||
|
headers: dict[str, str] = functional_settings.tests_settings.api.headers,
|
||||||
|
body: dict[str, typing.Any] | None = None,
|
||||||
|
jwt_token: str | None = None,
|
||||||
|
) -> HTTPResponse:
|
||||||
|
...
|
0
src/assistant/tests/functional/src/__init__.py
Normal file
0
src/assistant/tests/functional/src/__init__.py
Normal file
17
src/assistant/tests/functional/src/test_health.py
Normal file
17
src/assistant/tests/functional/src/test_health.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# import http
|
||||||
|
|
||||||
|
# import pytest
|
||||||
|
|
||||||
|
# import tests.functional.models as tests_functional_models
|
||||||
|
|
||||||
|
# pytestmark = [pytest.mark.asyncio]
|
||||||
|
|
||||||
|
|
||||||
|
# async def test_health(
|
||||||
|
# make_request: tests_functional_models.MakeResponseCallableType,
|
||||||
|
# ):
|
||||||
|
# response = await make_request(
|
||||||
|
# method=tests_functional_models.MethodsEnum.GET,
|
||||||
|
# api_method=f"/health/",
|
||||||
|
# )
|
||||||
|
# assert response.status_code == http.HTTPStatus.OK
|
0
src/assistant/tests/functional/testdata/__init__.py
vendored
Normal file
0
src/assistant/tests/functional/testdata/__init__.py
vendored
Normal file
3
src/assistant/tests/pytest.ini
Normal file
3
src/assistant/tests/pytest.ini
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[pytest]
|
||||||
|
log_format = %(asctime)s %(levelname)s %(message)s
|
||||||
|
log_date_format = %Y-%m-%d %H:%M:%S
|
0
src/assistant/tests/unit/__init__.py
Normal file
0
src/assistant/tests/unit/__init__.py
Normal file
0
src/assistant/tests/unit/src/__init__.py
Normal file
0
src/assistant/tests/unit/src/__init__.py
Normal file
11
src/assistant/tests/unit/src/test_health.py
Normal file
11
src/assistant/tests/unit/src/test_health.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import http
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
pytestmark = [pytest.mark.asyncio]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_health(app_http_client: httpx.AsyncClient) -> None:
|
||||||
|
response = await app_http_client.get("/health/")
|
||||||
|
assert response.status_code == http.HTTPStatus.OK
|
|
@ -9,6 +9,10 @@ NGINX_PORT=80
|
||||||
API_HOST=0.0.0.0
|
API_HOST=0.0.0.0
|
||||||
API_PORT=8000
|
API_PORT=8000
|
||||||
|
|
||||||
|
TEST_API_PROTOCOL=http
|
||||||
|
TEST_API_HOST=api
|
||||||
|
TEST_API_PORT=8000
|
||||||
|
|
||||||
JWT_SECRET_KEY=v9LctjUWwol4XbvczPiLFMDtZ8aal7mm
|
JWT_SECRET_KEY=v9LctjUWwol4XbvczPiLFMDtZ8aal7mm
|
||||||
JWT_ALGORITHM=HS256
|
JWT_ALGORITHM=HS256
|
||||||
|
|
||||||
|
|
18
src/template/Dockerfile.tests
Normal file
18
src/template/Dockerfile.tests
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
FROM python:3.11
|
||||||
|
|
||||||
|
RUN apt-get update
|
||||||
|
|
||||||
|
WORKDIR /opt/app
|
||||||
|
|
||||||
|
COPY pyproject.toml ./
|
||||||
|
COPY poetry.lock ./
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& pip install poetry \
|
||||||
|
&& poetry config virtualenvs.create false \
|
||||||
|
&& poetry install --no-dev
|
||||||
|
|
||||||
|
COPY tests tests
|
||||||
|
COPY lib lib
|
||||||
|
|
||||||
|
CMD ["pytest"]
|
|
@ -1,3 +1,14 @@
|
||||||
include ../../common_makefile.mk
|
include ../../common_makefile.mk
|
||||||
|
|
||||||
PROJECT_FOLDERS = bin lib tests
|
PROJECT_FOLDERS = bin lib tests
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
@echo 'Running tests...'
|
||||||
|
@$(PYTHON) -m pytest tests/unit
|
||||||
|
|
||||||
|
.PHONY: ci-test
|
||||||
|
ci-test:
|
||||||
|
@echo 'Running tests...'
|
||||||
|
@$(PYTHON) -m pytest tests/unit
|
||||||
|
|
56
src/template/docker-compose.tests.yml
Normal file
56
src/template/docker-compose.tests.yml
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:15.2
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
POSTGRES_DB: ${POSTGRES_NAME}
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
expose:
|
||||||
|
- "${POSTGRES_PORT}"
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data/
|
||||||
|
networks:
|
||||||
|
- backend_network
|
||||||
|
|
||||||
|
api:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
container_name: api
|
||||||
|
image: fastapi_app
|
||||||
|
restart: always
|
||||||
|
entrypoint: ["/opt/app/entrypoint.sh"]
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
expose:
|
||||||
|
- "${API_PORT}"
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
networks:
|
||||||
|
- backend_network
|
||||||
|
- api_network
|
||||||
|
|
||||||
|
tests:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: "Dockerfile.tests"
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
- api
|
||||||
|
networks:
|
||||||
|
- api_network
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
api_network:
|
||||||
|
driver: bridge
|
||||||
|
backend_network:
|
||||||
|
driver: bridge
|
197
src/template/poetry.lock
generated
197
src/template/poetry.lock
generated
|
@ -1,4 +1,4 @@
|
||||||
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alembic"
|
name = "alembic"
|
||||||
|
@ -296,7 +296,6 @@ files = [
|
||||||
{file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"},
|
{file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"},
|
||||||
{file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"},
|
{file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"},
|
||||||
{file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"},
|
{file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"},
|
||||||
{file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d967650d3f56af314b72df7089d96cda1083a7fc2da05b375d2bc48c82ab3f3c"},
|
|
||||||
{file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"},
|
{file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"},
|
||||||
{file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"},
|
{file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"},
|
||||||
{file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"},
|
{file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"},
|
||||||
|
@ -305,7 +304,6 @@ files = [
|
||||||
{file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"},
|
{file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"},
|
||||||
{file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"},
|
{file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"},
|
||||||
{file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"},
|
{file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"},
|
||||||
{file = "greenlet-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d4606a527e30548153be1a9f155f4e283d109ffba663a15856089fb55f933e47"},
|
|
||||||
{file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"},
|
{file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"},
|
||||||
{file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"},
|
{file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"},
|
||||||
{file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"},
|
{file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"},
|
||||||
|
@ -335,7 +333,6 @@ files = [
|
||||||
{file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"},
|
{file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"},
|
||||||
{file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"},
|
{file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"},
|
||||||
{file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"},
|
{file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"},
|
||||||
{file = "greenlet-2.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1087300cf9700bbf455b1b97e24db18f2f77b55302a68272c56209d5587c12d1"},
|
|
||||||
{file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"},
|
{file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"},
|
||||||
{file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"},
|
{file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"},
|
||||||
{file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"},
|
{file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"},
|
||||||
|
@ -344,7 +341,6 @@ files = [
|
||||||
{file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"},
|
{file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"},
|
||||||
{file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"},
|
{file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"},
|
||||||
{file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"},
|
{file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"},
|
||||||
{file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8512a0c38cfd4e66a858ddd1b17705587900dd760c6003998e9472b77b56d417"},
|
|
||||||
{file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"},
|
{file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"},
|
||||||
{file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"},
|
{file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"},
|
||||||
{file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"},
|
{file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"},
|
||||||
|
@ -589,6 +585,89 @@ files = [
|
||||||
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
|
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multidict"
|
||||||
|
version = "6.0.4"
|
||||||
|
description = "multidict implementation"
|
||||||
|
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"},
|
||||||
|
{file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"},
|
||||||
|
{file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"},
|
||||||
|
{file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"},
|
||||||
|
{file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"},
|
||||||
|
{file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"},
|
||||||
|
{file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"},
|
||||||
|
{file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"},
|
||||||
|
{file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"},
|
||||||
|
{file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"},
|
||||||
|
{file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"},
|
||||||
|
{file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"},
|
||||||
|
{file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"},
|
||||||
|
{file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"},
|
||||||
|
{file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"},
|
||||||
|
{file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"},
|
||||||
|
{file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"},
|
||||||
|
{file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"},
|
||||||
|
{file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"},
|
||||||
|
{file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"},
|
||||||
|
{file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"},
|
||||||
|
{file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"},
|
||||||
|
{file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"},
|
||||||
|
{file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"},
|
||||||
|
{file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"},
|
||||||
|
{file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"},
|
||||||
|
{file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"},
|
||||||
|
{file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"},
|
||||||
|
{file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"},
|
||||||
|
{file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"},
|
||||||
|
{file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"},
|
||||||
|
{file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"},
|
||||||
|
{file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"},
|
||||||
|
{file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"},
|
||||||
|
{file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"},
|
||||||
|
{file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"},
|
||||||
|
{file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"},
|
||||||
|
{file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"},
|
||||||
|
{file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"},
|
||||||
|
{file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"},
|
||||||
|
{file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"},
|
||||||
|
{file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"},
|
||||||
|
{file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"},
|
||||||
|
{file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"},
|
||||||
|
{file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"},
|
||||||
|
{file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"},
|
||||||
|
{file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"},
|
||||||
|
{file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"},
|
||||||
|
{file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"},
|
||||||
|
{file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"},
|
||||||
|
{file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"},
|
||||||
|
{file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"},
|
||||||
|
{file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"},
|
||||||
|
{file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"},
|
||||||
|
{file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"},
|
||||||
|
{file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"},
|
||||||
|
{file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"},
|
||||||
|
{file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"},
|
||||||
|
{file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"},
|
||||||
|
{file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"},
|
||||||
|
{file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"},
|
||||||
|
{file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"},
|
||||||
|
{file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"},
|
||||||
|
{file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"},
|
||||||
|
{file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"},
|
||||||
|
{file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"},
|
||||||
|
{file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"},
|
||||||
|
{file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"},
|
||||||
|
{file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"},
|
||||||
|
{file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"},
|
||||||
|
{file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"},
|
||||||
|
{file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mypy-extensions"
|
name = "mypy-extensions"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -736,23 +815,81 @@ dev = ["pre-commit", "tox"]
|
||||||
testing = ["pytest", "pytest-benchmark"]
|
testing = ["pytest", "pytest-benchmark"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "psycopg2"
|
name = "psycopg2-binary"
|
||||||
version = "2.9.7"
|
version = "2.9.9"
|
||||||
description = "psycopg2 - Python-PostgreSQL Database Adapter"
|
description = "psycopg2 - Python-PostgreSQL Database Adapter"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "psycopg2-2.9.7-cp310-cp310-win32.whl", hash = "sha256:1a6a2d609bce44f78af4556bea0c62a5e7f05c23e5ea9c599e07678995609084"},
|
{file = "psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c"},
|
||||||
{file = "psycopg2-2.9.7-cp310-cp310-win_amd64.whl", hash = "sha256:b22ed9c66da2589a664e0f1ca2465c29b75aaab36fa209d4fb916025fb9119e5"},
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202"},
|
||||||
{file = "psycopg2-2.9.7-cp311-cp311-win32.whl", hash = "sha256:44d93a0109dfdf22fe399b419bcd7fa589d86895d3931b01fb321d74dadc68f1"},
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7"},
|
||||||
{file = "psycopg2-2.9.7-cp311-cp311-win_amd64.whl", hash = "sha256:91e81a8333a0037babfc9fe6d11e997a9d4dac0f38c43074886b0d9dead94fe9"},
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b"},
|
||||||
{file = "psycopg2-2.9.7-cp37-cp37m-win32.whl", hash = "sha256:d1210fcf99aae6f728812d1d2240afc1dc44b9e6cba526a06fb8134f969957c2"},
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9"},
|
||||||
{file = "psycopg2-2.9.7-cp37-cp37m-win_amd64.whl", hash = "sha256:e9b04cbef584310a1ac0f0d55bb623ca3244c87c51187645432e342de9ae81a8"},
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84"},
|
||||||
{file = "psycopg2-2.9.7-cp38-cp38-win32.whl", hash = "sha256:d5c5297e2fbc8068d4255f1e606bfc9291f06f91ec31b2a0d4c536210ac5c0a2"},
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e"},
|
||||||
{file = "psycopg2-2.9.7-cp38-cp38-win_amd64.whl", hash = "sha256:8275abf628c6dc7ec834ea63f6f3846bf33518907a2b9b693d41fd063767a866"},
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98"},
|
||||||
{file = "psycopg2-2.9.7-cp39-cp39-win32.whl", hash = "sha256:c7949770cafbd2f12cecc97dea410c514368908a103acf519f2a346134caa4d5"},
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245"},
|
||||||
{file = "psycopg2-2.9.7-cp39-cp39-win_amd64.whl", hash = "sha256:b6bd7d9d3a7a63faae6edf365f0ed0e9b0a1aaf1da3ca146e6b043fb3eb5d723"},
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e"},
|
||||||
{file = "psycopg2-2.9.7.tar.gz", hash = "sha256:f00cc35bd7119f1fed17b85bd1007855194dde2cbd8de01ab8ebb17487440ad8"},
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-win32.whl", hash = "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp38-cp38-win32.whl", hash = "sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp39-cp39-win32.whl", hash = "sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1024,6 +1161,24 @@ pluggy = ">=0.12,<2.0"
|
||||||
[package.extras]
|
[package.extras]
|
||||||
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest-asyncio"
|
||||||
|
version = "0.21.1"
|
||||||
|
description = "Pytest support for asyncio"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "pytest-asyncio-0.21.1.tar.gz", hash = "sha256:40a7eae6dded22c7b604986855ea48400ab15b069ae38116e8c01238e9eeb64d"},
|
||||||
|
{file = "pytest_asyncio-0.21.1-py3-none-any.whl", hash = "sha256:8666c1c8ac02631d7c51ba282e0c69a8a452b211ffedf2599099845da5c5c37b"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pytest = ">=7.0.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"]
|
||||||
|
testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-dotenv"
|
name = "python-dotenv"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -1216,7 +1371,7 @@ files = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[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\""}
|
greenlet = {version = "!=0.4.17", markers = "platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\""}
|
||||||
typing-extensions = ">=4.2.0"
|
typing-extensions = ">=4.2.0"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
|
@ -1412,4 +1567,4 @@ files = [
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.11"
|
python-versions = "^3.11"
|
||||||
content-hash = "a1f51871ee88f7c8503f57105be988ea4ece9f41671d11a4464c382057acf3e7"
|
content-hash = "7f329541481928598b0dac2189439929e2e67949e9b67e3bca006dcefb79241c"
|
||||||
|
|
|
@ -25,10 +25,12 @@ asyncpg = "^0.28.0"
|
||||||
fastapi = "0.103.1"
|
fastapi = "0.103.1"
|
||||||
greenlet = "^2.0.2"
|
greenlet = "^2.0.2"
|
||||||
httpx = "^0.25.0"
|
httpx = "^0.25.0"
|
||||||
|
multidict = "^6.0.4"
|
||||||
orjson = "^3.9.7"
|
orjson = "^3.9.7"
|
||||||
psycopg2 = "^2.9.7"
|
psycopg2-binary = "^2.9.9"
|
||||||
pydantic = {extras = ["email"], version = "^2.3.0"}
|
pydantic = {extras = ["email"], version = "^2.3.0"}
|
||||||
pydantic-settings = "^2.0.3"
|
pydantic-settings = "^2.0.3"
|
||||||
|
pytest-asyncio = "^0.21.1"
|
||||||
python = "^3.11"
|
python = "^3.11"
|
||||||
python-jose = "^3.3.0"
|
python-jose = "^3.3.0"
|
||||||
sqlalchemy = "^2.0.20"
|
sqlalchemy = "^2.0.20"
|
||||||
|
@ -86,6 +88,7 @@ variable-rgx = "^_{0,2}[a-z][a-z0-9_]*$"
|
||||||
|
|
||||||
[tool.pyright]
|
[tool.pyright]
|
||||||
exclude = [
|
exclude = [
|
||||||
|
".pytest_cache",
|
||||||
".venv"
|
".venv"
|
||||||
]
|
]
|
||||||
pythonPlatform = "All"
|
pythonPlatform = "All"
|
||||||
|
|
70
src/template/tests/conftest.py
Normal file
70
src/template/tests/conftest.py
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import asyncio
|
||||||
|
import typing
|
||||||
|
|
||||||
|
import fastapi
|
||||||
|
import httpx
|
||||||
|
import pytest_asyncio
|
||||||
|
|
||||||
|
import lib.app as lib_app
|
||||||
|
import tests.core.settings as tests_core_settings
|
||||||
|
import tests.functional.models as functional_models
|
||||||
|
|
||||||
|
|
||||||
|
@pytest_asyncio.fixture # type: ignore[reportUntypedFunctionDecorator]
|
||||||
|
async def http_client(
|
||||||
|
base_url: str = tests_core_settings.tests_settings.api.get_api_url,
|
||||||
|
) -> typing.AsyncGenerator[httpx.AsyncClient, typing.Any]:
|
||||||
|
session = httpx.AsyncClient(base_url=base_url)
|
||||||
|
yield session
|
||||||
|
await session.aclose()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest_asyncio.fixture # type: ignore[reportUntypedFunctionDecorator]
|
||||||
|
async def make_request(http_client: httpx.AsyncClient):
|
||||||
|
async def inner(
|
||||||
|
api_method: str = "",
|
||||||
|
method: functional_models.MethodsEnum = functional_models.MethodsEnum.GET,
|
||||||
|
headers: dict[str, str] = tests_core_settings.tests_settings.api.headers,
|
||||||
|
body: dict[str, typing.Any] | None = None,
|
||||||
|
jwt_token: str | None = None,
|
||||||
|
) -> functional_models.HTTPResponse:
|
||||||
|
if jwt_token is not None:
|
||||||
|
headers["Authorization"] = f"Bearer {jwt_token}"
|
||||||
|
|
||||||
|
client_params = {"json": body, "headers": headers}
|
||||||
|
if method == functional_models.MethodsEnum.GET:
|
||||||
|
del client_params["json"]
|
||||||
|
|
||||||
|
response = await getattr(http_client, method.value)(api_method, **client_params)
|
||||||
|
return functional_models.HTTPResponse(
|
||||||
|
body=response.json(),
|
||||||
|
headers=response.headers,
|
||||||
|
status_code=response.status_code,
|
||||||
|
)
|
||||||
|
|
||||||
|
return inner
|
||||||
|
|
||||||
|
|
||||||
|
@pytest_asyncio.fixture(scope="session") # type: ignore[reportUntypedFunctionDecorator]
|
||||||
|
def app() -> fastapi.FastAPI:
|
||||||
|
settings = lib_app.Settings()
|
||||||
|
application = lib_app.Application.from_settings(settings)
|
||||||
|
fastapi_app = application._fastapi_app # type: ignore[reportPrivateUsage]
|
||||||
|
return fastapi_app
|
||||||
|
|
||||||
|
|
||||||
|
@pytest_asyncio.fixture # type: ignore[reportUntypedFunctionDecorator]
|
||||||
|
async def app_http_client(
|
||||||
|
app: fastapi.FastAPI,
|
||||||
|
base_url: str = tests_core_settings.tests_settings.api.get_api_url,
|
||||||
|
) -> typing.AsyncGenerator[httpx.AsyncClient, typing.Any]:
|
||||||
|
session = httpx.AsyncClient(app=app, base_url=base_url)
|
||||||
|
yield session
|
||||||
|
await session.aclose()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest_asyncio.fixture(scope="session") # type: ignore[reportUntypedFunctionDecorator]
|
||||||
|
def event_loop():
|
||||||
|
loop = asyncio.get_event_loop_policy().new_event_loop()
|
||||||
|
yield loop
|
||||||
|
loop.close()
|
5
src/template/tests/core/__init__.py
Normal file
5
src/template/tests/core/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from .settings import *
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"tests_settings",
|
||||||
|
]
|
17
src/template/tests/core/settings.py
Normal file
17
src/template/tests/core/settings.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import pydantic
|
||||||
|
import pydantic_settings
|
||||||
|
|
||||||
|
import tests.core.split_settings as app_split_settings
|
||||||
|
|
||||||
|
|
||||||
|
class TestsSettings(pydantic_settings.BaseSettings):
|
||||||
|
api: app_split_settings.ApiSettings = pydantic.Field(default_factory=lambda: app_split_settings.ApiSettings())
|
||||||
|
postgres: app_split_settings.PostgresSettings = pydantic.Field(
|
||||||
|
default_factory=lambda: app_split_settings.PostgresSettings()
|
||||||
|
)
|
||||||
|
project: app_split_settings.ProjectSettings = pydantic.Field(
|
||||||
|
default_factory=lambda: app_split_settings.ProjectSettings()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
tests_settings = TestsSettings()
|
9
src/template/tests/core/split_settings/__init__.py
Normal file
9
src/template/tests/core/split_settings/__init__.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
from .api import *
|
||||||
|
from .postgres import *
|
||||||
|
from .project import *
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"ApiSettings",
|
||||||
|
"PostgresSettings",
|
||||||
|
"ProjectSettings",
|
||||||
|
]
|
23
src/template/tests/core/split_settings/api.py
Normal file
23
src/template/tests/core/split_settings/api.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import pydantic
|
||||||
|
import pydantic_settings
|
||||||
|
|
||||||
|
import lib.app.split_settings.utils as app_split_settings_utils
|
||||||
|
|
||||||
|
|
||||||
|
class ApiSettings(pydantic_settings.BaseSettings):
|
||||||
|
model_config = pydantic_settings.SettingsConfigDict(
|
||||||
|
env_file=app_split_settings_utils.ENV_PATH,
|
||||||
|
env_prefix="TEST_API_",
|
||||||
|
env_file_encoding="utf-8",
|
||||||
|
extra="ignore",
|
||||||
|
)
|
||||||
|
|
||||||
|
protocol: str = "http"
|
||||||
|
host: str = "0.0.0.0"
|
||||||
|
port: int = 8000
|
||||||
|
headers: dict[str, str] = {"Content-Type": "application/json"}
|
||||||
|
|
||||||
|
@pydantic.computed_field
|
||||||
|
@property
|
||||||
|
def get_api_url(self) -> str:
|
||||||
|
return f"{self.protocol}://{self.host}:{self.port}/api/v1"
|
42
src/template/tests/core/split_settings/postgres.py
Normal file
42
src/template/tests/core/split_settings/postgres.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import pydantic
|
||||||
|
import pydantic_settings
|
||||||
|
|
||||||
|
import lib.app.split_settings.utils as app_split_settings_utils
|
||||||
|
|
||||||
|
|
||||||
|
class PostgresSettings(pydantic_settings.BaseSettings):
|
||||||
|
model_config = pydantic_settings.SettingsConfigDict(
|
||||||
|
env_file=app_split_settings_utils.ENV_PATH,
|
||||||
|
env_prefix="POSTGRES_",
|
||||||
|
env_file_encoding="utf-8",
|
||||||
|
extra="ignore",
|
||||||
|
)
|
||||||
|
|
||||||
|
name: str = "test_database_name"
|
||||||
|
host: str = "localhost"
|
||||||
|
port: int = 5432
|
||||||
|
user: str = "app"
|
||||||
|
password: pydantic.SecretStr = pydantic.Field(
|
||||||
|
default=...,
|
||||||
|
validation_alias=pydantic.AliasChoices("password", "postgres_password"),
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def db_uri_async(self) -> str:
|
||||||
|
db_uri: str = "postgresql+asyncpg://{pg_user}:{pg_pass}@{pg_host}/{pg_dbname}".format(
|
||||||
|
pg_user=self.user,
|
||||||
|
pg_pass=self.password.get_secret_value(),
|
||||||
|
pg_host=self.host,
|
||||||
|
pg_dbname=self.name,
|
||||||
|
)
|
||||||
|
return db_uri
|
||||||
|
|
||||||
|
@property
|
||||||
|
def db_uri_sync(self) -> str:
|
||||||
|
db_uri: str = "postgresql://{pg_user}:{pg_pass}@{pg_host}/{pg_dbname}".format(
|
||||||
|
pg_user=self.user,
|
||||||
|
pg_pass=self.password.get_secret_value(),
|
||||||
|
pg_host=self.host,
|
||||||
|
pg_dbname=self.name,
|
||||||
|
)
|
||||||
|
return db_uri
|
15
src/template/tests/core/split_settings/project.py
Normal file
15
src/template/tests/core/split_settings/project.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import pydantic
|
||||||
|
import pydantic_settings
|
||||||
|
|
||||||
|
import lib.app.split_settings.utils as app_split_settings_utils
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectSettings(pydantic_settings.BaseSettings):
|
||||||
|
model_config = pydantic_settings.SettingsConfigDict(
|
||||||
|
env_file=app_split_settings_utils.ENV_PATH,
|
||||||
|
env_file_encoding="utf-8",
|
||||||
|
extra="ignore",
|
||||||
|
)
|
||||||
|
|
||||||
|
debug: bool = False
|
||||||
|
jwt_secret_key: pydantic.SecretStr = pydantic.Field(default=..., validation_alias="jwt_secret_key")
|
4
src/template/tests/core/split_settings/utils.py
Normal file
4
src/template/tests/core/split_settings/utils.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
BASE_PATH = pathlib.Path(__file__).parent.parent.parent.parent.parent.resolve()
|
||||||
|
ENV_PATH = BASE_PATH / ".env"
|
0
src/template/tests/functional/__init__.py
Normal file
0
src/template/tests/functional/__init__.py
Normal file
7
src/template/tests/functional/models/__init__.py
Normal file
7
src/template/tests/functional/models/__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from .http import *
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"HTTPResponse",
|
||||||
|
"MakeResponseCallableType",
|
||||||
|
"MethodsEnum",
|
||||||
|
]
|
35
src/template/tests/functional/models/http.py
Normal file
35
src/template/tests/functional/models/http.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import dataclasses
|
||||||
|
import enum
|
||||||
|
import typing
|
||||||
|
|
||||||
|
import multidict
|
||||||
|
|
||||||
|
import tests.core.settings as functional_settings
|
||||||
|
|
||||||
|
|
||||||
|
class MethodsEnum(enum.Enum):
|
||||||
|
GET = "get"
|
||||||
|
POST = "post"
|
||||||
|
PUT = "put"
|
||||||
|
DELETE = "delete"
|
||||||
|
PATCH = "patch"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class HTTPResponse:
|
||||||
|
body: dict[str, typing.Any] | str
|
||||||
|
headers: multidict.CIMultiDictProxy[str]
|
||||||
|
status_code: int
|
||||||
|
|
||||||
|
|
||||||
|
class MakeResponseCallableType(typing.Protocol):
|
||||||
|
async def __call__(
|
||||||
|
self,
|
||||||
|
api_method: str = "",
|
||||||
|
url: str = functional_settings.tests_settings.api.get_api_url,
|
||||||
|
method: MethodsEnum = MethodsEnum.GET,
|
||||||
|
headers: dict[str, str] = functional_settings.tests_settings.api.headers,
|
||||||
|
body: dict[str, typing.Any] | None = None,
|
||||||
|
jwt_token: str | None = None,
|
||||||
|
) -> HTTPResponse:
|
||||||
|
...
|
0
src/template/tests/functional/src/__init__.py
Normal file
0
src/template/tests/functional/src/__init__.py
Normal file
17
src/template/tests/functional/src/test_health.py
Normal file
17
src/template/tests/functional/src/test_health.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import http
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import tests.functional.models as tests_functional_models
|
||||||
|
|
||||||
|
pytestmark = [pytest.mark.asyncio]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_health(
|
||||||
|
make_request: tests_functional_models.MakeResponseCallableType,
|
||||||
|
):
|
||||||
|
response = await make_request(
|
||||||
|
method=tests_functional_models.MethodsEnum.GET,
|
||||||
|
api_method=f"/health/",
|
||||||
|
)
|
||||||
|
assert response.status_code == http.HTTPStatus.OK
|
0
src/template/tests/functional/testdata/__init__.py
vendored
Normal file
0
src/template/tests/functional/testdata/__init__.py
vendored
Normal file
3
src/template/tests/pytest.ini
Normal file
3
src/template/tests/pytest.ini
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[pytest]
|
||||||
|
log_format = %(asctime)s %(levelname)s %(message)s
|
||||||
|
log_date_format = %Y-%m-%d %H:%M:%S
|
0
src/template/tests/unit/__init__.py
Normal file
0
src/template/tests/unit/__init__.py
Normal file
0
src/template/tests/unit/src/__init__.py
Normal file
0
src/template/tests/unit/src/__init__.py
Normal file
11
src/template/tests/unit/src/test_health.py
Normal file
11
src/template/tests/unit/src/test_health.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import http
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
pytestmark = [pytest.mark.asyncio]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_health(app_http_client: httpx.AsyncClient) -> None:
|
||||||
|
response = await app_http_client.get("/health/")
|
||||||
|
assert response.status_code == http.HTTPStatus.OK
|
Loading…
Reference in New Issue
Block a user