philiprehberger-money
Precise monetary calculations using integer cents with currency support and formatting.
Installation
pip install philiprehberger-money
Usage
from philiprehberger_money import Money
price = Money.from_major(19.99, "USD")
print(price.format(symbol="$")) # "$19.99"
Creating Money
from philiprehberger_money import Money
price = Money.from_major(19.99, "USD")
free = Money.zero("EUR")
Arithmetic
from philiprehberger_money import Money
a = Money.from_major(10.00, "USD")
b = Money.from_major(3.50, "USD")
total = a + b # $13.50
diff = a - b # $6.50
doubled = a * 2 # $20.00
split = a.divide(3) # $3.33 (rounded)
negated = -a # -$10.00
Safe Currency Handling
from philiprehberger_money import Money, CurrencyMismatchError
usd = Money.from_major(10, "USD")
eur = Money.from_major(10, "EUR")
usd + eur # raises CurrencyMismatchError
Allocation (Split Without Losing Cents)
from philiprehberger_money import Money
total = Money.from_major(100.00, "USD")
# Split 50/30/20
shares = total.allocate([50, 30, 20])
# [Money($50.00), Money($30.00), Money($20.00)]
# Handles remainders correctly
odd = Money.from_major(10.00, "USD")
thirds = odd.allocate([1, 1, 1])
# [Money($3.34), Money($3.33), Money($3.33)]
Denomination Rounding
from philiprehberger_money import Money
price = Money.from_major(1.23, "USD")
# Round to nearest 5 cents
rounded = price.round_to_nearest(5)
print(rounded.format(symbol="$")) # "$1.25"
# Round to nearest 10 cents
rounded = price.round_to_nearest(10)
print(rounded.format(symbol="$")) # "$1.20"
Currency Conversion
from philiprehberger_money import Money
usd = Money.from_major(100, "USD")
# Direct rate
eur = usd.convert("EUR", 0.92)
print(eur.format()) # "92.00 EUR"
# Using a rates dictionary
eur = usd.convert(to="EUR", rates={"USD/EUR": 0.92})
# Using a rate provider callable
def get_rate(from_currency: str, to_currency: str) -> float:
return 0.92 # fetch from API, database, etc.
eur = usd.convert(to="EUR", rate_provider=get_rate)
Locale-Aware Formatting
from philiprehberger_money import Money
price = Money.from_major(1234.56, "USD")
print(price.format()) # "1234.56 USD"
print(price.format(symbol="$")) # "$1234.56"
print(price.format(locale="en_US")) # "$1,234.56"
print(price.format(locale="de_DE")) # "$1.234,56"
Rounding Modes
from philiprehberger_money import Money, RoundingMode, set_default_rounding_mode
# Per-instance rounding mode
m = Money(amount_cents=5, currency="USD", rounding_mode=RoundingMode.ROUND_HALF_EVEN)
result = m.divide(2) # 2.5 -> 2 (banker's rounding)
# Change rounding mode on existing instance
m2 = m.with_rounding_mode(RoundingMode.ROUND_UP)
# Set global default (affects all instances without explicit mode)
set_default_rounding_mode(RoundingMode.ROUND_HALF_EVEN)
Comparisons
from philiprehberger_money import Money
a = Money.from_major(10, "USD")
b = Money.from_major(20, "USD")
a < b # True
a == b # False
a.is_positive() # True
a.is_zero() # False
Zero-Decimal Currencies
from philiprehberger_money import Money
yen = Money.from_major(1000, "JPY")
print(yen.format(symbol="\u00a5")) # "\u00a51000"
Serialization
from philiprehberger_money import Money
m = Money.from_major(19.99, "USD")
d = m.to_dict() # {"amount_cents": 1999, "currency": "USD"}
m2 = Money.from_dict(d) # Money(19.99 USD)
Sum Multiple Values
from philiprehberger_money import Money
items = [Money.from_major(10, "USD"), Money.from_major(20, "USD"), Money.from_major(30, "USD")]
total = Money.sum(items)
print(total.format(symbol="$")) # "$60.00"
Percentage
from philiprehberger_money import Money
price = Money.from_major(200, "USD")
tip = price.percentage(15)
print(tip.format(symbol="$")) # "$30.00"
Even Split
from philiprehberger_money import Money
bill = Money.from_major(100, "USD")
shares = bill.split_even(3)
# [Money($33.34), Money($33.33), Money($33.33)]
API
| Function / Class | Description |
|---|---|
Money.from_major(amount, currency, *, rounding_mode=None) |
Create from major units (dollars, euros, etc.) |
Money.zero(currency, *, rounding_mode=None) |
Create zero-value Money |
Money.from_dict(data) |
Create from dict |
.add(other) / + |
Add two Money values (same currency) |
.subtract(other) / - |
Subtract (same currency) |
.multiply(factor) / * |
Multiply by number |
.divide(divisor) |
Divide by number |
.allocate(ratios) |
Split into parts without losing cents |
.round_to_nearest(step) |
Round minor units to nearest multiple |
.convert(to, rate=None, *, rates=None, rate_provider=None) |
Convert to another currency using a rate, rates dict, or callable |
.format(symbol=None, *, locale=None) |
Format as string, optionally locale-aware |
.with_rounding_mode(mode) |
Return copy with specified rounding mode |
.negate() / -m |
Negate amount |
.abs() |
Absolute value |
.is_zero() / .is_positive() / .is_negative() |
Predicates |
.to_dict() |
Serialize to dict |
.amount |
Major unit value as float |
.decimals |
Currency decimal places |
Money.sum(moneys) |
Sum a list of Money values (same currency) |
.percentage(pct) |
Calculate a percentage of this money value |
.split_even(n) |
Split evenly into n parts, distributing remainders |
RoundingMode |
Enum: ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_DOWN, ROUND_UP |
set_default_rounding_mode(mode) |
Set global default rounding mode |
get_default_rounding_mode() |
Get current global default rounding mode |
CurrencyMismatchError |
Raised on mixed-currency operations |
Development
pip install -e .
python -m pytest tests/ -v
Support
If you find this project useful:
License
Metadata
Release files for philiprehberger-money 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| philiprehberger_money-0.5.0.tar.gz | 12.2 kB | Without provenance | Details for philiprehberger_money-0.5.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| philiprehberger_money-0.5.0-py3-none-any.whl | Python 3 | none | any | Details for philiprehberger_money-0.5.0-py3-none-any.whl |
Total release size: 21.4 kB
Release files / philiprehberger_money-0.5.0.tar.gz
| Download URL | philiprehberger_money-0.5.0.tar.gz |
|---|---|
| Size | 12.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d446e81e509d587f696515274a8523d1238e433ea61965611b27643fba01fd82
|
|
BLAKE2b-256 checksum How to use checksums |
ffa8197decee35d2c8122569ad17575e8f37f3cccfddabdd9d321820d79354bf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / philiprehberger_money-0.5.0-py3-none-any.whl
| Download URL | philiprehberger_money-0.5.0-py3-none-any.whl |
|---|---|
| Size | 9.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
721c6d807212fe056423cf349c0a11436683531c3d7eb1ccf52b0fdf6f4662de
|
|
BLAKE2b-256 checksum How to use checksums |
82d8d90b8890c0debe7dc26fe979fd4be9957eee4dcba3cadc6bd74c15b0c4c3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Security for philiprehberger-money 0.5.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.