diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6716a19 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +.dockerignore +/venv +Dockerfile +.env +*.db diff --git a/.gitignore b/.gitignore index 4934ad1..44ede21 100644 --- a/.gitignore +++ b/.gitignore @@ -193,3 +193,5 @@ pyrightconfig.json .ionide # End of https://www.toptal.com/developers/gitignore/api/python,visualstudiocode + +*.db diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..01b2366 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3.12 + +WORKDIR /app + +COPY . . + +RUN pip install -r requirements.txt + +EXPOSE 8000 + +ENV DB_NAME="" DB_USER="" DB_PASSWORD="" DB_PORT=0 DB_HOST="" + +CMD ["python", "main.py"] diff --git a/db.py b/db.py index 9838ac1..710e375 100644 --- a/db.py +++ b/db.py @@ -7,16 +7,8 @@ class Database: def __init__(self, settings: Settings): - url = URL.create( - drivername="mysql+pymysql", - username=settings.db_user, - password=settings.db_password, - host=settings.db_host, - port=settings.db_port, - database=settings.db_name - ) self.engine = create_engine( - url=url + url=settings.get_db_url() ) self.session = sessionmaker( autocommit=False, diff --git a/dto/product.py b/dto/product.py index 0f09163..3d28458 100644 --- a/dto/product.py +++ b/dto/product.py @@ -20,10 +20,10 @@ class ProductResponseDto(ProductDto): @staticmethod def from_entity( product: Product, - like_count: int, - dislike_count: int, - is_like: bool, - is_dislike: bool, + like_count: int = 0, + dislike_count: int = 0, + is_like: bool = False, + is_dislike: bool = False, ): return ProductResponseDto( id=product.id, diff --git a/main.py b/main.py index dc4a8db..d7f4f36 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,9 @@ +import uvicorn + from app import create_app from settings import Settings app = create_app(Settings()) + +if __name__ == "__main__": + uvicorn.run("main:app", port=8000, host="0.0.0.0") diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..19af4f7 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,60 @@ +alembic==1.13.2 +annotated-types==0.7.0 +anyio==4.4.0 +certifi==2024.7.4 +cffi==1.17.0 +cfgv==3.4.0 +click==8.1.7 +cryptography==43.0.0 +distlib==0.3.8 +dnspython==2.6.1 +email_validator==2.2.0 +fastapi==0.112.1 +fastapi-cli==0.0.5 +filelock==3.15.4 +h11==0.14.0 +httpcore==1.0.5 +httptools==0.6.1 +httpx==0.27.0 +identify==2.6.0 +idna==3.8 +iniconfig==2.0.0 +itsdangerous==2.2.0 +Jinja2==3.1.4 +load-config==0.2.0b6 +Mako==1.3.5 +markdown-it-py==3.0.0 +MarkupSafe==2.1.5 +mdurl==0.1.2 +nodeenv==1.9.1 +orjson==3.10.7 +packaging==24.1 +platformdirs==4.2.2 +pluggy==1.5.0 +pre-commit==3.8.0 +pycparser==2.22 +pydantic==2.8.2 +pydantic-extra-types==2.9.0 +pydantic-settings==2.4.0 +pydantic_core==2.20.1 +Pygments==2.18.0 +PyMySQL==1.1.1 +pytest==8.3.2 +pytest-asyncio==0.24.0 +python-dotenv==1.0.1 +python-multipart==0.0.9 +PyYAML==6.0.2 +rich==13.7.1 +shellingham==1.5.4 +sniffio==1.3.1 +SQLAlchemy==2.0.32 +starlette==0.38.2 +toml==0.10.2 +typer==0.12.4 +typing_extensions==4.12.2 +ujson==5.10.0 +uvicorn==0.30.6 +uvloop==0.20.0 +virtualenv==20.26.3 +watchfiles==0.23.0 +websockets==13.0 diff --git a/settings.py b/settings.py index 45edea8..c63063c 100644 --- a/settings.py +++ b/settings.py @@ -1,4 +1,7 @@ +from typing import override + from pydantic_settings import BaseSettings, SettingsConfigDict +from sqlalchemy import URL class Settings(BaseSettings): @@ -12,7 +15,19 @@ class Settings(BaseSettings): db_host: str db_port: int + def get_db_url(self): + return URL.create( + drivername="mysql+pymysql", + username=self.db_user, + password=self.db_password, + host=self.db_host, + port=self.db_port, + database=self.db_name + ) + class TestSettings(Settings): - db_port: int = 9999 - db_name: str = "test" + + @override + def get_db_url(self): + return "sqlite:///pangtok.db" diff --git a/tests/conftest.py b/tests/conftest.py index 5d4cc4a..0e8969f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -26,16 +26,8 @@ async def test_fastapi_app(settings): @pytest_asyncio.fixture(scope="function") async def engine(settings): - url = URL.create( - drivername="mysql+pymysql", - username=settings.db_user, - password=settings.db_password, - host=settings.db_host, - port=settings.db_port, - database=settings.db_name - ) eng = create_engine( - url=url + url=settings.get_db_url() ) Base.metadata.create_all(eng) yield eng @@ -45,7 +37,7 @@ async def engine(settings): @pytest_asyncio.fixture(scope="function") async def session(engine): sessionLocal = sessionmaker(engine) - return sessionLocal() + yield sessionLocal() @pytest_asyncio.fixture(scope="function") diff --git a/tests/e2e/test_product.py b/tests/e2e/test_product.py index cac51e0..6782856 100644 --- a/tests/e2e/test_product.py +++ b/tests/e2e/test_product.py @@ -12,7 +12,7 @@ async def test_show_product_detail_returns_200( async with AsyncClient( transport=ASGITransport(app=test_fastapi_app), base_url="http://test" ) as client: - response = await client.get("/product/0") + response = await client.get("/product/0/1") assert response.status_code == status.HTTP_200_OK