Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e87880654 | |||
| 400e4d393e | |||
| ec306b38fe | |||
| 27a449793c |
@ -50,10 +50,6 @@ EMAIL_RECIPIENT=someone@somewhere.com
|
|||||||
EMAIL_SENDER=root@localhost
|
EMAIL_SENDER=root@localhost
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
TESTS_DB_HOST=localhost
|
|
||||||
TESTS_DB_PORT=5432
|
|
||||||
TESTS_DB_NAME=test_db-name
|
|
||||||
TESTS_DB_USER=db-user
|
|
||||||
TESTS_DB_PASSWORD=db-password
|
TESTS_DB_PASSWORD=db-password
|
||||||
TESTS_DROP_DATABASE_BEFORE_TESTS=True
|
TESTS_DROP_DATABASE_BEFORE_TESTS=True
|
||||||
TESTS_DROP_DATABASE_AFTER_TESTS=True
|
TESTS_DROP_DATABASE_AFTER_TESTS=True
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,3 +4,5 @@
|
|||||||
|
|
||||||
__pycache__
|
__pycache__
|
||||||
/.env
|
/.env
|
||||||
|
/.env.testing
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
Take note of the environment variable prefixes required for each
|
Take note of the environment variable prefixes required for each
|
||||||
settings class, except `AppSettings`.
|
settings class, except `AppSettings`.
|
||||||
"""
|
"""
|
||||||
|
import sys
|
||||||
from typing import Literal, Optional, Union
|
from typing import Literal, Optional, Union
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
@ -14,21 +15,16 @@ __all__ = [
|
|||||||
"ServerSettings",
|
"ServerSettings",
|
||||||
]
|
]
|
||||||
|
|
||||||
from pydantic import Extra
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
from pydantic_settings import BaseSettings
|
|
||||||
|
from const import ROOT_DIR
|
||||||
|
|
||||||
|
|
||||||
class BaseEnvSettings(BaseSettings):
|
class BaseEnvSettings(BaseSettings):
|
||||||
class Config:
|
model_config = SettingsConfigDict(case_sensitive=True, extra="ignore", env_file_encoding="utf-8")
|
||||||
env_file = ".env"
|
|
||||||
env_file_encoding = "utf-8"
|
|
||||||
extra = Extra.ignore
|
|
||||||
|
|
||||||
|
|
||||||
class AppSettings(BaseEnvSettings):
|
class AppSettings(BaseEnvSettings):
|
||||||
class Config:
|
|
||||||
case_sensitive = True
|
|
||||||
|
|
||||||
BUILD_NUMBER: str = "0"
|
BUILD_NUMBER: str = "0"
|
||||||
DEBUG: bool = False
|
DEBUG: bool = False
|
||||||
ENVIRONMENT: str = "local"
|
ENVIRONMENT: str = "local"
|
||||||
@ -41,9 +37,7 @@ class AppSettings(BaseEnvSettings):
|
|||||||
|
|
||||||
|
|
||||||
class APISettings(BaseEnvSettings):
|
class APISettings(BaseEnvSettings):
|
||||||
class Config:
|
model_config = SettingsConfigDict(env_prefix="API_")
|
||||||
env_prefix = "API_"
|
|
||||||
case_sensitive = True
|
|
||||||
|
|
||||||
CACHE_EXPIRATION: int = 60
|
CACHE_EXPIRATION: int = 60
|
||||||
DB_SESSION_DEPENDENCY_KEY: str = "db_session"
|
DB_SESSION_DEPENDENCY_KEY: str = "db_session"
|
||||||
@ -55,9 +49,7 @@ class APISettings(BaseEnvSettings):
|
|||||||
|
|
||||||
|
|
||||||
class OpenAPISettings(BaseEnvSettings):
|
class OpenAPISettings(BaseEnvSettings):
|
||||||
class Config:
|
model_config = SettingsConfigDict(env_prefix="OPENAPI_")
|
||||||
env_prefix = "OPENAPI_"
|
|
||||||
case_sensitive = True
|
|
||||||
|
|
||||||
TITLE: Optional[str] = "My Litestar App"
|
TITLE: Optional[str] = "My Litestar App"
|
||||||
VERSION: str = "0.1.0"
|
VERSION: str = "0.1.0"
|
||||||
@ -66,9 +58,7 @@ class OpenAPISettings(BaseEnvSettings):
|
|||||||
|
|
||||||
|
|
||||||
class DatabaseSettings(BaseEnvSettings):
|
class DatabaseSettings(BaseEnvSettings):
|
||||||
class Config:
|
model_config = SettingsConfigDict(env_prefix="DB_")
|
||||||
env_prefix = "DB_"
|
|
||||||
case_sensitive = True
|
|
||||||
|
|
||||||
ECHO: bool = False
|
ECHO: bool = False
|
||||||
ECHO_POOL: Union[bool, Literal["debug"]] = False
|
ECHO_POOL: Union[bool, Literal["debug"]] = False
|
||||||
@ -85,24 +75,15 @@ class DatabaseSettings(BaseEnvSettings):
|
|||||||
|
|
||||||
|
|
||||||
class TestingSettings(BaseEnvSettings):
|
class TestingSettings(BaseEnvSettings):
|
||||||
class Config:
|
model_config = SettingsConfigDict(env_prefix="TESTS_")
|
||||||
env_prefix = "TESTS_"
|
|
||||||
case_sensitive = True
|
|
||||||
|
|
||||||
DB_HOST: str = "localhost"
|
|
||||||
DB_PORT: int = 5432
|
|
||||||
DB_TEMPLATE_NAME: str = "db-template-name"
|
DB_TEMPLATE_NAME: str = "db-template-name"
|
||||||
DB_NAME: str = "test_db-name"
|
|
||||||
DB_USER: str = "db-user"
|
|
||||||
DB_PASSWORD: str = "db-password"
|
|
||||||
DROP_DATABASE_BEFORE_TESTS: bool = True
|
DROP_DATABASE_BEFORE_TESTS: bool = True
|
||||||
DROP_DATABASE_AFTER_TESTS: bool = True
|
DROP_DATABASE_AFTER_TESTS: bool = True
|
||||||
|
|
||||||
|
|
||||||
class ServerSettings(BaseEnvSettings):
|
class ServerSettings(BaseEnvSettings):
|
||||||
class Config:
|
model_config = SettingsConfigDict(env_prefix="UVICORN_")
|
||||||
env_prefix = "UVICORN_"
|
|
||||||
case_sensitive = True
|
|
||||||
|
|
||||||
HOST: str = "localhost"
|
HOST: str = "localhost"
|
||||||
LOG_LEVEL: str = "info"
|
LOG_LEVEL: str = "info"
|
||||||
@ -112,16 +93,21 @@ class ServerSettings(BaseEnvSettings):
|
|||||||
|
|
||||||
|
|
||||||
class EmailSettings(BaseEnvSettings):
|
class EmailSettings(BaseEnvSettings):
|
||||||
class Config:
|
model_config = SettingsConfigDict(env_prefix="EMAIL_")
|
||||||
env_prefix = "EMAIL_"
|
|
||||||
case_sensitive = True
|
|
||||||
|
|
||||||
|
|
||||||
# `.parse_obj()` thing is a workaround for pyright and pydantic interplay, see:
|
if "pytest" in sys.modules:
|
||||||
# https://github.com/pydantic/pydantic/issues/3753#issuecomment-1087417884
|
env_file = ROOT_DIR / ".env.testing"
|
||||||
api = APISettings.parse_obj({})
|
else:
|
||||||
app = AppSettings.parse_obj({})
|
env_file = ROOT_DIR / ".env"
|
||||||
db = DatabaseSettings.parse_obj({})
|
|
||||||
openapi = OpenAPISettings.parse_obj({})
|
params = {
|
||||||
server = ServerSettings.parse_obj({})
|
"_env_file": env_file,
|
||||||
testing = TestingSettings.parse_obj({})
|
}
|
||||||
|
|
||||||
|
api = APISettings(**params)
|
||||||
|
app = AppSettings(**params)
|
||||||
|
db = DatabaseSettings(**params)
|
||||||
|
openapi = OpenAPISettings(**params)
|
||||||
|
server = ServerSettings(**params)
|
||||||
|
testing = TestingSettings(**params)
|
||||||
|
|||||||
@ -74,26 +74,15 @@ def create_db_engine(connection_settings: DBConnectionSettings) -> AsyncEngine:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if "pytest" in sys.modules:
|
engine = create_db_engine(
|
||||||
engine = create_db_engine(
|
connection_settings=DBConnectionSettings(
|
||||||
connection_settings=DBConnectionSettings(
|
username=settings.db.USER,
|
||||||
username=settings.testing.DB_USER,
|
password=settings.db.PASSWORD,
|
||||||
password=settings.testing.DB_PASSWORD,
|
host=settings.db.HOST,
|
||||||
host=settings.testing.DB_HOST,
|
port=settings.db.PORT,
|
||||||
port=settings.testing.DB_PORT,
|
database=settings.db.NAME,
|
||||||
database=settings.testing.DB_NAME,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
engine = create_db_engine(
|
|
||||||
connection_settings=DBConnectionSettings(
|
|
||||||
username=settings.db.USER,
|
|
||||||
password=settings.db.PASSWORD,
|
|
||||||
host=settings.db.HOST,
|
|
||||||
port=settings.db.PORT,
|
|
||||||
database=settings.db.NAME,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
"""Configure via DatabaseSettings.
|
"""Configure via DatabaseSettings.
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from typing import Protocol
|
from dataclasses import dataclass
|
||||||
|
|
||||||
import asyncpg
|
import asyncpg
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
@ -7,13 +7,14 @@ from asyncpg import Connection, DuplicateDatabaseError, InvalidCatalogNameError
|
|||||||
from migrate import DatabaseConfig, migrate
|
from migrate import DatabaseConfig, migrate
|
||||||
|
|
||||||
|
|
||||||
class TestingSettingsInitOptions(Protocol):
|
@dataclass
|
||||||
|
class TestingSettingsInitOptions:
|
||||||
DB_HOST: str
|
DB_HOST: str
|
||||||
DB_PORT: int
|
DB_PORT: int
|
||||||
DB_TEMPLATE_NAME: str
|
|
||||||
DB_NAME: str
|
DB_NAME: str
|
||||||
DB_USER: str
|
DB_USER: str
|
||||||
DB_PASSWORD: str
|
DB_PASSWORD: str
|
||||||
|
DB_TEMPLATE_NAME: str
|
||||||
DROP_DATABASE_BEFORE_TESTS: bool
|
DROP_DATABASE_BEFORE_TESTS: bool
|
||||||
DROP_DATABASE_AFTER_TESTS: bool
|
DROP_DATABASE_AFTER_TESTS: bool
|
||||||
|
|
||||||
|
|||||||
3
const.py
Normal file
3
const.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT_DIR = Path(__file__).absolute().parent
|
||||||
2
main.py
2
main.py
@ -32,7 +32,7 @@ app = create_app()
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
app,
|
app="main:app",
|
||||||
host=settings.server.HOST,
|
host=settings.server.HOST,
|
||||||
log_level=settings.server.LOG_LEVEL,
|
log_level=settings.server.LOG_LEVEL,
|
||||||
port=settings.server.PORT,
|
port=settings.server.PORT,
|
||||||
|
|||||||
105
poetry.lock
generated
105
poetry.lock
generated
@ -545,13 +545,13 @@ testing = ["pytest", "pytest-benchmark"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polyfactory"
|
name = "polyfactory"
|
||||||
version = "2.8.1"
|
version = "2.9.0"
|
||||||
description = "Mock data generation factories"
|
description = "Mock data generation factories"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8,<4.0"
|
python-versions = ">=3.8,<4.0"
|
||||||
files = [
|
files = [
|
||||||
{file = "polyfactory-2.8.1-py3-none-any.whl", hash = "sha256:3f7525ffa6736181cf746d3c30063a953e6b566aec07e8b7268f52913a2838dd"},
|
{file = "polyfactory-2.9.0-py3-none-any.whl", hash = "sha256:7513347be6327739174dbd4ca6ddd96981fb697437283acb5362a604cf6d7f58"},
|
||||||
{file = "polyfactory-2.8.1.tar.gz", hash = "sha256:2b947f6ae8df96cfbca0ba94a573a885e4291eb893c3eb5daa7c1efa3385834e"},
|
{file = "polyfactory-2.9.0.tar.gz", hash = "sha256:af61fc5b03d0c5bb343a2289bdce457f27bbf8aefba69c592dca0841f905e7a5"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -559,12 +559,13 @@ faker = "*"
|
|||||||
typing-extensions = "*"
|
typing-extensions = "*"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
attrs = ["attrs"]
|
attrs = ["attrs (>=22.2.0)"]
|
||||||
beanie = ["beanie", "pydantic[email]"]
|
beanie = ["beanie", "pydantic[email]"]
|
||||||
full = ["attrs", "beanie", "msgspec", "odmantic", "pydantic[email]"]
|
full = ["attrs (>=22.2.0)", "beanie", "msgspec", "odmantic", "pydantic[email]", "sqlalchemy (>=2)"]
|
||||||
msgspec = ["msgspec"]
|
msgspec = ["msgspec"]
|
||||||
odmantic = ["odmantic", "pydantic[email]"]
|
odmantic = ["odmantic", "pydantic[email]"]
|
||||||
pydantic = ["pydantic[email]"]
|
pydantic = ["pydantic[email]"]
|
||||||
|
sqlalchemy = ["sqlalchemy (>=2)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
@ -867,52 +868,52 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlalchemy"
|
name = "sqlalchemy"
|
||||||
version = "2.0.20"
|
version = "2.0.21"
|
||||||
description = "Database Abstraction Library"
|
description = "Database Abstraction Library"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "SQLAlchemy-2.0.20-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:759b51346aa388c2e606ee206c0bc6f15a5299f6174d1e10cadbe4530d3c7a98"},
|
{file = "SQLAlchemy-2.0.21-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1e7dc99b23e33c71d720c4ae37ebb095bebebbd31a24b7d99dfc4753d2803ede"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1506e988ebeaaf316f183da601f24eedd7452e163010ea63dbe52dc91c7fc70e"},
|
{file = "SQLAlchemy-2.0.21-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7f0c4ee579acfe6c994637527c386d1c22eb60bc1c1d36d940d8477e482095d4"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5768c268df78bacbde166b48be788b83dddaa2a5974b8810af422ddfe68a9bc8"},
|
{file = "SQLAlchemy-2.0.21-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f7d57a7e140efe69ce2d7b057c3f9a595f98d0bbdfc23fd055efdfbaa46e3a5"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3f0dd6d15b6dc8b28a838a5c48ced7455c3e1fb47b89da9c79cc2090b072a50"},
|
{file = "SQLAlchemy-2.0.21-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca38746eac23dd7c20bec9278d2058c7ad662b2f1576e4c3dbfcd7c00cc48fa"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:243d0fb261f80a26774829bc2cee71df3222587ac789b7eaf6555c5b15651eed"},
|
{file = "SQLAlchemy-2.0.21-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3cf229704074bce31f7f47d12883afee3b0a02bb233a0ba45ddbfe542939cca4"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6eb6d77c31e1bf4268b4d61b549c341cbff9842f8e115ba6904249c20cb78a61"},
|
{file = "SQLAlchemy-2.0.21-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fb87f763b5d04a82ae84ccff25554ffd903baafba6698e18ebaf32561f2fe4aa"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp310-cp310-win32.whl", hash = "sha256:bcb04441f370cbe6e37c2b8d79e4af9e4789f626c595899d94abebe8b38f9a4d"},
|
{file = "SQLAlchemy-2.0.21-cp310-cp310-win32.whl", hash = "sha256:89e274604abb1a7fd5c14867a412c9d49c08ccf6ce3e1e04fffc068b5b6499d4"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp310-cp310-win_amd64.whl", hash = "sha256:d32b5ffef6c5bcb452723a496bad2d4c52b346240c59b3e6dba279f6dcc06c14"},
|
{file = "SQLAlchemy-2.0.21-cp310-cp310-win_amd64.whl", hash = "sha256:e36339a68126ffb708dc6d1948161cea2a9e85d7d7b0c54f6999853d70d44430"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd81466bdbc82b060c3c110b2937ab65ace41dfa7b18681fdfad2f37f27acdd7"},
|
{file = "SQLAlchemy-2.0.21-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bf8eebccc66829010f06fbd2b80095d7872991bfe8415098b9fe47deaaa58063"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6fe7d61dc71119e21ddb0094ee994418c12f68c61b3d263ebaae50ea8399c4d4"},
|
{file = "SQLAlchemy-2.0.21-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b977bfce15afa53d9cf6a632482d7968477625f030d86a109f7bdfe8ce3c064a"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4e571af672e1bb710b3cc1a9794b55bce1eae5aed41a608c0401885e3491179"},
|
{file = "SQLAlchemy-2.0.21-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ff3dc2f60dbf82c9e599c2915db1526d65415be323464f84de8db3e361ba5b9"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3364b7066b3c7f4437dd345d47271f1251e0cfb0aba67e785343cdbdb0fff08c"},
|
{file = "SQLAlchemy-2.0.21-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44ac5c89b6896f4740e7091f4a0ff2e62881da80c239dd9408f84f75a293dae9"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1be86ccea0c965a1e8cd6ccf6884b924c319fcc85765f16c69f1ae7148eba64b"},
|
{file = "SQLAlchemy-2.0.21-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:87bf91ebf15258c4701d71dcdd9c4ba39521fb6a37379ea68088ce8cd869b446"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1d35d49a972649b5080557c603110620a86aa11db350d7a7cb0f0a3f611948a0"},
|
{file = "SQLAlchemy-2.0.21-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b69f1f754d92eb1cc6b50938359dead36b96a1dcf11a8670bff65fd9b21a4b09"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp311-cp311-win32.whl", hash = "sha256:27d554ef5d12501898d88d255c54eef8414576f34672e02fe96d75908993cf53"},
|
{file = "SQLAlchemy-2.0.21-cp311-cp311-win32.whl", hash = "sha256:af520a730d523eab77d754f5cf44cc7dd7ad2d54907adeb3233177eeb22f271b"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp311-cp311-win_amd64.whl", hash = "sha256:411e7f140200c02c4b953b3dbd08351c9f9818d2bd591b56d0fa0716bd014f1e"},
|
{file = "SQLAlchemy-2.0.21-cp311-cp311-win_amd64.whl", hash = "sha256:141675dae56522126986fa4ca713739d00ed3a6f08f3c2eb92c39c6dfec463ce"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3c6aceebbc47db04f2d779db03afeaa2c73ea3f8dcd3987eb9efdb987ffa09a3"},
|
{file = "SQLAlchemy-2.0.21-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7614f1eab4336df7dd6bee05bc974f2b02c38d3d0c78060c5faa4cd1ca2af3b8"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d3f175410a6db0ad96b10bfbb0a5530ecd4fcf1e2b5d83d968dd64791f810ed"},
|
{file = "SQLAlchemy-2.0.21-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d59cb9e20d79686aa473e0302e4a82882d7118744d30bb1dfb62d3c47141b3ec"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea8186be85da6587456c9ddc7bf480ebad1a0e6dcbad3967c4821233a4d4df57"},
|
{file = "SQLAlchemy-2.0.21-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a95aa0672e3065d43c8aa80080cdd5cc40fe92dc873749e6c1cf23914c4b83af"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c3d99ba99007dab8233f635c32b5cd24fb1df8d64e17bc7df136cedbea427897"},
|
{file = "SQLAlchemy-2.0.21-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8c323813963b2503e54d0944813cd479c10c636e3ee223bcbd7bd478bf53c178"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:76fdfc0f6f5341987474ff48e7a66c3cd2b8a71ddda01fa82fedb180b961630a"},
|
{file = "SQLAlchemy-2.0.21-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:419b1276b55925b5ac9b4c7044e999f1787c69761a3c9756dec6e5c225ceca01"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp37-cp37m-win32.whl", hash = "sha256:d3793dcf5bc4d74ae1e9db15121250c2da476e1af8e45a1d9a52b1513a393459"},
|
{file = "SQLAlchemy-2.0.21-cp37-cp37m-win32.whl", hash = "sha256:4615623a490e46be85fbaa6335f35cf80e61df0783240afe7d4f544778c315a9"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp37-cp37m-win_amd64.whl", hash = "sha256:79fde625a0a55220d3624e64101ed68a059c1c1f126c74f08a42097a72ff66a9"},
|
{file = "SQLAlchemy-2.0.21-cp37-cp37m-win_amd64.whl", hash = "sha256:cca720d05389ab1a5877ff05af96551e58ba65e8dc65582d849ac83ddde3e231"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:599ccd23a7146e126be1c7632d1d47847fa9f333104d03325c4e15440fc7d927"},
|
{file = "SQLAlchemy-2.0.21-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b4eae01faee9f2b17f08885e3f047153ae0416648f8e8c8bd9bc677c5ce64be9"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1a58052b5a93425f656675673ef1f7e005a3b72e3f2c91b8acca1b27ccadf5f4"},
|
{file = "SQLAlchemy-2.0.21-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3eb7c03fe1cd3255811cd4e74db1ab8dca22074d50cd8937edf4ef62d758cdf4"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79543f945be7a5ada9943d555cf9b1531cfea49241809dd1183701f94a748624"},
|
{file = "SQLAlchemy-2.0.21-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2d494b6a2a2d05fb99f01b84cc9af9f5f93bf3e1e5dbdafe4bed0c2823584c1"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63e73da7fb030ae0a46a9ffbeef7e892f5def4baf8064786d040d45c1d6d1dc5"},
|
{file = "SQLAlchemy-2.0.21-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b19ae41ef26c01a987e49e37c77b9ad060c59f94d3b3efdfdbf4f3daaca7b5fe"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3ce5e81b800a8afc870bb8e0a275d81957e16f8c4b62415a7b386f29a0cb9763"},
|
{file = "SQLAlchemy-2.0.21-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:fc6b15465fabccc94bf7e38777d665b6a4f95efd1725049d6184b3a39fd54880"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cb0d3e94c2a84215532d9bcf10229476ffd3b08f481c53754113b794afb62d14"},
|
{file = "SQLAlchemy-2.0.21-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:014794b60d2021cc8ae0f91d4d0331fe92691ae5467a00841f7130fe877b678e"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp38-cp38-win32.whl", hash = "sha256:8dd77fd6648b677d7742d2c3cc105a66e2681cc5e5fb247b88c7a7b78351cf74"},
|
{file = "SQLAlchemy-2.0.21-cp38-cp38-win32.whl", hash = "sha256:0268256a34806e5d1c8f7ee93277d7ea8cc8ae391f487213139018b6805aeaf6"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp38-cp38-win_amd64.whl", hash = "sha256:6f8a934f9dfdf762c844e5164046a9cea25fabbc9ec865c023fe7f300f11ca4a"},
|
{file = "SQLAlchemy-2.0.21-cp38-cp38-win_amd64.whl", hash = "sha256:73c079e21d10ff2be54a4699f55865d4b275fd6c8bd5d90c5b1ef78ae0197301"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:26a3399eaf65e9ab2690c07bd5cf898b639e76903e0abad096cd609233ce5208"},
|
{file = "SQLAlchemy-2.0.21-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:785e2f2c1cb50d0a44e2cdeea5fd36b5bf2d79c481c10f3a88a8be4cfa2c4615"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4cde2e1096cbb3e62002efdb7050113aa5f01718035ba9f29f9d89c3758e7e4e"},
|
{file = "SQLAlchemy-2.0.21-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c111cd40910ffcb615b33605fc8f8e22146aeb7933d06569ac90f219818345ef"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1b09ba72e4e6d341bb5bdd3564f1cea6095d4c3632e45dc69375a1dbe4e26ec"},
|
{file = "SQLAlchemy-2.0.21-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9cba4e7369de663611ce7460a34be48e999e0bbb1feb9130070f0685e9a6b66"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b74eeafaa11372627ce94e4dc88a6751b2b4d263015b3523e2b1e57291102f0"},
|
{file = "SQLAlchemy-2.0.21-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50a69067af86ec7f11a8e50ba85544657b1477aabf64fa447fd3736b5a0a4f67"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:77d37c1b4e64c926fa3de23e8244b964aab92963d0f74d98cbc0783a9e04f501"},
|
{file = "SQLAlchemy-2.0.21-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ccb99c3138c9bde118b51a289d90096a3791658da9aea1754667302ed6564f6e"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:eefebcc5c555803065128401a1e224a64607259b5eb907021bf9b175f315d2a6"},
|
{file = "SQLAlchemy-2.0.21-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:513fd5b6513d37e985eb5b7ed89da5fd9e72354e3523980ef00d439bc549c9e9"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp39-cp39-win32.whl", hash = "sha256:3423dc2a3b94125094897118b52bdf4d37daf142cbcf26d48af284b763ab90e9"},
|
{file = "SQLAlchemy-2.0.21-cp39-cp39-win32.whl", hash = "sha256:f9fefd6298433b6e9188252f3bff53b9ff0443c8fde27298b8a2b19f6617eeb9"},
|
||||||
{file = "SQLAlchemy-2.0.20-cp39-cp39-win_amd64.whl", hash = "sha256:5ed61e3463021763b853628aef8bc5d469fe12d95f82c74ef605049d810f3267"},
|
{file = "SQLAlchemy-2.0.21-cp39-cp39-win_amd64.whl", hash = "sha256:2e617727fe4091cedb3e4409b39368f424934c7faa78171749f704b49b4bb4ce"},
|
||||||
{file = "SQLAlchemy-2.0.20-py3-none-any.whl", hash = "sha256:63a368231c53c93e2b67d0c5556a9836fdcd383f7e3026a39602aad775b14acf"},
|
{file = "SQLAlchemy-2.0.21-py3-none-any.whl", hash = "sha256:ea7da25ee458d8f404b93eb073116156fd7d8c2a776d8311534851f28277b4ce"},
|
||||||
{file = "SQLAlchemy-2.0.20.tar.gz", hash = "sha256:ca8a5ff2aa7f3ade6c498aaafce25b1eaeabe4e42b73e25519183e4566a16fc6"},
|
{file = "SQLAlchemy-2.0.21.tar.gz", hash = "sha256:05b971ab1ac2994a14c56b35eaaa91f86ba080e9ad481b20d99d77f381bb6258"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -945,13 +946,13 @@ sqlcipher = ["sqlcipher3-binary"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typing-extensions"
|
name = "typing-extensions"
|
||||||
version = "4.7.1"
|
version = "4.8.0"
|
||||||
description = "Backported and Experimental Type Hints for Python 3.7+"
|
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"},
|
{file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"},
|
||||||
{file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"},
|
{file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
import logging
|
|
||||||
|
|
||||||
POSTGRES_HOST: str = "localhost"
|
|
||||||
POSTGRES_PORT: int = 5432
|
|
||||||
POSTGRES_TEST_USER = "addressbook"
|
|
||||||
POSTGRES_TEST_PASSWORD = "addressbook"
|
|
||||||
|
|
||||||
LOG_PATH = "/tmp/addressbook-log"
|
|
||||||
MIN_LOG_LEVEL: int = logging.INFO
|
|
||||||
DROP_TEMPLATE_DATABASE_BEFORE_TESTS: bool = False
|
|
||||||
FLYWAY_BINARY_PATH: str = "/usr/bin/flyway"
|
|
||||||
@ -3,14 +3,20 @@ import logging
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import AsyncGenerator
|
from typing import AsyncGenerator
|
||||||
|
|
||||||
|
import pytest
|
||||||
import pytest_asyncio
|
import pytest_asyncio
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
|
from litestar.testing import AsyncTestClient
|
||||||
from sqlalchemy import event
|
from sqlalchemy import event
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
|
||||||
|
|
||||||
from app.lib import settings
|
from app.lib import settings
|
||||||
from app.lib.sqlalchemy_plugin import DBConnectionSettings, create_db_engine
|
from app.lib.sqlalchemy_plugin import DBConnectionSettings, create_db_engine
|
||||||
from app.lib.test_extras.db_setup import TestingDatabaseSetup
|
from app.lib.test_extras.db_setup import (
|
||||||
|
TestingDatabaseSetup,
|
||||||
|
TestingSettingsInitOptions,
|
||||||
|
)
|
||||||
|
from main import app
|
||||||
|
|
||||||
# A Guide To Database Unit Testing with Pytest and SQLAlchemy
|
# A Guide To Database Unit Testing with Pytest and SQLAlchemy
|
||||||
# https://coderpad.io/blog/development/a-guide-to-database-unit-testing-with-pytest-and-sqlalchemy/
|
# https://coderpad.io/blog/development/a-guide-to-database-unit-testing-with-pytest-and-sqlalchemy/
|
||||||
@ -18,11 +24,11 @@ from app.lib.test_extras.db_setup import TestingDatabaseSetup
|
|||||||
|
|
||||||
engine = create_db_engine(
|
engine = create_db_engine(
|
||||||
connection_settings=DBConnectionSettings(
|
connection_settings=DBConnectionSettings(
|
||||||
username=settings.testing.DB_USER,
|
username=settings.db.USER,
|
||||||
password=settings.testing.DB_PASSWORD,
|
password=settings.db.PASSWORD,
|
||||||
host=settings.testing.DB_HOST,
|
host=settings.db.HOST,
|
||||||
port=settings.testing.DB_PORT,
|
port=settings.db.PORT,
|
||||||
database=settings.testing.DB_NAME,
|
database=settings.db.NAME,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -63,14 +69,30 @@ async def db_session() -> AsyncGenerator[AsyncSession, None]:
|
|||||||
pytest_plugins = ()
|
pytest_plugins = ()
|
||||||
|
|
||||||
|
|
||||||
|
db_options = TestingSettingsInitOptions(
|
||||||
|
DB_HOST=settings.db.HOST,
|
||||||
|
DB_PORT=settings.db.PORT,
|
||||||
|
DB_NAME=settings.db.NAME,
|
||||||
|
DB_USER=settings.db.USER,
|
||||||
|
DB_PASSWORD=settings.db.PASSWORD,
|
||||||
|
DB_TEMPLATE_NAME=settings.testing.DB_TEMPLATE_NAME,
|
||||||
|
DROP_DATABASE_BEFORE_TESTS=settings.testing.DROP_DATABASE_BEFORE_TESTS,
|
||||||
|
DROP_DATABASE_AFTER_TESTS=settings.testing.DROP_DATABASE_AFTER_TESTS,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def async_client() -> AsyncTestClient:
|
||||||
|
return AsyncTestClient(app=app)
|
||||||
|
|
||||||
|
|
||||||
def pytest_configure(config: Config) -> None:
|
def pytest_configure(config: Config) -> None:
|
||||||
logging.info(f"Starting tests: {datetime.utcnow()}")
|
logging.info(f"Starting tests: {datetime.utcnow()}")
|
||||||
db_setup = TestingDatabaseSetup(options=settings.testing)
|
db_setup = TestingDatabaseSetup(db_options)
|
||||||
asyncio.run(db_setup.init_db())
|
asyncio.run(db_setup.init_db())
|
||||||
print()
|
|
||||||
|
|
||||||
|
|
||||||
def pytest_unconfigure(config: Config) -> None:
|
def pytest_unconfigure(config: Config) -> None:
|
||||||
logging.info(f"Ending tests: {datetime.utcnow()}")
|
logging.info(f"Ending tests: {datetime.utcnow()}")
|
||||||
db_setup = TestingDatabaseSetup(options=settings.testing)
|
db_setup = TestingDatabaseSetup(db_options)
|
||||||
asyncio.run(db_setup.tear_down_db())
|
asyncio.run(db_setup.tear_down_db())
|
||||||
|
|||||||
@ -3,14 +3,14 @@ from litestar.status_codes import HTTP_200_OK
|
|||||||
from litestar.testing import AsyncTestClient
|
from litestar.testing import AsyncTestClient
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from main import app
|
|
||||||
from tests.factories.city_factory import CityFactory
|
from tests.factories.city_factory import CityFactory
|
||||||
|
|
||||||
|
|
||||||
class TestCitiesEndpoints:
|
class TestCitiesEndpoints:
|
||||||
@pytest.fixture(scope="function", autouse=True)
|
@pytest.fixture(scope="function", autouse=True)
|
||||||
def setup_class(self, db_session: AsyncSession):
|
def setup_class(self, db_session: AsyncSession, async_client: AsyncTestClient):
|
||||||
self.db_session = db_session
|
self.db_session = db_session
|
||||||
|
self.async_client = async_client
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get(self):
|
async def test_get(self):
|
||||||
@ -20,9 +20,9 @@ class TestCitiesEndpoints:
|
|||||||
city_4 = await CityFactory.create()
|
city_4 = await CityFactory.create()
|
||||||
city_5 = await CityFactory.create()
|
city_5 = await CityFactory.create()
|
||||||
|
|
||||||
async with AsyncTestClient(app=app) as client:
|
async with self.async_client as client:
|
||||||
response = await client.get("/v1/cities")
|
response = await client.get("/v1/cities")
|
||||||
print("#" * 100)
|
print("#" * 100)
|
||||||
print(response.content)
|
print(response.json())
|
||||||
print("#" * 100)
|
print("#" * 100)
|
||||||
assert response.status_code == HTTP_200_OK
|
assert response.status_code == HTTP_200_OK
|
||||||
Reference in New Issue
Block a user