[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] [taler-taler-util] 15/51: Update amount.
From: |
gnunet |
Subject: |
[GNUnet-SVN] [taler-taler-util] 15/51: Update amount. |
Date: |
Mon, 23 Sep 2019 22:02:06 +0200 |
This is an automated email from the git hooks/post-receive script.
ng0 pushed a commit to branch master
in repository taler-util.
commit d08a5943a5308311db629642c0f921db5388bdea
Author: Marcello Stanisci <address@hidden>
AuthorDate: Tue Feb 5 15:30:38 2019 +0100
Update amount.
Taking latest Amount logic from the bank,
and adding new tests for new changes.
---
python/amount/amount.py | 82 +++++++++++++++++++++++++++-----------------
python/amount/test_amount.py | 19 ++++++++--
2 files changed, 67 insertions(+), 34 deletions(-)
diff --git a/python/amount/amount.py b/python/amount/amount.py
index e5ac4a7..34ff93a 100644
--- a/python/amount/amount.py
+++ b/python/amount/amount.py
@@ -4,56 +4,71 @@
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
+# version 2.1 of the License, or (at your option) any later
+# version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
+# License along with this library; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
#
# @author Marcello Stanisci
-# @version 0.2
+# @version 0.1
# @repository https://git.taler.net/copylib.git/
# This code is "copylib", it is versioned under the Git repository
-# mentioned above, and it is meant to be manually copied into any project
-# which might need it.
+# mentioned above, and it is meant to be manually copied into
+# any project which might need it.
class CurrencyMismatch(Exception):
- def __init__(self, curr1, curr2):
+ hint = "Internal logic error (currency mismatch)"
+ http_status_code = 500
+ def __init__(self, curr1, curr2) -> None:
super(CurrencyMismatch, self).__init__(
"%s vs %s" % (curr1, curr2))
class BadFormatAmount(Exception):
- def __init__(self, faulty_str):
+ def __init__(self, faulty_str) -> None:
super(BadFormatAmount, self).__init__(
"Bad format amount: " + faulty_str)
+class NumberTooBig(Exception):
+ def __init__(self) -> None:
+ super(NumberTooBig, self).__init__(
+ "Number given is too big!")
+
+class NegativeNumber(Exception):
+ def __init__(self) -> None:
+ super(NegativeNumber, self).__init__(
+ "Negative number given as value and/or fraction!")
+
class Amount:
# How many "fraction" units make one "value" unit of currency
# (Taler requires 10^8). Do not change this 'constant'.
@staticmethod
- def _fraction():
+ def _fraction() -> int:
return 10 ** 8
@staticmethod
- def _max_value():
+ def _max_value() -> int:
return (2 ** 53) - 1
- def __init__(self, currency, value=0, fraction=0):
- # type: (str, int, int) -> Amount
- assert value >= 0 and fraction >= 0
+ def __init__(self, currency, value=0, fraction=0) -> None:
+ if value < 0 or fraction < 0:
+ raise NegativeNumber()
self.value = value
self.fraction = fraction
self.currency = currency
self.__normalize()
- assert self.value <= Amount._max_value()
+ if self.value > Amount._max_value():
+ raise NumberTooBig()
# Normalize amount
- def __normalize(self):
+ def __normalize(self) -> None:
if self.fraction >= Amount._fraction():
self.value += int(self.fraction / Amount._fraction())
self.fraction = self.fraction % Amount._fraction()
@@ -61,15 +76,15 @@ class Amount:
# Parse a string matching the format "A:B.C"
# instantiating an amount object.
@classmethod
- def parse(cls, amount_str):
- exp = r'^\s*([-_*A-Za-z0-9]+):([0-9]+)\.([0-9]+)\s*$'
+ def parse(cls, amount_str: str):
+ exp = r'^\s*([-_*A-Za-z0-9]+):([0-9]+)\.?([0-9]+)?\s*$'
import re
parsed = re.search(exp, amount_str)
if not parsed:
raise BadFormatAmount(amount_str)
value = int(parsed.group(2))
fraction = 0
- for i, digit in enumerate(parsed.group(3)):
+ for i, digit in enumerate(parsed.group(3) or "0"):
fraction += int(int(digit) * (Amount._fraction() / 10 ** (i+1)))
return cls(parsed.group(1), value, fraction)
@@ -78,7 +93,7 @@ class Amount:
# 0 if a == b
# 1 if a > b
@staticmethod
- def cmp(am1, am2):
+ def cmp(am1, am2) -> int:
if am1.currency != am2.currency:
raise CurrencyMismatch(am1.currency, am2.currency)
if am1.value == am2.value:
@@ -91,13 +106,13 @@ class Amount:
return -1
return 1
- def set(self, currency, value=0, fraction=0):
+ def set(self, currency: str, value=0, fraction=0) -> None:
self.currency = currency
self.value = value
self.fraction = fraction
# Add the given amount to this one
- def add(self, amount):
+ def add(self, amount) -> None:
if self.currency != amount.currency:
raise CurrencyMismatch(self.currency, amount.currency)
self.value += amount.value
@@ -105,7 +120,7 @@ class Amount:
self.__normalize()
# Subtract passed amount from this one
- def subtract(self, amount):
+ def subtract(self, amount) -> None:
if self.currency != amount.currency:
raise CurrencyMismatch(self.currency, amount.currency)
if self.fraction < amount.fraction:
@@ -118,18 +133,21 @@ class Amount:
# Dump string from this amount, will put 'ndigits' numbers
# after the dot.
- def stringify(self, ndigits):
- assert ndigits > 0
- ret = '%s:%s.' % (self.currency, str(self.value))
- fraction = self.fraction
+ def stringify(self, ndigits: int, pretty=False) -> str:
+ if ndigits <= 0:
+ raise BadFormatAmount("ndigits must be > 0")
+ tmp = self.fraction
+ fraction_str = ""
while ndigits > 0:
- ret += str(int(fraction / (Amount._fraction() / 10)))
- fraction = (fraction * 10) % (Amount._fraction())
+ fraction_str += str(int(tmp / (Amount._fraction() / 10)))
+ tmp = (tmp * 10) % (Amount._fraction())
ndigits -= 1
- return ret
+ if not pretty:
+ return "%s:%d.%s" % (self.currency, self.value, fraction_str)
+ return "%d.%s %s" % (self.value, fraction_str, self.currency)
# Dump the Taler-compliant 'dict' amount
- def dump(self):
+ def dump(self) -> dict:
return dict(value=self.value,
fraction=self.fraction,
currency=self.currency)
diff --git a/python/amount/test_amount.py b/python/amount/test_amount.py
old mode 100644
new mode 100755
index 106b360..41b9037
--- a/python/amount/test_amount.py
+++ b/python/amount/test_amount.py
@@ -23,7 +23,7 @@
# which might need it.
from __future__ import unicode_literals
-from .amount import Amount, BadAmount
+from amount import Amount, BadFormatAmount, NumberTooBig, NegativeNumber
from unittest import TestCase
import json
from mock import MagicMock
@@ -31,6 +31,21 @@ from mock import MagicMock
class TestAmount(TestCase):
def setUp(self):
self.amount = Amount('TESTKUDOS')
+
+ def test_very_big_number(self):
+ with self.assertRaises(NumberTooBig):
+ self.Amount = Amount('TESTKUDOS',
+
value=99999999999999999999999999999999999999999999)
+
+ def test_negative_value(self):
+ with self.assertRaises(NegativeNumber):
+ self.Amount = Amount('TESTKUDOS',
+ value=-9)
+
+ def test_bad_stringification(self):
+ amount = Amount('TESTKUDOS')
+ with self.assertRaises(BadFormatAmount):
+ amount.stringify(0)
def test_parse_and_cmp(self):
a = self.amount.parse('TESTKUDOS:0.0')
@@ -41,7 +56,7 @@ class TestAmount(TestCase):
self.assertEqual(Amount.cmp(Amount('TESTKUDOS', 3, 30000000), c), 0)
self.assertEqual(Amount.cmp(a, b), -1)
self.assertEqual(Amount.cmp(c, b), 1)
- with self.assertRaises(BadAmount):
+ with self.assertRaises(BadFormatAmount):
Amount.parse(':3')
def test_add_and_dump(self):
--
To stop receiving notification emails like this one, please contact
address@hidden.
- [GNUnet-SVN] [taler-taler-util] 11/51: Towards a usable solution for #4453., (continued)
- [GNUnet-SVN] [taler-taler-util] 11/51: Towards a usable solution for #4453., gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 13/51: Give loglevels dedicate class + test., gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 16/51: Updating Amount from bank., gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 19/51: Parsing GNUNET_FORCE_LOGFILE., gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 26/51: 4453. Check against further fields (filename, func, lineno), gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 17/51: 4453., gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 24/51: fix filename extraction., gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 18/51: 4453., gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 20/51: 4453., gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 22/51: 4453, use regex., gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 15/51: Update amount.,
gnunet <=
- [GNUnet-SVN] [taler-taler-util] 21/51: 4453., gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 23/51: fetch caller's metadata., gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 29/51: rename function, gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 30/51: Testing env var GNUNET_LOG., gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 32/51: 4453. Testing mixed situation,, gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 37/51: fix after file rename, gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 38/51: 4453. Test GNUNET_FORCE_LOGFILE., gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 50/51: Make tests work again., gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 33/51: 4453. Test manual loglevel setup and nonforced env., gnunet, 2019/09/23
- [GNUnet-SVN] [taler-taler-util] 27/51: syntax, gnunet, 2019/09/23