Easy Money
py_simple.easy_money
easy_money formats prices and splits bills without the decimal boilerplate.
EasyMoneyError
Bases: Exception
Raised when a money calculation cannot be completed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
Description of what went wrong. |
required |
add_tax(amount, rate)
Add a tax rate to an amount and round to cents.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
amount
|
The price before tax. |
required | |
rate
|
float
|
Tax rate as a percent, such as |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Decimal |
Decimal
|
The price after tax, rounded to two decimal places. |
Raises:
| Type | Description |
|---|---|
EasyMoneyError
|
If |
Example
from py_simple import add_tax
total = add_tax(10, 8.5)
from decimal import Decimal, ROUND_HALF_UP
total = (Decimal("10") * (1 + Decimal("8.5") / 100)).quantize(
Decimal("0.01"), rounding=ROUND_HALF_UP
)
calculate_discount(amount, discount_rate)
Calculate the price after applying a percentage discount.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
amount
|
The original price before the discount. |
required | |
discount_rate
|
float
|
Discount percentage, such as |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Decimal |
Decimal
|
The discounted price, rounded to two decimal places. |
Raises:
| Type | Description |
|---|---|
EasyMoneyError
|
If the amount or discount rate is invalid, or if the discount rate is outside the range of 0 to 100. |
Example
from py_simple import calculate_discount
discounted_price = calculate_discount(2000, 15)
from decimal import Decimal, ROUND_HALF_UP
amount = Decimal("2000")
discount_rate = Decimal("15")
discounted_price = (amount * (1 - discount_rate / 100)).quantize(
Decimal("0.01"), rounding=ROUND_HALF_UP
)
calculate_tip(amount, tip_rate)
Calculate the tip amount for a bill given a percentage rate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
amount
|
The bill amount before tip. |
required | |
tip_rate
|
float
|
Tip percentage, such as |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Decimal |
Decimal
|
The tip amount to add, rounded to two decimal places. |
Raises:
| Type | Description |
|---|---|
EasyMoneyError
|
If |
Example
from py_simple import calculate_tip
tip = calculate_tip(50, 18)
from decimal import Decimal, ROUND_HALF_UP
bill = Decimal("50")
rate = Decimal("18")
tip = (bill * (rate / Decimal(100))).quantize(
Decimal("0.01"), rounding=ROUND_HALF_UP
)
format_money(amount, symbol='$')
Format a number as money with two decimal places.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
amount
|
The amount to format. |
required | |
symbol
|
str
|
Currency symbol placed before the number.
Defaults to |
'$'
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The formatted amount, such as |
Raises:
| Type | Description |
|---|---|
EasyMoneyError
|
If |
Example
from py_simple import format_money
print(format_money(12.5))
from decimal import Decimal, ROUND_HALF_UP
cents = Decimal("12.5").quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
print(f"${cents}")
split_bill(total, people)
Split a bill evenly and round each share to cents.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
total
|
The full bill. |
required | |
people
|
int
|
How many people are paying. Must be at least 1. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Decimal |
Decimal
|
One person's share, rounded to two decimal places. |
Raises:
| Type | Description |
|---|---|
EasyMoneyError
|
If |
Example
from py_simple import split_bill
share = split_bill(48, 3)
from decimal import Decimal, ROUND_HALF_UP
share = (Decimal("48") / 3).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
split_bill_exact(total, people)
Splits a bill into cent-precise shares that preserve the rounded total.
Rounds the full bill once using ROUND_HALF_UP, then gives leftover cents to the first shares. Shares differ by at most one cent. Refunds use the same allocation with negative shares; zero shares are 0.00. Existing split_bill still returns one independently rounded share.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
total
|
int | float | str | Decimal
|
Finite amount. Floats are converted through their string representation. |
required |
people
|
int
|
Number of shares. Must be at least 1; booleans and non-integers are not accepted. |
required |
Returns:
| Type | Description |
|---|---|
list[Decimal]
|
list[Decimal]: Exactly |
Raises:
| Type | Description |
|---|---|
EasyMoneyError
|
If the amount/count is invalid or rounding cannot be completed in the current Decimal context. |
Example
from py_simple import split_bill_exact
shares = split_bill_exact("10.00", 3)
print(shares) # [Decimal('3.34'), Decimal('3.33'), Decimal('3.33')]
print(sum(shares)) # 10.00
from decimal import Decimal, ROUND_HALF_UP
total, people = Decimal("10.00"), 3
rounded = total.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
numerator, denominator = rounded.as_integer_ratio()
cents = abs(numerator) * 100 // denominator
base, remainder = divmod(cents, people)
sign = -1 if rounded < 0 else 1
shares = []
for i in range(people):
cent_share = Decimal(sign * (base + (i < remainder)))
parts = cent_share.as_tuple()
shares.append(Decimal((parts.sign, parts.digits, -2)))
print(shares) # [Decimal('3.34'), Decimal('3.33'), Decimal('3.33')]
print(sum(shares)) # 10.00