Skip to content

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 8.5 for 8.5%.

required

Returns:

Name Type Description
Decimal Decimal

The price after tax, rounded to two decimal places.

Raises:

Type Description
EasyMoneyError

If amount or rate is not a number, or if rate is negative.

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 15 for 15%.

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 15 or 20 for 15% or 20%.

required

Returns:

Name Type Description
Decimal Decimal

The tip amount to add, rounded to two decimal places.

Raises:

Type Description
EasyMoneyError

If amount or tip_rate is not a valid number, or if tip_rate is negative.

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 "$12.50".

Raises:

Type Description
EasyMoneyError

If amount is not a number.

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 people is less than 1 or total is not a number.

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 people shares with two decimal places. For example, 10 split three ways gives 3.34, 3.33 and 3.33.

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