Skip to content

Commit 7563481

Browse files
ChemicalLuckclaude
andcommitted
Fix Charge model validation errors against real API responses
Adds field validators to handle format discrepancies returned by the Recharge API that differ from strict model expectations: - Uppercase status/type literals before validation (API sends lowercase) - Split comma-separated tags string into list - Coerce empty-list utm_params to None - Allow None for order_attributes value - Allow bool for shipping_lines taxable Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 7f51948 commit 7563481

2 files changed

Lines changed: 26 additions & 5 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "recharge-api"
3-
version = "2.0.1"
3+
version = "2.0.2"
44
authors = [
55
{ name="ChemicalLuck", email="j.tebbett@outlook.com" }
66
]

recharge/model/v2/charge.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from typing import Literal, Optional
1+
from typing import Any, Literal, Optional, Union
22

3-
from pydantic import BaseModel, ConfigDict
3+
from pydantic import BaseModel, ConfigDict, field_validator
44

55
ChargeStatus = Literal[
66
"SUCCESS", "QUEUED", "ERROR", "REFUNDED", "PARTIALLY_REFUNDED", "SKIPPED"
@@ -26,6 +26,13 @@ class ChargeAnalyticsData(BaseModel):
2626

2727
utm_params: Optional[ChargeAnalyticsDataUtmParams] = None
2828

29+
@field_validator("utm_params", mode="before")
30+
@classmethod
31+
def coerce_utm_params(cls, v: Any) -> Any:
32+
if isinstance(v, list):
33+
return None
34+
return v
35+
2936

3037
class ChargeBillingAddress(BaseModel):
3138
model_config = ConfigDict(extra="allow", populate_by_name=True)
@@ -153,7 +160,7 @@ class ChargeOrderAttribute(BaseModel):
153160
model_config = ConfigDict(extra="allow", populate_by_name=True)
154161

155162
name: str
156-
value: str
163+
value: Optional[str] = None
157164

158165

159166
class ChargeShippingAddress(BaseModel):
@@ -178,13 +185,27 @@ class ChargeShippingLine(BaseModel):
178185
price: Optional[str] = None
179186
source: Optional[str] = None
180187
title: Optional[str] = None
181-
taxable: Optional[str] = None
188+
taxable: Optional[Union[str, bool]] = None
182189
tax_lines: list[ChargeTaxLine] = []
183190

184191

185192
class Charge(BaseModel):
186193
model_config = ConfigDict(extra="allow", populate_by_name=True)
187194

195+
@field_validator("status", "type", mode="before")
196+
@classmethod
197+
def uppercase_literals(cls, v: Any) -> Any:
198+
if isinstance(v, str):
199+
return v.upper()
200+
return v
201+
202+
@field_validator("tags", mode="before")
203+
@classmethod
204+
def coerce_tags(cls, v: Any) -> Any:
205+
if isinstance(v, str):
206+
return [t.strip() for t in v.split(",") if t.strip()]
207+
return v
208+
188209
id: int
189210
address_id: Optional[int] = None
190211
analytics_data: Optional[ChargeAnalyticsData] = None

0 commit comments

Comments
 (0)