From 0c362f2c8f0cb3c202acecb4925c28991dbef0ee Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Mon, 4 Jun 2018 20:55:55 +0200 Subject: [PATCH] Added some general currency utilities. --- fulbank/currency.py | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 fulbank/currency.py diff --git a/fulbank/currency.py b/fulbank/currency.py new file mode 100644 index 0000000..547acb9 --- /dev/null +++ b/fulbank/currency.py @@ -0,0 +1,145 @@ +class currency(object): + def __init__(self, symbol): + self.symbol = symbol + + def sformat(self, amount): + return "%s %s" % (self.symbol, self.format(amount)) + + def __repr__(self): + return "#" % self.symbol + + @property + def zero(self): + return value(0, self) + + _known = {} + @classmethod + def define(cls, *args, **kwargs): + self = cls(*args, **kwargs) + cls._known[self.symbol] = self + @classmethod + def get(cls, symbol): + return cls._known[symbol] + + def __reduce__(self): + return _currency_restore, (type(self), self.symbol,) +def _currency_restore(cls, symbol): + return cls.get(symbol) + +class integral(currency): + def __init__(self, symbol): + super().__init__(symbol) + + def format(self, amount): + return "%i" % amount + + def parse(self, text): + return value(int(text), self) + +class decimal(currency): + def __init__(self, symbol, separator, thseparator, decimals=2): + super().__init__(symbol) + self.separator = separator + self.thseparator = thseparator + self.decimals = decimals + + def format(self, amount): + if amount < 0: + return "-" + self.format(-amount) + bias = 10 ** self.decimals + ip = amount // bias + fp = amount - (ip * bias) + return "%i.%0*i" % (ip, self.decimals, fp) + + def parse(self, text): + def parse2(text): + p = text.find(self.separator) + bias = 10 ** self.decimals + if p < 0: + text = text.replace(self.thseparator) + if not text.isdigit(): + raise ValueError(text) + return int(text) * bias + else: + if p != len(text) - 3: + raise ValueError(text) + ip = text[:p].replace(self.thseparator, "") + fp = text[p + 1:] + if not (ip.isdigit() and fp.isdigit()): + raise ValueError(text) + ip = int(ip) + fp = int(fp) + if fp >= bias: + raise ValueError(text) + return (ip * bias) + fp + if text[0:1] == "-": + return value(-parse2(text[1:]), self) + else: + return value(parse2(text), self) + +decimal.define("SEK", ",", " ") +decimal.define("USD", ".", ",") +integral.define("JPY") + +class value(object): + __slots__ = ["amount", "currency"] + def __init__(self, amount, currency): + self.amount = int(amount) + self.currency = currency + + def __repr__(self): + return "%s %s" % (self.currency.symbol, self.currency.format(self.amount)) + + def __add__(self, other): + if self.currency != other.currency: + raise ValueError("cannot add %s to %s" % (other.currency.symbol, self.currency.symbol)) + return value(int(self.amount + other.amount), self.currency) + def __sub__(self, other): + if self.currency != other.currency: + raise ValueError("cannot subtract %s from %s" % (other.currency.symbol, self.currency.symbol)) + return value(int(self.amount - other.amount), self.currency) + def __mul__(self, other): + return value(int(self.amount * other), self.currency) + def __truediv__(self, other): + if self.currency != other.currency: + raise ValueError("cannot divide %s with %s" % (self.currency.symbol, other.currency.symbol)) + return self.amount / other.amount + def __floordiv__(self, other): + if self.currency != other.currency: + raise ValueError("cannot divide %s with %s" % (self.currency.symbol, other.currency.symbol)) + return self.amount // other.amount + def __mod__(self, other): + if self.currency != other.currency: + raise ValueError("cannot divide %s with %s" % (self.currency.symbol, other.currency.symbol)) + return value(int(self.amount % other.amount), self.currency) + def __divmod__(self, other): + if self.currency != other.currency: + raise ValueError("cannot divide %s with %s" % (self.currency.symbol, other.currency.symbol)) + return (self.amount // other.amount, value(int(self.amount % other.amount), self.currency)) + def __neg__(self): + return value(-self.amount, self.currency) + + def __eq__(self, other): + if self.currency != other.currency: + raise ValueError("cannot compare %s with %s" % (self.currency.symbol, other.currency.symbol)) + return self.amount == other.amount + def __ne__(self, other): + if self.currency != other.currency: + raise ValueError("cannot compare %s with %s" % (self.currency.symbol, other.currency.symbol)) + return self.amount != other.amount + def __lt__(self, other): + if self.currency != other.currency: + raise ValueError("cannot compare %s with %s" % (self.currency.symbol, other.currency.symbol)) + return self.amount < other.amount + def __le__(self, other): + if self.currency != other.currency: + raise ValueError("cannot compare %s with %s" % (self.currency.symbol, other.currency.symbol)) + return self.amount <= other.amount + def __gt__(self, other): + if self.currency != other.currency: + raise ValueError("cannot compare %s with %s" % (self.currency.symbol, other.currency.symbol)) + return self.amount > other.amount + def __ge__(self, other): + if self.currency != other.currency: + raise ValueError("cannot compare %s with %s" % (self.currency.symbol, other.currency.symbol)) + return self.amount >= other.amount -- 2.11.0