Skip to content
Snippets Groups Projects
Commit bde53801 authored by Holger's avatar Holger
Browse files

Use decimal for amount in the Amount class

* change the internal representation of amount from float to Decimal
* Round amount down to precision
* Adapt amount test to Decimal
* Round down all other number in all operation 
parent 13424bd1
No related branches found
No related tags found
No related merge requests found
......@@ -8,6 +8,7 @@ from future.utils import python_2_unicode_compatible
from beemgraphenebase.py23 import bytes_types, integer_types, string_types, text_type
from beem.instance import shared_steem_instance
from beem.asset import Asset
from decimal import Decimal, ROUND_DOWN
def check_asset(other, self):
......@@ -19,6 +20,13 @@ def check_asset(other, self):
raise AssertionError()
def quantize(amount, precision):
# make sure amount is decimal and has the asset precision
amount = Decimal(amount)
places = Decimal(10) ** (-precision)
return amount.quantize(places, rounding=ROUND_DOWN)
@python_2_unicode_compatible
class Amount(dict):
""" This class deals with Amounts of any asset to simplify dealing with the tuple::
......@@ -81,14 +89,14 @@ class Amount(dict):
elif amount and asset is None and isinstance(amount, list) and len(amount) == 3:
# Copy Asset object
self["amount"] = int(amount[0]) / (10 ** amount[1])
self["amount"] = Decimal(amount[0]) / Decimal(10 ** amount[1])
self["asset"] = Asset(amount[2], steem_instance=self.steem)
self["symbol"] = self["asset"]["symbol"]
elif amount and asset is None and isinstance(amount, dict) and "amount" in amount and "nai" in amount and "precision" in amount:
# Copy Asset object
self.new_appbase_format = True
self["amount"] = int(amount["amount"]) / (10 ** amount["precision"])
self["amount"] = Decimal(amount["amount"]) / Decimal(10 ** amount["precision"])
self["asset"] = Asset(amount["nai"], steem_instance=self.steem)
self["symbol"] = self["asset"]["symbol"]
......@@ -99,12 +107,12 @@ class Amount(dict):
elif (amount and asset is None and isinstance(amount, dict) and "amount" in amount and "asset_id" in amount):
self["asset"] = Asset(amount["asset_id"], steem_instance=self.steem)
self["symbol"] = self["asset"]["symbol"]
self["amount"] = int(amount["amount"]) / 10 ** self["asset"]["precision"]
self["amount"] = Decimal(amount["amount"]) / Decimal(10 ** self["asset"]["precision"])
elif (amount and asset is None and isinstance(amount, dict) and "amount" in amount and "asset" in amount):
self["asset"] = Asset(amount["asset"], steem_instance=self.steem)
self["symbol"] = self["asset"]["symbol"]
self["amount"] = int(amount["amount"]) / 10 ** self["asset"]["precision"]
self["amount"] = Decimal(amount["amount"]) / Decimal(10 ** self["asset"]["precision"])
elif amount and asset and isinstance(asset, Asset):
self["amount"] = amount
......@@ -116,25 +124,23 @@ class Amount(dict):
self["asset"] = Asset(asset, steem_instance=self.steem)
self["symbol"] = self["asset"]["symbol"]
elif isinstance(amount, (integer_types, float)) and asset and isinstance(asset, Asset):
elif isinstance(amount, (integer_types, float, Decimal)) and asset and isinstance(asset, Asset):
self["amount"] = amount
self["asset"] = asset
self["symbol"] = self["asset"]["symbol"]
elif isinstance(amount, (integer_types, float)) and asset and isinstance(asset, dict):
elif isinstance(amount, (integer_types, float, Decimal)) and asset and isinstance(asset, dict):
self["amount"] = amount
self["asset"] = asset
self["symbol"] = self["asset"]["symbol"]
elif isinstance(amount, (integer_types, float)) and asset and isinstance(asset, string_types):
elif isinstance(amount, (integer_types, float, Decimal)) and asset and isinstance(asset, string_types):
self["amount"] = amount
self["asset"] = Asset(asset, steem_instance=self.steem)
self["symbol"] = asset
else:
raise ValueError
# make sure amount is a float
self["amount"] = float(self["amount"])
self["amount"] = quantize(self["amount"], self["asset"]["precision"])
def copy(self):
""" Copy the instance and make sure not to use a reference
......@@ -196,7 +202,7 @@ class Amount(dict):
check_asset(other["asset"], self["asset"])
a["amount"] += other["amount"]
else:
a["amount"] += float(other)
a["amount"] += quantize(other, self["asset"]["precision"])
return a
def __sub__(self, other):
......@@ -205,7 +211,7 @@ class Amount(dict):
check_asset(other["asset"], self["asset"])
a["amount"] -= other["amount"]
else:
a["amount"] -= float(other)
a["amount"] -= quantize(other, self["asset"]["precision"])
return a
def __mul__(self, other):
......@@ -214,7 +220,7 @@ class Amount(dict):
check_asset(other["asset"], self["asset"])
a["amount"] *= other["amount"]
else:
a["amount"] *= other
a["amount"] *= quantize(other, self["asset"]["precision"])
return a
def __floordiv__(self, other):
......@@ -224,7 +230,7 @@ class Amount(dict):
from .price import Price
return Price(self, other, steem_instance=self.steem)
else:
a["amount"] //= other
a["amount"] //= quantize(other, self["asset"]["precision"])
return a
def __div__(self, other):
......@@ -234,7 +240,7 @@ class Amount(dict):
from .price import Price
return Price(self, other, steem_instance=self.steem)
else:
a["amount"] /= other
a["amount"] /= quantize(other, self["asset"]["precision"])
return a
def __mod__(self, other):
......@@ -243,7 +249,7 @@ class Amount(dict):
check_asset(other["asset"], self["asset"])
a["amount"] %= other["amount"]
else:
a["amount"] %= other
a["amount"] %= quantize(other, self["asset"]["precision"])
return a
def __pow__(self, other):
......@@ -252,7 +258,7 @@ class Amount(dict):
check_asset(other["asset"], self["asset"])
a["amount"] **= other["amount"]
else:
a["amount"] **= other
a["amount"] **= quantize(other, self["asset"]["precision"])
return a
def __iadd__(self, other):
......@@ -260,7 +266,7 @@ class Amount(dict):
check_asset(other["asset"], self["asset"])
self["amount"] += other["amount"]
else:
self["amount"] += other
self["amount"] += quantize(other, self["asset"]["precision"])
return self
def __isub__(self, other):
......@@ -268,7 +274,7 @@ class Amount(dict):
check_asset(other["asset"], self["asset"])
self["amount"] -= other["amount"]
else:
self["amount"] -= other
self["amount"] -= quantize(other, self["asset"]["precision"])
return self
def __imul__(self, other):
......@@ -276,7 +282,7 @@ class Amount(dict):
check_asset(other["asset"], self["asset"])
self["amount"] *= other["amount"]
else:
self["amount"] *= other
self["amount"] *= quantize(other, self["asset"]["precision"])
return self
def __idiv__(self, other):
......@@ -284,14 +290,14 @@ class Amount(dict):
check_asset(other["asset"], self["asset"])
return self["amount"] / other["amount"]
else:
self["amount"] /= other
self["amount"] /= quantize(other, self["asset"]["precision"])
return self
def __ifloordiv__(self, other):
if isinstance(other, Amount):
self["amount"] //= other["amount"]
else:
self["amount"] //= other
self["amount"] //= quantize(other, self["asset"]["precision"])
return self
def __imod__(self, other):
......@@ -299,11 +305,14 @@ class Amount(dict):
check_asset(other["asset"], self["asset"])
self["amount"] %= other["amount"]
else:
self["amount"] %= other
self["amount"] %= quantize(other, self["asset"]["precision"])
return self
def __ipow__(self, other):
self["amount"] **= other
if isinstance(other, Amount):
self["amount"] **= other
else:
self["amount"] **= quantize(other, self["asset"]["precision"])
return self
def __lt__(self, other):
......@@ -311,42 +320,42 @@ class Amount(dict):
check_asset(other["asset"], self["asset"])
return self["amount"] < other["amount"]
else:
return self["amount"] < float(other or 0)
return self["amount"] < quantize((other or 0), self["asset"]["precision"])
def __le__(self, other):
if isinstance(other, Amount):
check_asset(other["asset"], self["asset"])
return self["amount"] <= other["amount"]
else:
return self["amount"] <= float(other or 0)
return self["amount"] <= quantize((other or 0), self["asset"]["precision"])
def __eq__(self, other):
if isinstance(other, Amount):
check_asset(other["asset"], self["asset"])
return self["amount"] == other["amount"]
else:
return self["amount"] == float(other or 0)
return self["amount"] == quantize((other or 0), self["asset"]["precision"])
def __ne__(self, other):
if isinstance(other, Amount):
check_asset(other["asset"], self["asset"])
return self["amount"] != other["amount"]
else:
return self["amount"] != float(other or 0)
return self["amount"] != quantize((other or 0), self["asset"]["precision"])
def __ge__(self, other):
if isinstance(other, Amount):
check_asset(other["asset"], self["asset"])
return self["amount"] >= other["amount"]
else:
return self["amount"] >= float(other or 0)
return self["amount"] >= quantize((other or 0), self["asset"]["precision"])
def __gt__(self, other):
if isinstance(other, Amount):
check_asset(other["asset"], self["asset"])
return self["amount"] > other["amount"]
else:
return self["amount"] > float(other or 0)
return self["amount"] > quantize((other or 0), self["asset"]["precision"])
__repr__ = __str__
__truediv__ = __div__
......
......@@ -14,6 +14,7 @@ from .amount import Amount
from .asset import Asset
from .utils import formatTimeString
from .utils import parse_time, assets_from_string
from decimal import Decimal
@python_2_unicode_compatible
......@@ -245,7 +246,7 @@ class Price(dict):
)
def __float__(self):
return self["price"]
return float(self["price"])
def _check_other(self, other):
if not other["base"]["symbol"] == self["base"]["symbol"]:
......
......@@ -10,6 +10,7 @@ from beem.amount import Amount
from beem.asset import Asset
from beem.nodelist import NodeList
from beem.instance import set_shared_steem_instance, SharedInstance
from decimal import Decimal
class Testcases(unittest.TestCase):
......@@ -38,7 +39,7 @@ class Testcases(unittest.TestCase):
self.assertEqual(float(ret), float(amount))
self.assertEqual(ret["symbol"], symbol)
self.assertIsInstance(ret["asset"], dict)
self.assertIsInstance(ret["amount"], float)
self.assertIsInstance(ret["amount"], Decimal)
def test_init(self):
stm = self.bts
......@@ -78,6 +79,9 @@ class Testcases(unittest.TestCase):
# keyword inits
amount = Amount(amount=1.3, asset=Asset("SBD", steem_instance=stm), steem_instance=stm)
self.dotest(amount, 1.3, symbol)
amount = Amount(amount=1.3001, asset=Asset("SBD", steem_instance=stm), steem_instance=stm)
self.dotest(amount, 1.3, symbol)
# keyword inits
amount = Amount(amount=1.3, asset=dict(Asset("SBD", steem_instance=stm)), steem_instance=stm)
......@@ -152,6 +156,8 @@ class Testcases(unittest.TestCase):
self.dotest(a2, 3, self.symbol)
a2 += 5
self.dotest(a2, 8, self.symbol)
a2 += Decimal(2)
self.dotest(a2, 10, self.symbol)
with self.assertRaises(Exception):
a1 += Amount(1, asset=self.asset2)
......@@ -250,6 +256,7 @@ class Testcases(unittest.TestCase):
self.assertTrue(a1 >= a2)
self.assertTrue(a1 <= 1)
self.assertTrue(a1 >= 1)
self.assertTrue(a1 == 1.0001)
def test_ne(self):
a1 = Amount(1, self.symbol)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment