Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update FastAPI 0.87.0 → 0.95.1 #31

Merged
merged 1 commit into from
May 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions dearmep/main.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import logging
from typing import Optional

from fastapi import FastAPI
from prometheus_fastapi_instrumentator import Instrumentator
from pydantic import ValidationError
from starlette_exporter import PrometheusMiddleware, handle_metrics
from starlette_exporter.optional_metrics import request_body_size, \
response_body_size
from yaml.parser import ParserError

from . import __version__, static_files
Expand Down Expand Up @@ -49,13 +52,15 @@ def create_app(config_dict: Optional[dict] = None) -> FastAPI:
version=__version__,
)

@app.on_event("startup")
def prometheus_instrument():
Instrumentator(
should_group_status_codes=False,
).instrument(app).expose(app)

app.include_router(api_v1.router, prefix="/api/v1")
static_files.mount_if_configured(app, "/static")

app.add_middleware(
PrometheusMiddleware,
app_name=APP_NAME,
group_paths=True,
optional_metrics=[request_body_size, response_body_size],
)
app.add_route("/metrics", handle_metrics)

return app
54 changes: 27 additions & 27 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ dearmep = "dearmep.cli:run"

[tool.poetry.dependencies]
python = "^3.8"
fastapi = "^0.87"
prometheus-fastapi-instrumentator = "^5.9.1"
fastapi = "^0.95.1"
PyYAML = "^6.0"
limits = "^3.3.1"
lzip = "^1.2.0"
Expand All @@ -23,6 +22,7 @@ defusedxml = "^0.7.1"
httpx = ">=0.23"
uvicorn = {extras = ["standard"], version = "^0.21.1"}
python-geoacumen = ">=2023"
starlette-exporter = "^0.15.1"

[tool.poetry.group.dev.dependencies]
flake8 = "^4.0.1"
Expand Down
36 changes: 10 additions & 26 deletions tests/test_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,19 @@
from fastapi.testclient import TestClient
import pytest

from conftest import fastapi_app_func, fastapi_factory_func
from dearmep.config import APP_NAME


# If we initialize the Prometheus instrumentator more than once, it will create
# duplicate timeseries, which is not allowed. Therefore, we only get to call
# this once.
@pytest.fixture(scope="session")
def prom_client():
# We can't simply use the fastapi_app fixture because its scope is
# per-function, not per-session.
with fastapi_factory_func() as start:
with fastapi_app_func(start) as app:
client = TestClient(app)

with client as client_with_events:
# The `with` causes `@app.on_event("startup")` code to run.
# <https://fastapi.tiangolo.com/advanced/testing-events/>
yield client_with_events


def metrics_lines_func(prom_client: TestClient) -> Iterable[str]:
res = prom_client.get("/metrics")
def metrics_lines_func(client: TestClient) -> Iterable[str]:
res = client.get("/metrics")
assert res.status_code == status.HTTP_200_OK
for line in res.iter_lines():
yield str(line).rstrip("\r\n")


@pytest.fixture
def metrics_lines(prom_client: TestClient):
yield list(metrics_lines_func(prom_client))
def metrics_lines(client: TestClient):
yield list(metrics_lines_func(client))


def test_python_info_in_metrics(metrics_lines: Iterable[str]):
Expand All @@ -45,14 +28,15 @@ def test_python_info_in_metrics(metrics_lines: Iterable[str]):
]


def test_non_grouped_status_codes(prom_client: TestClient):
def test_non_grouped_status_codes(client: TestClient):
# Do a throwaway request in order to have at least one request in the
# metrics when doing the actual test.
assert prom_client.get("/metrics").status_code == status.HTTP_200_OK
assert client.get("/metrics").status_code == status.HTTP_200_OK

mark = 'http_requests_total{handler="/metrics",method="GET",status="200"} '
mark = f'starlette_requests_total{{app_name="{APP_NAME}",method="GET",' \
+ 'path="/metrics",status_code="200"} '
assert [
line
for line in metrics_lines_func(prom_client)
for line in metrics_lines_func(client)
if line.startswith(mark)
]