Compare commits
No commits in common. "7eefa8e5db06399d303b012c872528a7ac26246a" and "bde95810908d57e9a34701ef5f96ef9c324a540f" have entirely different histories.
7eefa8e5db
...
bde9581090
14
Dockerfile
14
Dockerfile
|
@ -1,13 +1,15 @@
|
||||||
FROM python:3.10-slim
|
FROM python:3.10-slim
|
||||||
|
|
||||||
|
RUN mkdir /fastfood
|
||||||
|
|
||||||
|
WORKDIR /fastfood
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
RUN pip install poetry
|
RUN pip install poetry
|
||||||
|
|
||||||
RUN poetry config virtualenvs.create false
|
RUN poetry config virtualenvs.create false
|
||||||
|
|
||||||
RUN mkdir -p /usr/src/fastfood
|
|
||||||
|
|
||||||
WORKDIR /usr/src/fastfood
|
|
||||||
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
RUN poetry install
|
RUN poetry install
|
||||||
|
|
||||||
|
RUN chmod a+x scripts/*.sh
|
||||||
|
|
40
README.md
40
README.md
|
@ -81,7 +81,8 @@ Fastapi веб приложение реализующее api для общеп
|
||||||
- docker-compose
|
- docker-compose
|
||||||
|
|
||||||
## Установка
|
## Установка
|
||||||
|
### Docker
|
||||||
|
Для запуска необходимы установленные приложения docker и docker-compose
|
||||||
Клонируйте репозиторий
|
Клонируйте репозиторий
|
||||||
> `$ git clone https://git.pi3c.ru/pi3c/fastfood.git`
|
> `$ git clone https://git.pi3c.ru/pi3c/fastfood.git`
|
||||||
|
|
||||||
|
@ -90,31 +91,19 @@ Fastapi веб приложение реализующее api для общеп
|
||||||
|
|
||||||
Создадим файл .env из шаблона
|
Создадим файл .env из шаблона
|
||||||
>`$ cp ./example.env ./.env`
|
>`$ cp ./example.env ./.env`
|
||||||
|
|
||||||
Если планируется запуск проекта в Docker контейнере, то `.env` можно не изменять. Если запуск будет локальным, то необходимо изменить переменные окружения, для подключения к БД postgres.
|
|
||||||
|
|
||||||
### Docker
|
|
||||||
Для запуска необходимы установленные приложения docker и docker-compose
|
|
||||||
Для теста изменять файл .env не требуется.
|
Для теста изменять файл .env не требуется.
|
||||||
Однако Вы можете изменить имя пользователя, пароль и имя базы данных по своему усмотрению.
|
Однако Вы можете изменить имя пользователя, пароль и имя базы данных по своему усмотрению. При таких изменениях, нужно будет отредактировать
|
||||||
|
файл `db_prepare.sql` в папке `scripts/`, так чтобы sql команда приняла вид:
|
||||||
|
`CREATE DATABASE <db_name>_test WITH OWNER <db_user>;`
|
||||||
|
где <db_name> и <db_user> соответвтовали POSTGRES_DB и POSTGRES_USER в файле `.env`
|
||||||
|
|
||||||
И запустите образы:
|
Создайте и запустите образы
|
||||||
|
> `$ docker-compose up -d --build`
|
||||||
- Запуск FAstAPI приложения
|
|
||||||
> `$ docker-compose -f compose_app.yml up `
|
|
||||||
|
|
||||||
По завершении работы остановите контейнеры
|
|
||||||
> `$ docker-compose -f compose_app.yml down`
|
|
||||||
|
|
||||||
После успешного запуска образов документация по API будет доступна по адресу <a href="http://localhost:8000/docs">http://localhost:8000</a>
|
После успешного запуска образов документация по API будет доступна по адресу <a href="http://localhost:8000/docs">http://localhost:8000</a>
|
||||||
|
|
||||||
|
Для запуска тестов pytest поднимаем контейнер tests
|
||||||
- Запуск тестов
|
> `$ docker-compose up tests`
|
||||||
> `$ docker-compose -f compose_test.yml up`
|
|
||||||
|
|
||||||
По завершении работы остановите контейнеры
|
|
||||||
> `$ docker-compose -f compose_test.yml down`
|
|
||||||
|
|
||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
Установите и настройте postgresql согласно офф. документации. Создайте пользователя и бд.
|
Установите и настройте postgresql согласно офф. документации. Создайте пользователя и бд.
|
||||||
|
@ -133,6 +122,14 @@ Fastapi веб приложение реализующее api для общеп
|
||||||
|
|
||||||
Создастся виртуальное окружение и установятся зависимости
|
Создастся виртуальное окружение и установятся зависимости
|
||||||
|
|
||||||
|
Файл example.env является образцом файла .env, который необходимо создать перед запуском проекта.
|
||||||
|
В нем указанны переменные необходимые для подключения к БД.
|
||||||
|
Создадим файл .env
|
||||||
|
|
||||||
|
>`$ cp ./example.env ./.env`
|
||||||
|
|
||||||
|
Далее отредактируйте .env файл в соответствии с Вашими данными подключения к БД
|
||||||
|
|
||||||
## Запуск
|
## Запуск
|
||||||
Запуск проекта возможен в 2х режимах:
|
Запуск проекта возможен в 2х режимах:
|
||||||
- Запуск в режиме "prod" с ключем --run-server
|
- Запуск в режиме "prod" с ключем --run-server
|
||||||
|
@ -157,6 +154,7 @@ Fastapi веб приложение реализующее api для общеп
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
- Написать тесты для кривых данных
|
- Написать тесты для кривых данных
|
||||||
|
- Добавить миграции
|
||||||
- Провести рефакторинг, много дублирующего кода
|
- Провести рефакторинг, много дублирующего кода
|
||||||
- Много чего другого :)
|
- Много чего другого :)
|
||||||
|
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
version: "3.8"
|
|
||||||
services:
|
|
||||||
db:
|
|
||||||
container_name: pgdb
|
|
||||||
|
|
||||||
image: postgres:15.1-alpine
|
|
||||||
|
|
||||||
env_file:
|
|
||||||
- .env
|
|
||||||
|
|
||||||
environment:
|
|
||||||
POSTGRES_DB: ${POSTGRES_DB}
|
|
||||||
POSTGRES_USER: ${POSTGRES_USER}
|
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
|
||||||
|
|
||||||
ports:
|
|
||||||
- 6432:5432
|
|
||||||
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
|
|
||||||
app:
|
|
||||||
container_name: fastfood_app
|
|
||||||
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
|
|
||||||
env_file:
|
|
||||||
- .env
|
|
||||||
|
|
||||||
ports:
|
|
||||||
- 8000:8000
|
|
||||||
|
|
||||||
depends_on:
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
|
|
||||||
restart: always
|
|
||||||
|
|
||||||
command: /bin/bash -c 'poetry run python /usr/src/fastfood/manage.py --run-test-server'
|
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
version: "3.8"
|
|
||||||
services:
|
|
||||||
db:
|
|
||||||
container_name: pgdb_test
|
|
||||||
|
|
||||||
image: postgres:15.1-alpine
|
|
||||||
|
|
||||||
env_file:
|
|
||||||
- .env
|
|
||||||
|
|
||||||
environment:
|
|
||||||
POSTGRES_DB: ${POSTGRES_DB_TEST}
|
|
||||||
POSTGRES_USER: ${POSTGRES_USER}
|
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
|
||||||
|
|
||||||
ports:
|
|
||||||
- 6432:5432
|
|
||||||
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB_TEST}"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
|
|
||||||
app:
|
|
||||||
container_name: fastfood_app_test
|
|
||||||
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
|
|
||||||
env_file:
|
|
||||||
- .env
|
|
||||||
|
|
||||||
ports:
|
|
||||||
- 8000:8000
|
|
||||||
|
|
||||||
depends_on:
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
|
|
||||||
restart: always
|
|
||||||
|
|
||||||
command: /bin/bash -c 'poetry run pytest -vv'
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
version: "3.8"
|
||||||
|
services:
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:15.1-alpine
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
container_name: pgdatabase
|
||||||
|
ports:
|
||||||
|
- 6432:5432
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
volumes:
|
||||||
|
- ./scripts/db_prepare.sql:/docker-entrypoint-initdb.d/db_prepare.sql
|
||||||
|
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
container_name: fastfood_app
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
command: ["/fastfood/scripts/migrate_and_run.sh"]
|
||||||
|
ports:
|
||||||
|
- 8000:8000
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
tests:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
container_name: tests
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
app:
|
||||||
|
condition: service_started
|
||||||
|
command: ["/fastfood/scripts/testing.sh"]
|
|
@ -1,6 +1,5 @@
|
||||||
DB_HOST=db
|
DB_HOST=db
|
||||||
DB_PORT=5432
|
DB_PORT=5432
|
||||||
POSTGRES_USER=testuser
|
POSTGRES_USER=postges
|
||||||
POSTGRES_PASSWORD=test
|
POSTGRES_PASSWORD=postgres
|
||||||
POSTGRES_DB=fastfood_db
|
POSTGRES_DB=fastfood_db
|
||||||
POSTGRES_DB_TEST=testdb
|
|
|
@ -61,7 +61,7 @@ tags_metadata = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def create_app() -> FastAPI:
|
def create_app():
|
||||||
"""
|
"""
|
||||||
Фабрика FastAPI.
|
Фабрика FastAPI.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -2,12 +2,11 @@ from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
DB_HOST: str = ""
|
DB_HOST: str = "db"
|
||||||
DB_PORT: int = 5432
|
DB_PORT: int = 5432
|
||||||
POSTGRES_DB: str = ""
|
POSTGRES_DB: str = "fastfod_db"
|
||||||
POSTGRES_PASSWORD: str = ""
|
POSTGRES_PASSWORD: str = "postgres"
|
||||||
POSTGRES_USER: str = ""
|
POSTGRES_USER: str = "postgres"
|
||||||
POSTGRES_DB_TEST: str = ""
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def DATABASE_URL_asyncpg(self):
|
def DATABASE_URL_asyncpg(self):
|
||||||
|
@ -28,7 +27,7 @@ class Settings(BaseSettings):
|
||||||
return (
|
return (
|
||||||
"postgresql+asyncpg://"
|
"postgresql+asyncpg://"
|
||||||
f"{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}"
|
f"{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}"
|
||||||
f"@{self.DB_HOST}:{self.DB_PORT}/{self.POSTGRES_DB_TEST}"
|
f"@{self.DB_HOST}:{self.DB_PORT}/{self.POSTGRES_DB}_test"
|
||||||
)
|
)
|
||||||
|
|
||||||
model_config = SettingsConfigDict(env_file=".env")
|
model_config = SettingsConfigDict(env_file=".env")
|
||||||
|
|
|
@ -1,5 +1,24 @@
|
||||||
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alembic"
|
||||||
|
version = "1.13.1"
|
||||||
|
description = "A database migration tool for SQLAlchemy."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "alembic-1.13.1-py3-none-any.whl", hash = "sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43"},
|
||||||
|
{file = "alembic-1.13.1.tar.gz", hash = "sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
Mako = "*"
|
||||||
|
SQLAlchemy = ">=1.3.0"
|
||||||
|
typing-extensions = ">=4"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
tz = ["backports.zoneinfo"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "annotated-types"
|
name = "annotated-types"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
|
@ -421,6 +440,94 @@ files = [
|
||||||
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mako"
|
||||||
|
version = "1.3.0"
|
||||||
|
description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "Mako-1.3.0-py3-none-any.whl", hash = "sha256:57d4e997349f1a92035aa25c17ace371a4213f2ca42f99bee9a602500cfd54d9"},
|
||||||
|
{file = "Mako-1.3.0.tar.gz", hash = "sha256:e3a9d388fd00e87043edbe8792f45880ac0114e9c4adc69f6e9bfb2c55e3b11b"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
MarkupSafe = ">=0.9.2"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
babel = ["Babel"]
|
||||||
|
lingua = ["lingua"]
|
||||||
|
testing = ["pytest"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "markupsafe"
|
||||||
|
version = "2.1.4"
|
||||||
|
description = "Safely add untrusted strings to HTML/XML markup."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp310-cp310-win32.whl", hash = "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp311-cp311-win32.whl", hash = "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp312-cp312-win32.whl", hash = "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp37-cp37m-win32.whl", hash = "sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp37-cp37m-win_amd64.whl", hash = "sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp38-cp38-win32.whl", hash = "sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp38-cp38-win_amd64.whl", hash = "sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp39-cp39-win32.whl", hash = "sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6"},
|
||||||
|
{file = "MarkupSafe-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959"},
|
||||||
|
{file = "MarkupSafe-2.1.4.tar.gz", hash = "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "packaging"
|
name = "packaging"
|
||||||
version = "23.2"
|
version = "23.2"
|
||||||
|
@ -447,6 +554,87 @@ files = [
|
||||||
dev = ["pre-commit", "tox"]
|
dev = ["pre-commit", "tox"]
|
||||||
testing = ["pytest", "pytest-benchmark"]
|
testing = ["pytest", "pytest-benchmark"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "psycopg2-binary"
|
||||||
|
version = "2.9.9"
|
||||||
|
description = "psycopg2 - Python-PostgreSQL Database Adapter"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e"},
|
||||||
|
{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-macosx_11_0_arm64.whl", hash = "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d"},
|
||||||
|
{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-cp312-cp312-win32.whl", hash = "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93"},
|
||||||
|
{file = "psycopg2_binary-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab"},
|
||||||
|
{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]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.5.3"
|
version = "2.5.3"
|
||||||
|
@ -829,4 +1017,4 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)",
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.10"
|
python-versions = "^3.10"
|
||||||
content-hash = "5bbc3cad36f6f40d10cb848918426b640f9e703bc2c6b22b5b8fe381a6251ded"
|
content-hash = "21d68c7a50ac5fb0af89a33a484094ea6a69f1e9a03d0f8cb5c6dc35400c760a"
|
||||||
|
|
|
@ -12,14 +12,16 @@ fastapi = "^0.109.0"
|
||||||
uvicorn = "^0.26.0"
|
uvicorn = "^0.26.0"
|
||||||
asyncpg = "^0.29.0"
|
asyncpg = "^0.29.0"
|
||||||
pydantic-settings = "^2.1.0"
|
pydantic-settings = "^2.1.0"
|
||||||
|
psycopg2-binary = "^2.9.9"
|
||||||
email-validator = "^2.1.0.post1"
|
email-validator = "^2.1.0.post1"
|
||||||
pytest-asyncio = "^0.23.3"
|
pytest-asyncio = "^0.23.3"
|
||||||
|
httpx = "^0.26.0"
|
||||||
|
pytest-cov = "^4.1.0"
|
||||||
|
alembic = "^1.13.1"
|
||||||
|
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
pytest = "^7.4.4"
|
pytest = "^7.4.4"
|
||||||
pytest-cov = "^4.1.0"
|
|
||||||
httpx = "^0.26.0"
|
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core"]
|
requires = ["poetry-core"]
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
CREATE DATABASE fastfood_db_test WITH OWNER postgres;
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Тут можно выполнить миграции или дополнительные перед запуском приложения
|
||||||
|
#
|
||||||
|
poetry run python manage.py --run-test-server
|
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/bash
|
||||||
|
poetry run pytest -vv
|
|
@ -1,18 +1,20 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from typing import AsyncGenerator, Generator
|
from typing import AsyncGenerator
|
||||||
|
from httpx import AsyncClient
|
||||||
import pytest
|
import pytest
|
||||||
import pytest_asyncio
|
import pytest_asyncio
|
||||||
from fastapi import FastAPI
|
from sqlalchemy.ext.asyncio import (
|
||||||
from httpx import AsyncClient
|
AsyncSession,
|
||||||
from sqlalchemy.ext.asyncio import (AsyncSession, async_sessionmaker,
|
async_sessionmaker,
|
||||||
create_async_engine)
|
create_async_engine,
|
||||||
|
)
|
||||||
from fastfood.app import create_app
|
from fastfood.app import create_app
|
||||||
|
|
||||||
from fastfood.config import settings
|
from fastfood.config import settings
|
||||||
from fastfood.dbase import get_async_session
|
from fastfood.dbase import get_async_session
|
||||||
from fastfood.models import Base
|
from fastfood.models import Base
|
||||||
|
|
||||||
|
|
||||||
async_engine = create_async_engine(settings.TESTDATABASE_URL_asyncpg)
|
async_engine = create_async_engine(settings.TESTDATABASE_URL_asyncpg)
|
||||||
async_session_maker = async_sessionmaker(
|
async_session_maker = async_sessionmaker(
|
||||||
async_engine,
|
async_engine,
|
||||||
|
@ -21,7 +23,7 @@ async_session_maker = async_sessionmaker(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session", autouse=True)
|
@pytest.fixture(scope="session")
|
||||||
def event_loop():
|
def event_loop():
|
||||||
try:
|
try:
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
|
@ -32,7 +34,7 @@ def event_loop():
|
||||||
|
|
||||||
|
|
||||||
@pytest_asyncio.fixture(scope="function", autouse=True)
|
@pytest_asyncio.fixture(scope="function", autouse=True)
|
||||||
async def db_init(event_loop):
|
async def db_init():
|
||||||
async with async_engine.begin() as conn:
|
async with async_engine.begin() as conn:
|
||||||
await conn.run_sync(Base.metadata.drop_all)
|
await conn.run_sync(Base.metadata.drop_all)
|
||||||
await conn.run_sync(Base.metadata.create_all)
|
await conn.run_sync(Base.metadata.create_all)
|
||||||
|
@ -47,22 +49,21 @@ async def get_test_session() -> AsyncGenerator[AsyncSession, None]:
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
def app(event_loop) -> Generator[FastAPI, None, None]:
|
def app():
|
||||||
app: FastAPI = create_app()
|
app = create_app()
|
||||||
app.dependency_overrides[get_async_session] = get_test_session
|
app.dependency_overrides[get_async_session] = get_test_session
|
||||||
yield app
|
yield app
|
||||||
|
|
||||||
|
|
||||||
@pytest_asyncio.fixture(scope="function")
|
@pytest_asyncio.fixture(scope="function")
|
||||||
async def client(app) -> AsyncGenerator[AsyncClient, None]:
|
async def client(app):
|
||||||
async with AsyncClient(
|
async with AsyncClient(
|
||||||
app=app,
|
app=app, base_url="http://localhost:8000/api/v1/menus",
|
||||||
base_url="http://localhost:8000/api/v1/menus",
|
|
||||||
) as async_client:
|
) as async_client:
|
||||||
yield async_client
|
yield async_client
|
||||||
|
|
||||||
|
|
||||||
@pytest_asyncio.fixture(scope="function")
|
@pytest_asyncio.fixture(scope="function")
|
||||||
async def asession(event_loop) -> AsyncGenerator[AsyncSession, None]:
|
async def asession() -> AsyncGenerator[AsyncSession, None]:
|
||||||
async with async_session_maker() as session:
|
async with async_session_maker() as session:
|
||||||
yield session
|
yield session
|
||||||
|
|
|
@ -1,134 +1,110 @@
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from httpx import AsyncClient, Response
|
|
||||||
|
|
||||||
|
|
||||||
class TestBaseCrud:
|
class TestBaseCrud:
|
||||||
class Menu:
|
class Menu:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def read_all(ac: AsyncClient) -> Tuple[int, dict]:
|
async def read_all(ac):
|
||||||
"""чтение всех меню"""
|
"""чтение всех меню"""
|
||||||
response: Response = await ac.get("/")
|
response = await ac.get("/")
|
||||||
return response.status_code, response.json()
|
return response.status_code, response.json()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get(ac: AsyncClient, data: dict) -> Tuple[int, dict]:
|
async def get(ac, data):
|
||||||
"""Получение меню по id"""
|
"""Получение меню по id"""
|
||||||
response: Response = await ac.get(f"/{data.get('id')}")
|
response = await ac.get(f"/{data.get('id')}")
|
||||||
return response.status_code, response.json()
|
return response.status_code, response.json()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def write(ac: AsyncClient, data: dict) -> Tuple[int, dict]:
|
async def write(ac, data):
|
||||||
"""создания меню"""
|
"""создания меню"""
|
||||||
response: Response = await ac.post("/", json=data)
|
response = await ac.post("/", json=data)
|
||||||
return response.status_code, response.json()
|
return response.status_code, response.json()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def update(ac: AsyncClient, data: dict) -> Tuple[int, dict]:
|
async def update(ac, data):
|
||||||
"""Обновление меню по id"""
|
"""Обновление меню по id"""
|
||||||
response: Response = await ac.patch(
|
response = await ac.patch(f"/{data.get('id')}", json=data)
|
||||||
f"/{data.get('id')}",
|
|
||||||
json=data,
|
|
||||||
)
|
|
||||||
return response.status_code, response.json()
|
return response.status_code, response.json()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def delete(ac: AsyncClient, data: dict) -> int:
|
async def delete(ac, data):
|
||||||
"""Удаление меню по id"""
|
"""Удаление меню по id"""
|
||||||
response: Response = await ac.delete(f"/{data.get('id')}")
|
response = await ac.delete(f"/{data.get('id')}")
|
||||||
return response.status_code
|
return response.status_code
|
||||||
|
|
||||||
class Submenu:
|
class Submenu:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def read_all(ac: AsyncClient, menu: dict) -> Tuple[int, dict]:
|
async def read_all(ac, menu):
|
||||||
"""чтение всех меню"""
|
"""чтение всех меню"""
|
||||||
response: Response = await ac.get(f"/{menu.get('id')}/submenus/")
|
response = await ac.get(f"/{menu.get('id')}/submenus/")
|
||||||
return response.status_code, response.json()
|
return response.status_code, response.json()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get(
|
async def get(ac, menu, submenu):
|
||||||
ac: AsyncClient,
|
|
||||||
menu: dict,
|
|
||||||
submenu: dict,
|
|
||||||
) -> Tuple[int, dict]:
|
|
||||||
"""Получение меню по id"""
|
"""Получение меню по id"""
|
||||||
response: Response = await ac.get(
|
response = await ac.get(
|
||||||
f"/{menu.get('id')}/submenus/{submenu.get('id')}",
|
f"/{menu.get('id')}/submenus/{submenu.get('id')}",
|
||||||
)
|
)
|
||||||
return response.status_code, response.json()
|
return response.status_code, response.json()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def write(
|
async def write(ac, menu, submenu):
|
||||||
ac: AsyncClient,
|
|
||||||
menu: dict,
|
|
||||||
submenu: dict,
|
|
||||||
) -> Tuple[int, dict]:
|
|
||||||
"""создания меню"""
|
"""создания меню"""
|
||||||
response: Response = await ac.post(
|
response = await ac.post(
|
||||||
f"/{menu.get('id')}/submenus/",
|
f"/{menu.get('id')}/submenus/",
|
||||||
json=submenu,
|
json=submenu,
|
||||||
)
|
)
|
||||||
return response.status_code, response.json()
|
return response.status_code, response.json()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def update(
|
async def update(ac, menu, submenu):
|
||||||
ac: AsyncClient, menu: dict, submenu: dict
|
|
||||||
) -> Tuple[int, dict]:
|
|
||||||
"""Обновление меню по id"""
|
"""Обновление меню по id"""
|
||||||
response: Response = await ac.patch(
|
response = await ac.patch(
|
||||||
f"/{menu.get('id')}/submenus/{submenu.get('id')}",
|
f"/{menu.get('id')}/submenus/{submenu.get('id')}",
|
||||||
json=submenu,
|
json=submenu,
|
||||||
)
|
)
|
||||||
return response.status_code, response.json()
|
return response.status_code, response.json()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def delete(ac: AsyncClient, menu: dict, submenu: dict) -> int:
|
async def delete(ac, menu, submenu):
|
||||||
"""Удаление меню по id"""
|
"""Удаление меню по id"""
|
||||||
response: Response = await ac.delete(
|
response = await ac.delete(
|
||||||
f"/{menu.get('id')}/submenus/{submenu.get('id')}"
|
f"/{menu.get('id')}/submenus/{submenu.get('id')}"
|
||||||
)
|
)
|
||||||
return response.status_code
|
return response.status_code
|
||||||
|
|
||||||
class Dish:
|
class Dish:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def read_all(
|
async def read_all(ac, menu, submenu):
|
||||||
ac: AsyncClient, menu: dict, submenu: dict
|
|
||||||
) -> Tuple[int, dict]:
|
|
||||||
"""чтение всех блюд"""
|
"""чтение всех блюд"""
|
||||||
response: Response = await ac.get(
|
response = await ac.get(
|
||||||
f"/{menu.get('id')}/submenus/{submenu.get('id')}/dishes/",
|
f"/{menu.get('id')}/submenus/{submenu.get('id')}/dishes/",
|
||||||
)
|
)
|
||||||
return response.status_code, response.json()
|
return response.status_code, response.json()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get(
|
async def get(ac, menu, submenu, dish):
|
||||||
ac: AsyncClient, menu: dict, submenu: dict, dish: dict
|
|
||||||
) -> Tuple[int, dict]:
|
|
||||||
"""Получение блюда по id"""
|
"""Получение блюда по id"""
|
||||||
response: Response = await ac.get(
|
response = await ac.get(
|
||||||
f"/{menu.get('id')}/submenus/{submenu.get('id')}"
|
f"/{menu.get('id')}/submenus/{submenu.get('id')}"
|
||||||
f"/dishes/{dish.get('id')}",
|
f"/dishes/{dish.get('id')}",
|
||||||
)
|
)
|
||||||
return response.status_code, response.json()
|
return response.status_code, response.json()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def write(
|
async def write(ac, menu, submenu, dish):
|
||||||
ac: AsyncClient, menu: dict, submenu: dict, dish: dict
|
|
||||||
) -> Tuple[int, dict]:
|
|
||||||
"""создания блюда"""
|
"""создания блюда"""
|
||||||
response: Response = await ac.post(
|
response = await ac.post(
|
||||||
f"/{menu.get('id')}/submenus/{submenu.get('id')}/dishes/",
|
f"/{menu.get('id')}/submenus/{submenu.get('id')}/dishes/",
|
||||||
json=dish,
|
json=dish,
|
||||||
)
|
)
|
||||||
return response.status_code, response.json()
|
return response.status_code, response.json()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def update(
|
async def update(ac, menu, submenu, dish):
|
||||||
ac: AsyncClient, menu: dict, submenu: dict, dish: dict
|
|
||||||
) -> Tuple[int, dict]:
|
|
||||||
"""Обновление блюда по id"""
|
"""Обновление блюда по id"""
|
||||||
response: Response = await ac.patch(
|
response = await ac.patch(
|
||||||
f"/{menu.get('id')}/submenus/{submenu.get('id')}"
|
f"/{menu.get('id')}/submenus/{submenu.get('id')}"
|
||||||
f"/dishes/{dish.get('id')}",
|
f"/dishes/{dish.get('id')}",
|
||||||
json=dish,
|
json=dish,
|
||||||
|
@ -136,16 +112,16 @@ class TestBaseCrud:
|
||||||
return response.status_code, response.json()
|
return response.status_code, response.json()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def delete(ac: AsyncClient, menu: dict, submenu: dict, dish: dict) -> int:
|
async def delete(ac, menu, submenu, dish):
|
||||||
"""Удаление блюда по id"""
|
"""Удаление блюда по id"""
|
||||||
response: Response = await ac.delete(
|
response = await ac.delete(
|
||||||
f"/{menu.get('id')}/submenus/{submenu.get('id')}"
|
f"/{menu.get('id')}/submenus/{submenu.get('id')}"
|
||||||
f"/dishes/{dish.get('id')}"
|
f"/dishes/{dish.get('id')}"
|
||||||
)
|
)
|
||||||
return response.status_code
|
return response.status_code
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_menu_crud(self, client: AsyncClient) -> None:
|
async def test_menu_crud(self, client):
|
||||||
"""Тестирование функций меню"""
|
"""Тестирование функций меню"""
|
||||||
code, rspn = await self.Menu.read_all(client)
|
code, rspn = await self.Menu.read_all(client)
|
||||||
assert code == 200
|
assert code == 200
|
||||||
|
@ -176,7 +152,7 @@ class TestBaseCrud:
|
||||||
assert code == 404
|
assert code == 404
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_submenus(self, client) -> None:
|
async def test_submenus(self, client):
|
||||||
# Создаем меню и проверяем ответ
|
# Создаем меню и проверяем ответ
|
||||||
menu = {"title": "Menu", "description": "main menu"}
|
menu = {"title": "Menu", "description": "main menu"}
|
||||||
code, rspn = await self.Menu.write(client, menu)
|
code, rspn = await self.Menu.write(client, menu)
|
||||||
|
@ -227,7 +203,7 @@ class TestBaseCrud:
|
||||||
await self.Menu.delete(client, menu)
|
await self.Menu.delete(client, menu)
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_dishes(self, client: AsyncClient) -> None:
|
async def test_dishes(self, client):
|
||||||
# Создаем меню и проверяем ответ
|
# Создаем меню и проверяем ответ
|
||||||
menu = {
|
menu = {
|
||||||
"title": "Menu",
|
"title": "Menu",
|
||||||
|
|
|
@ -3,11 +3,9 @@ from uuid import UUID
|
||||||
import pytest
|
import pytest
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from fastfood.cruds.dish import DishCrud
|
|
||||||
from fastfood.cruds.menu import MenuCrud
|
from fastfood.cruds.menu import MenuCrud
|
||||||
from fastfood.cruds.submenu import SubMenuCrud
|
from fastfood.cruds.submenu import SubMenuCrud
|
||||||
from fastfood.models import Dish, Menu, SubMenu
|
from fastfood.models import Menu, SubMenu
|
||||||
from fastfood.schemas import DishBase as dishschema
|
|
||||||
from fastfood.schemas import Menu as menuschema
|
from fastfood.schemas import Menu as menuschema
|
||||||
from fastfood.schemas import MenuBase as menubaseschema
|
from fastfood.schemas import MenuBase as menubaseschema
|
||||||
|
|
||||||
|
@ -71,19 +69,14 @@ async def test_submenu(asession: AsyncSession) -> None:
|
||||||
|
|
||||||
# Проверяем подменю
|
# Проверяем подменю
|
||||||
req_submenu = await SubMenuCrud.get_submenu_item(
|
req_submenu = await SubMenuCrud.get_submenu_item(
|
||||||
menu_id,
|
menu_id, submenu.id, asession,
|
||||||
submenu.id,
|
|
||||||
asession,
|
|
||||||
)
|
)
|
||||||
assert submenu == req_submenu
|
assert submenu == req_submenu
|
||||||
assert submenu.dishes_count == 0
|
|
||||||
|
|
||||||
# Обновляем меню
|
# Обновляем меню
|
||||||
submenu.title = "UpdatedSubmenu"
|
submenu.title = "UpdatedSubmenu"
|
||||||
req_submenu = await SubMenuCrud.update_submenu_item(
|
req_submenu = await SubMenuCrud.update_submenu_item(
|
||||||
submenu_id,
|
submenu_id, menubaseschema.model_validate(submenu), asession,
|
||||||
menubaseschema.model_validate(submenu),
|
|
||||||
asession,
|
|
||||||
)
|
)
|
||||||
assert submenu == req_submenu.scalar_one_or_none()
|
assert submenu == req_submenu.scalar_one_or_none()
|
||||||
|
|
||||||
|
@ -99,81 +92,9 @@ async def test_submenu(asession: AsyncSession) -> None:
|
||||||
await MenuCrud.delete_menu_item(menu_id, asession)
|
await MenuCrud.delete_menu_item(menu_id, asession)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_dish(asession: AsyncSession):
|
async def test_dish(asession: AsyncSession):
|
||||||
"""Not Implemented yet"""
|
"""Not Implemented yet"""
|
||||||
async with asession:
|
async with asession:
|
||||||
# Создаем меню напрямую
|
pass
|
||||||
menu = Menu(title="SomeMenu", description="SomeDescription")
|
|
||||||
asession.add(menu)
|
|
||||||
await asession.commit()
|
|
||||||
await asession.refresh(menu)
|
|
||||||
menu_id: UUID = menu.id
|
|
||||||
|
|
||||||
# Создаем подменю
|
|
||||||
submenu: SubMenu = SubMenu(
|
|
||||||
title="submenu",
|
|
||||||
description="",
|
|
||||||
parent_menu=menu_id,
|
|
||||||
)
|
|
||||||
asession.add(submenu)
|
|
||||||
await asession.commit()
|
|
||||||
await asession.refresh(submenu)
|
|
||||||
submenu_id = submenu.id
|
|
||||||
|
|
||||||
# Создаем блюдо
|
|
||||||
dish: Dish = Dish(
|
|
||||||
title="dish1",
|
|
||||||
description="dish number 1",
|
|
||||||
price="12.5",
|
|
||||||
parent_submenu=submenu_id,
|
|
||||||
)
|
|
||||||
dish = await DishCrud.create_dish_item(
|
|
||||||
submenu_id,
|
|
||||||
dishschema.model_validate(dish),
|
|
||||||
asession,
|
|
||||||
)
|
|
||||||
dish_id = dish.id
|
|
||||||
|
|
||||||
# Проверяем блюдо
|
|
||||||
req_dish = await DishCrud.get_dish_item(
|
|
||||||
dish_id,
|
|
||||||
asession,
|
|
||||||
)
|
|
||||||
assert dish == req_dish
|
|
||||||
|
|
||||||
menu = await MenuCrud.get_menu_item(menu_id, asession)
|
|
||||||
submenu = await SubMenuCrud.get_submenu_item(
|
|
||||||
menu_id,
|
|
||||||
submenu.id,
|
|
||||||
asession,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert menu.submenus_count == 1
|
|
||||||
assert menu.dishes_count == 1
|
|
||||||
assert submenu.dishes_count == 1
|
|
||||||
|
|
||||||
# Обновляем блюдо
|
|
||||||
dish.price = 177
|
|
||||||
req_dish = await DishCrud.update_dish_item(
|
|
||||||
dish_id,
|
|
||||||
dishschema.model_validate(dish),
|
|
||||||
asession,
|
|
||||||
)
|
|
||||||
assert dish == req_dish
|
|
||||||
|
|
||||||
# Удаляем длюдо
|
|
||||||
await DishCrud.delete_dish_item(dish_id, asession)
|
|
||||||
|
|
||||||
menu = await MenuCrud.get_menu_item(menu_id, asession)
|
|
||||||
submenu = await SubMenuCrud.get_submenu_item(
|
|
||||||
menu_id,
|
|
||||||
submenu.id,
|
|
||||||
asession,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert menu.dishes_count == 0
|
|
||||||
assert submenu.dishes_count == 0
|
|
||||||
|
|
||||||
await SubMenuCrud.delete_submenu_item(submenu_id, asession)
|
|
||||||
await MenuCrud.delete_menu_item(menu_id, asession)
|
|
||||||
|
|
Loading…
Reference in New Issue