Skip to content

Commit

Permalink
updates
Browse files Browse the repository at this point in the history
  • Loading branch information
mjhea0 committed Jan 26, 2024
1 parent ede52f0 commit ed7a335
Show file tree
Hide file tree
Showing 12 changed files with 119 additions and 75 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ jobs:
-p 5003:8765 \
${{ env.IMAGE }}-final:latest
- name: Install requirements
run: docker exec fastapi-tdd pip install black==23.1.0 flake8==6.0.0 isort==5.12.0 pytest==7.2.2
run: docker exec fastapi-tdd pip install black==23.12.1 flake8==7.0.0 isort==5.13.2 pytest==7.4.4
- name: Pytest
run: docker exec fastapi-tdd python -m pytest .
- name: Flake8
Expand All @@ -98,7 +98,7 @@ jobs:
runs-on: ubuntu-latest
needs: [build, test]
env:
HEROKU_APP_NAME: radiant-everglades-49858
HEROKU_APP_NAME: quiet-citadel-80656
HEROKU_REGISTRY_IMAGE: registry.heroku.com/${HEROKU_APP_NAME}/summarizer
steps:
- name: Checkout
Expand Down
4 changes: 2 additions & 2 deletions project/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# pull official base image
FROM python:3.11.2-slim-buster
FROM python:3.12.1-slim-bookworm

# set working directory
WORKDIR /usr/src/app
Expand All @@ -10,7 +10,7 @@ ENV PYTHONUNBUFFERED 1

# install system dependencies
RUN apt-get update \
&& apt-get -y install netcat gcc postgresql \
&& apt-get -y install netcat-traditional gcc postgresql \
&& apt-get clean

# install python dependencies
Expand Down
16 changes: 8 additions & 8 deletions project/Dockerfile.prod
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
###########

# pull official base image
FROM python:3.11.2-slim-buster as builder
FROM python:3.12.1-slim-bookworm as builder

# install system dependencies
RUN apt-get update \
&& apt-get -y install gcc postgresql \
&& apt-get -y install netcat-traditional gcc postgresql \
&& apt-get clean

# set work directory
Expand All @@ -24,18 +24,18 @@ RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requir

# lint
COPY . /usr/src/app/
RUN pip install black==23.1.0 flake8==6.0.0 isort==5.12.0
RUN pip install black==23.12.1 flake8==7.0.0 isort==5.13.2
RUN flake8 .
RUN black --exclude=migrations .
RUN isort .
RUN black --exclude=migrations . --check
RUN isort . --check-only


#########
# FINAL #
#########

# pull official base image
FROM python:3.11.2-slim-buster
FROM python:3.12.1-slim-bookworm

# create directory for the app user
RUN mkdir -p /home/app
Expand All @@ -57,15 +57,15 @@ ENV TESTING 0

# install system dependencies
RUN apt-get update \
&& apt-get -y install netcat gcc postgresql \
&& apt-get -y install netcat-traditional gcc postgresql \
&& apt-get clean

