Skip to main content

Precise monetary calculations using integer cents with currency support and formatting.

Project description

philiprehberger-money

Tests PyPI version Last updated

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:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

philiprehberger_money-0.5.0.tar.gz (12.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

philiprehberger_money-0.5.0-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

Details for the file philiprehberger_money-0.5.0.tar.gz.

File metadata

  • Download URL: philiprehberger_money-0.5.0.tar.gz
  • Upload date:
  • Size: 12.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for philiprehberger_money-0.5.0.tar.gz
Algorithm Hash digest
SHA256 d446e81e509d587f696515274a8523d1238e433ea61965611b27643fba01fd82
MD5 a033c4945639d8c9f6978d892ba54f05
BLAKE2b-256 ffa8197decee35d2c8122569ad17575e8f37f3cccfddabdd9d321820d79354bf

See more details on using hashes here.

File details

Details for the file philiprehberger_money-0.5.0-py3-none-any.whl.

File metadata

File hashes

Hashes for philiprehberger_money-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 721c6d807212fe056423cf349c0a11436683531c3d7eb1ccf52b0fdf6f4662de
MD5 7ea0ef7a86f63d39e0bf45b3ca659415
BLAKE2b-256 82d8d90b8890c0debe7dc26fe979fd4be9957eee4dcba3cadc6bd74c15b0c4c3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page