Skip to content

Commit

Permalink
Added support for specifying units and nanos as input values
Browse files Browse the repository at this point in the history
  • Loading branch information
kalaspuff committed Nov 23, 2019
1 parent a906eb9 commit 98c33a8
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 1 deletion.
31 changes: 30 additions & 1 deletion stockholm/money.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
DEFAULT_MIN_DECIMALS = 2
DEFAULT_MAX_DECIMALS = 9
MAX_DECIMALS = 9
UNITS_MAX_LENGTH = 18
NANOS_LENGTH = 9

HIGHEST_SUPPORTED_AMOUNT = "999999999999999999.999999999"
Expand Down Expand Up @@ -44,12 +45,37 @@ def __init__(
amount: Optional[Union["Money", Decimal, int, float, str, object]] = None,
currency: Optional[str] = None,
is_cents: Optional[bool] = None,
units: Optional[int] = None,
nanos: Optional[int] = None,
**kwargs: Any,
) -> None:
validate_amounts = []

if units is not None or nanos is not None:
try:
units = units or 0
nanos = nanos or 0
if (units > 0 and nanos < 0) or (units < 0 and nanos > 0):
raise ValueError
units_str = str(units).lstrip("-")
nanos_str = str(nanos).lstrip("-").rjust(NANOS_LENGTH, "0")
if len(units_str) > UNITS_MAX_LENGTH:
raise ValueError
if len(nanos_str) != NANOS_LENGTH:
raise ValueError
sign = "-" if nanos < 0 or units < 0 else ""
units_amount = Decimal(f"{sign}{units_str}.{nanos_str}")
if amount is None:
amount = units_amount
else:
validate_amounts.append(units_amount)
except Exception:
raise ConversionError("Invalid values for units and nanos")

if amount is None:
raise ConversionError("Missing input values for monetary amount")

if isinstance(amount, Money) and currency is None and is_cents is None:
if isinstance(amount, Money) and currency is None and is_cents is None and units is None and nanos is None:
object.__setattr__(self, "_amount", amount._amount)
object.__setattr__(self, "_currency", amount._currency)
return
Expand Down Expand Up @@ -146,6 +172,9 @@ def __init__(
if output_amount == 0 and str(output_amount).startswith("-"):
output_amount = Decimal(0)

if any([output_amount != a for a in validate_amounts]):
raise ConversionError("Input arguments does not match")

object.__setattr__(self, "_amount", output_amount)
object.__setattr__(self, "_currency", output_currency)

Expand Down
7 changes: 7 additions & 0 deletions tests/test_init.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import pytest

import stockholm


Expand All @@ -13,3 +15,8 @@ def test_init() -> None:
def test_hash() -> None:
m = stockholm.Money(0)
assert hash(m)


def test_empty_construct() -> None:
with pytest.raises(stockholm.ConversionError):
stockholm.Money()
42 changes: 42 additions & 0 deletions tests/test_input_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,45 @@ def __str__(self) -> str:

with pytest.raises(ConversionError):
Money(ThirdPartyMoney(None, output="USD USD"))


def test_units_input() -> None:
assert Money(units=0, nanos=0) == 0
assert Money(units=0) == 0
assert Money(nanos=0) == 0
assert Money(units=0, nanos=1) == Money("0.000000001")
assert Money(nanos=2) == Money("0.000000002")
assert Money(nanos=-2) == Money("-0.000000002")
assert Money(units=4711) == Money(4711)
assert Money(units=-4711) == Money(-4711)
assert Money(units=1, nanos=750000000) == Money("1.75")
assert Money(units=0, nanos=100000000) == Money("0.1")
assert Money(units=-1, nanos=-750000000) == Money("-1.75")
assert Money(units=13381339, nanos=5005335) == Money("13381339.005005335")
assert Money(units=999999999999999999, nanos=999999999) == Money("999999999999999999.999999999")
assert Money(units=-999999999999999999, nanos=-999999999) == Money("-999999999999999999.999999999")

assert Money(units=1338, amount=1338) == Money(1338)
assert Money(units=1338, nanos=250000000, amount=Decimal("1338.25")) == Money("1338.25")
assert Money(units=1338, nanos=250000000, amount="1338.25 SEK") == Money("1338.25", currency="SEK")

with pytest.raises(ConversionError):
Money(units=-1, nanos=750000000)

with pytest.raises(ConversionError):
Money(units=1, nanos=-1)

with pytest.raises(ConversionError):
Money(nanos=1000000000)

with pytest.raises(ConversionError):
Money(units=1000000000000000000)

with pytest.raises(ConversionError):
Money(units=1338, amount=1337)

with pytest.raises(ConversionError):
Money(units=1338, nanos=250000000, amount=1338)

with pytest.raises(ConversionError):
Money(units=1338, nanos=250000000, amount="1338")

0 comments on commit 98c33a8

Please sign in to comment.