Skip to content

Commit 16433b6

Browse files
authored
Merge pull request #44 from testdrivenio/updates
updates
2 parents 13cff42 + 315e351 commit 16433b6

14 files changed

+44
-60
lines changed

.github/workflows/main.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ jobs:
8383
-p 5003:8765 \
8484
${{ env.IMAGE }}-final:latest
8585
- name: Install requirements
86-
run: docker exec fastapi-tdd pip install black==23.12.1 flake8==7.0.0 isort==5.13.2 pytest==7.4.4
86+
run: docker exec fastapi-tdd python3 -m pip install black==25.1.0 flake8==7.2.0 isort==6.0.1 pytest==8.3.5
8787
- name: Pytest
8888
run: docker exec fastapi-tdd python -m pytest .
8989
- name: Flake8
@@ -98,7 +98,7 @@ jobs:
9898
runs-on: ubuntu-latest
9999
needs: [build, test]
100100
env:
101-
HEROKU_APP_NAME: quiet-citadel-80656
101+
HEROKU_APP_NAME: shrouded-shelf-89730
102102
HEROKU_REGISTRY_IMAGE: registry.heroku.com/${HEROKU_APP_NAME}/summarizer
103103
steps:
104104
- name: Checkout

docker-compose.yml

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
version: '3.8'
2-
31
services:
42

53
web:

project/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# pull official base image
2-
FROM python:3.12.1-slim-bookworm
2+
FROM python:3.13.3-slim-bookworm
33

44
# set working directory
55
WORKDIR /usr/src/app

project/Dockerfile.prod

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
###########
44

55
# pull official base image
6-
FROM python:3.12.1-slim-bookworm as builder
6+
FROM python:3.13.3-slim-bookworm as builder
77

88
# install system dependencies
99
RUN apt-get update \
@@ -24,7 +24,7 @@ RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requir
2424

2525
# lint
2626
COPY . /usr/src/app/
27-
RUN pip install black==23.12.1 flake8==7.0.0 isort==5.13.2
27+
RUN pip install black==25.1.0 flake8==7.2.0 isort==6.0.1
2828
RUN flake8 .
2929
RUN black --exclude=migrations . --check
3030
RUN isort . --check-only
@@ -35,7 +35,7 @@ RUN isort . --check-only
3535
#########
3636

3737
# pull official base image
38-
FROM python:3.12.1-slim-bookworm
38+
FROM python:3.13.3-slim-bookworm
3939