# install python dependencies
COPY --from=builder /usr/src/app/wheels /wheels
COPY --from=builder /usr/src/app/requirements.txt .
RUN pip install --upgrade pip
RUN pip install --no-cache /wheels/*
RUN pip install "uvicorn[standard]==0.21.1"
RUN pip install "uvicorn[standard]==0.26.0"

# add app
COPY . .
Expand Down
10 changes: 5 additions & 5 deletions project/app/api/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
from app.models.tortoise import TextSummary


async def get_all() -> List:
summaries = await TextSummary.all().values()
return summaries


async def get(id: int) -> Union[dict, None]:
summary = await TextSummary.filter(id=id).first().values()
if summary:
return summary
return None


async def get_all() -> List:
summaries = await TextSummary.all().values()
return summaries


async def post(payload: SummaryPayloadSchema) -> int:
summary = TextSummary(url=payload.url, summary="")
await summary.save()
Expand Down
12 changes: 6 additions & 6 deletions project/app/api/summaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@
router = APIRouter()


@router.get("/", response_model=List[SummarySchema])
async def read_all_summaries() -> List[SummarySchema]:
return await crud.get_all()


@router.get("/{id}/", response_model=SummarySchema)
async def read_summary(id: int = Path(..., gt=0)) -> SummarySchema:
summary = await crud.get(id)
Expand All @@ -29,13 +24,18 @@ async def read_summary(id: int = Path(..., gt=0)) -> SummarySchema:
return summary


@router.get("/", response_model=List[SummarySchema])
async def read_all_summaries() -> List[SummarySchema]:
return await crud.get_all()


@router.post("/", response_model=SummaryResponseSchema, status_code=201)
async def create_summary(
payload: SummaryPayloadSchema, background_tasks: BackgroundTasks
) -> SummaryResponseSchema:
summary_id = await crud.post(payload)

background_tasks.add_task(generate_summary, summary_id, payload.url)
background_tasks.add_task(generate_summary, summary_id, str(payload.url))

response_object = {"id": summary_id, "url": payload.url}
return response_object
Expand Down
3 changes: 2 additions & 1 deletion project/app/config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import logging
from functools import lru_cache

from pydantic import AnyUrl, BaseSettings
from pydantic import AnyUrl
from pydantic_settings import BaseSettings

log = logging.getLogger("uvicorn")

Expand Down
2 changes: 1 addition & 1 deletion project/db/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# pull official base image
FROM postgres:15
FROM postgres:16

# run create.sql on init
ADD create.sql /docker-entrypoint-initdb.d
12 changes: 6 additions & 6 deletions project/requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
black==23.1.0
flake8==6.0.0
isort==5.12.0
pytest==7.2.2
pytest-cov==4.0.0
pytest-xdist==3.2.1
black==23.12.1
flake8==7.0.0
isort==5.13.2
pytest==7.4.4
pytest-cov==4.1.0
pytest-xdist==3.5.0

-r requirements.txt
15 changes: 8 additions & 7 deletions project/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
aerich==0.7.1
asyncpg==0.27.0
fastapi==0.94.1
gunicorn==20.1.0
httpx==0.23.3
aerich==0.7.2
asyncpg==0.29.0
fastapi==0.109.0
gunicorn==21.0.1
httpx==0.26.0
newspaper3k==0.2.8
tortoise-orm==0.19.3
uvicorn==0.21.1
pydantic-settings==2.1.0
tortoise-orm==0.20.0
uvicorn==0.26.0
65 changes: 42 additions & 23 deletions project/tests/test_summaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def mock_generate_summary(summary_id, url):
)

assert response.status_code == 201
assert response.json()["url"] == "https://foo.bar"
assert response.json()["url"] == "https://foo.bar/"


def test_create_summaries_invalid_json(test_app):
Expand All @@ -25,16 +25,20 @@ def test_create_summaries_invalid_json(test_app):
assert response.json() == {
"detail": [
{
"input": {},
"loc": ["body", "url"],
"msg": "field required",
"type": "value_error.missing",
"msg": "Field required",
"type": "missing",
"url": "https://errors.pydantic.dev/2.5/v/missing",
}
]
}

response = test_app.post("/summaries/", data=json.dumps({"url": "invalid://url"}))
assert response.status_code == 422
assert response.json()["detail"][0]["msg"] == "URL scheme not permitted"
assert (
response.json()["detail"][0]["msg"] == "URL scheme should be 'http' or 'https'"
)


def test_read_summary(test_app_with_db, monkeypatch):
Expand All @@ -53,7 +57,7 @@ def mock_generate_summary(summary_id, url):

response_dict = response.json()
assert response_dict["id"] == summary_id
assert response_dict["url"] == "https://foo.bar"
assert response_dict["url"] == "https://foo.bar/"
assert response_dict["created_at"]


Expand All @@ -67,10 +71,12 @@ def test_read_summary_incorrect_id(test_app_with_db):
assert response.json() == {
"detail": [
{
"ctx": {"gt": 0},
"input": "0",
"loc": ["path", "id"],
"msg": "ensure this value is greater than 0",
"type": "value_error.number.not_gt",
"ctx": {"limit_value": 0},
"msg": "Input should be greater than 0",
"type": "greater_than",
"url": "https://errors.pydantic.dev/2.5/v/greater_than",
}
]
}
Expand Down Expand Up @@ -107,7 +113,7 @@ def mock_generate_summary(summary_id, url):

response = test_app_with_db.delete(f"/summaries/{summary_id}/")
assert response.status_code == 200
assert response.json() == {"id": summary_id, "url": "https://foo.bar"}
assert response.json() == {"id": summary_id, "url": "https://foo.bar/"}


def test_remove_summary_incorrect_id(test_app_with_db):
Expand All @@ -120,10 +126,12 @@ def test_remove_summary_incorrect_id(test_app_with_db):
assert response.json() == {
"detail": [
{
"ctx": {"gt": 0},
"input": "0",
"loc": ["path", "id"],
"msg": "ensure this value is greater than 0",
"type": "value_error.number.not_gt",
"ctx": {"limit_value": 0},
"msg": "Input should be greater than 0",
"type": "greater_than",
"url": "https://errors.pydantic.dev/2.5/v/greater_than",
}
]
}
Expand All @@ -148,7 +156,7 @@ def mock_generate_summary(summary_id, url):

response_dict = response.json()
assert response_dict["id"] == summary_id
assert response_dict["url"] == "https://foo.bar"
assert response_dict["url"] == "https://foo.bar/"
assert response_dict["summary"] == "updated!"
assert response_dict["created_at"]

Expand All @@ -168,10 +176,12 @@ def mock_generate_summary(summary_id, url):
422,
[
{
"type": "greater_than",
"loc": ["path", "id"],
"msg": "ensure this value is greater than 0",
"type": "value_error.number.not_gt",
"ctx": {"limit_value": 0},
"msg": "Input should be greater than 0",
"input": "0",
"ctx": {"gt": 0},
"url": "https://errors.pydantic.dev/2.5/v/greater_than",
}
],
],
Expand All @@ -181,14 +191,18 @@ def mock_generate_summary(summary_id, url):
422,
[
{
"type": "missing",
"loc": ["body", "url"],
"msg": "field required",
"type": "value_error.missing",
"msg": "Field required",
"input": {},
"url": "https://errors.pydantic.dev/2.5/v/missing",
},
{
"type": "missing",
"loc": ["body", "summary"],
"msg": "field required",
"type": "value_error.missing",
"msg": "Field required",
"input": {},
"url": "https://errors.pydantic.dev/2.5/v/missing",
},
],
],
Expand All @@ -198,9 +212,11 @@ def mock_generate_summary(summary_id, url):
422,
[
{
"type": "missing",
"loc": ["body", "summary"],
"msg": "field required",
"type": "value_error.missing",
"msg": "Field required",
"input": {"url": "https://foo.bar"},
"url": "https://errors.pydantic.dev/2.5/v/missing",
}
],
],
Expand All @@ -213,6 +229,7 @@ def test_update_summary_invalid(
f"/summaries/{summary_id}/", data=json.dumps(payload)
)
assert response.status_code == status_code
print(response.json()["detail"])
assert response.json()["detail"] == detail


Expand All @@ -222,4 +239,6 @@ def test_update_summary_invalid_url(test_app):
data=json.dumps({"url": "invalid://url", "summary": "updated!"}),
)
assert response.status_code == 422
assert response.json()["detail"][0]["msg"] == "URL scheme not permitted"
assert (
response.json()["detail"][0]["msg"] == "URL scheme should be 'http' or 'https'"
)
Loading

0 comments on commit ed7a335

Please sign in to comment.