Commit | Line | Data |
---|---|---|
0c362f2c FT |
1 | class currency(object): |
2 | def __init__(self, symbol): | |
3 | self.symbol = symbol | |
4 | ||
5 | def sformat(self, amount): | |
6 | return "%s %s" % (self.symbol, self.format(amount)) | |
7 | ||
8 | def __repr__(self): | |
9 | return "#<currency %s>" % self.symbol | |
10 | ||
11 | @property | |
12 | def zero(self): | |
13 | return value(0, self) | |
14 | ||
15 | _known = {} | |
16 | @classmethod | |
17 | def define(cls, *args, **kwargs): | |
18 | self = cls(*args, **kwargs) | |
19 | cls._known[self.symbol] = self | |
20 | @classmethod | |
21 | def get(cls, symbol): | |
22 | return cls._known[symbol] | |
23 | ||
24 | def __reduce__(self): | |
25 | return _currency_restore, (type(self), self.symbol,) | |
26 | def _currency_restore(cls, symbol): | |
27 | return cls.get(symbol) | |
28 | ||
29 | class integral(currency): | |
30 | def __init__(self, symbol): | |
31 | super().__init__(symbol) | |
32 | ||
33 | def format(self, amount): | |
34 | return "%i" % amount | |
35 | ||
36 | def parse(self, text): | |
37 | return value(int(text), self) | |
38 | ||
39 | class decimal(currency): | |
40 | def __init__(self, symbol, separator, thseparator, decimals=2): | |
41 | super().__init__(symbol) | |
42 | self.separator = separator | |
43 | self.thseparator = thseparator | |
44 | self.decimals = decimals | |
45 | ||
46 | def format(self, amount): | |
47 | if amount < 0: | |
48 | return "-" + self.format(-amount) | |
49 | bias = 10 ** self.decimals | |
50 | ip = amount // bias | |
51 | fp = amount - (ip * bias) | |
52 | return "%i.%0*i" % (ip, self.decimals, fp) | |
53 | ||
54 | def parse(self, text): | |
55 | def parse2(text): | |
56 | p = text.find(self.separator) | |
57 | bias = 10 ** self.decimals | |
58 | if p < 0: | |
59 | text = text.replace(self.thseparator) | |
60 | if not text.isdigit(): | |
61 | raise ValueError(text) | |
62 | return int(text) * bias | |
63 | else: | |
64 | if p != len(text) - 3: | |
65 | raise ValueError(text) | |
66 | ip = text[:p].replace(self.thseparator, "") | |
67 | fp = text[p + 1:] | |
68 | if not (ip.isdigit() and fp.isdigit()): | |
69 | raise ValueError(text) | |
70 | ip = int(ip) | |
71 | fp = int(fp) | |
72 | if fp >= bias: | |
73 | raise ValueError(text) | |
74 | return (ip * bias) + fp | |
75 | if text[0:1] == "-": | |
76 | return value(-parse2(text[1:]), self) | |
77 | else: | |
78 | return value(parse2(text), self) | |
79 | ||
80 | decimal.define("SEK", ",", " ") | |
81 | decimal.define("USD", ".", ",") | |
82 | integral.define("JPY") | |
83 | ||
84 | class value(object): | |
85 | __slots__ = ["amount", "currency"] | |
86 | def __init__(self, amount, currency): | |
87 | self.amount = int(amount) | |
88 | self.currency = currency | |
89 | ||
90 | def __repr__(self): | |
91 | return "%s %s" % (self.currency.symbol, self.currency.format(self.amount)) | |
92 | ||
93 | def __add__(self, other): | |
94 | if self.currency != other.currency: | |
95 | raise ValueError("cannot add %s to %s" % (other.currency.symbol, self.currency.symbol)) | |
96 | return value(int(self.amount + other.amount), self.currency) | |
97 | def __sub__(self, other): | |
98 | if self.currency != other.currency: | |
99 | raise ValueError("cannot subtract %s from %s" % (other.currency.symbol, self.currency.symbol)) | |
100 | return value(int(self.amount - other.amount), self.currency) | |
101 | def __mul__(self, other): | |
102 | return value(int(self.amount * other), self.currency) | |
103 | def __truediv__(self, other): | |
104 | if self.currency != other.currency: | |
105 | raise ValueError("cannot divide %s with %s" % (self.currency.symbol, other.currency.symbol)) | |
106 | return self.amount / other.amount | |
107 | def __floordiv__(self, other): | |
108 | if self.currency != other.currency: | |
109 | raise ValueError("cannot divide %s with %s" % (self.currency.symbol, other.currency.symbol)) | |
110 | return self.amount // other.amount | |
111 | def __mod__(self, other): | |
112 | if self.currency != other.currency: | |
113 | raise ValueError("cannot divide %s with %s" % (self.currency.symbol, other.currency.symbol)) | |
114 | return value(int(self.amount % other.amount), self.currency) | |
115 | def __divmod__(self, other): | |
116 | if self.currency != other.currency: | |
117 | raise ValueError("cannot divide %s with %s" % (self.currency.symbol, other.currency.symbol)) | |
118 | return (self.amount // other.amount, value(int(self.amount % other.amount), self.currency)) | |
119 | def __neg__(self): | |
120 | return value(-self.amount, self.currency) | |
121 | ||
122 | def __eq__(self, other): | |
123 | if self.currency != other.currency: | |
124 | raise ValueError("cannot compare %s with %s" % (self.currency.symbol, other.currency.symbol)) | |
125 | return self.amount == other.amount | |
126 | def __ne__(self, other): | |
127 | if self.currency != other.currency: | |
128 | raise ValueError("cannot compare %s with %s" % (self.currency.symbol, other.currency.symbol)) | |
129 | return self.amount != other.amount | |
130 | def __lt__(self, other): | |
131 | if self.currency != other.currency: | |
132 | raise ValueError("cannot compare %s with %s" % (self.currency.symbol, other.currency.symbol)) | |
133 | return self.amount < other.amount | |
134 | def __le__(self, other): | |
135 | if self.currency != other.currency: | |
136 | raise ValueError("cannot compare %s with %s" % (self.currency.symbol, other.currency.symbol)) | |
137 | return self.amount <= other.amount | |
138 | def __gt__(self, other): | |
139 | if self.currency != other.currency: | |
140 | raise ValueError("cannot compare %s with %s" % (self.currency.symbol, other.currency.symbol)) | |
141 | return self.amount > other.amount | |
142 | def __ge__(self, other): | |
143 | if self.currency != other.currency: | |
144 | raise ValueError("cannot compare %s with %s" % (self.currency.symbol, other.currency.symbol)) | |
145 | return self.amount >= other.amount | |
619e377b FT |
146 | |
147 | def __hash__(self): | |
148 | return hash(self.amount) + hash(self.currency) |