1
0

Massive refactoring continues. All the mess I made last night is fixed next night. Program works!

This commit is contained in:
Alexander Andreev 2020-06-05 03:51:29 +04:00
parent df78739a36
commit 1da27a0271
9 changed files with 100 additions and 84 deletions

View File

@ -1,3 +1,8 @@
__all__ = ["__date__", "__version__", "__author__", "__email__",
"__copyright__", "__license__", "PIGGYBANK_FILE_EXTENSION",
"print_program_version"]
__date__ = "4 June 2020"
__version__ = "1.0.0"
__author__ = "Alexander \"Arav\" Andreev"

View File

@ -1,12 +1,13 @@
from re import search
from typing import List, Callable
from sys import argv, exit
from sys import argv
from piggybank import print_program_version
from piggybank.configuration import Configuration
from piggybank.currencies import CURRENCIES
__all__ = ["handle_default_arguments", "complement_array_of_coins"]
__all__ = ["handle_default_arguments", "complement_list_of_coins",
"print_supported_currencies", "decimal_to_float"]
USAGE_COMMON: str = "Usage: piggybank-* " \
@ -26,28 +27,31 @@ def parse_common_arguments(args: str):
if not argd is None:
argd = argd.groupdict()
return {
"help": argd["help"] is None,
"version": argd["transactions"] is None,
"list-currencies": argd["list_currencies"] is None,
"help": not argd["help"] is None,
"version": not argd["version"] is None,
"list-currencies": not argd["list_currencies"] is None,
"default-currency": argd["default_currency"] }
return None
def handle_default_arguments(args: dict, help_func: Callable) -> None:
cargs = parse_common_arguments(' '.join(argv))
if cargs["help"]:
help_func()
print(USAGE_COMMON)
exit()
elif cargs["version"]:
print_program_version()
exit()
elif cargs["list-currencies"]:
print_supported_currencies()
exit()
elif not cargs["default-currency"] is None:
Configuration()["default-currency"] = cargs["default-currency"]
exit()
if not cargs is None:
if cargs["help"]:
help_func()
print(USAGE_COMMON)
exit()
elif cargs["version"]:
print_program_version()
exit()
elif cargs["list-currencies"]:
print_supported_currencies()
exit()
elif not cargs["default-currency"] is None:
conf = Configuration()
conf["default-currency"] = cargs["default-currency"]
conf.save()
exit()
def print_supported_currencies() -> None:
@ -59,8 +63,12 @@ def print_supported_currencies() -> None:
print("Default currency is", Configuration()["default-currency"])
def complement_array_of_coins(coins: List[int], currency: str,
def complement_list_of_coins(coins: List[int], currency: str,
_reversed: bool = False) -> List[int]:
"""Complements array of coins up to the count of currency's coins."""
"""Complements list of coins up to the count of currency's coins."""
offset_array = [0] * (CURRENCIES[currency]["count"] - len(coins))
return offset_array + coins if not _reversed else coins + offset_array
def decimal_to_float(lst: List[int]) -> List[float]:
"""Converts decimal style of storing money amounts to float."""
return list(map(lambda x: x / 100, lst))

View File

@ -1,11 +1,10 @@
"""CLI: Put a set of coins into a piggy bank."""
from re import match
from sys import argv, exit, stderr
from re import split, search
from sys import argv, stderr
from piggybank import print_program_version
from piggybank.configuration import Configuration
from piggybank.cli import complement_array_of_coins, handle_default_arguments
from piggybank.cli import complement_list_of_coins, handle_default_arguments
from piggybank.currencies import CURRENCIES, BaseCurrencyError
from piggybank.piggybank import PiggyBank
@ -21,34 +20,39 @@ USAGE_PUT = "Usage: piggybank-put [-r|--reversed] COINS in FILE of CURRENCY\n" \
def parse_put_arguments(args):
r = r"^(?P<reversed>-r|--reversed)? (?P<coins>[\d ,]+)" \
r" in (?P<file>\S+)(?= of (?P<currency>\w+))?"
argd = match(r, args)
r = r"(?P<reversed>-r|--reversed)? ?(?P<coins>[\d ,]+) in (?P<file>\S+)(?= of (?P<currency>\S+))?"
argd = search(r, args)
if not argd is None:
argd = argd.groupdict()
return {
"coins": list(map(str, argd["coins"].split(", "))),
"coins": list(map(int, split(r"\D",argd["coins"]))),
"file": argd["file"],
"currency": Configuration()["default-currency"] \
if argd["currency"] is None else argd["currency"],
"reversed": argd["reversed"] is None }
"reversed": not argd["reversed"] is None }
return None
def main() -> None:
handle_default_arguments(' '.join(argv), lambda: print(USAGE_PUT))
handle_default_arguments(' '.join(argv[1:]), lambda: print(USAGE_PUT))
args = parse_put_arguments(' '.join(argv[1:]))
args = parse_put_arguments(' '.join(argv))
if args is None:
print(USAGE_PUT)
exit()
try:
try:
piggybank = PiggyBank.from_file(args["file"])
except FileNotFoundError:
piggybank = PiggyBank(args["currency"])
coins = complement_array_of_coins(args["coins"], piggybank.currency,
args["reversed"])
currency = Configuration()["default-currency"] \
if args["currency"] is None else args["currency"]
piggybank = PiggyBank(currency)
coins = complement_list_of_coins(args["coins"], piggybank.currency,
args["reversed"])
piggybank.transact(coins)
piggybank.save(args["file"])
except BaseCurrencyError:
except BaseCurrencyError as err:
print(f"{type(err).__name__}:", err, file=stderr)
except ValueError as err:
print(f"{type(err).__name__}:", err, file=stderr)

