Marshmallow Extension¶
Custom Marshmallow fields for serializing and deserializing Money, Rate, and InterestRate objects.
Installation¶
Fields¶
MoneyField¶
Serializes Money instances. The representation parameter controls the format:
| Representation | Serialized type | Serialize logic | Deserialize logic |
|---|---|---|---|
"raw" (default) |
str |
str(money.raw_amount) |
Money(value) |
"real" |
str |
str(money.real_amount) |
Money(value) |
"cents" |
int |
money.cents |
Money.from_cents(value) |
"float" |
float |
float(money.real_amount) |
Money(str(value)) |
RateField¶
Serializes Rate instances. The representation parameter controls the format:
| Representation | Serialized type | Example output |
|---|---|---|
"string" (default) |
str |
"5.250% annual" |
"dict" |
dict |
{"rate": "0.0525", "period": "annually", ...} |
String mode outputs a parseable format that feeds directly back into Rate(...). Field-level defaults (year_size, precision, rounding, str_style) are applied on deserialization.
Dict mode captures all constructor params (rate, period, year_size, precision, rounding, str_style) for lossless reconstruction.
InterestRateField¶
Inherits from RateField with RATE_CLASS = InterestRate. Same representations, but constructs InterestRate on deserialization (rejects negative values).
Usage¶
from marshmallow import Schema
from money_warp import Money, InterestRate
from money_warp.ext.marshmallow import MoneyField, InterestRateField
class LoanSchema(Schema):
principal = MoneyField(representation="raw")
rate = InterestRateField(representation="string")
schema = LoanSchema()
# Serialize
data = schema.dump({"principal": Money("10000"), "rate": InterestRate("5.25% a")})
# {"principal": "10000", "rate": "5.250% annual"}
# Deserialize
result = schema.load(data)
# {"principal": Money(10000), "rate": InterestRate(5.25% annually)}
Dict representation for lossless round-trips¶
from money_warp.ext.marshmallow import RateField
from money_warp import Rate, CompoundingFrequency, YearSize
class DetailedSchema(Schema):
rate = RateField(representation="dict")
schema = DetailedSchema()
rate = Rate(0.0525, CompoundingFrequency.ANNUALLY, year_size=YearSize.banker)
data = schema.dump({"rate": rate})
# {
# "rate": {
# "rate": "0.0525",
# "period": "annually",
# "year_size": 360,
# "precision": None,
# "rounding": "ROUND_HALF_UP",
# "str_style": "long"
# }
# }
restored = schema.load(data)
# Rate is fully reconstructed with all original parameters
Cents representation for integer storage¶
class PaymentSchema(Schema):
amount = MoneyField(representation="cents")
schema = PaymentSchema()
data = schema.dump({"amount": Money("123.45")})
# {"amount": 12345}
result = schema.load(data)
# {"amount": Money("123.45")}
Float representation for JSON-friendly APIs¶
class ApiSchema(Schema):
amount = MoneyField(representation="float")
schema = ApiSchema()
data = schema.dump({"amount": Money("123.45")})
# {"amount": 123.45}
result = schema.load(data)
# {"amount": Money("123.45")}
Notes¶
- All fields pass
Nonethrough in both directions. - String round-trips lose some precision: the percentage rate is formatted with 3 decimal places. Use dict representation for rates with more than 3 decimal digits in percentage form.
InterestRateFieldraises a validation error for negative rates.