diff --git a/.env b/.env index 40406ac..b74f7ac 100644 --- a/.env +++ b/.env @@ -1,17 +1,10 @@ PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 -SQL_DB=devdb -SQL_TEST_DB=testdb -SQL_HOST=db -SQL_USER=user -SQL_PASS=secret - # Postgres -POSTGRES_SERVER=db +POSTGRES_HOST=db POSTGRES_PORT=5432 POSTGRES_DB=devdb -POSTGRES_TEST_DB=testdb POSTGRES_USER=user POSTGRES_PASSWORD=secret diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 9553359..977311d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -18,9 +18,9 @@ jobs: env: PYTHONDONTWRITEBYTECODE: 1 PYTHONUNBUFFERED: 1 - SQL_DB: testdb - SQL_HOST: 127.0.0.1 - SQL_USER: app-user + POSTGRES_DB: testdb + POSTGRES_HOST: 127.0.0.1 + POSTGRES_USER: app-user POSTGRES_PASSWORD: secret PGPASSWORD: secret REDIS_HOST: 127.0.0.1 diff --git a/app/config.py b/app/config.py index 5afcc49..9bb375b 100644 --- a/app/config.py +++ b/app/config.py @@ -21,10 +21,10 @@ class Settings(BaseSettings): JWT_ALGORITHM: str JWT_EXPIRE: int - SQL_USER: str - SQL_PASS: str - SQL_HOST: str - SQL_DB: str + POSTGRES_USER: str + POSTGRES_PASSWORD: str + POSTGRES_HOST: str + POSTGRES_DB: str @computed_field @property @@ -57,20 +57,20 @@ class Settings(BaseSettings): The URL is built using the MultiHostUrl.build method, which takes the following parameters: - scheme: The scheme of the URL. In this case, it is "postgresql+asyncpg". - - username: The username for the SQL database, retrieved from the SQL_USER environment variable. - - password: The password for the SQL database, retrieved from the SQL_PASS environment variable. - - host: The host of the SQL database, retrieved from the SQL_HOST environment variable. - - path: The path of the SQL database, retrieved from the SQL_DB environment variable. + - username: The username for the Postgres database, retrieved from the POSTGRES_USER environment variable. + - password: The password for the Postgres database, retrieved from the POSTGRES_PASSWORD environment variable. + - host: The host of the Postgres database, retrieved from the POSTGRES_HOST environment variable. + - path: The path of the Postgres database, retrieved from the POSTGRES_DB environment variable. Returns: PostgresDsn: The constructed PostgresDsn URL for asyncpg. """ return MultiHostUrl.build( scheme="postgresql+asyncpg", - username=self.SQL_USER, - password=self.SQL_PASS, - host=self.SQL_HOST, - path=self.SQL_DB, + username=self.POSTGRES_USER, + password=self.POSTGRES_PASSWORD, + host=self.POSTGRES_HOST, + path=self.POSTGRES_DB, ) diff --git a/db/create.sql b/db/create.sql index 35d64d4..6df30d2 100644 --- a/db/create.sql +++ b/db/create.sql @@ -1,3 +1,5 @@ +-- DROP DATABASE IF EXISTS devdb; +-- CREATE DATABASE devdb; \connect devdb; CREATE SCHEMA shakespeare; CREATE SCHEMA happy_hog; diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 8e3ec04..f32246c 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -3,9 +3,9 @@ version: '3.8' services: app: environment: - - SQL_DB=testdb + - POSTGRES_DB=testdb db: environment: - - POSTGRES_USER=${SQL_USER} - - SQL_DB=testdb \ No newline at end of file + - POSTGRES_USER=${POSTGRES_USER} + - POSTGRES_DB=testdb \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index cbc0456..c43a332 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,15 +31,16 @@ services: - fastapi_postgres_data:/var/lib/postgresql/data env_file: - .env - - .secrets ports: - 5432:5432 environment: - - POSTGRES_USER=${SQL_USER} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD?Variable not set} + - POSTGRES_USER=${POSTGRES_USER?Variable not set} + - POSTGRES_DB=${POSTGRES_DB?Variable not set} healthcheck: test: [ - "CMD-SHELL", "pg_isready -d $SQL_DB -U $SQL_USER" + "CMD-SHELL", "pg_isready -d $POSTGRES_DB -U $POSTGRES_USER" ] interval: 5s timeout: 5s diff --git a/poetry.lock b/poetry.lock index d78ea3a..d8576a0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -68,17 +68,6 @@ six = ">=1.12.0" astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] -[[package]] -name = "async-timeout" -version = "4.0.3" -description = "Timeout context manager for asyncio programs" -optional = false -python-versions = ">=3.7" -files = [ - {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, - {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, -] - [[package]] name = "asyncpg" version = "0.29.0" @@ -129,9 +118,6 @@ files = [ {file = "asyncpg-0.29.0.tar.gz", hash = "sha256:d1c49e1f44fffafd9a55e1a9b101590859d881d639ea2922516f5d9c512d354e"}, ] -[package.dependencies] -async-timeout = {version = ">=4.0.3", markers = "python_version < \"3.12.0\""} - [package.extras] docs = ["Sphinx (>=5.3.0,<5.4.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] test = ["flake8 (>=6.1,<7.0)", "uvloop (>=0.15.3)"] @@ -1582,9 +1568,6 @@ files = [ {file = "redis-5.0.3.tar.gz", hash = "sha256:4973bae7444c0fbed64a06b87446f79361cb7e4ec1538c022d696ed7a5015580"}, ] -[package.dependencies] -async-timeout = {version = ">=4.0.3", markers = "python_full_version < \"3.11.3\""} - [package.extras] hiredis = ["hiredis (>=1.0.0)"] ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] @@ -1707,28 +1690,28 @@ files = [ [[package]] name = "ruff" -version = "0.3.3" +version = "0.3.4" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.3.3-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:973a0e388b7bc2e9148c7f9be8b8c6ae7471b9be37e1cc732f8f44a6f6d7720d"}, - {file = "ruff-0.3.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:cfa60d23269d6e2031129b053fdb4e5a7b0637fc6c9c0586737b962b2f834493"}, - {file = "ruff-0.3.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1eca7ff7a47043cf6ce5c7f45f603b09121a7cc047447744b029d1b719278eb5"}, - {file = "ruff-0.3.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7d3f6762217c1da954de24b4a1a70515630d29f71e268ec5000afe81377642d"}, - {file = "ruff-0.3.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b24c19e8598916d9c6f5a5437671f55ee93c212a2c4c569605dc3842b6820386"}, - {file = "ruff-0.3.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5a6cbf216b69c7090f0fe4669501a27326c34e119068c1494f35aaf4cc683778"}, - {file = "ruff-0.3.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352e95ead6964974b234e16ba8a66dad102ec7bf8ac064a23f95371d8b198aab"}, - {file = "ruff-0.3.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d6ab88c81c4040a817aa432484e838aaddf8bfd7ca70e4e615482757acb64f8"}, - {file = "ruff-0.3.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79bca3a03a759cc773fca69e0bdeac8abd1c13c31b798d5bb3c9da4a03144a9f"}, - {file = "ruff-0.3.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2700a804d5336bcffe063fd789ca2c7b02b552d2e323a336700abb8ae9e6a3f8"}, - {file = "ruff-0.3.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fd66469f1a18fdb9d32e22b79f486223052ddf057dc56dea0caaf1a47bdfaf4e"}, - {file = "ruff-0.3.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:45817af234605525cdf6317005923bf532514e1ea3d9270acf61ca2440691376"}, - {file = "ruff-0.3.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0da458989ce0159555ef224d5b7c24d3d2e4bf4c300b85467b08c3261c6bc6a8"}, - {file = "ruff-0.3.3-py3-none-win32.whl", hash = "sha256:f2831ec6a580a97f1ea82ea1eda0401c3cdf512cf2045fa3c85e8ef109e87de0"}, - {file = "ruff-0.3.3-py3-none-win_amd64.whl", hash = "sha256:be90bcae57c24d9f9d023b12d627e958eb55f595428bafcb7fec0791ad25ddfc"}, - {file = "ruff-0.3.3-py3-none-win_arm64.whl", hash = "sha256:0171aab5fecdc54383993389710a3d1227f2da124d76a2784a7098e818f92d61"}, - {file = "ruff-0.3.3.tar.gz", hash = "sha256:38671be06f57a2f8aba957d9f701ea889aa5736be806f18c0cd03d6ff0cbca8d"}, + {file = "ruff-0.3.4-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:60c870a7d46efcbc8385d27ec07fe534ac32f3b251e4fc44b3cbfd9e09609ef4"}, + {file = "ruff-0.3.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6fc14fa742e1d8f24910e1fff0bd5e26d395b0e0e04cc1b15c7c5e5fe5b4af91"}, + {file = "ruff-0.3.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3ee7880f653cc03749a3bfea720cf2a192e4f884925b0cf7eecce82f0ce5854"}, + {file = "ruff-0.3.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf133dd744f2470b347f602452a88e70dadfbe0fcfb5fd46e093d55da65f82f7"}, + {file = "ruff-0.3.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f3860057590e810c7ffea75669bdc6927bfd91e29b4baa9258fd48b540a4365"}, + {file = "ruff-0.3.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:986f2377f7cf12efac1f515fc1a5b753c000ed1e0a6de96747cdf2da20a1b369"}, + {file = "ruff-0.3.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fd98e85869603e65f554fdc5cddf0712e352fe6e61d29d5a6fe087ec82b76c"}, + {file = "ruff-0.3.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64abeed785dad51801b423fa51840b1764b35d6c461ea8caef9cf9e5e5ab34d9"}, + {file = "ruff-0.3.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df52972138318bc7546d92348a1ee58449bc3f9eaf0db278906eb511889c4b50"}, + {file = "ruff-0.3.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:98e98300056445ba2cc27d0b325fd044dc17fcc38e4e4d2c7711585bd0a958ed"}, + {file = "ruff-0.3.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:519cf6a0ebed244dce1dc8aecd3dc99add7a2ee15bb68cf19588bb5bf58e0488"}, + {file = "ruff-0.3.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:bb0acfb921030d00070539c038cd24bb1df73a2981e9f55942514af8b17be94e"}, + {file = "ruff-0.3.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:cf187a7e7098233d0d0c71175375c5162f880126c4c716fa28a8ac418dcf3378"}, + {file = "ruff-0.3.4-py3-none-win32.whl", hash = "sha256:af27ac187c0a331e8ef91d84bf1c3c6a5dea97e912a7560ac0cef25c526a4102"}, + {file = "ruff-0.3.4-py3-none-win_amd64.whl", hash = "sha256:de0d5069b165e5a32b3c6ffbb81c350b1e3d3483347196ffdf86dc0ef9e37dd6"}, + {file = "ruff-0.3.4-py3-none-win_arm64.whl", hash = "sha256:6810563cc08ad0096b57c717bd78aeac888a1bfd38654d9113cb3dc4d3f74232"}, + {file = "ruff-0.3.4.tar.gz", hash = "sha256:f0f4484c6541a99862b693e13a151435a279b271cff20e37101116a21e2a1ad1"}, ] [[package]] @@ -2268,5 +2251,5 @@ files = [ [metadata] lock-version = "2.0" -python-versions = "^3.11" -content-hash = "6004dd5a71508cdb85a3155477fd26c09b656ddd7365c763691d7eb02bd2073f" +python-versions = "^3.12" +content-hash = "453a4f4415f5dde1de71d039dfed1bab2f5dcad2f42b916467e0997caebc3836" diff --git a/pyproject.toml b/pyproject.toml index 2a1c563..5232bd4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,13 +1,13 @@ [tool.poetry] name = "fastapi-sqlalchemy-asyncpg" -version = "0.0.8" +version = "0.0.9" description = "" authors = ["Jakub Miazek "] packages = [] license = "MIT" [tool.poetry.dependencies] -python = "^3.11" +python = "^3.12" fastapi = "0.110.0" pydantic = {version = "2.6.4", extras = ["email"]} pydantic-settings = "2.2.1" @@ -54,8 +54,8 @@ ignore = ["E501"] # Exclude a variety of commonly ignored directories. exclude = ["alembic",] -# Assume Python 3.10. -target-version = "py311" +# Assume Python 3.11. +target-version = "py312" [tool.ruff.flake8-quotes] docstring-quotes = "double" diff --git a/tests/conftest.py b/tests/conftest.py index 97e6f0e..88b5ff6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,5 @@ import pytest -from httpx import AsyncClient +from httpx import AsyncClient, ASGITransport from app.database import engine from app.main import app @@ -29,10 +29,16 @@ async def start_db(): @pytest.fixture(scope="session") async def client(start_db) -> AsyncClient: - async with AsyncClient( + + transport = ASGITransport( app=app, + + ) + async with AsyncClient( + # app=app, base_url="http://testserver/v1", headers={"Content-Type": "application/json"}, + transport=transport, ) as test_client: app.state.redis = await get_redis() yield test_client