Final rewrite of CLI arguments form. Now program has single entry point that serves everything. README to be updated.
This commit is contained in:
parent
ab6647ceb3
commit
f4f026f8b2
@ -1,9 +1,9 @@
|
|||||||
__all__ = ["__date__", "__version__", "__author__", "__author_email__",
|
__all__ = ["__date__", "__version__", "__author__", "__author_email__",
|
||||||
"__copyright__", "__license__", "PIGGYBANK_FILE_EXTENSION",
|
"__copyright__", "__license__", "PIGGYBANK_FILE_EXTENSION",
|
||||||
"print_program_version"]
|
"VERSION"]
|
||||||
|
|
||||||
|
|
||||||
__date__ = "6 June 2020"
|
__date__ = "7 June 2020"
|
||||||
__version__ = "1.0.0"
|
__version__ = "1.0.0"
|
||||||
__author__ = "Alexander \"Arav\" Andreev"
|
__author__ = "Alexander \"Arav\" Andreev"
|
||||||
__author_email__ = "me@arav.top"
|
__author_email__ = "me@arav.top"
|
||||||
@ -17,10 +17,5 @@ http://www.wtfpl.net/ for more details."""
|
|||||||
|
|
||||||
|
|
||||||
PIGGYBANK_FILE_EXTENSION = ".pb"
|
PIGGYBANK_FILE_EXTENSION = ".pb"
|
||||||
|
VERSION = f"PiggyBank ver. {__version__} ({__date__})\n\n{__copyright__}\n" \
|
||||||
|
f"\n{__license__}"
|
||||||
def print_program_version() -> None:
|
|
||||||
"""Print information about program. Includes name and version; copyright
|
|
||||||
notice and license."""
|
|
||||||
print(f"PiggyBank ver. {__version__} ({__date__})\n\n{__copyright__}\n"
|
|
||||||
f"\n{__license__}")
|
|
||||||
|
@ -1,74 +1,12 @@
|
|||||||
from re import search
|
from typing import List
|
||||||
from typing import List, Callable
|
|
||||||
from sys import argv
|
|
||||||
|
|
||||||
from piggybank import print_program_version
|
|
||||||
from piggybank.configuration import Configuration
|
|
||||||
from piggybank.currencies import CURRENCIES
|
from piggybank.currencies import CURRENCIES
|
||||||
|
|
||||||
__all__ = ["handle_default_arguments", "complement_list_of_coins",
|
__all__ = ["complement_list_of_coins"]
|
||||||
"print_supported_currencies", "decimal_to_float"]
|
|
||||||
|
|
||||||
|
|
||||||
USAGE_COMMON: str = "Usage: piggybank-* " \
|
|
||||||
"[(-h|--help)|(-v|--version)|(-L|--list-currencies)]\n" \
|
|
||||||
"A set of common flags. Only one could be specified.\n" \
|
|
||||||
"-h, --help -- print this help;\n" \
|
|
||||||
"-v, --version -- print program version;\n" \
|
|
||||||
"-L, --list-currencies -- print supported currencies;\n" \
|
|
||||||
"--set-default-currency CURRENCY -- set default currency.\n"
|
|
||||||
|
|
||||||
|
|
||||||
def parse_common_arguments(args: str):
|
|
||||||
r = r"(?P<help>-h|--help)|(?P<version>-v|--version)" \
|
|
||||||
r"|(?P<list_currencies>-L|--list-currencies)" \
|
|
||||||
r"|(?=--set-default-currency (?P<default_currency>\w+))"
|
|
||||||
argd = search(r, args)
|
|
||||||
if not argd is None:
|
|
||||||
argd = argd.groupdict()
|
|
||||||
return {
|
|
||||||
"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 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:
|
|
||||||
"""Print a list of supported currencies."""
|
|
||||||
print("Supported currencies are:")
|
|
||||||
for cur in CURRENCIES:
|
|
||||||
print(f" {cur:^4} ┃ {CURRENCIES[cur]['name']:^31}"
|
|
||||||
f" ┃ {CURRENCIES[cur]['description']}")
|
|
||||||
print("Default currency is", Configuration()["default-currency"])
|
|
||||||
|
|
||||||
|
|
||||||
def complement_list_of_coins(coins: List[int], currency: str,
|
def complement_list_of_coins(coins: List[int], currency: str,
|
||||||
_reversed: bool = False) -> List[int]:
|
_reversed: bool = False) -> List[int]:
|
||||||
"""Complements list 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))
|
offset_array = [0] * (len(CURRENCIES[currency]) - len(coins))
|
||||||
return offset_array + coins if not _reversed else coins + offset_array
|
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))
|
|
||||||
|
178
piggybank/cli/main.py
Normal file
178
piggybank/cli/main.py
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
"""CLI: main"""
|
||||||
|
|
||||||
|
from re import search, split
|
||||||
|
from sys import argv, stderr
|
||||||
|
|
||||||
|
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
|
||||||
|
from piggybank.transaction import sum_transactions, TYPE_INCOME, TYPE_OUTCOME
|
||||||
|
|
||||||
|
__all__ = ["main"]
|
||||||
|
|
||||||
|
|
||||||
|
USAGE = \
|
||||||
|
"""Usage: piggybank [OPTIONS] (COINS in FILE [of CURRENCY] | COINS from FILE
|
||||||
|
| show FILE [with t(ransactions)])
|
||||||
|
|
||||||
|
Options:
|
||||||
|
\t-h,--help -- print this help;
|
||||||
|
\t-v,--version -- print program version;
|
||||||
|
\t-L,--list-currencies -- list supported currencies and a default one;
|
||||||
|
\t--set-default-currency -- set currency that'll be used as a default;
|
||||||
|
\t-r,--reversed -- change COINS' complementation from left to right.
|
||||||
|
\t (e.g. 4 5 -> 0 0 0 0 4 5 by default; 4 5 0 0 0 0
|
||||||
|
\t with this flag. If currency has 6 coins)
|
||||||
|
|
||||||
|
There are three actions available: put, take and show.
|
||||||
|
|
||||||
|
Put: piggybank [-r|--reversed] COINS in FILE [of CURRENCY]
|
||||||
|
Take: piggybank [-r|--reversed] COINS from FILE
|
||||||
|
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;
|
||||||
|
\twith t(ransactions) -- print a table of transactions as well.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def parse_common_arguments(args: str) -> dict:
|
||||||
|
r = r"(?P<help>-h|--help)|(?P<version>-v|--version)" \
|
||||||
|
r"|(?P<list_currencies>-L|--list-currencies)" \
|
||||||
|
r"|(?=--set-default-currency (?P<default_currency>\w+))"
|
||||||
|
argd = search(r, args)
|
||||||
|
if not argd is None:
|
||||||
|
argd = argd.groupdict()
|
||||||
|
return {
|
||||||
|
"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 parse_arguments(args: str) -> dict:
|
||||||
|
r = r"((?P<reversed>-r|--reversed)? ?(?P<coins>[\d, ]+)?)" \
|
||||||
|
r" ?(?P<action>in|from|show) (?P<file>\S+)" \
|
||||||
|
r" ?(?=(?=of (?P<currency>\S+)" \
|
||||||
|
r"|(?=with (?P<transactions>t|transactions))))?"
|
||||||
|
argd = search(r, args)
|
||||||
|
if not argd is None:
|
||||||
|
argd = argd.groupdict()
|
||||||
|
return {
|
||||||
|
"reversed": not argd["reversed"] is None,
|
||||||
|
"coins": list(map(int, split(r"\D", argd["coins"].strip()))) \
|
||||||
|
if not argd["coins"] is None else None,
|
||||||
|
"action": argd["action"],
|
||||||
|
"file": argd["file"],
|
||||||
|
"currency": argd["currency"],
|
||||||
|
"show-transactions": argd["transactions"] }
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def print_transactions(pb: PiggyBank) -> None:
|
||||||
|
cur = CURRENCIES[pb.currency]
|
||||||
|
def print_separator(l: str, m: str, r: str):
|
||||||
|
print(f"{l}{'━'*21}{m}{'━'*5}{m}{m.join(['━'*12]*cur.count)}{r}")
|
||||||
|
|
||||||
|
print_separator("┏", "┳", "┓")
|
||||||
|
print(f"┃{'Timestamp':^21}┃ I/O ┃" \
|
||||||
|
f"{'┃'.join(f'{n:^12}' for n in cur.coin_names)}┃")
|
||||||
|
print_separator("┣", "╋", "┫")
|
||||||
|
for t in pb.transactions:
|
||||||
|
print(f"┃ {t.timestamp.replace('T', ' ')} "
|
||||||
|
f"┃{t.direction:^5}"
|
||||||
|
f"┃{'┃'.join(f'{c:^12}' for c in t.coins)}┃")
|
||||||
|
print_separator("┗", "┻", "┛")
|
||||||
|
|
||||||
|
def print_summary(pb: PiggyBank) -> None:
|
||||||
|
cur = CURRENCIES[pb.currency]
|
||||||
|
def print_separator(l: str, lm: str, rm: str, r:str):
|
||||||
|
print(f"{l}{'━'*27}{lm}{rm.join(['━'*12]*cur.count)}{r}")
|
||||||
|
|
||||||
|
print_separator("┏", "┳", "┳", "┓")
|
||||||
|
print(f"┃{cur.name:^27}┃{'┃'.join(f'{n:^12}' for n in cur.coin_names)}┃")
|
||||||
|
print_separator("┣", "╋", "╋", "┫")
|
||||||
|
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)}┃")
|
||||||
|
print_separator("┣", "╋", "┻", "┫")
|
||||||
|
s = sum(s)
|
||||||
|
print(f"┃{'Total':^27}┃{s:^{12*cur.count+cur.count-1}}┃")
|
||||||
|
print_separator("┗", "┻", "━", "┛")
|
||||||
|
|
||||||
|
|
||||||
|
def print_supported_currencies() -> None:
|
||||||
|
"""Print a list of supported currencies."""
|
||||||
|
print("Supported currencies are:")
|
||||||
|
for cur in CURRENCIES.keys():
|
||||||
|
print(f" {cur:^4} ┃ {CURRENCIES[cur].name:^31}"
|
||||||
|
f" ┃ {CURRENCIES[cur].description}")
|
||||||
|
print("Default currency is", Configuration()["default-currency"])
|
||||||
|
|
||||||
|
|
||||||
|
def load_user_defined_currencies() -> None:
|
||||||
|
if not "currency" in Configuration().items:
|
||||||
|
return
|
||||||
|
for iso, cur in Configuration()["currency"].items():
|
||||||
|
CURRENCIES[iso] = Currency.from_string(cur)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
cargs = parse_common_arguments(' '.join(argv))
|
||||||
|
if not cargs is None:
|
||||||
|
if cargs["help"]:
|
||||||
|
print(USAGE)
|
||||||
|
exit()
|
||||||
|
elif cargs["version"]:
|
||||||
|
print(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()
|
||||||
|
|
||||||
|
args = parse_arguments(' '.join(argv))
|
||||||
|
if not args:
|
||||||
|
print(USAGE)
|
||||||
|
exit()
|
||||||
|
|
||||||
|
try:
|
||||||
|
load_user_defined_currencies()
|
||||||
|
try:
|
||||||
|
pb = PiggyBank.from_file(args["file"])
|
||||||
|
except FileNotFoundError:
|
||||||
|
if args["action"] == "in":
|
||||||
|
currency = Configuration()["default-currency"] \
|
||||||
|
if args["currency"] is None else args["currency"]
|
||||||
|
pb = PiggyBank(currency)
|
||||||
|
else:
|
||||||
|
raise FileNotFoundError(f"{args['file']} is missing.")
|
||||||
|
if args["action"] in ["in", "from"]:
|
||||||
|
coins = complement_list_of_coins(args["coins"], pb.currency,
|
||||||
|
args["reversed"])
|
||||||
|
pb.transact(coins, TYPE_INCOME if args["action"] == "in" \
|
||||||
|
else TYPE_OUTCOME)
|
||||||
|
pb.save(args["file"])
|
||||||
|
elif args["action"] == "show":
|
||||||
|
print_summary(pb)
|
||||||
|
if args["show-transactions"]:
|
||||||
|
print_transactions(pb)
|
||||||
|
except BaseCurrencyError as err:
|
||||||
|
print(f"{type(err).__name__}:", err, file=stderr)
|
||||||
|
except FileNotFoundError as err:
|
||||||
|
print(f"{type(err).__name__}:", err, file=stderr)
|
||||||
|
except ValueError as err:
|
||||||
|
print(f"{type(err).__name__}:", err, file=stderr)
|
||||||
|
except Exception as err:
|
||||||
|
print(f"Something went exceptionally wrong. Error:",
|
||||||
|
f"{type(err).__name__}:", err, file=stderr)
|
@ -1,61 +0,0 @@
|
|||||||
"""CLI: Put a set of coins into a piggy bank."""
|
|
||||||
|
|
||||||
from re import split, search
|
|
||||||
from sys import argv, stderr
|
|
||||||
|
|
||||||
from piggybank.configuration import Configuration
|
|
||||||
from piggybank.cli import complement_list_of_coins, handle_default_arguments
|
|
||||||
from piggybank.currencies import CURRENCIES, BaseCurrencyError
|
|
||||||
from piggybank.piggybank import PiggyBank
|
|
||||||
|
|
||||||
__all__ = ["main"]
|
|
||||||
|
|
||||||
|
|
||||||
USAGE_PUT = "Usage: piggybank-put [-r|--reversed] COINS in FILE of CURRENCY\n" \
|
|
||||||
"Put a set of coins in a piggybank. Set a currency of a new one.\n\n" \
|
|
||||||
"-r, --reversed -- use reversed order of COINS (from greater to least);\n" \
|
|
||||||
"COINS -- array of comma or whitespace separated coins;\n" \
|
|
||||||
"in FILE -- .pb file name of your piggybank;\n" \
|
|
||||||
"of CURRENCY -- set a currency for a new piggybank.\n"
|
|
||||||
|
|
||||||
|
|
||||||
def parse_put_arguments(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(int, split(r"\D",argd["coins"]))),
|
|
||||||
"file": argd["file"],
|
|
||||||
"currency": Configuration()["default-currency"] \
|
|
||||||
if argd["currency"] is None else argd["currency"],
|
|
||||||
"reversed": not argd["reversed"] is None }
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
handle_default_arguments(' '.join(argv[1:]), lambda: print(USAGE_PUT))
|
|
||||||
args = parse_put_arguments(' '.join(argv[1:]))
|
|
||||||
|
|
||||||
if args is None:
|
|
||||||
print(USAGE_PUT)
|
|
||||||
exit()
|
|
||||||
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
piggybank = PiggyBank.from_file(args["file"])
|
|
||||||
except FileNotFoundError:
|
|
||||||
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 as err:
|
|
||||||
print(f"{type(err).__name__}:", err, file=stderr)
|
|
||||||
except ValueError as err:
|
|
||||||
print(f"{type(err).__name__}:", err, file=stderr)
|
|
||||||
except Exception as err:
|
|
||||||
print(f"Something went exceptionally wrong. Error:",
|
|
||||||
f"{type(err).__name__}:", err, file=stderr)
|
|
@ -1,108 +0,0 @@
|
|||||||
"""CLI: Show summarised information on a piggybank."""
|
|
||||||
|
|
||||||
from re import match
|
|
||||||
from sys import argv, exit, stderr
|
|
||||||
|
|
||||||
from piggybank.cli import handle_default_arguments
|
|
||||||
from piggybank.currencies import CURRENCIES, BaseCurrencyError
|
|
||||||
from piggybank.piggybank import PiggyBank
|
|
||||||
from piggybank.transaction import sum_transactions, multiply_transactions
|
|
||||||
|
|
||||||
__all__ = ["main"]
|
|
||||||
|
|
||||||
|
|
||||||
USAGE_SHOW: str = "Usage: piggybank-show FILE [with t,transactions]\n\n" \
|
|
||||||
"Show statistics about a piggybank.\n" \
|
|
||||||
"FILE -- .pb file name of your piggybank;\n" \
|
|
||||||
"with (t|transaction) -- also list all transactions.\n"
|
|
||||||
|
|
||||||
DEFAULT_COIN_CENTERING: int = 10
|
|
||||||
|
|
||||||
|
|
||||||
def parse_show_arguments(args):
|
|
||||||
r = r"^(?P<file>\S+)(?= with (?P<transactions>t|transactions))?"
|
|
||||||
argd = match(r, args)
|
|
||||||
if not argd is None:
|
|
||||||
argd = argd.groupdict()
|
|
||||||
return {
|
|
||||||
"file": argd["file"],
|
|
||||||
"transactions": not argd["transactions"] is None }
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def print_summary(piggybank: PiggyBank,
|
|
||||||
centering: int = DEFAULT_COIN_CENTERING) -> None:
|
|
||||||
"""Print summarised information on a piggy bank.
|
|
||||||
Prints a table with totals of how much coins of which face value are in a
|
|
||||||
piggy bank; A total sum converted to its currency for each face value and
|
|
||||||
overall total sum in a currency of a piggy bank."""
|
|
||||||
def print_separator(left="┣", lmiddle="╋", rmiddle="╋", right="┫"):
|
|
||||||
line = rmiddle.join('━' * centering
|
|
||||||
for _ in
|
|
||||||
range(CURRENCIES[piggybank.currency]['count']))
|
|
||||||
print(f"{left}{'━'*27}{lmiddle}{line}{right}")
|
|
||||||
|
|
||||||
cc = sum_transactions(piggybank.transactions)
|
|
||||||
cs = multiply_transactions(piggybank.transactions, piggybank.currency)
|
|
||||||
ct = sum(cc)
|
|
||||||
|
|
||||||
nline = "┃".join([f'{l:^{centering}}'
|
|
||||||
for l in CURRENCIES[piggybank.currency]["names"]])
|
|
||||||
nline_len = len(nline)
|
|
||||||
|
|
||||||
print_separator(left="┏", lmiddle="┳", rmiddle="━", right="┓")
|
|
||||||
print(f"┃{'currency':^27}┃"
|
|
||||||
f"{CURRENCIES[piggybank.currency]['name']:^{nline_len}}┃")
|
|
||||||
print_separator(rmiddle="┳")
|
|
||||||
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, nline_len)}┃")
|
|
||||||
print_separator(left="┗", lmiddle="┻", rmiddle="━", right="┛")
|
|
||||||
|
|
||||||
|
|
||||||
def print_transactions(piggybank, centering=DEFAULT_COIN_CENTERING):
|
|
||||||
"""Print a list of all transactions stored in a piggy bank."""
|
|
||||||
def print_separator(left="┏", middle="┳", right="┓"):
|
|
||||||
line = middle.join('━' * centering
|
|
||||||
for _ in
|
|
||||||
range(CURRENCIES[piggybank.currency]['count']))
|
|
||||||
print(f"{left}━━━━━━━━━━━━━━━━━━━━━{middle}━━━━━{middle}{line}{right}")
|
|
||||||
|
|
||||||
nline = "┃".join([f'{l:^{centering}}'
|
|
||||||
for l in CURRENCIES[piggybank.currency]["names"]])
|
|
||||||
|
|
||||||
print_separator()
|
|
||||||
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])
|
|
||||||
ts = tr.timestamp.replace("T", " ")
|
|
||||||
print(f"┃ {ts} ┃{tr.direction:^5}┃{coin_line}┃")
|
|
||||||
print_separator("┗", "┻", "┛")
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
handle_default_arguments(' '.join(argv[1:]), lambda: print(USAGE_SHOW))
|
|
||||||
args = parse_show_arguments(' '.join(argv[1:]))
|
|
||||||
|
|
||||||
if args is None:
|
|
||||||
print(USAGE_SHOW)
|
|
||||||
exit()
|
|
||||||
|
|
||||||
try:
|
|
||||||
piggybank = PiggyBank.from_file(args["file"])
|
|
||||||
print_summary(piggybank)
|
|
||||||
if args["transactions"]:
|
|
||||||
print_transactions(piggybank)
|
|
||||||
except BaseCurrencyError as err:
|
|
||||||
print(f"{type(err).__name__}:", err, file=stderr)
|
|
||||||
except FileNotFoundError as err:
|
|
||||||
print(f"{type(err).__name__}:", f"{err} doesn't exist.", file=stderr)
|
|
||||||
except Exception as err:
|
|
||||||
print(f"Something went exceptionally wrong. Error:",
|
|
||||||
f"{type(err).__name__}:", err, file=stderr)
|
|
@ -1,57 +0,0 @@
|
|||||||
"""CLI: Take a set of coins from a coin box."""
|
|
||||||
|
|
||||||
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_list_of_coins, handle_default_arguments
|
|
||||||
from piggybank.currencies import CURRENCIES, BaseCurrencyError
|
|
||||||
from piggybank.piggybank import PiggyBank
|
|
||||||
from piggybank.transaction import TYPE_OUTCOME
|
|
||||||
|
|
||||||
__all__ = ["main"]
|
|
||||||
|
|
||||||
|
|
||||||
USAGE_TAKE: str = "Usage: piggybank-take [-r|--reversed] COINS from FILE\n\n" \
|
|
||||||
"Take a set of coins from a piggybank.\n" \
|
|
||||||
"-r, --reversed -- use reversed order of COINS (from greater to least);\n" \
|
|
||||||
"COINS -- array of comma or whitespace separated coins;\n" \
|
|
||||||
"from FILE -- .pb filename.\n"
|
|
||||||
|
|
||||||
|
|
||||||
def parse_take_arguments(args):
|
|
||||||
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(int, split(r"\D", argd["coins"]))),
|
|
||||||
"file": argd["file"],
|
|
||||||
"reversed": not argd["reversed"] is None }
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
handle_default_arguments(' '.join(argv[1:]), lambda: print(USAGE_TAKE))
|
|
||||||
args = parse_take_arguments(' '.join(argv[1:]))
|
|
||||||
|
|
||||||
if args is None:
|
|
||||||
print(USAGE_TAKE)
|
|
||||||
exit()
|
|
||||||
|
|
||||||
try:
|
|
||||||
piggybank = PiggyBank.from_file(args["file"])
|
|
||||||
coins = complement_list_of_coins(args["coins"], piggybank.currency,
|
|
||||||
args["reversed"])
|
|
||||||
piggybank.transact(coins, TYPE_OUTCOME)
|
|
||||||
piggybank.save(args["file"])
|
|
||||||
except BaseCurrencyError as err:
|
|
||||||
print(f"{type(err).__name__}:", err, file=stderr)
|
|
||||||
except ValueError as err:
|
|
||||||
print(f"{type(err).__name__}:", err, file=stderr)
|
|
||||||
except FileNotFoundError as err:
|
|
||||||
print(f"{type(err).__name__}:", f"{err} doesn't exist.", file=stderr)
|
|
||||||
except Exception as err:
|
|
||||||
print(f"Something went exceptionally wrong. Error:",
|
|
||||||
f"{type(err).__name__}:", err, file=stderr)
|
|
@ -59,6 +59,10 @@ class Configuration:
|
|||||||
for key, value in self._configuration.items():
|
for key, value in self._configuration.items():
|
||||||
cf.write(f"{key} = {value}\n")
|
cf.write(f"{key} = {value}\n")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def items(self) -> dict:
|
||||||
|
return self._configuration
|
||||||
|
|
||||||
def __getitem__(self, key: str) -> Union[int, str, bool]:
|
def __getitem__(self, key: str) -> Union[int, str, bool]:
|
||||||
return self._configuration[key]
|
return self._configuration[key]
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ CURRENCIES: Dict[str, Currency] = {
|
|||||||
[1, 5, 10, 50, 1_00, 2_00, 5_00, 10_00]),
|
[1, 5, 10, 50, 1_00, 2_00, 5_00, 10_00]),
|
||||||
"SRUB": Currency("SRUB", "Russian ruble (shortened)",
|
"SRUB": Currency("SRUB", "Russian ruble (shortened)",
|
||||||
"Russian Federation. Excluding coins of 1 and 5 kopek.",
|
"Russian Federation. Excluding coins of 1 and 5 kopek.",
|
||||||
8, ["10к.", "50к.", "1₽", "2₽", "5₽", "10₽"],
|
6, ["10к.", "50к.", "1₽", "2₽", "5₽", "10₽"],
|
||||||
[10, 50, 1_00, 2_00, 5_00, 10_00]),
|
[10, 50, 1_00, 2_00, 5_00, 10_00]),
|
||||||
"BYN": Currency("BYN", "Belarusian ruble", "Belarus", 8,
|
"BYN": Currency("BYN", "Belarusian ruble", "Belarus", 8,
|
||||||
["1к.", "2к.", "5к.", "10к.", "20к.", "50к.", "1р.", "2р."],
|
["1к.", "2к.", "5к.", "10к.", "20к.", "50к.", "1р.", "2р."],
|
||||||
|
@ -23,10 +23,10 @@ class PiggyBank:
|
|||||||
|
|
||||||
def transact(self, coins: List[int], direction: str = TYPE_INCOME) -> None:
|
def transact(self, coins: List[int], direction: str = TYPE_INCOME) -> None:
|
||||||
"""Make a transaction."""
|
"""Make a transaction."""
|
||||||
if len(coins) != CURRENCIES[self._currency]["count"]:
|
if len(coins) != len(CURRENCIES[self._currency]):
|
||||||
raise ValueError("Length of passed coins list doesn't match the " \
|
raise ValueError("Length of passed coins list doesn't match the " \
|
||||||
f"currency's coins count. ({len(coins)} " \
|
f"currency's coins count. ({len(coins)} " \
|
||||||
f"!= {CURRENCIES[self._currency]['count']})")
|
f"!= {len(CURRENCIES[self._currency])})")
|
||||||
self._last_transaction = Transaction(coins, direction)
|
self._last_transaction = Transaction(coins, direction)
|
||||||
self._transactions.append(self._last_transaction)
|
self._transactions.append(self._last_transaction)
|
||||||
for coin_count in sum_transactions(self._transactions):
|
for coin_count in sum_transactions(self._transactions):
|
||||||
|
Loading…
Reference in New Issue
Block a user