From ec42985e21fb6c9f2454ac034823d858c5618caf Mon Sep 17 00:00:00 2001 From: Masum Billal Date: Sun, 16 Jun 2024 21:16:46 +0600 Subject: [PATCH] refactored to remove unnecessary commands --- tests/conftest.py | 4 +- tests/test_bug.py | 21 +++++++--- tests/test_story.py | 9 +++-- tracker/main.py | 4 +- tracker/models/bug.py | 3 -- tracker/{serializers => responses}/base.py | 0 tracker/{serializers => responses}/bug.py | 4 +- tracker/{serializers => responses}/story.py | 2 +- tracker/{views => routers}/bug.py | 12 ++---- tracker/{views => routers}/story.py | 10 ++--- tracker/services/bug.py | 43 +++++++-------------- tracker/services/story.py | 11 +++--- 12 files changed, 53 insertions(+), 70 deletions(-) rename tracker/{serializers => responses}/base.py (100%) rename tracker/{serializers => responses}/bug.py (78%) rename tracker/{serializers => responses}/story.py (85%) rename tracker/{views => routers}/bug.py (71%) rename tracker/{views => routers}/story.py (81%) diff --git a/tests/conftest.py b/tests/conftest.py index 9b8dce0..24f7527 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,8 +10,8 @@ from tracker.db.session import get_db from tracker.models.base import Base -from tracker.views.bug import router as bug_router -from tracker.views.story import router as story_router +from tracker.routers.bug import router as bug_router +from tracker.routers.story import router as story_router SQLALCHEMY_DATABASE_URL = "sqlite+aiosqlite:///./test_db.db" diff --git a/tests/test_bug.py b/tests/test_bug.py index 835fa55..aa9359b 100644 --- a/tests/test_bug.py +++ b/tests/test_bug.py @@ -1,10 +1,11 @@ import pytest +from fastapi import status from httpx import AsyncClient from tests.common import detail_not_found -class TestStory: +class TestBug: async def __test_bug(self, bug: dict): assert isinstance(bug, dict) assert "id" in bug @@ -22,14 +23,24 @@ async def test_create(self, client: AsyncClient) -> None: "story_id": 1, } response = await client.post(url="/bugs/", json=json) - assert response.status_code == 200 + assert response.status_code == status.HTTP_200_OK bug = response.json() await self.__test_bug(bug=bug) + @pytest.mark.asyncio + async def test_create_exception(self, client: AsyncClient) -> None: + json = { + "title": "Test Bug", + "description": "Description of Test Bug", + "story_id": 100, + } + response = await client.post(url="/bugs/", json=json) + assert response.status_code == status.HTTP_404_NOT_FOUND + @pytest.mark.asyncio async def test_get(self, client: AsyncClient) -> None: response = await client.get(url="/bugs/") - assert response.status_code == 200 + assert response.status_code == status.HTTP_200_OK bugs = response.json() assert isinstance(bugs, list) @@ -39,13 +50,13 @@ async def test_get(self, client: AsyncClient) -> None: @pytest.mark.asyncio async def test_get_by_id(self, client: AsyncClient) -> None: response = await client.get(url="/bugs/1") - assert response.status_code == 200 + assert response.status_code == status.HTTP_200_OK bug = response.json() await self.__test_bug(bug=bug) @pytest.mark.asyncio async def test_get_not_found(self, client: AsyncClient) -> None: response = await client.get(url="/bugs/2") - assert response.status_code == 404 + assert response.status_code == status.HTTP_404_NOT_FOUND error = response.json() detail_not_found(error=error) diff --git a/tests/test_story.py b/tests/test_story.py index 27fa017..bea37b7 100644 --- a/tests/test_story.py +++ b/tests/test_story.py @@ -1,4 +1,5 @@ import pytest +from fastapi import status from httpx import AsyncClient from tests.common import detail_not_found @@ -15,14 +16,14 @@ async def __test_story(self, story: dict): async def test_create(self, client: AsyncClient) -> None: json = {"name": "Test Story"} response = await client.post(url="/stories/", json=json) - assert response.status_code == 200 + assert response.status_code == status.HTTP_200_OK story = response.json() await self.__test_story(story=story) @pytest.mark.asyncio async def test_get(self, client: AsyncClient) -> None: response = await client.get(url="/stories/") - assert response.status_code == 200 + assert response.status_code == status.HTTP_200_OK data = response.json() assert isinstance(data, list) @@ -32,13 +33,13 @@ async def test_get(self, client: AsyncClient) -> None: @pytest.mark.asyncio async def test_get_by_id(self, client: AsyncClient) -> None: response = await client.get(url="/stories/1") - assert response.status_code == 200 + assert response.status_code == status.HTTP_200_OK story = response.json() await self.__test_story(story=story) @pytest.mark.asyncio async def test_get_not_found(self, client: AsyncClient) -> None: response = await client.get(url="/stories/2") - assert response.status_code == 404 + assert response.status_code == status.HTTP_404_NOT_FOUND error = response.json() detail_not_found(error=error) diff --git a/tracker/main.py b/tracker/main.py index d103016..71f371e 100644 --- a/tracker/main.py +++ b/tracker/main.py @@ -4,8 +4,8 @@ from fastapi import FastAPI from tracker.db.session import engine -from tracker.views.bug import router as bug_router -from tracker.views.story import router as story_router +from tracker.routers.bug import router as bug_router +from tracker.routers.story import router as story_router async def configure_router(): diff --git a/tracker/models/bug.py b/tracker/models/bug.py index 1ee8838..63d46cb 100644 --- a/tracker/models/bug.py +++ b/tracker/models/bug.py @@ -14,6 +14,3 @@ class Bug(Base): class Config: orm_mode = True - - def __repr__(self) -> str: - return f"{self.title}, {self.story_id}" diff --git a/tracker/serializers/base.py b/tracker/responses/base.py similarity index 100% rename from tracker/serializers/base.py rename to tracker/responses/base.py diff --git a/tracker/serializers/bug.py b/tracker/responses/bug.py similarity index 78% rename from tracker/serializers/bug.py rename to tracker/responses/bug.py index 767228d..de28007 100644 --- a/tracker/serializers/bug.py +++ b/tracker/responses/bug.py @@ -2,8 +2,8 @@ from pydantic import ConfigDict -from tracker.serializers.base import Base -from tracker.serializers.story import StoryOutput +from tracker.responses.base import Base +from tracker.responses.story import StoryOutput class BugBase(Base): diff --git a/tracker/serializers/story.py b/tracker/responses/story.py similarity index 85% rename from tracker/serializers/story.py rename to tracker/responses/story.py index 8e6c8a9..921246c 100644 --- a/tracker/serializers/story.py +++ b/tracker/responses/story.py @@ -2,7 +2,7 @@ from pydantic import ConfigDict -from tracker.serializers.base import Base +from tracker.responses.base import Base class StoryInput(Base): diff --git a/tracker/views/bug.py b/tracker/routers/bug.py similarity index 71% rename from tracker/views/bug.py rename to tracker/routers/bug.py index 43fddf4..e4415f1 100644 --- a/tracker/views/bug.py +++ b/tracker/routers/bug.py @@ -4,7 +4,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from tracker.db.session import get_db -from tracker.serializers.bug import BugInput, BugOutput +from tracker.responses.bug import BugInput, BugOutput from tracker.services.bug import bug_by_id, bugs from tracker.services.bug import create as create_bug @@ -13,9 +13,7 @@ @router.post("/bugs/", response_model=BugOutput) async def create(bug: BugInput, db: Annotated[AsyncSession, Depends(get_db)]): - obj = await create_bug(db=db, bug=bug) - - return obj + return BugOutput.model_validate(await create_bug(db=db, bug=bug)) @router.get("/bugs/", response_model=list[BugOutput]) @@ -26,7 +24,5 @@ async def get( @router.get("/bugs/{id}", response_model=BugOutput) -async def get_bug(id: int, db: Annotated[AsyncSession, Depends(get_db)]): - obj = await bug_by_id(db=db, id=id) - - return obj +async def get_by_id(id: int, db: Annotated[AsyncSession, Depends(get_db)]): + return BugOutput.model_validate(await bug_by_id(db=db, id=id)) diff --git a/tracker/views/story.py b/tracker/routers/story.py similarity index 81% rename from tracker/views/story.py rename to tracker/routers/story.py index b0c0f79..4d6d92b 100644 --- a/tracker/views/story.py +++ b/tracker/routers/story.py @@ -4,7 +4,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from tracker.db.session import get_db -from tracker.serializers.story import StoryInput, StoryOutput +from tracker.responses.story import StoryInput, StoryOutput from tracker.services.story import create as create_story from tracker.services.story import stories, story_by_id @@ -13,9 +13,7 @@ @router.post("/stories/", response_model=StoryOutput) async def create(story: StoryInput, db: Annotated[AsyncSession, Depends(get_db)]): - obj = await create_story(db=db, story=story) - - return obj + return await create_story(db=db, story=story) @router.get("/stories/", response_model=list[StoryOutput]) @@ -27,6 +25,4 @@ async def get_stories( @router.get("/stories/{id}", response_model=StoryOutput) async def get_story(id: int, db: Annotated[AsyncSession, Depends(get_db)]): - obj = await story_by_id(db=db, id=id) - - return obj + return StoryOutput.model_validate(await story_by_id(db=db, id=id)) diff --git a/tracker/services/bug.py b/tracker/services/bug.py index 9e20635..a851d3d 100644 --- a/tracker/services/bug.py +++ b/tracker/services/bug.py @@ -1,54 +1,37 @@ -from http import HTTPStatus +from typing import Sequence -from fastapi import HTTPException -from fastapi.encoders import jsonable_encoder +from fastapi import HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select from tracker.models.bug import Bug -from tracker.serializers.bug import BugInput, BugOutput +from tracker.responses.bug import BugInput, BugOutput from tracker.services.story import story_by_id -async def bug_by_id(db: AsyncSession, id: int) -> BugOutput | HTTPException: +async def bug_by_id(db: AsyncSession, id: int) -> Bug: query = await db.execute(select(Bug).filter(Bug.id == id)) res = query.scalars().all() if len(res) > 0: return res[0] - raise HTTPException(status_code=HTTPStatus.NOT_FOUND) + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) -def bug_output(bug: Bug) -> BugOutput: - story = jsonable_encoder(obj=bug.story) - bug_output = BugOutput( - id=int(bug.id), - title=bug.title, - description=bug.description, - story=story, - story_id=bug.story_id, - created_at=bug.created_at, - updated_at=bug.updated_at, - ) +async def bugs(db: AsyncSession, skip: int = 0, limit: int = 10) -> Sequence[BugOutput]: + query = await db.execute(select(Bug).offset(skip).limit(limit=limit)) - return bug_output - - -async def bugs(db: AsyncSession, skip: int = 0, limit: int = 10) -> list[BugOutput]: - bugs = await db.scalars(select(Bug).offset(offset=skip).limit(limit=limit)) - output = [] - - for bug in bugs: - output.append(bug_output(bug=bug)) - - return output + return query.scalars().all() async def create(db: AsyncSession, bug: BugInput) -> BugOutput: - story = await story_by_id(db=db, id=bug.story_id) + response = await story_by_id(db=db, id=bug.story_id) + + if isinstance(response, HTTPException): + raise response - obj = Bug(**bug.model_dump(), story=story) + obj = Bug(**bug.model_dump(), story=response) db.add(obj) await db.commit() diff --git a/tracker/services/story.py b/tracker/services/story.py index cf59ad0..f276402 100644 --- a/tracker/services/story.py +++ b/tracker/services/story.py @@ -1,12 +1,11 @@ -from http import HTTPStatus from typing import Sequence -from fastapi import HTTPException +from fastapi import HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.future import select from tracker.models.story import Story -from tracker.serializers.story import StoryInput, StoryOutput +from tracker.responses.story import StoryInput, StoryOutput async def stories( @@ -17,14 +16,14 @@ async def stories( return query.scalars().all() -async def story_by_id(db: AsyncSession, id: int) -> StoryOutput | HTTPException: +async def story_by_id(db: AsyncSession, id: int) -> Story: query = await db.execute(select(Story).where(Story.id == id)) stories = query.scalars().all() if len(stories) > 0: return stories[0] - raise HTTPException(status_code=HTTPStatus.NOT_FOUND) + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) async def create(db: AsyncSession, story: StoryInput) -> StoryOutput: @@ -34,4 +33,4 @@ async def create(db: AsyncSession, story: StoryInput) -> StoryOutput: await db.commit() await db.refresh(story_new) - return story_new + return StoryOutput.model_validate(story_new)