Update dependencies to use httpx2 and refactor tests for compatibility
This commit is contained in:
+2
-2
@@ -4,7 +4,7 @@ import random
|
|||||||
from collections.abc import Awaitable, Callable
|
from collections.abc import Awaitable, Callable
|
||||||
from datetime import UTC, datetime
|
from datetime import UTC, datetime
|
||||||
|
|
||||||
import httpx
|
import httpx2
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from sqlalchemy.ext.asyncio import async_sessionmaker
|
from sqlalchemy.ext.asyncio import async_sessionmaker
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ class WebhookClient:
|
|||||||
self._timeout = timeout
|
self._timeout = timeout
|
||||||
|
|
||||||
async def send(self, url: str, payload: PaymentWebhook) -> None:
|
async def send(self, url: str, payload: PaymentWebhook) -> None:
|
||||||
async with httpx.AsyncClient(timeout=self._timeout) as client:
|
async with httpx2.AsyncClient(timeout=self._timeout) as client:
|
||||||
response = await client.post(url, json=payload.model_dump(mode="json"))
|
response = await client.post(url, json=payload.model_dump(mode="json"))
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ dependencies = [
|
|||||||
"asyncpg>=0.30,<1",
|
"asyncpg>=0.30,<1",
|
||||||
"fastapi>=0.115,<1",
|
"fastapi>=0.115,<1",
|
||||||
"faststream[cli,rabbit]>=0.5.48,<1",
|
"faststream[cli,rabbit]>=0.5.48,<1",
|
||||||
"httpx>=0.28,<1",
|
"httpx2>=2.13,<3",
|
||||||
"pydantic>=2.10,<3",
|
"pydantic>=2.10,<3",
|
||||||
"pydantic-settings>=2.7,<3",
|
"pydantic-settings>=2.7,<3",
|
||||||
"sqlalchemy[asyncio]>=2.0.36,<3",
|
"sqlalchemy[asyncio]>=2.0.36,<3",
|
||||||
|
|||||||
+42
-35
@@ -1,58 +1,65 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
from collections.abc import AsyncIterator
|
||||||
|
|
||||||
|
import httpx2
|
||||||
|
import pytest
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.testclient import TestClient
|
|
||||||
|
|
||||||
from app.api import router
|
from app.api import router
|
||||||
|
|
||||||
|
|
||||||
def make_client() -> TestClient:
|
@pytest.fixture
|
||||||
|
async def client() -> AsyncIterator[httpx2.AsyncClient]:
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
app.include_router(router)
|
app.include_router(router)
|
||||||
return TestClient(app)
|
transport = httpx2.ASGITransport(app=app)
|
||||||
|
async with httpx2.AsyncClient(
|
||||||
|
transport=transport,
|
||||||
|
base_url="http://testserver",
|
||||||
|
) as test_client:
|
||||||
|
yield test_client
|
||||||
|
|
||||||
|
|
||||||
def test_get_payment_requires_api_key() -> None:
|
async def test_get_payment_requires_api_key(client: httpx2.AsyncClient) -> None:
|
||||||
with make_client() as client:
|
response = await client.get(f"/api/v1/payments/{uuid.uuid4()}")
|
||||||
response = client.get(f"/api/v1/payments/{uuid.uuid4()}")
|
|
||||||
|
|
||||||
assert response.status_code == 401
|
assert response.status_code == 401
|
||||||
assert response.json() == {"detail": "Invalid or missing API key"}
|
assert response.json() == {"detail": "Invalid or missing API key"}
|
||||||
|
|
||||||
|
|
||||||
def test_create_payment_requires_idempotency_key() -> None:
|
async def test_create_payment_requires_idempotency_key(client: httpx2.AsyncClient) -> None:
|
||||||
with make_client() as client:
|
response = await client.post(
|
||||||
response = client.post(
|
"/api/v1/payments",
|
||||||
"/api/v1/payments",
|
headers={"X-API-Key": "change-me"},
|
||||||
headers={"X-API-Key": "change-me"},
|
json={
|
||||||
json={
|
"amount": "100.00",
|
||||||
"amount": "100.00",
|
"currency": "RUB",
|
||||||
"currency": "RUB",
|
"description": "Test payment",
|
||||||
"description": "Test payment",
|
"metadata": {},
|
||||||
"metadata": {},
|
"webhook_url": "https://example.com/webhook",
|
||||||
"webhook_url": "https://example.com/webhook",
|
},
|
||||||
},
|
)
|
||||||
)
|
|
||||||
|
|
||||||
assert response.status_code == 422
|
assert response.status_code == 422
|
||||||
assert response.json()["detail"][0]["loc"] == ["header", "Idempotency-Key"]
|
assert response.json()["detail"][0]["loc"] == ["header", "Idempotency-Key"]
|
||||||
|
|
||||||
|
|
||||||
def test_create_payment_rejects_unsupported_currency() -> None:
|
async def test_create_payment_rejects_unsupported_currency(
|
||||||
with make_client() as client:
|
client: httpx2.AsyncClient,
|
||||||
response = client.post(
|
) -> None:
|
||||||
"/api/v1/payments",
|
response = await client.post(
|
||||||
headers={
|
"/api/v1/payments",
|
||||||
"X-API-Key": "change-me",
|
headers={
|
||||||
"Idempotency-Key": "test-key",
|
"X-API-Key": "change-me",
|
||||||
},
|
"Idempotency-Key": "test-key",
|
||||||
json={
|
},
|
||||||
"amount": "100.00",
|
json={
|
||||||
"currency": "GBP",
|
"amount": "100.00",
|
||||||
"description": "Test payment",
|
"currency": "GBP",
|
||||||
"metadata": {},
|
"description": "Test payment",
|
||||||
"webhook_url": "https://example.com/webhook",
|
"metadata": {},
|
||||||
},
|
"webhook_url": "https://example.com/webhook",
|
||||||
)
|
},
|
||||||
|
)
|
||||||
|
|
||||||
assert response.status_code == 422
|
assert response.status_code == 422
|
||||||
|
|||||||
@@ -117,15 +117,6 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/3c/d7/8fb3044eaef08a310acfe23dae9a8e2e07d305edc29a53497e52bc76eca7/asyncpg-0.31.0-cp314-cp314t-win_amd64.whl", hash = "sha256:bd4107bb7cdd0e9e65fae66a62afd3a249663b844fa34d479f6d5b3bef9c04c3", size = 706062, upload-time = "2025-11-24T23:26:44.086Z" },
|
{ url = "https://files.pythonhosted.org/packages/3c/d7/8fb3044eaef08a310acfe23dae9a8e2e07d305edc29a53497e52bc76eca7/asyncpg-0.31.0-cp314-cp314t-win_amd64.whl", hash = "sha256:bd4107bb7cdd0e9e65fae66a62afd3a249663b844fa34d479f6d5b3bef9c04c3", size = 706062, upload-time = "2025-11-24T23:26:44.086Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "certifi"
|
|
||||||
version = "2026.7.22"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "click"
|
name = "click"
|
||||||
version = "8.5.0"
|
version = "8.5.0"
|
||||||
@@ -278,16 +269,16 @@ wheels = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httpcore"
|
name = "httpcore2"
|
||||||
version = "1.0.9"
|
version = "2.13.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "certifi" },
|
|
||||||
{ name = "h11" },
|
{ name = "h11" },
|
||||||
|
{ name = "truststore" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/15/8c/e925b1c92018abb3a1863ce1549d76d2381e334d21d65d4ac8f65dabd78a/httpcore2-2.13.0.tar.gz", hash = "sha256:2adc8be4fb285fbcd6d894298db3b52c177e74b6674eda3a76bd36be3292a3db", size = 67740, upload-time = "2026-09-14T14:18:04.717Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
|
{ url = "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl", hash = "sha256:35ae5be347aa40467b4a5dc032ac67ebb6d27189fc97e8cebcf99616f6a1bb9e", size = 83162, upload-time = "2026-09-14T14:18:02.529Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -327,18 +318,29 @@ wheels = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httpx"
|
name = "httpx2"
|
||||||
version = "0.28.1"
|
version = "2.13.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "anyio" },
|
{ name = "anyio", marker = "sys_platform != 'emscripten'" },
|
||||||
{ name = "certifi" },
|
{ name = "httpcore2", marker = "sys_platform != 'emscripten'" },
|
||||||
{ name = "httpcore" },
|
{ name = "httpx2-jsfetch", marker = "sys_platform == 'emscripten'" },
|
||||||
{ name = "idna" },
|
{ name = "idna" },
|
||||||
|
{ name = "truststore", marker = "sys_platform != 'emscripten'" },
|
||||||
|
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/b9/a0/e9deef4654132857b5a5dbe4eddd0ac59c2814500e11f2f5044cd81103ee/httpx2-2.13.0.tar.gz", hash = "sha256:81bd07dc67a3701729ef1f777a3c00c915d4539604fdb5afd327f8682f6b7b44", size = 100290, upload-time = "2026-09-14T14:18:05.486Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
|
{ url = "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl", hash = "sha256:fc12720cedf72faa26cca6b4ca394e05c894e7d7933fc45cafe767960804e49a", size = 95565, upload-time = "2026-09-14T14:18:03.553Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpx2-jsfetch"
|
||||||
|
version = "1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/cd/c4/0e5636363151a2a1795e0a77617168b9ca438e1748ec05fc9b5687f93d64/httpx2_jsfetch-1.0.tar.gz", hash = "sha256:70a0e3eabfef7cce5ad9c629f7d01ca05e418f586646f4ddf14782e4c1454c60", size = 6872, upload-time = "2026-08-07T00:13:07.492Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9b/43/832f631d32e4f1211caa2ba368317739fe71f0b8530e4c9d15dc454bac2a/httpx2_jsfetch-1.0-py3-none-any.whl", hash = "sha256:cb916b707601e69a07721aabc8f3f6659be3a6893bc1ff5c6f9e02241df2da32", size = 6382, upload-time = "2026-08-07T00:13:06.567Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -620,7 +622,7 @@ dependencies = [
|
|||||||
{ name = "asyncpg" },
|
{ name = "asyncpg" },
|
||||||
{ name = "fastapi" },
|
{ name = "fastapi" },
|
||||||
{ name = "faststream", extra = ["cli", "rabbit"] },
|
{ name = "faststream", extra = ["cli", "rabbit"] },
|
||||||
{ name = "httpx" },
|
{ name = "httpx2" },
|
||||||
{ name = "pydantic" },
|
{ name = "pydantic" },
|
||||||
{ name = "pydantic-settings" },
|
{ name = "pydantic-settings" },
|
||||||
{ name = "sqlalchemy", extra = ["asyncio"] },
|
{ name = "sqlalchemy", extra = ["asyncio"] },
|
||||||
@@ -641,7 +643,7 @@ requires-dist = [
|
|||||||
{ name = "asyncpg", specifier = ">=0.30,<1" },
|
{ name = "asyncpg", specifier = ">=0.30,<1" },
|
||||||
{ name = "fastapi", specifier = ">=0.115,<1" },
|
{ name = "fastapi", specifier = ">=0.115,<1" },
|
||||||
{ name = "faststream", extras = ["cli", "rabbit"], specifier = ">=0.5.48,<1" },
|
{ name = "faststream", extras = ["cli", "rabbit"], specifier = ">=0.5.48,<1" },
|
||||||
{ name = "httpx", specifier = ">=0.28,<1" },
|
{ name = "httpx2", specifier = ">=2.13,<3" },
|
||||||
{ name = "pydantic", specifier = ">=2.10,<3" },
|
{ name = "pydantic", specifier = ">=2.10,<3" },
|
||||||
{ name = "pydantic-settings", specifier = ">=2.7,<3" },
|
{ name = "pydantic-settings", specifier = ">=2.7,<3" },
|
||||||
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8.3,<9" },
|
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8.3,<9" },
|
||||||
@@ -1075,6 +1077,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl", hash = "sha256:a86dd39d14bb45f85a3d18525215a9ef0cfd1f192ac793220e72598c90335f0c", size = 75969, upload-time = "2026-08-08T18:27:56.196Z" },
|
{ url = "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl", hash = "sha256:a86dd39d14bb45f85a3d18525215a9ef0cfd1f192ac793220e72598c90335f0c", size = 75969, upload-time = "2026-08-08T18:27:56.196Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "truststore"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/53/a3/1585216310e344e8102c22482f6060c7a6ea0322b63e026372e6dcefcfd6/truststore-0.10.4.tar.gz", hash = "sha256:9d91bd436463ad5e4ee4aba766628dd6cd7010cf3e2461756b3303710eebc301", size = 26169, upload-time = "2025-08-12T18:49:02.73Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl", hash = "sha256:adaeaecf1cbb5f4de3b1959b42d41f6fab57b2b1666adb59e89cb0b53361d981", size = 18660, upload-time = "2025-08-12T18:49:01.46Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ty"
|
name = "ty"
|
||||||
version = "0.0.81"
|
version = "0.0.81"
|
||||||
|
|||||||
Reference in New Issue
Block a user