Skip to content
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
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.12.10
3.14.3
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Set default values for build arguments
ARG PARENT_VERSION=latest-3.12
ARG PARENT_VERSION=2.2.1-python3.14.3
ARG PORT=8085
ARG PORT_DEBUG=8086

Expand Down
24 changes: 0 additions & 24 deletions app/common/http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,6 @@

logger = getLogger(__name__)

async_proxy_mounts = (
{
"http://": httpx.AsyncHTTPTransport(proxy=str(config.http_proxy)),
"https://": httpx.AsyncHTTPTransport(proxy=str(config.http_proxy)),
}
if config.http_proxy
else {}
)

sync_proxy_mounts = (
{
"http://": httpx.HTTPTransport(proxy=str(config.http_proxy)),
"https://": httpx.HTTPTransport(proxy=str(config.http_proxy)),
}
if config.http_proxy
else {}
)


async def async_hook_request_tracing(request):
trace_id = ctx_trace_id.get(None)
Expand Down Expand Up @@ -53,9 +35,6 @@ def create_async_client(request_timeout: int = 30) -> httpx.AsyncClient:
"event_hooks": {"request": [async_hook_request_tracing]},
}

if config.http_proxy:
client_kwargs["mounts"] = async_proxy_mounts

return httpx.AsyncClient(**client_kwargs)


Expand All @@ -74,7 +53,4 @@ def create_client(request_timeout: int = 30) -> httpx.Client:
"event_hooks": {"request": [hook_request_tracing]},
}

if config.http_proxy:
client_kwargs["mounts"] = sync_proxy_mounts

return httpx.Client(**client_kwargs)
24 changes: 0 additions & 24 deletions app/common/test_http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,3 @@ def test_trace_id_set():
)
resp = client.get("http://localhost:1234/test")
assert resp.text == "trace-id-value"


def test_create_client_with_proxy(monkeypatch):
import importlib

from pydantic import HttpUrl

# Set http_proxy config before reloading http_client
monkeypatch.setattr(
"app.config.config.http_proxy", HttpUrl("http://proxy.example.com:8080")
)

# Reload the http_client module to trigger creation of proxy_mounts with HttpUrl set
# This would fail with the old code (AttributeError: 'HttpUrl' object has no attribute 'url')
import app.common.http_client

importlib.reload(app.common.http_client)

# Verify clients can be created
client = app.common.http_client.create_client()
assert client is not None

async_client = app.common.http_client.create_async_client()
assert async_client is not None
4 changes: 4 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from contextlib import asynccontextmanager
from logging import getLogger

Expand Down Expand Up @@ -36,6 +37,9 @@ async def lifespan(_: FastAPI):


def main() -> None: # pragma: no cover
os.environ["HTTP_PROXY"] = str(config.http_proxy)
os.environ["HTTPS_PROXY"] = str(config.http_proxy)

uvicorn.run(
"app.main:app",
host=config.host,
Expand Down
44 changes: 43 additions & 1 deletion app/test_main.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import os

from fastapi.testclient import TestClient

import app.main as main_mod

from .main import app

client = TestClient(app)


def test_lifespan(mocker):
mock_mongo_client = mocker.AsyncMock()
mock_get_mongo = mocker.patch("app.main.get_mongo_client", return_value=mock_mongo_client)
mock_get_mongo = mocker.patch(
"app.main.get_mongo_client", return_value=mock_mongo_client
)

# Using TestClient as a context manager triggers lifespan startup/shutdown
with TestClient(app):
Expand All @@ -31,3 +37,39 @@ def test_health():
def test_root():
response = client.get("/")
assert response.status_code == 404


def test_main_sets_proxy_envs(mocker, monkeypatch):
mocker.patch("app.main.uvicorn.run")

monkeypatch.delenv("HTTP_PROXY", raising=False)
monkeypatch.delenv("HTTPS_PROXY", raising=False)

monkeypatch.setattr(main_mod.config, "http_proxy", "http://proxy:8080")
monkeypatch.setattr(main_mod.config, "host", "127.0.0.1")
monkeypatch.setattr(main_mod.config, "port", 9000)
monkeypatch.setattr(main_mod.config, "log_config", None)
monkeypatch.setattr(main_mod.config, "python_env", "production")

main_mod.main()

assert os.environ.get("HTTP_PROXY") == "http://proxy:8080"
assert os.environ.get("HTTPS_PROXY") == "http://proxy:8080"


def test_main_no_proxy_in_config(mocker, monkeypatch):
mocker.patch("app.main.uvicorn.run")

monkeypatch.delenv("HTTP_PROXY", raising=False)
monkeypatch.delenv("HTTPS_PROXY", raising=False)

monkeypatch.setattr(main_mod.config, "http_proxy", None)
monkeypatch.setattr(main_mod.config, "host", "127.0.0.1")
monkeypatch.setattr(main_mod.config, "port", 8086)
monkeypatch.setattr(main_mod.config, "log_config", None)
monkeypatch.setattr(main_mod.config, "python_env", "production")

main_mod.main()

assert os.environ.get("HTTP_PROXY") == "None"
assert os.environ.get("HTTPS_PROXY") == "None"
7 changes: 3 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ name = "cdp-python-backend-template"
version = "0.1.0"
description = "CDP Python Backend Template"
readme = "README.md"
requires-python = ">=3.12"
requires-python = ">=3.14"
dependencies = [
"asgi-logger==0.1.0",
"aws-embedded-metrics==3.3.0",
"dnspython==2.7.0",
"ecs-logging==2.2.0",
"fastapi==0.115.12",
"fastapi==0.129.0",
"httpx==0.28.1",
"pydantic-settings==2.9.1",
"pymongo[aws,encryption,snappy,zstd]==4.13.1",
Expand All @@ -18,12 +18,11 @@ dependencies = [

[dependency-groups]
dev = [
"httpx==0.28.1",
"pre-commit==4.2.0",
"pytest==8.4.0",
"pytest-asyncio==1.0.0",
"pytest-cov==6.2.1",
"pytest-mock>=3.15.1",
"pytest-mock==3.15.1",
"ruff==0.11.13",
"taskipy==1.14.1",
]
Expand Down
3 changes: 2 additions & 1 deletion sonar-project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ sonar.exclusions=app/**/test_*.py
sonar.tests=tests/
sonar.test.inclusions=app/**/test_*.py

sonar.javascript.lcov.reportPaths=./coverage/lcov.info
sonar.python.version=3.14
sonar.python.lcov.reportPaths=./coverage/lcov.info
Loading