View File

@ -3,12 +3,10 @@
from re import match
from sys import argv, exit, stderr
from piggybank import print_program_version, PIGGYBANK_FILE_EXTENSION
from piggybank.configuration import Configuration
from piggybank.cli import handle_default_arguments
from piggybank.currencies import CURRENCIES, \
BaseCurrencyError
from piggybank.currencies import CURRENCIES, BaseCurrencyError
from piggybank.piggybank import PiggyBank
from piggybank.transaction import sum_transactions, multiply_transactions
__all__ = ["main"]
@ -28,7 +26,8 @@ def parse_show_arguments(args):
argd = argd.groupdict()
return {
"file": argd["file"],
"transactions": argd["transactions"] is None }
"transactions": not argd["transactions"] is None }
return None
def print_summary(piggybank: PiggyBank,
@ -43,24 +42,26 @@ def print_summary(piggybank: PiggyBank,
range(CURRENCIES[piggybank.currency]['count']))
print(f"{left}{''*27}{lmiddle}{line}{right}")
cc, cs, ct = piggybank.count, piggybank.sum, piggybank.total
cc = sum_transactions(piggybank.transactions)
cs = multiply_transactions(piggybank.transactions, piggybank.currency)
ct = sum(cc)
cline = "".join([f'{l:^{centering}}'
nline = "".join([f'{l:^{centering}}'
for l in CURRENCIES[piggybank.currency]["names"]])
cline_len = len(cline)
nline_len = len(nline)
print_separator(left="", lmiddle="", rmiddle="", right="")
print(f"{'currency':^27}"
f"{CURRENCIES[piggybank.currency]['name']:^{cline_len}}")
f"{CURRENCIES[piggybank.currency]['name']:^{nline_len}}")
print_separator(rmiddle="")
print(f"{'face values':^27}{cline}")
print(f"{'face values':^27}{nline}")
print_separator()
print(f"{'amount':^27}{''.join([f'{c:^{centering}}' for c in cc])}")
print_separator()
print(f"{'sum':^27}"
f"{''.join(['{:^{}.2f}'.format(c / 100, centering) for c in cs])}")
print_separator(rmiddle="")
print(f"{'total':^27}{'{:^{}.2f}'.format(ct / 100, cline_len)}")
print(f"{'total':^27}{'{:^{}.2f}'.format(ct / 100, nline_len)}")
print_separator(left="", lmiddle="", rmiddle="", right="")
@ -72,11 +73,11 @@ def print_transactions(piggybank, centering=DEFAULT_COIN_CENTERING):
range(CURRENCIES[piggybank.currency]['count']))
print(f"{left}━━━━━━━━━━━━━━━━━━━━━{middle}━━━━━{middle}{line}{right}")
cline = "".join([f'{l:^{centering}}'
nline = "".join([f'{l:^{centering}}'
for l in CURRENCIES[piggybank.currency]["names"]])
print_separator()
print(f"{'Timestamp':^21}┃ I/O ┃{cline}")
print(f"{'Timestamp':^21}┃ I/O ┃{nline}")
print_separator("", "", "")
for tr in piggybank.transactions:
coin_line = "".join([f'{c:^{centering}}' for c in tr.coins])
@ -86,9 +87,12 @@ def print_transactions(piggybank, centering=DEFAULT_COIN_CENTERING):
def main() -> None:
handle_default_arguments(' '.join(argv), lambda: print(USAGE_SHOW))
handle_default_arguments(' '.join(argv[1:]), lambda: print(USAGE_SHOW))
args = parse_show_arguments(' '.join(argv[1:]))
args = parse_show_arguments(' '.join(argv))
if args is None:
print(USAGE_SHOW)
exit()
try:
piggybank = PiggyBank.from_file(args["file"])

View File

@ -1,11 +1,11 @@
"""CLI: Take a set of coins from a coin box."""
from re import match, search
from re import match, split
from sys import argv, exit, stderr
from piggybank import print_program_version
from piggybank.configuration import Configuration
from piggybank.cli import complement_array_of_coins, handle_default_arguments
from piggybank.cli import complement_list_of_coins, handle_default_arguments
from piggybank.currencies import CURRENCIES, BaseCurrencyError
from piggybank.piggybank import PiggyBank
from piggybank.transaction import TYPE_OUTCOME
@ -21,28 +21,28 @@ USAGE_TAKE: str = "Usage: piggybank-take [-r|--reversed] COINS from FILE\n\n" \
def parse_take_arguments(args):
r = r"^(?P<reversed>-r|--reversed)?(?P<coins>[\d ,]+) from (?P<file>\S+)"
r = r"^(?P<reversed>-r|--reversed)? ?(?P<coins>[\d ,]+) from (?P<file>\S+)"
argd = match(r, args)
if not argd is None:
argd = argd.groupdict()
return {
"coins": list(map(str, argd["coins"].split(", "))),
"coins": list(map(int, split(r"\D", argd["coins"]))),
"file": argd["file"],
"reversed": argd["reversed"] is None }
"reversed": not argd["reversed"] is None }
return None
def main():
handle_default_arguments(' '.join(argv), lambda: print(USAGE_TAKE))
handle_default_arguments(' '.join(argv[1:]), lambda: print(USAGE_TAKE))
args = parse_take_arguments(' '.join(argv[1:]))
args = parse_take_arguments(' '.join(argv))
if args["coins"] is None or args["file"] is None:
if args is None:
print(USAGE_TAKE)
exit()
try:
piggybank = PiggyBank.from_file(args["file"])
coins = complement_array_of_coins(args["coins"], piggybank.currency,
coins = complement_list_of_coins(args["coins"], piggybank.currency,
args["reversed"])
piggybank.transact(coins, TYPE_OUTCOME)
piggybank.save(args["file"])

View File

@ -8,12 +8,6 @@ from typing import Union
__all__ = ["Configuration", "get_configuration_path"]
DEFAULT_CONFIGURATION = {
"default-currency": "SRUB"
}
DEFAULT_CONFIGURATION_FILE = join(get_configuration_path(), "piggybank.conf")
def get_configuration_path():
if system() == "Linux":
return getenv("XDG_CONFIG_HOME") or f"{getenv('HOME')}/.config"
@ -21,12 +15,17 @@ def get_configuration_path():
return getenv("APPDATA")
DEFAULT_CONFIGURATION = {
"default-currency": "SRUB"
}
DEFAULT_CONFIGURATION_FILE = join(get_configuration_path(), "piggybank.conf")
class Configuration:
def __init__(self, configuration_file: str = DEFAULT_CONFIGURATION_FILE,
default_configuration: dict = DEFAULT_CONFIGURATION) -> None:
self._configuration_file = configuration_file
self._configuration = dict()
if exists(self._configuration_file):
self.load()
elif not default_configuration is None:
@ -35,7 +34,7 @@ class Configuration:
def load(self) -> None:
for line in open(self._configuration_file, 'r'):
key, value = line.split(" = ")
key, value = line[:-1].split(" = ")
self._configuration[key] = value
def save(self) -> None:

View File

@ -22,7 +22,7 @@ this number by 100 to get a regular floating-point number.
from typing import Dict, List, TypedDict
__all__ = ["CURRENCIES", "BaseCurrencyError", "CurrencyIsNotSupportedError",
"CurrenciesCoinCountMismatchError", "CurrencyMismatchError"]
"CurrenciesCoinCountMismatchError", "CurrencyMismatchError"]
class BaseCurrencyError(Exception):

View File

@ -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, CurrenciesCoinCountMismatchError, \
from piggybank.currencies import CURRENCIES, CurrencyIsNotSupportedError, \
CurrencyMismatchError
from piggybank.transaction import Transaction, sum_transactions, TYPE_INCOME
@ -16,6 +15,7 @@ __all__ = ["PiggyBank"]
class PiggyBank:
"""This class stores array of transactions and perform some actions on it."""
def __init__(self, currency: str = None) -> None:
self._currency = None
if not currency is None:
self.currency = currency
self._transactions = []
@ -42,16 +42,11 @@ class PiggyBank:
return self._currency
@currency.setter
def currency(self, currency: str = None) -> None:
"""Sets a currency of a PiggyBank with check for support. And if count
of coins doesn't match the old currency it won't set a new one."""
def currency(self, currency: str) -> None:
"""Sets a currency of a PiggyBank with check for support."""
currency = currency.upper()
if not currency in CURRENCIES:
if not currency in CURRENCIES.keys():
raise CurrencyIsNotSupportedError
if not self._currency is None and \
CURRENCIES[currency]["count"] \
!= CURRENCIES[self._currency]["count"]:
raise CurrenciesCoinCountMismatchError
self._currency = currency
@property

View File

@ -10,6 +10,7 @@ from piggybank.currencies import CURRENCIES
__all__ = ["Transaction", "sum_transactions", "multiply_transactions",
"TYPE_INCOME", "TYPE_OUTCOME", "TIME_FORMAT"]
TYPE_INCOME = "i"
TYPE_OUTCOME = "o"
TIME_FORMAT = "%Y-%m-%dT%H:%M:%S"
@ -21,9 +22,9 @@ def sum_transactions(transactions: List[Transaction]) -> List[int]:
coins = [0] * len(transactions[0].coins)
for transaction in transactions:
if transaction.direction == TYPE_INCOME:
coins = list(map(add, transaction.coins, coins))
coins = list(map(add, coins, transaction.coins))
else:
coins = list(map(sub, transaction.coins, coins))
coins = list(map(sub, coins, transaction.coins))
return coins
def multiply_transactions(transactions: Union[List[Transaction], Transaction],
@ -57,7 +58,7 @@ class Transaction:
@coins.setter
def coins(self, coins: List[int]) -> None:
if coins is list:
if type(coins) is list:
self._coins = coins
else:
raise TypeError("Coins must be of type 'list'.")