From 6d6b25f41b3aa360f9e58b36a7bd38fe1690d15d Mon Sep 17 00:00:00 2001 From: Roberto Sanchez Date: Thu, 9 Apr 2026 13:05:43 -0600 Subject: [PATCH] Update health check URL and improve code formatting - Updated health check URL in CI/CD workflow to include port 8000. - Reformatted code in various files for improved readability, including function definitions and import statements. - Ensured consistent use of multi-line formatting for long lines in schemas and routes. --- .github/workflows/cd.yml | 4 +- apps/api/app/main.py | 6 +- apps/api/app/routes/email.py | 11 +++- apps/api/app/routes/health.py | 4 +- apps/api/app/routes/payments.py | 10 ++- apps/api/app/routes/webhooks.py | 7 ++- apps/api/app/schemas/email.py | 7 ++- apps/api/app/schemas/payment.py | 13 +++- apps/api/app/schemas/webhook.py | 2 +- .../tests/integration/test_webhooks_api.py | 5 +- apps/api/tests/unit/test_email_models.py | 40 +++++++----- .../tests/unit/test_error_normalization.py | 6 +- apps/api/tests/unit/test_payment_models.py | 3 +- apps/api/tests/unit/test_sendgrid_adapter.py | 24 +++++--- apps/api/tests/unit/test_stripe_adapter.py | 2 +- apps/api/tests/unit/test_webhook_utils.py | 61 +++++++++++-------- infra/terraform/outputs.tf | 6 +- .../adapter_core/adapter_core/errors/base.py | 4 +- .../adapter_core/interfaces/__init__.py | 2 +- .../adapter_core/models/__init__.py | 10 +-- .../adapter_core/adapter_core/models/email.py | 2 +- .../adapter_core/models/payment.py | 8 ++- .../adapter_core/models/webhook.py | 4 +- .../providers/email/postmark_adapter.py | 4 +- .../providers/email/sendgrid_adapter.py | 8 ++- .../providers/payments/paypal_adapter.py | 18 ++++-- .../providers/payments/stripe_adapter.py | 11 ++-- .../adapter_core/adapter_core/utils/retry.py | 5 +- 28 files changed, 180 insertions(+), 107 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 7136beb..c50cf5c 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -93,10 +93,10 @@ jobs: - name: Wait for health check run: | - echo "Waiting for application to start at http://${{ steps.ec2_ip.outputs.ip }}/health ..." + echo "Waiting for application to start at http://${{ steps.ec2_ip.outputs.ip }}:8000/health ..." for i in $(seq 1 20); do STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ - "http://${{ steps.ec2_ip.outputs.ip }}/health" || echo "000") + "http://${{ steps.ec2_ip.outputs.ip }}:8000/health" || echo "000") if [ "$STATUS" = "200" ]; then echo "Health check passed!" exit 0 diff --git a/apps/api/app/main.py b/apps/api/app/main.py index 4569e75..a8746f1 100644 --- a/apps/api/app/main.py +++ b/apps/api/app/main.py @@ -4,7 +4,7 @@ from adapter_core.errors.base import AdapterError, ErrorResponse from app.limiter import limiter -from app.routes import health, payments, email, webhooks +from app.routes import email, health, payments, webhooks app = FastAPI( title="OpenAdapter API", @@ -20,7 +20,9 @@ @app.exception_handler(RateLimitExceeded) -async def openadapter_rate_limit_handler(_request: Request, _exc: RateLimitExceeded) -> JSONResponse: +async def openadapter_rate_limit_handler( + _request: Request, _exc: RateLimitExceeded +) -> JSONResponse: return JSONResponse( status_code=429, content={ diff --git a/apps/api/app/routes/email.py b/apps/api/app/routes/email.py index 2d6bd34..959574f 100644 --- a/apps/api/app/routes/email.py +++ b/apps/api/app/routes/email.py @@ -1,8 +1,11 @@ from fastapi import APIRouter, Depends, HTTPException, Request, status from adapter_core.errors.base import AdapterError, ErrorResponse -from adapter_core.models.email import EmailStatusResponse, SendEmailResponse -from adapter_core.models.email import SendEmailRequest +from adapter_core.models.email import ( + EmailStatusResponse, + SendEmailRequest, + SendEmailResponse, +) from app.config import Settings, get_settings from app.limiter import api_rate_limit, limiter from app.schemas.email import SendEmailRequestBody @@ -26,7 +29,9 @@ def _adapter_error_to_http(exc: AdapterError) -> HTTPException: ) -@router.post("/send", response_model=SendEmailResponse, status_code=status.HTTP_202_ACCEPTED) +@router.post( + "/send", response_model=SendEmailResponse, status_code=status.HTTP_202_ACCEPTED +) @limiter.limit(api_rate_limit) async def send_email( request: Request, # noqa: ARG001 diff --git a/apps/api/app/routes/health.py b/apps/api/app/routes/health.py index 7a0160c..a1e65c6 100644 --- a/apps/api/app/routes/health.py +++ b/apps/api/app/routes/health.py @@ -25,6 +25,8 @@ async def health() -> HealthResponse: return HealthResponse(status="healthy", version="1.0.0", environment="production") -@router.get("/providers", response_model=ProvidersResponse, summary="List supported providers") +@router.get( + "/providers", response_model=ProvidersResponse, summary="List supported providers" +) async def providers() -> ProvidersResponse: return ProvidersResponse(**SUPPORTED_PROVIDERS) diff --git a/apps/api/app/routes/payments.py b/apps/api/app/routes/payments.py index b1f687f..afcc2d0 100644 --- a/apps/api/app/routes/payments.py +++ b/apps/api/app/routes/payments.py @@ -1,7 +1,11 @@ from fastapi import APIRouter, Depends, HTTPException, Request, status from adapter_core.errors.base import AdapterError, ErrorResponse -from adapter_core.models.payment import ChargeResponse, PaymentDetailsResponse, RefundResponse +from adapter_core.models.payment import ( + ChargeResponse, + PaymentDetailsResponse, + RefundResponse, +) from app.config import Settings, get_settings from app.limiter import api_rate_limit, limiter from app.schemas.payment import ChargeRequestBody, RefundRequestBody @@ -25,7 +29,9 @@ def _adapter_error_to_http(exc: AdapterError) -> HTTPException: ) -@router.post("/charge", response_model=ChargeResponse, status_code=status.HTTP_201_CREATED) +@router.post( + "/charge", response_model=ChargeResponse, status_code=status.HTTP_201_CREATED +) @limiter.limit(api_rate_limit) async def charge( request: Request, # noqa: ARG001 diff --git a/apps/api/app/routes/webhooks.py b/apps/api/app/routes/webhooks.py index 7390ddd..fc8ea15 100644 --- a/apps/api/app/routes/webhooks.py +++ b/apps/api/app/routes/webhooks.py @@ -1,11 +1,10 @@ from fastapi import APIRouter, Depends, HTTPException, Request, status -from adapter_core.errors.base import AdapterError, ErrorCode +from adapter_core.errors.base import ErrorCode from adapter_core.models.webhook import NormalizedWebhookEvent from adapter_core.utils.webhook import ( normalize_event_type, verify_stripe_signature, - verify_hmac_sha256, ) from app.config import Settings, get_settings @@ -49,6 +48,7 @@ async def receive_payment_webhook( payload = request.app.state # placeholder — parse body below try: import json + payload = json.loads(body) except Exception: raise HTTPException(status_code=400, detail="Invalid JSON body") @@ -65,6 +65,7 @@ async def receive_payment_webhook( elif provider == "paypal": try: import json + payload = json.loads(body) except Exception: raise HTTPException(status_code=400, detail="Invalid JSON body") @@ -91,6 +92,7 @@ async def receive_email_webhook( if provider == "sendgrid": try: import json + events = json.loads(body) if not isinstance(events, list): events = [events] @@ -117,6 +119,7 @@ async def receive_email_webhook( raise _verification_failed_exc(provider) try: import json + payload = json.loads(body) except Exception: raise HTTPException(status_code=400, detail="Invalid JSON body") diff --git a/apps/api/app/schemas/email.py b/apps/api/app/schemas/email.py index d424f0e..c6d0020 100644 --- a/apps/api/app/schemas/email.py +++ b/apps/api/app/schemas/email.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel, Field, ConfigDict +from pydantic import BaseModel, ConfigDict, Field from adapter_core.models.email import EmailStatusResponse, SendEmailResponse @@ -8,7 +8,10 @@ class SendEmailRequestBody(BaseModel): model_config = ConfigDict(populate_by_name=True) - provider: str | None = Field(default=None, description="Provider override; defaults to DEFAULT_EMAIL_PROVIDER") + provider: str | None = Field( + default=None, + description="Provider override; defaults to DEFAULT_EMAIL_PROVIDER", + ) to: list[str] sender: str = Field(..., alias="from") subject: str diff --git a/apps/api/app/schemas/payment.py b/apps/api/app/schemas/payment.py index a26fbad..7e3dc7f 100644 --- a/apps/api/app/schemas/payment.py +++ b/apps/api/app/schemas/payment.py @@ -10,8 +10,13 @@ class ChargeRequestBody(BaseModel): """API request body for POST /payments/charge.""" - provider: str | None = Field(default=None, description="Provider override; defaults to DEFAULT_PAYMENT_PROVIDER") - amount: int = Field(..., description="Amount in smallest currency unit (e.g. cents)") + provider: str | None = Field( + default=None, + description="Provider override; defaults to DEFAULT_PAYMENT_PROVIDER", + ) + amount: int = Field( + ..., description="Amount in smallest currency unit (e.g. cents)" + ) currency: str = Field(default="USD") customer_email: str source_token: str @@ -23,7 +28,9 @@ class RefundRequestBody(BaseModel): provider: str | None = None transaction_id: str - amount: int | None = Field(default=None, description="Partial refund amount; omit for full refund") + amount: int | None = Field( + default=None, description="Partial refund amount; omit for full refund" + ) reason: str | None = None diff --git a/apps/api/app/schemas/webhook.py b/apps/api/app/schemas/webhook.py index e02ac62..3cfced4 100644 --- a/apps/api/app/schemas/webhook.py +++ b/apps/api/app/schemas/webhook.py @@ -1,4 +1,4 @@ -from adapter_core.models.webhook import NormalizedWebhookEvent from adapter_core.errors.base import ErrorResponse +from adapter_core.models.webhook import NormalizedWebhookEvent __all__ = ["NormalizedWebhookEvent", "ErrorResponse"] diff --git a/apps/api/tests/integration/test_webhooks_api.py b/apps/api/tests/integration/test_webhooks_api.py index e9f872d..05a8832 100644 --- a/apps/api/tests/integration/test_webhooks_api.py +++ b/apps/api/tests/integration/test_webhooks_api.py @@ -48,7 +48,10 @@ def test_stripe_webhook_invalid_signature(client: TestClient) -> None: response = client.post( "/webhooks/payments/stripe", content=body, - headers={"stripe-signature": "t=123,v1=badsig", "content-type": "application/json"}, + headers={ + "stripe-signature": "t=123,v1=badsig", + "content-type": "application/json", + }, ) assert response.status_code == 401 diff --git a/apps/api/tests/unit/test_email_models.py b/apps/api/tests/unit/test_email_models.py index 25e376d..230520f 100644 --- a/apps/api/tests/unit/test_email_models.py +++ b/apps/api/tests/unit/test_email_models.py @@ -1,17 +1,23 @@ import pytest from pydantic import ValidationError -from adapter_core.models.email import SendEmailRequest, SendEmailResponse, EmailStatusResponse +from adapter_core.models.email import ( + EmailStatusResponse, + SendEmailRequest, + SendEmailResponse, +) def test_send_email_request_via_alias() -> None: - req = SendEmailRequest.model_validate({ - "provider": "sendgrid", - "to": ["user@example.com"], - "from": "team@openadapter.dev", - "subject": "Hello", - "text": "World", - }) + req = SendEmailRequest.model_validate( + { + "provider": "sendgrid", + "to": ["user@example.com"], + "from": "team@openadapter.dev", + "subject": "Hello", + "text": "World", + } + ) assert req.sender == "team@openadapter.dev" assert req.to == ["user@example.com"] @@ -28,12 +34,14 @@ def test_send_email_request_via_field_name() -> None: def test_send_email_request_missing_required() -> None: with pytest.raises(ValidationError): - SendEmailRequest.model_validate({ - "provider": "sendgrid", - "to": ["a@b.com"], - # missing "from" / sender - "subject": "Hi", - }) + SendEmailRequest.model_validate( + { + "provider": "sendgrid", + "to": ["a@b.com"], + # missing "from" / sender + "subject": "Hi", + } + ) def test_send_email_response_defaults() -> None: @@ -42,7 +50,9 @@ def test_send_email_response_defaults() -> None: def test_email_status_response_optional_fields() -> None: - resp = EmailStatusResponse(provider="postmark", message_id="abc", status="delivered") + resp = EmailStatusResponse( + provider="postmark", message_id="abc", status="delivered" + ) assert resp.submitted_at is None diff --git a/apps/api/tests/unit/test_error_normalization.py b/apps/api/tests/unit/test_error_normalization.py index 828d8e6..23d56a2 100644 --- a/apps/api/tests/unit/test_error_normalization.py +++ b/apps/api/tests/unit/test_error_normalization.py @@ -1,11 +1,9 @@ -import pytest - from adapter_core.errors.base import ( + HTTP_STATUS_ERROR_MAP, + RETRYABLE_CODES, AdapterError, ErrorCode, ErrorResponse, - HTTP_STATUS_ERROR_MAP, - RETRYABLE_CODES, ) diff --git a/apps/api/tests/unit/test_payment_models.py b/apps/api/tests/unit/test_payment_models.py index 534bd12..b596dbf 100644 --- a/apps/api/tests/unit/test_payment_models.py +++ b/apps/api/tests/unit/test_payment_models.py @@ -4,9 +4,8 @@ from adapter_core.models.payment import ( ChargeRequest, ChargeResponse, - RefundRequest, - RefundResponse, PaymentDetailsResponse, + RefundRequest, ) diff --git a/apps/api/tests/unit/test_sendgrid_adapter.py b/apps/api/tests/unit/test_sendgrid_adapter.py index 9bdea6c..bd31656 100644 --- a/apps/api/tests/unit/test_sendgrid_adapter.py +++ b/apps/api/tests/unit/test_sendgrid_adapter.py @@ -1,6 +1,6 @@ +import httpx import pytest import respx -import httpx from adapter_core.errors.base import AdapterError, ErrorCode from adapter_core.models.email import SendEmailRequest @@ -12,13 +12,15 @@ @pytest.fixture def email_payload() -> SendEmailRequest: - return SendEmailRequest.model_validate({ - "provider": "sendgrid", - "to": ["user@example.com"], - "from": "team@openadapter.dev", - "subject": "Hello", - "text": "World", - }) + return SendEmailRequest.model_validate( + { + "provider": "sendgrid", + "to": ["user@example.com"], + "from": "team@openadapter.dev", + "subject": "Hello", + "text": "World", + } + ) @respx.mock @@ -71,7 +73,11 @@ async def test_get_message_success() -> None: respx.get(f"{SG_BASE}/messages/msg_abc").mock( return_value=httpx.Response( 200, - json={"msg_id": "msg_abc", "status": "delivered", "last_event_time": "2024-01-01T00:00:00Z"}, + json={ + "msg_id": "msg_abc", + "status": "delivered", + "last_event_time": "2024-01-01T00:00:00Z", + }, ) ) result = await ADAPTER.get_message("msg_abc") diff --git a/apps/api/tests/unit/test_stripe_adapter.py b/apps/api/tests/unit/test_stripe_adapter.py index 3ea7532..55c0a10 100644 --- a/apps/api/tests/unit/test_stripe_adapter.py +++ b/apps/api/tests/unit/test_stripe_adapter.py @@ -1,6 +1,6 @@ +import httpx import pytest import respx -import httpx from adapter_core.errors.base import AdapterError, ErrorCode from adapter_core.models.payment import ChargeRequest, RefundRequest diff --git a/apps/api/tests/unit/test_webhook_utils.py b/apps/api/tests/unit/test_webhook_utils.py index d056842..1b6fe03 100644 --- a/apps/api/tests/unit/test_webhook_utils.py +++ b/apps/api/tests/unit/test_webhook_utils.py @@ -1,6 +1,5 @@ import hashlib import hmac -import json import time import pytest @@ -9,10 +8,6 @@ normalize_event_type, verify_hmac_sha256, verify_stripe_signature, - STRIPE_EVENT_MAP, - PAYPAL_EVENT_MAP, - SENDGRID_EVENT_MAP, - POSTMARK_EVENT_MAP, ) @@ -59,39 +54,51 @@ def test_verify_stripe_signature_malformed_header() -> None: assert verify_stripe_signature(b"data", "not-a-valid-header", "secret") is False -@pytest.mark.parametrize("raw,expected", [ - ("payment_intent.succeeded", "payment.succeeded"), - ("payment_intent.payment_failed", "payment.failed"), - ("charge.refunded", "payment.refunded"), - ("unknown_event", "stripe.unknown_event"), -]) +@pytest.mark.parametrize( + "raw,expected", + [ + ("payment_intent.succeeded", "payment.succeeded"), + ("payment_intent.payment_failed", "payment.failed"), + ("charge.refunded", "payment.refunded"), + ("unknown_event", "stripe.unknown_event"), + ], +) def test_normalize_stripe_event(raw: str, expected: str) -> None: assert normalize_event_type("stripe", raw) == expected -@pytest.mark.parametrize("raw,expected", [ - ("PAYMENT.CAPTURE.COMPLETED", "payment.succeeded"), - ("PAYMENT.CAPTURE.DENIED", "payment.failed"), - ("unknown", "paypal.unknown"), -]) +@pytest.mark.parametrize( + "raw,expected", + [ + ("PAYMENT.CAPTURE.COMPLETED", "payment.succeeded"), + ("PAYMENT.CAPTURE.DENIED", "payment.failed"), + ("unknown", "paypal.unknown"), + ], +) def test_normalize_paypal_event(raw: str, expected: str) -> None: assert normalize_event_type("paypal", raw) == expected -@pytest.mark.parametrize("raw,expected", [ - ("delivered", "email.delivered"), - ("bounce", "email.bounced"), - ("open", "email.opened"), - ("unknown_ev", "sendgrid.unknown_ev"), -]) +@pytest.mark.parametrize( + "raw,expected", + [ + ("delivered", "email.delivered"), + ("bounce", "email.bounced"), + ("open", "email.opened"), + ("unknown_ev", "sendgrid.unknown_ev"), + ], +) def test_normalize_sendgrid_event(raw: str, expected: str) -> None: assert normalize_event_type("sendgrid", raw) == expected -@pytest.mark.parametrize("raw,expected", [ - ("Delivery", "email.delivered"), - ("Bounce", "email.bounced"), - ("unknown", "postmark.unknown"), -]) +@pytest.mark.parametrize( + "raw,expected", + [ + ("Delivery", "email.delivered"), + ("Bounce", "email.bounced"), + ("unknown", "postmark.unknown"), + ], +) def test_normalize_postmark_event(raw: str, expected: str) -> None: assert normalize_event_type("postmark", raw) == expected diff --git a/infra/terraform/outputs.tf b/infra/terraform/outputs.tf index ddfb7cf..1f63fb4 100644 --- a/infra/terraform/outputs.tf +++ b/infra/terraform/outputs.tf @@ -9,11 +9,11 @@ output "instance_id" { } output "api_url" { - description = "Base URL of the deployed OpenAdapter API" - value = "http://${aws_eip.openadapter.public_ip}" + description = "Base URL of the deployed OpenAdapter API (container listens on 8000)" + value = "http://${aws_eip.openadapter.public_ip}:8000" } output "health_check_url" { description = "Health check endpoint" - value = "http://${aws_eip.openadapter.public_ip}/health" + value = "http://${aws_eip.openadapter.public_ip}:8000/health" } diff --git a/packages/adapter_core/adapter_core/errors/base.py b/packages/adapter_core/adapter_core/errors/base.py index 19538b2..0ad6c65 100644 --- a/packages/adapter_core/adapter_core/errors/base.py +++ b/packages/adapter_core/adapter_core/errors/base.py @@ -44,7 +44,9 @@ def __init__( self.code = ErrorCode(code) if isinstance(code, str) else code self.message = message self.provider = provider - self.retryable = retryable if retryable is not None else self.code in RETRYABLE_CODES + self.retryable = ( + retryable if retryable is not None else self.code in RETRYABLE_CODES + ) self.raw = raw or {} @classmethod diff --git a/packages/adapter_core/adapter_core/interfaces/__init__.py b/packages/adapter_core/adapter_core/interfaces/__init__.py index 8513ca5..2b817d4 100644 --- a/packages/adapter_core/adapter_core/interfaces/__init__.py +++ b/packages/adapter_core/adapter_core/interfaces/__init__.py @@ -1,4 +1,4 @@ -from adapter_core.interfaces.payment import PaymentAdapter from adapter_core.interfaces.email import EmailAdapter +from adapter_core.interfaces.payment import PaymentAdapter __all__ = ["PaymentAdapter", "EmailAdapter"] diff --git a/packages/adapter_core/adapter_core/models/__init__.py b/packages/adapter_core/adapter_core/models/__init__.py index 5070d13..f008ac4 100644 --- a/packages/adapter_core/adapter_core/models/__init__.py +++ b/packages/adapter_core/adapter_core/models/__init__.py @@ -1,3 +1,8 @@ +from adapter_core.models.email import ( + EmailStatusResponse, + SendEmailRequest, + SendEmailResponse, +) from adapter_core.models.payment import ( ChargeRequest, ChargeResponse, @@ -5,11 +10,6 @@ RefundRequest, RefundResponse, ) -from adapter_core.models.email import ( - EmailStatusResponse, - SendEmailRequest, - SendEmailResponse, -) from adapter_core.models.webhook import NormalizedWebhookEvent __all__ = [ diff --git a/packages/adapter_core/adapter_core/models/email.py b/packages/adapter_core/adapter_core/models/email.py index 7b124fd..a757522 100644 --- a/packages/adapter_core/adapter_core/models/email.py +++ b/packages/adapter_core/adapter_core/models/email.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel, Field, ConfigDict +from pydantic import BaseModel, ConfigDict, Field class SendEmailRequest(BaseModel): diff --git a/packages/adapter_core/adapter_core/models/payment.py b/packages/adapter_core/adapter_core/models/payment.py index f8ac2ba..05d058b 100644 --- a/packages/adapter_core/adapter_core/models/payment.py +++ b/packages/adapter_core/adapter_core/models/payment.py @@ -3,7 +3,9 @@ class ChargeRequest(BaseModel): provider: str - amount: int = Field(..., description="Amount in smallest currency unit (e.g. cents)") + amount: int = Field( + ..., description="Amount in smallest currency unit (e.g. cents)" + ) currency: str = Field(default="USD", description="ISO 4217 currency code") customer_email: str source_token: str = Field(..., description="Provider-specific payment token") @@ -22,7 +24,9 @@ class ChargeResponse(BaseModel): class RefundRequest(BaseModel): provider: str transaction_id: str - amount: int | None = Field(default=None, description="Partial refund amount; None = full refund") + amount: int | None = Field( + default=None, description="Partial refund amount; None = full refund" + ) reason: str | None = None diff --git a/packages/adapter_core/adapter_core/models/webhook.py b/packages/adapter_core/adapter_core/models/webhook.py index 00c6125..ca06802 100644 --- a/packages/adapter_core/adapter_core/models/webhook.py +++ b/packages/adapter_core/adapter_core/models/webhook.py @@ -3,7 +3,9 @@ class NormalizedWebhookEvent(BaseModel): provider: str - event_type: str = Field(..., description="Normalized event type, e.g. payment.succeeded") + event_type: str = Field( + ..., description="Normalized event type, e.g. payment.succeeded" + ) event_id: str | None = None payload: dict = Field(default_factory=dict) raw: dict = Field(default_factory=dict) diff --git a/packages/adapter_core/adapter_core/providers/email/postmark_adapter.py b/packages/adapter_core/adapter_core/providers/email/postmark_adapter.py index 8ed741b..cee128b 100644 --- a/packages/adapter_core/adapter_core/providers/email/postmark_adapter.py +++ b/packages/adapter_core/adapter_core/providers/email/postmark_adapter.py @@ -10,7 +10,9 @@ _BASE_URL = "https://api.postmarkapp.com" -def _handle_postmark_error(response: httpx.Response, provider: str = "postmark") -> None: +def _handle_postmark_error( + response: httpx.Response, provider: str = "postmark" +) -> None: if response.is_success: return try: diff --git a/packages/adapter_core/adapter_core/providers/email/sendgrid_adapter.py b/packages/adapter_core/adapter_core/providers/email/sendgrid_adapter.py index ff093e7..5b21c21 100644 --- a/packages/adapter_core/adapter_core/providers/email/sendgrid_adapter.py +++ b/packages/adapter_core/adapter_core/providers/email/sendgrid_adapter.py @@ -10,7 +10,9 @@ _BASE_URL = "https://api.sendgrid.com/v3" -def _handle_sendgrid_error(response: httpx.Response, provider: str = "sendgrid") -> None: +def _handle_sendgrid_error( + response: httpx.Response, provider: str = "sendgrid" +) -> None: if response.is_success: return try: @@ -19,7 +21,9 @@ def _handle_sendgrid_error(response: httpx.Response, provider: str = "sendgrid") message = errors[0].get("message") if errors else f"HTTP {response.status_code}" except Exception: message = f"HTTP {response.status_code}" - raise AdapterError.from_http_status(response.status_code, provider, message, raw={"body": str(response.text)}) + raise AdapterError.from_http_status( + response.status_code, provider, message, raw={"body": str(response.text)} + ) class SendGridAdapter: diff --git a/packages/adapter_core/adapter_core/providers/payments/paypal_adapter.py b/packages/adapter_core/adapter_core/providers/payments/paypal_adapter.py index 5865df2..0429844 100644 --- a/packages/adapter_core/adapter_core/providers/payments/paypal_adapter.py +++ b/packages/adapter_core/adapter_core/providers/payments/paypal_adapter.py @@ -1,6 +1,6 @@ import httpx -from adapter_core.errors.base import AdapterError, ErrorCode +from adapter_core.errors.base import AdapterError from adapter_core.models.payment import ( ChargeRequest, ChargeResponse, @@ -18,14 +18,20 @@ def _handle_paypal_error(response: httpx.Response, provider: str = "paypal") -> return try: body = response.json() - message = body.get("message") or body.get("error_description", "Unknown PayPal error") + message = body.get("message") or body.get( + "error_description", "Unknown PayPal error" + ) except Exception: message = f"HTTP {response.status_code}" - raise AdapterError.from_http_status(response.status_code, provider, message, raw={"body": str(response.text)}) + raise AdapterError.from_http_status( + response.status_code, provider, message, raw={"body": str(response.text)} + ) class PayPalAdapter: - def __init__(self, client_id: str, client_secret: str, sandbox: bool = True) -> None: + def __init__( + self, client_id: str, client_secret: str, sandbox: bool = True + ) -> None: self._client_id = client_id self._client_secret = client_secret self._base_url = _SANDBOX_URL if sandbox else _LIVE_URL @@ -95,7 +101,9 @@ async def charge(self, payload: ChargeRequest) -> ChargeResponse: status=captured.get("status", "UNKNOWN").lower(), transaction_id=capture_detail.get("id", order_id), amount=int(float(amount_val) * 100), - currency=capture_detail.get("amount", {}).get("currency_code", payload.currency).upper(), + currency=capture_detail.get("amount", {}) + .get("currency_code", payload.currency) + .upper(), raw=captured, ) diff --git a/packages/adapter_core/adapter_core/providers/payments/stripe_adapter.py b/packages/adapter_core/adapter_core/providers/payments/stripe_adapter.py index b611a1f..84603d9 100644 --- a/packages/adapter_core/adapter_core/providers/payments/stripe_adapter.py +++ b/packages/adapter_core/adapter_core/providers/payments/stripe_adapter.py @@ -31,10 +31,13 @@ def _handle_stripe_error(response: httpx.Response, provider: str = "stripe") -> "rate_limit": ErrorCode.RATE_LIMIT, "authentication_required": ErrorCode.AUTHENTICATION_ERROR, } - code = code_map.get(stripe_code) or AdapterError.from_http_status( - response.status_code, provider, message - ).code - raise AdapterError(code=code, message=message, provider=provider, raw={"stripe_code": stripe_code}) + code = ( + code_map.get(stripe_code) + or AdapterError.from_http_status(response.status_code, provider, message).code + ) + raise AdapterError( + code=code, message=message, provider=provider, raw={"stripe_code": stripe_code} + ) class StripeAdapter: diff --git a/packages/adapter_core/adapter_core/utils/retry.py b/packages/adapter_core/adapter_core/utils/retry.py index 0b56fdd..9ccaf69 100644 --- a/packages/adapter_core/adapter_core/utils/retry.py +++ b/packages/adapter_core/adapter_core/utils/retry.py @@ -1,13 +1,10 @@ import asyncio from collections.abc import Awaitable, Callable -from typing import TypeVar from adapter_core.errors.base import AdapterError -T = TypeVar("T") - -async def retry_async( +async def retry_async[T]( func: Callable[[], Awaitable[T]], max_attempts: int = 3, base_delay: float = 1.0,