4040
# create directory for the app user
4141
RUN mkdir -p /home/app
@@ -65,7 +65,7 @@ COPY --from=builder /usr/src/app/wheels /wheels
6565
COPY --from=builder /usr/src/app/requirements.txt .
6666
RUN pip install --upgrade pip
6767
RUN pip install --no-cache /wheels/*
68-
RUN pip install "uvicorn[standard]==0.26.0"
68+
RUN pip install "uvicorn[standard]==0.34.1"
6969

7070
# add app
7171
COPY . .

project/app/api/crud.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
from typing import List, Union
22

3-
from app.models.pydantic import SummaryPayloadSchema
43
from app.models.tortoise import TextSummary
54

5+
from app.models.pydantic import ( # isort:skip
6+
SummaryPayloadSchema,
7+
SummaryUpdatePayloadSchema,
8+
)
9+
610

711
async def get(id: int) -> Union[dict, None]:
812
summary = await TextSummary.filter(id=id).first().values()
@@ -22,7 +26,7 @@ async def post(payload: SummaryPayloadSchema) -> int:
2226
return summary.id
2327

2428

25-
async def put(id: int, payload: SummaryPayloadSchema) -> Union[dict, None]:
29+
async def put(id: int, payload: SummaryUpdatePayloadSchema) -> Union[dict, None]:
2630
summary = await TextSummary.filter(id=id).update(
2731
url=payload.url, summary=payload.summary
2832
)

project/app/main.py

+1-10
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,4 @@ def create_application() -> FastAPI:
2020

2121
app = create_application()
2222

23-
24-
@app.on_event("startup")
25-
async def startup_event():
26-
log.info("Starting up...")
27-
init_db(app)
28-
29-
30-
@app.on_event("shutdown")
31-
async def shutdown_event():
32-
log.info("Shutting down...")
23+
init_db(app)

project/app/summarizer.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ async def generate_summary(summary_id: int, url: str) -> None:
1010
article.parse()
1111

1212
try:
13-
nltk.data.find("tokenizers/punkt")
13+
nltk.data.find("tokenizers/punkt_tab")
1414
except LookupError:
15-
nltk.download("punkt")
15+
nltk.download("punkt_tab")
1616
finally:
1717
article.nlp()
1818

project/db/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# pull official base image
2-
FROM postgres:16
2+
FROM postgres:17
33

44
# run create.sql on init
55
ADD create.sql /docker-entrypoint-initdb.d

project/migrations/models/0_20240122171233_init.py renamed to project/migrations/models/0_20250421234125_init.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ async def upgrade(db: BaseDBAsyncClient) -> str:
77
"id" SERIAL NOT NULL PRIMARY KEY,
88
"url" TEXT NOT NULL,
99
"summary" TEXT NOT NULL,
10-
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
10+
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
1111
);
1212
CREATE TABLE IF NOT EXISTS "aerich" (
1313
"id" SERIAL NOT NULL PRIMARY KEY,

project/requirements-dev.txt

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
black==23.12.1
2-
flake8==7.0.0
3-
isort==5.13.2
4-
pytest==7.4.4
5-
pytest-cov==4.1.0
6-
pytest-xdist==3.5.0
1+
black==25.1.0
2+
flake8==7.2.0
3+
isort==6.0.1
4+
pytest==8.3.5
5+
pytest-cov==6.1.1
6+
pytest-xdist==3.6.1
77

88
-r requirements.txt

project/requirements.txt

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
aerich==0.7.2
2-
asyncpg==0.29.0
3-
fastapi==0.109.0
4-
gunicorn==21.0.1
5-
httpx==0.26.0
1+
aerich[toml]==0.8.2
2+
asyncpg==0.30.0
3+
fastapi==0.115.12
4+
gunicorn==22.0.0
5+
httpx==0.28.1
6+
lxml-html-clean==0.4.2
67
newspaper3k==0.2.8
7-
pydantic-settings==2.1.0
8-
tortoise-orm==0.20.0
9-
uvicorn==0.26.0
8+
pydantic-settings==2.8.1
9+
tortoise-orm==0.25.0
10+
uvicorn==0.34.1

project/tests/conftest.py

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ def test_app():
1818
app = create_application()
1919
app.dependency_overrides[get_settings] = get_settings_override
2020
with TestClient(app) as test_client:
21+
2122
# testing
2223
yield test_client
2324

@@ -37,6 +38,7 @@ def test_app_with_db():
3738
add_exception_handlers=True,
3839
)
3940
with TestClient(app) as test_client:
41+
4042
# testing
4143
yield test_client
4244

project/tests/test_summaries.py

+9-16
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ def test_create_summaries_invalid_json(test_app):
2929
"loc": ["body", "url"],
3030
"msg": "Field required",
3131
"type": "missing",
32-
"url": "https://errors.pydantic.dev/2.5/v/missing",
3332
}
3433
]
3534
}
@@ -48,7 +47,7 @@ def mock_generate_summary(summary_id, url):
4847
monkeypatch.setattr(summaries, "generate_summary", mock_generate_summary)
4948

5049
response = test_app_with_db.post(
51-
"/summaries/", data=json.dumps({"url": "https://foo.bar"})
50+
"/summaries/", data=json.dumps({"url": "https://foo.bar/"})
5251
)
5352
summary_id = response.json()["id"]
5453

@@ -76,7 +75,6 @@ def test_read_summary_incorrect_id(test_app_with_db):
7675
"loc": ["path", "id"],
7776
"msg": "Input should be greater than 0",
7877
"type": "greater_than",
79-
"url": "https://errors.pydantic.dev/2.5/v/greater_than",
8078
}
8179
]
8280
}
@@ -89,7 +87,7 @@ def mock_generate_summary(summary_id, url):
8987
monkeypatch.setattr(summaries, "generate_summary", mock_generate_summary)
9088

9189
response = test_app_with_db.post(
92-
"/summaries/", data=json.dumps({"url": "https://foo.bar"})
90+
"/summaries/", data=json.dumps({"url": "https://foo.bar/"})
9391
)
9492
summary_id = response.json()["id"]
9593

@@ -107,7 +105,7 @@ def mock_generate_summary(summary_id, url):
107105
monkeypatch.setattr(summaries, "generate_summary", mock_generate_summary)
108106

109107
response = test_app_with_db.post(
110-
"/summaries/", data=json.dumps({"url": "https://foo.bar"})
108+
"/summaries/", data=json.dumps({"url": "https://foo.bar/"})
111109
)
112110
summary_id = response.json()["id"]
113111

@@ -131,7 +129,6 @@ def test_remove_summary_incorrect_id(test_app_with_db):
131129
"loc": ["path", "id"],
132130
"msg": "Input should be greater than 0",
133131
"type": "greater_than",
134-
"url": "https://errors.pydantic.dev/2.5/v/greater_than",
135132
}
136133
]
137134
}
@@ -144,13 +141,13 @@ def mock_generate_summary(summary_id, url):
144141
monkeypatch.setattr(summaries, "generate_summary", mock_generate_summary)
145142

146143
response = test_app_with_db.post(
147-
"/summaries/", data=json.dumps({"url": "https://foo.bar"})
144+
"/summaries/", data=json.dumps({"url": "https://foo.bar/"})
148145
)
149146
summary_id = response.json()["id"]
150147

151148
response = test_app_with_db.put(
152149
f"/summaries/{summary_id}/",
153-
data=json.dumps({"url": "https://foo.bar", "summary": "updated!"}),
150+
data=json.dumps({"url": "https://foo.bar/", "summary": "updated!"}),
154151
)
155152
assert response.status_code == 200
156153

@@ -166,13 +163,13 @@ def mock_generate_summary(summary_id, url):
166163
[
167164
[
168165
999,
169-
{"url": "https://foo.bar", "summary": "updated!"},
166+
{"url": "https://foo.bar/", "summary": "updated!"},
170167
404,
171168
"Summary not found",
172169
],
173170
[
174171
0,
175-
{"url": "https://foo.bar", "summary": "updated!"},
172+
{"url": "https://foo.bar/", "summary": "updated!"},
176173
422,
177174
[
178175
{
@@ -181,7 +178,6 @@ def mock_generate_summary(summary_id, url):
181178
"msg": "Input should be greater than 0",
182179
"input": "0",
183180
"ctx": {"gt": 0},
184-
"url": "https://errors.pydantic.dev/2.5/v/greater_than",
185181
}
186182
],
187183
],
@@ -195,28 +191,25 @@ def mock_generate_summary(summary_id, url):
195191
"loc": ["body", "url"],
196192
"msg": "Field required",
197193
"input": {},
198-
"url": "https://errors.pydantic.dev/2.5/v/missing",
199194
},
200195
{
201196
"type": "missing",
202197
"loc": ["body", "summary"],
203198
"msg": "Field required",
204199
"input": {},
205-
"url": "https://errors.pydantic.dev/2.5/v/missing",
206200
},
207201
],
208202
],
209203
[
210204
1,
211-
{"url": "https://foo.bar"},
205+
{"url": "https://foo.bar/"},
212206
422,
213207
[
214208
{
215209
"type": "missing",
216210
"loc": ["body", "summary"],
217211
"msg": "Field required",
218-
"input": {"url": "https://foo.bar"},
219-
"url": "https://errors.pydantic.dev/2.5/v/missing",
212+
"input": {"url": "https://foo.bar/"},
220213
}
221214
],
222215
],

project/tests/test_summaries_unit.py

-5
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ def test_create_summaries_invalid_json(test_app):
3939
"loc": ["body", "url"],
4040
"msg": "Field required",
4141
"input": {},
42-
"url": "https://errors.pydantic.dev/2.5/v/missing",
4342
}
4443
]
4544
}
@@ -180,7 +179,6 @@ async def mock_put(id, payload):
180179
"msg": "Input should be greater than 0",
181180
"input": "0",
182181
"ctx": {"gt": 0},
183-
"url": "https://errors.pydantic.dev/2.5/v/greater_than",
184182
}
185183
],
186184
],
@@ -194,14 +192,12 @@ async def mock_put(id, payload):
194192
"loc": ["body", "url"],
195193
"msg": "Field required",
196194
"input": {},
197-
"url": "https://errors.pydantic.dev/2.5/v/missing",
198195
},
199196
{
200197
"type": "missing",
201198
"loc": ["body", "summary"],
202199
"msg": "Field required",
203200
"input": {},
204-
"url": "https://errors.pydantic.dev/2.5/v/missing",
205201
},
206202
],
207203
],
@@ -215,7 +211,6 @@ async def mock_put(id, payload):
215211
"loc": ["body", "summary"],
216212
"msg": "Field required",
217213
"input": {"url": "https://foo.bar"},
218-
"url": "https://errors.pydantic.dev/2.5/v/missing",
219214
}
220215
],
221216
],

0 commit comments

Comments
 (0)