gnunet-svn
[Top][All Lists]
Advanced

[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.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]