X-Git-Url: https://wannabe.guru.org/gitweb/?a=blobdiff_plain;f=type%2Fcentcount.py;h=e78d068910e8281cbf28ee8674e7b6cff44f89fd;hb=532df2c5b57c7517dfb3dddd8c1358fbadf8baf3;hp=4181721bbc0d4ab7efe38608b821faa26ecf5bae;hpb=4faa994d32223c8d560d9dad0ca90a3f7eb10d6a;p=python_utils.git diff --git a/type/centcount.py b/type/centcount.py index 4181721..e78d068 100644 --- a/type/centcount.py +++ b/type/centcount.py @@ -1,26 +1,23 @@ #!/usr/bin/env python3 -import re -from typing import Optional, TypeVar, Tuple +# © Copyright 2021-2022, Scott Gasch -import math_utils +"""An amount of money (USD) represented as an integral count of +cents.""" +import re +from typing import Optional, Tuple -T = TypeVar('T', bound='CentCount') +import math_utils class CentCount(object): """A class for representing monetary amounts potentially with - different currencies. + different currencies meant to avoid floating point rounding + issues by treating amount as a simple integral count of cents. """ - def __init__ ( - self, - centcount, - currency: str = 'USD', - *, - strict_mode = False - ): + def __init__(self, centcount, currency: str = 'USD', *, strict_mode=False): self.strict_mode = strict_mode if isinstance(centcount, str): ret = CentCount._parse(centcount) @@ -36,7 +33,7 @@ class CentCount(object): if not currency: self.currency: Optional[str] = None else: - self.currency: Optional[str] = currency + self.currency = currency def __repr__(self): a = float(self.centcount) @@ -44,9 +41,9 @@ class CentCount(object): a = round(a, 2) s = f'{a:,.2f}' if self.currency is not None: - return '%s %s' % (s, self.currency) + return f'{s} {self.currency}' else: - return '$%s' % s + return f'${s}' def __pos__(self): return CentCount(centcount=self.centcount, currency=self.currency) @@ -58,8 +55,8 @@ class CentCount(object): if isinstance(other, CentCount): if self.currency == other.currency: return CentCount( - centcount = self.centcount + other.centcount, - currency = self.currency + centcount=self.centcount + other.centcount, + currency=self.currency, ) else: raise TypeError('Incompatible currencies in add expression') @@ -73,8 +70,8 @@ class CentCount(object): if isinstance(other, CentCount): if self.currency == other.currency: return CentCount( - centcount = self.centcount - other.centcount, - currency = self.currency + centcount=self.centcount - other.centcount, + currency=self.currency, ) else: raise TypeError('Incompatible currencies in add expression') @@ -89,8 +86,8 @@ class CentCount(object): raise TypeError('can not multiply monetary quantities') else: return CentCount( - centcount = int(self.centcount * float(other)), - currency = self.currency + centcount=int(self.centcount * float(other)), + currency=self.currency, ) def __truediv__(self, other): @@ -98,8 +95,8 @@ class CentCount(object): raise TypeError('can not divide monetary quantities') else: return CentCount( - centcount = int(float(self.centcount) / float(other)), - currency = self.currency + centcount=int(float(self.centcount) / float(other)), + currency=self.currency, ) def __int__(self): @@ -124,8 +121,8 @@ class CentCount(object): if isinstance(other, CentCount): if self.currency == other.currency: return CentCount( - centcount = other.centcount - self.centcount, - currency = self.currency + centcount=other.centcount - self.centcount, + currency=self.currency, ) else: raise TypeError('Incompatible currencies in sub expression') @@ -134,8 +131,8 @@ class CentCount(object): raise TypeError('In strict_mode only two moneys can be added') else: return CentCount( - centcount = int(other) - self.centcount, - currency = self.currency + centcount=int(other) - self.centcount, + currency=self.currency, ) __rmul__ = __mul__ @@ -147,10 +144,7 @@ class CentCount(object): if other is None: return False if isinstance(other, CentCount): - return ( - self.centcount == other.centcount and - self.currency == other.currency - ) + return self.centcount == other.centcount and self.currency == other.currency if self.strict_mode: raise TypeError("In strict mode only two CentCounts can be compared") else: @@ -192,11 +186,11 @@ class CentCount(object): def __ge__(self, other): return self > other or self == other - def __hash__(self): - return self.__repr__ + def __hash__(self) -> int: + return hash(self.__repr__) - CENTCOUNT_RE = re.compile("^([+|-]?)(\d+)(\.\d+)$") - CURRENCY_RE = re.compile("^[A-Z][A-Z][A-Z]$") + CENTCOUNT_RE = re.compile(r"^([+|-]?)(\d+)(\.\d+)$") + CURRENCY_RE = re.compile(r"^[A-Z][A-Z][A-Z]$") @classmethod def _parse(cls, s: str) -> Optional[Tuple[int, str]]: @@ -210,7 +204,7 @@ class CentCount(object): centcount = int(float(chunk) * 100.0) elif CentCount.CURRENCY_RE.match(chunk) is not None: currency = chunk - except: + except Exception: pass if centcount is not None and currency is not None: return (centcount, currency) @@ -219,7 +213,7 @@ class CentCount(object): return None @classmethod - def parse(cls, s: str) -> T: + def parse(cls, s: str) -> 'CentCount': chunks = CentCount._parse(s) if chunks is not None: return CentCount(chunks[0], chunks[1])