I moved built-in currencies to a configuration file. Made some clean ups, fixed what I've done last night. I guess, it's READY!
This commit is contained in:
parent
0efb129ad3
commit
f2d2e75128
18
README.md
18
README.md
@ -7,26 +7,12 @@ you decide to take them all out.
|
||||
Yes, only coins, no banknots. Well, you actually can easily add support for
|
||||
banknots, but table will become indeed wide.
|
||||
|
||||
# Backstory
|
||||
|
||||
Many years ago I wrote a little script to store info on how much coins I have
|
||||
in my piggy bank. It used SQLite 3 database for it and was hardcoded to rubles.
|
||||
Why had I use whole SQL database? That was the first time I tried SQLite in
|
||||
Python.
|
||||
|
||||
Once I came up with an idea that it would be good to learn on how to make
|
||||
packages for Python. And with no better ideas I took my piggy bank script to be
|
||||
rewritten to support any currency. Database was thrown away and its place was
|
||||
took by a simple text format.
|
||||
|
||||
# Usage
|
||||
|
||||
This is a CLI program that is broken down to three separate programs:
|
||||
|
||||
piggybank [OPTIONS] (COINS in FILE [of CURRENCY] | COINS from FILE
|
||||
| show FILE [with t(ransactions)])
|
||||
|
||||
Options:
|
||||
Common options:
|
||||
|
||||
- `-h,--help` — print this help;
|
||||
|
||||
@ -120,6 +106,6 @@ Currency is defined following way:
|
||||
|
||||
That is best described with an example. Here it is:
|
||||
|
||||
currency.SRUB = SRUB;Russian ruble (shortened);Russian Federation. Excluding coins of 1 and 5 kopek;6;10к.,50к.,1₽,2₽,5₽,10₽;10,50,100,200,500,1000
|
||||
currency.EXM = EXM;Example;Example currency;2;1E,2E;100,200
|
||||
|
||||
Yes, long and clunky way... May be I'll come up with something better.
|
||||
|
@ -1,4 +1,4 @@
|
||||
__all__ = ["__date__", "__version__", "__author__", "__author_email__",
|
||||
__all__ = ["__date__", "__version__", "__author__", "__email__",
|
||||
"__copyright__", "__license__", "PIGGYBANK_FILE_EXTENSION",
|
||||
"VERSION"]
|
||||
|
||||
@ -6,8 +6,8 @@ __all__ = ["__date__", "__version__", "__author__", "__author_email__",
|
||||
__date__ = "7 June 2020"
|
||||
__version__ = "1.0.0"
|
||||
__author__ = "Alexander \"Arav\" Andreev"
|
||||
__author_email__ = "me@arav.top"
|
||||
__copyright__ = f"Copyright (c) 2020 {__author__} <{__author_email__}>"
|
||||
__email__ = "me@arav.top"
|
||||
__copyright__ = f"Copyright (c) 2020 {__author__} <{__email__}>"
|
||||
__license__ = \
|
||||
"""This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
|
@ -1,12 +0,0 @@
|
||||
from typing import List
|
||||
|
||||
from piggybank.currencies import CURRENCIES
|
||||
|
||||
__all__ = ["complement_list_of_coins"]
|
||||
|
||||
|
||||
def complement_list_of_coins(coins: List[int], currency: str,
|
||||
_reversed: bool = False) -> List[int]:
|
||||
"""Complements list of coins up to the count of currency's coins."""
|
||||
offset_array = [0] * (len(CURRENCIES[currency]) - len(coins))
|
||||
return offset_array + coins if not _reversed else coins + offset_array
|
@ -2,9 +2,9 @@
|
||||
|
||||
from re import search, split
|
||||
from sys import argv, stderr
|
||||
from typing import List
|
||||
|
||||
from piggybank import VERSION
|
||||
from piggybank.cli import complement_list_of_coins
|
||||
from piggybank.configuration import Configuration
|
||||
from piggybank.currencies import Currency, BaseCurrencyError, CURRENCIES
|
||||
from piggybank.piggybank import PiggyBank
|
||||
@ -34,8 +34,8 @@ Show: piggybank show FILE [with t(ransactions)]
|
||||
|
||||
Arguments:
|
||||
\tCOINS -- a set of comma or whitespace separated coin counts;
|
||||
\tFILE -- a filename of a piggybank;
|
||||
\tof CURRENCY -- set a partcular currency for a piggybank;
|
||||
\tFILE -- a filename of a piggy bank;
|
||||
\tof CURRENCY -- set a partcular currency for a piggy bank;
|
||||
\twith t(ransactions) -- print a table of transactions as well.
|
||||
"""
|
||||
|
||||
@ -99,11 +99,11 @@ def print_summary(pb: PiggyBank) -> None:
|
||||
s = sum_transactions(pb.transactions)
|
||||
print(f"┃{'Counts':^27}┃{'┃'.join(f'{c:^12}' for c in s)}┃")
|
||||
print_separator("┣", "╋", "╋", "┫")
|
||||
s = cur.multiply(s)
|
||||
print(f"┃{'Sums':^27}┃{'┃'.join(f'{c/100:^12.2f}' for c in s)}┃")
|
||||
s = cur * s
|
||||
print(f"┃{'Sums in currency':^27}┃{'┃'.join(f'{c/100:^12.2f}' for c in s)}┃")
|
||||
print_separator("┣", "╋", "┻", "┫")
|
||||
s = sum(s)
|
||||
print(f"┃{'Total':^27}┃{s:^{12*cur.count+cur.count-1}}┃")
|
||||
print(f"┃{'Total in currency':^27}┃{s/100:^{12*cur.count+cur.count-1}.2f}┃")
|
||||
print_separator("┗", "┻", "━", "┛")
|
||||
|
||||
|
||||
@ -115,12 +115,18 @@ def print_supported_currencies() -> None:
|
||||
f" ┃ {CURRENCIES[cur].description}")
|
||||
print("Default currency is", Configuration()["default-currency"])
|
||||
|
||||
|
||||
def load_user_defined_currencies() -> None:
|
||||
def load_currencies() -> None:
|
||||
"""Load currencies defined in a configuration file."""
|
||||
if not "currency" in Configuration().items:
|
||||
return
|
||||
for iso, cur in Configuration()["currency"].items():
|
||||
CURRENCIES[iso] = Currency.from_string(cur)
|
||||
CURRENCIES[iso.upper()] = Currency.from_string(cur)
|
||||
|
||||
def complement_list_of_coins(coins: List[int], currency: str,
|
||||
_reversed: bool = False) -> List[int]:
|
||||
"""Complements list of coins up to the count of currency's coins."""
|
||||
offset_array = [0] * (len(CURRENCIES[currency]) - len(coins))
|
||||
return offset_array + coins if not _reversed else coins + offset_array
|
||||
|
||||
|
||||
def main():
|
||||
@ -133,6 +139,7 @@ def main():
|
||||
print(VERSION)
|
||||
exit()
|
||||
elif cargs["list-currencies"]:
|
||||
load_currencies()
|
||||
print_supported_currencies()
|
||||
exit()
|
||||
elif not cargs["default-currency"] is None:
|
||||
@ -147,7 +154,7 @@ def main():
|
||||
exit()
|
||||
|
||||
try:
|
||||
load_user_defined_currencies()
|
||||
load_currencies()
|
||||
try:
|
||||
pb = PiggyBank.from_file(args["file"])
|
||||
except FileNotFoundError:
|
||||
|
@ -27,7 +27,22 @@ def get_configuration_path() -> str:
|
||||
|
||||
|
||||
DEFAULT_CONFIGURATION = {
|
||||
"default-currency": "SRUB" }
|
||||
"default-currency": "SRUB",
|
||||
"currency": {
|
||||
"RUB": "RUB;Russian ruble;Russian Federation;8;" \
|
||||
"1к,5к,10к,50к,1₽,2₽,5₽,10₽;1,5,10,50,100,200,500,1000",
|
||||
"SRUB": "SRUB;Russian ruble (short);No 1 and 5 kopek;6;" \
|
||||
"10к,50к,1₽,2₽,5₽,10₽;10,50,100,200,500,1000",
|
||||
"BYN": "BYN;Belarusian ruble;Belarus;8;" \
|
||||
"1к,2к,5к,10к,20к,50к,1р,2р;1,2,5,10,20,50,100,200",
|
||||
"UAH": "UAH;Ukrainian hryvnia;Ukraine;10;" \
|
||||
"1к,2к,5к,10к,25к,50к,₴1,₴2,₴5,₴10;1,2,5,10,25,50,100,200,500,1000",
|
||||
"USD": "USD;US Dollar;United States of America;6;" \
|
||||
"1¢,5¢,10¢,25¢,50¢,$1;1,5,10,25,50,100",
|
||||
"EUR": "EUR;Euro;European Union;8;" \
|
||||
"1c,2c,5c,10c,20c,50c,€1,€2;1,2,5,10,20,50,100,200",
|
||||
"GBP": "GBP;Pound sterling;United Kingdom;9;" \
|
||||
"1p,2p,5p,10p,20p,25p,50p,£1,£2;1,2,5,10,20,25,50,100,200" } }
|
||||
|
||||
DEFAULT_CONFIGURATION_FILE = join(get_configuration_path(), "piggybank.conf")
|
||||
|
||||
@ -45,19 +60,25 @@ class Configuration:
|
||||
|
||||
def load(self) -> None:
|
||||
for line in open(self._configuration_file, 'r'):
|
||||
if line[0] == "#":
|
||||
if line[0] == "#" or line[0] == "\n":
|
||||
continue
|
||||
key, value = line[:-1].split(" = ")
|
||||
if key.find(".") != -1:
|
||||
k0, k1 = key.split(".")
|
||||
self._configuration[k0] = {k1 : value}
|
||||
if not k0 in self._configuration:
|
||||
self._configuration[k0] = dict()
|
||||
self._configuration[k0][k1] = value
|
||||
else:
|
||||
self._configuration[key] = value
|
||||
|
||||
def save(self) -> None:
|
||||
with open(self._configuration_file, 'w') as cf:
|
||||
for key, value in self._configuration.items():
|
||||
cf.write(f"{key} = {value}\n")
|
||||
if type(value) is dict:
|
||||
for subkey, subvalue in value.items():
|
||||
cf.write(f"{key}.{subkey} = {subvalue}\n")
|
||||
else:
|
||||
cf.write(f"{key} = {value}\n")
|
||||
|
||||
@property
|
||||
def items(self) -> dict:
|
||||
|
@ -16,6 +16,9 @@ __all__ = [ "Currency", "CURRENCIES", "BaseCurrencyError",
|
||||
"CurrencyMismatchError"]
|
||||
|
||||
|
||||
CURRENCIES: Dict[str, Currency] = dict()
|
||||
|
||||
|
||||
class BaseCurrencyError(Exception):
|
||||
"""Base class for all currency exeptions."""
|
||||
def __init__(self, message=None, *args, **kwargs) -> None:
|
||||
@ -122,27 +125,27 @@ class Currency:
|
||||
f"{','.join(list(map(str, self.face_values)))}"
|
||||
|
||||
|
||||
CURRENCIES: Dict[str, Currency] = {
|
||||
"RUB": Currency("RUB", "Russian ruble", "Russian Federation", 8,
|
||||
["1к.", "5к.", "10к.", "50к.", "1₽", "2₽", "5₽", "10₽"],
|
||||
[1, 5, 10, 50, 1_00, 2_00, 5_00, 10_00]),
|
||||
"SRUB": Currency("SRUB", "Russian ruble (shortened)",
|
||||
"Russian Federation. Excluding coins of 1 and 5 kopek.",
|
||||
6, ["10к.", "50к.", "1₽", "2₽", "5₽", "10₽"],
|
||||
[10, 50, 1_00, 2_00, 5_00, 10_00]),
|
||||
"BYN": Currency("BYN", "Belarusian ruble", "Belarus", 8,
|
||||
["1к.", "2к.", "5к.", "10к.", "20к.", "50к.", "1р.", "2р."],
|
||||
[1, 2, 5, 10, 20, 50, 1_00, 2_00]),
|
||||
"UAH": Currency("UAH", "Ukrainian hryvnia", "Ukraine", 10,
|
||||
["1к.", "2к.", "5к.", "10к.", "25к.", "50к.", "₴1", "₴2", "₴5", "₴10"],
|
||||
[1, 2, 5, 10, 25, 50, 1_00, 2_00, 5_00, 10_00]),
|
||||
"USD": Currency("USD", "US Dollar", "United States of America", 6,
|
||||
["1¢", "5¢", "10¢", "25¢", "50¢", "$1"],
|
||||
[1, 5, 10, 25, 50, 1_00]),
|
||||
"EUR": Currency("EUR", "Euro", "European Union", 8,
|
||||
["1c", "2c", "5c", "10c", "20c", "50c", "€1", "€2"],
|
||||
[1, 2, 5, 10, 20, 50, 1_00, 2_00]),
|
||||
"GBP": Currency("GBP", "Pound sterling", "United Kingdom", 9,
|
||||
["1p", "2p", "5p", "10p", "20p", "25p", "50p", "£1", "£2"],
|
||||
[1, 2, 5, 10, 20, 25, 50, 1_00, 2_00])
|
||||
}
|
||||
# CURRENCIES: Dict[str, Currency] = {
|
||||
# "RUB": Currency("RUB", "Russian ruble", "Russian Federation", 8,
|
||||
# ["1к.", "5к.", "10к.", "50к.", "1₽", "2₽", "5₽", "10₽"],
|
||||
# [1, 5, 10, 50, 1_00, 2_00, 5_00, 10_00]),
|
||||
# "SRUB": Currency("SRUB", "Russian ruble (shortened)",
|
||||
# "Russian Federation. Excluding coins of 1 and 5 kopek.",
|
||||
# 6, ["10к.", "50к.", "1₽", "2₽", "5₽", "10₽"],
|
||||
# [10, 50, 1_00, 2_00, 5_00, 10_00]),
|
||||
# "BYN": Currency("BYN", "Belarusian ruble", "Belarus", 8,
|
||||
# ["1к.", "2к.", "5к.", "10к.", "20к.", "50к.", "1р.", "2р."],
|
||||
# [1, 2, 5, 10, 20, 50, 1_00, 2_00]),
|
||||
# "UAH": Currency("UAH", "Ukrainian hryvnia", "Ukraine", 10,
|
||||
# ["1к.", "2к.", "5к.", "10к.", "25к.", "50к.", "₴1", "₴2", "₴5", "₴10"],
|
||||
# [1, 2, 5, 10, 25, 50, 1_00, 2_00, 5_00, 10_00]),
|
||||
# "USD": Currency("USD", "US Dollar", "United States of America", 6,
|
||||
# ["1¢", "5¢", "10¢", "25¢", "50¢", "$1"],
|
||||
# [1, 5, 10, 25, 50, 1_00]),
|
||||
# "EUR": Currency("EUR", "Euro", "European Union", 8,
|
||||
# ["1c", "2c", "5c", "10c", "20c", "50c", "€1", "€2"],
|
||||
# [1, 2, 5, 10, 20, 50, 1_00, 2_00]),
|
||||
# "GBP": Currency("GBP", "Pound sterling", "United Kingdom", 9,
|
||||
# ["1p", "2p", "5p", "10p", "20p", "25p", "50p", "£1", "£2"],
|
||||
# [1, 2, 5, 10, 20, 25, 50, 1_00, 2_00])
|
||||
# }
|
||||
|
@ -5,8 +5,7 @@ from os.path import exists
|
||||
from typing import List
|
||||
|
||||
from piggybank import PIGGYBANK_FILE_EXTENSION
|
||||
from piggybank.currencies import CURRENCIES, CurrencyIsNotSupportedError, \
|
||||
CurrencyMismatchError
|
||||
from piggybank.currencies import CURRENCIES, CurrencyIsNotSupportedError
|
||||
from piggybank.transaction import Transaction, sum_transactions, TYPE_INCOME
|
||||
|
||||
__all__ = ["PiggyBank"]
|
||||
@ -93,10 +92,3 @@ class PiggyBank:
|
||||
def __eq__(self, piggybank: PiggyBank) -> str:
|
||||
"""Compares only currency."""
|
||||
return self._currency == piggybank.currency
|
||||
|
||||
def __add__(self, piggybank: PiggyBank) -> PiggyBank:
|
||||
if self != piggybank:
|
||||
raise CurrencyMismatchError
|
||||
new = PiggyBank(self._currency)
|
||||
new._transactions = self._transactions + piggybank._transactions
|
||||
return new
|
||||
|
@ -7,7 +7,7 @@ from typing import Optional, List, Union
|
||||
|
||||
from piggybank.currencies import CURRENCIES
|
||||
|
||||
__all__ = ["Transaction", "sum_transactions", "multiply_transactions",
|
||||
__all__ = ["Transaction", "sum_transactions",
|
||||
"TYPE_INCOME", "TYPE_OUTCOME", "TIME_FORMAT"]
|
||||
|
||||
|
||||
@ -27,16 +27,6 @@ def sum_transactions(transactions: List[Transaction]) -> List[int]:
|
||||
coins = list(map(sub, coins, transaction.coins))
|
||||
return coins
|
||||
|
||||
def multiply_transactions(transactions: Union[List[Transaction], Transaction],
|
||||
currency: str) -> List[int]:
|
||||
"""Multiplies coins' counts by currency."""
|
||||
if type(transactions) is Transaction:
|
||||
return list(map(mul, transactions.coins, \
|
||||
CURRENCIES[currency]["multipliers"]))
|
||||
else:
|
||||
coins = sum_transactions(transactions)
|
||||
return list(map(mul, coins, CURRENCIES[currency]["multipliers"]))
|
||||
|
||||
|
||||
class Transaction:
|
||||
"""An object that holds a single transaction.
|
||||
|
Loading…
Reference in New Issue
Block a user