diff --git a/piggybank/cli/__init__.py b/piggybank/cli/__init__.py index 93b5dd1..f3a6286 100644 --- a/piggybank/cli/__init__.py +++ b/piggybank/cli/__init__.py @@ -1,13 +1,66 @@ -from typing import List +from re import search +from typing import List, Callable +from sys import argv, exit +from piggybank import print_program_version +from piggybank.configuration import Configuration from piggybank.currencies import CURRENCIES -EPILOGUE = """This program is to assist you to keep track of how much coins -you have across your piggy banks.""" +__all__ = ["handle_default_arguments", "complement_array_of_coins"] + + +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-h|--help)|(?P-v|--version)" \ + r"|(?P-L|--list-currencies)" \ + r"|(?=--set-default-currency (?P\w+))" + argd = search(r, args) + 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, + "default-currency": argd["default_currency"] } + + +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() + + +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_array_of_coins(coins: List[int], currency: str, _reversed: bool = False) -> List[int]: """Complements array 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 \ No newline at end of file + return offset_array + coins if not _reversed else coins + offset_array diff --git a/piggybank/cli/main.py b/piggybank/cli/main.py deleted file mode 100644 index e8d8e17..0000000 --- a/piggybank/cli/main.py +++ /dev/null @@ -1,70 +0,0 @@ -from re import match -from sys import argv - -from piggybank import print_program_version -from piggybank.currencies import print_supported_currencies - - -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" - -USAGE_TAKE = "Take a set of coins from a piggybank.\n" \ - "Usage: piggybank take [-r|--reversed] COINS from FILE\n\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 file of your piggybank.\n" \ - -USAGE_SHOW = "Show statistics about a piggybank.\n" \ - "Usage: piggybank show FILE [with t,transactions]\n\n" \ - "FILE -- .pb file name of your piggybank;\n" \ - "with t,transaction -- list all transactions.\n" - -HELP = "Usage: piggybank [put | take | show] [-v | --version] " \ - "[-h | --help] [-L | --list-currencies]\n\n" \ - f"{USAGE_PUT}\n" \ - f"{USAGE_TAKE}\n" \ - f"{USAGE_SHOW}\n\n" \ - "-L,--list-currencies -- list all supported currencies and a default one;" \ - "-v,--version -- print version of a program;\n" \ - "-h,--help -- print this help.\n" - -def put(args): - r = r"^put(?P -r| --reversed)? (?P[\d ,]+) in (?P\S+)(?= of (?P\w+))?" - -def take(args): - r = r"^take(?P -r| --reversed)? (?P[\d ,]+) from (?P\S+)" - -def show(args): - r = r"^show (?P\S+)(?= with (?Pt|transactions))?" - -def common(args): - r = r"(?P-v|--version)?(?P-h|--help)?(?P-L|--list-currencies)?" - argd = match(r, args).groupdict() - - if not argd["version"] is None: - print_program_version() - exit() - elif not argd["help"] is None: - print(HELP) - elif not argd["list_currencies"] is None: - print_supported_currencies() - -def main(): - command = argv[1] - args_str = " ".join(argv[1:]) - if command == "put": - put(args_str) - elif command == "take": - take(args_str) - elif command == "show": - show(args_str) - else: - common(args_str) - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/piggybank/cli/put.py b/piggybank/cli/put.py index 3e750a5..ea0a11d 100644 --- a/piggybank/cli/put.py +++ b/piggybank/cli/put.py @@ -1,64 +1,53 @@ """CLI: Put a set of coins into a piggy bank.""" -from argparse import ArgumentParser -from os.path import exists -from sys import exit, stderr +from re import match +from sys import argv, exit, stderr from piggybank import print_program_version -from piggybank.cli import EPILOGUE, complement_array_of_coins -from piggybank.currencies import CURRENCIES, DEFAULT_CURRENCY, \ - BaseCurrencyError, print_supported_currencies +from piggybank.configuration import Configuration +from piggybank.cli import complement_array_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-r|--reversed)? (?P[\d ,]+)" \ + r" in (?P\S+)(?= of (?P\w+))?" + argd = match(r, args) + if not argd is None: + argd = argd.groupdict() + return { + "coins": list(map(str, argd["coins"].split(", "))), + "file": argd["file"], + "currency": Configuration()["default-currency"] \ + if argd["currency"] is None else argd["currency"], + "reversed": argd["reversed"] is None } + + def main() -> None: - """An entry point for a put command.""" - parser = ArgumentParser(prog="piggybank-put", - description="Add a set of coins to a piggy bank.", - epilog=EPILOGUE) - parser.add_argument("file", type=str, - help="a piggy bank file name. Missing .pb extension" - "will be added") - parser.add_argument("coins", type=int, nargs="+", metavar="COIN", - help="a set of coins to add. A new file will be" - "created if it doesn't exist") - - parser.add_argument("-c", "--currency", type=str, default=DEFAULT_CURRENCY, - help="set currency of a piggy bank. Not applicable to" - "an existing one") - - parser.add_argument("-v", "--version", action="store_true", - help="show program's version and license and exit") - parser.add_argument("--list-currencies", action="store_true", - help="list all supported currencies and exit") - - parser.add_argument("-r", "--reverse", action="store_true", - help="reverse a set of coins so incomplete set" - "fills with zeros from right. E.g. '8 9' will be" - "interpreted as '8 9 0 0 0 0' instead of" - "'0 0 0 0 8 9'") - - args = parser.parse_args() - - if args.version: - print_program_version() - exit() - - if args.list_currencies: - print_supported_currencies() - exit() + handle_default_arguments(' '.join(argv), lambda: print(USAGE_PUT)) + + args = parse_put_arguments(' '.join(argv)) try: try: - piggybank = PiggyBank.from_file(args.file) + piggybank = PiggyBank.from_file(args["file"]) except FileNotFoundError: - piggybank = PiggyBank(args.currency) - coins = complement_array_of_coins(args.coins, piggybank.currency, - args.reverse) + piggybank = PiggyBank(args["currency"]) + coins = complement_array_of_coins(args["coins"], piggybank.currency, + args["reversed"]) piggybank.transact(coins) - piggybank.save(args.file) + piggybank.save(args["file"]) except BaseCurrencyError: print(f"{type(err).__name__}:", err, file=stderr) except ValueError as err: diff --git a/piggybank/cli/show.py b/piggybank/cli/show.py index 98b7dfe..dd2aae8 100644 --- a/piggybank/cli/show.py +++ b/piggybank/cli/show.py @@ -1,20 +1,36 @@ """CLI: Show summarised information on a piggybank.""" -from argparse import ArgumentParser -from os.path import exists -from sys import exit, stderr +from re import match +from sys import argv, exit, stderr from piggybank import print_program_version, PIGGYBANK_FILE_EXTENSION -from piggybank.cli import EPILOGUE -from piggybank.currencies import CURRENCIES, DEFAULT_CURRENCY, \ - BaseCurrencyError, print_supported_currencies +from piggybank.configuration import Configuration +from piggybank.cli import handle_default_arguments +from piggybank.currencies import CURRENCIES, \ + BaseCurrencyError from piggybank.piggybank import PiggyBank __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\S+)(?= with (?Pt|transactions))?" + argd = match(r, args) + if not argd is None: + argd = argd.groupdict() + return { + "file": argd["file"], + "transactions": argd["transactions"] is None } + + def print_summary(piggybank: PiggyBank, centering: int = DEFAULT_COIN_CENTERING) -> None: """Print summarised information on a piggy bank. @@ -69,48 +85,15 @@ def print_transactions(piggybank, centering=DEFAULT_COIN_CENTERING): print_separator("┗", "┻", "┛") -def main(): - """An entry point for a show command.""" - parser = ArgumentParser(prog="piggybank-show", - description="Show information on a piggy bank.", - epilog=EPILOGUE) +def main() -> None: + handle_default_arguments(' '.join(argv), lambda: print(USAGE_SHOW)) - parser.add_argument("file", type=str, - help="a piggy bank file name. Missing .pb extension" - "will be added") - - parser.add_argument("-t", "--transactions", action="store_true", - help="print a list of transactions as well") - - parser.add_argument("-m", "--merge", action="append", - type=str, metavar="FILE", - help="merge multiple files to show how much do you" - "have across them. They all should be of same currency") - - parser.add_argument("-v", "--version", action="store_true", - help="show program's version and license and exit") - parser.add_argument("--list-currencies", action="store_true", - help="list all supported currencies and exit") - - args = parser.parse_args() - - if args.version: - print_program_version() - exit() - - if args.list_currencies: - print_supported_currencies() - exit() + args = parse_show_arguments(' '.join(argv)) try: - piggybank = PiggyBank.from_file(args.file) - if args.merge: - for _file in args.merge: - merge_piggybank = PiggyBank.from_file(_file) - piggybank += merge_piggybank - print(_file) + piggybank = PiggyBank.from_file(args["file"]) print_summary(piggybank) - if args.transactions: + if args["transactions"]: print_transactions(piggybank) except BaseCurrencyError as err: print(f"{type(err).__name__}:", err, file=stderr) diff --git a/piggybank/cli/take.py b/piggybank/cli/take.py index 3dbddea..1db9211 100644 --- a/piggybank/cli/take.py +++ b/piggybank/cli/take.py @@ -1,57 +1,51 @@ """CLI: Take a set of coins from a coin box.""" -from argparse import ArgumentParser -from sys import exit, stderr +from re import match, search +from sys import argv, exit, stderr from piggybank import print_program_version -from piggybank.cli import EPILOGUE, complement_array_of_coins -from piggybank.currencies import CURRENCIES, DEFAULT_CURRENCY, \ - BaseCurrencyError, print_supported_currencies +from piggybank.configuration import Configuration +from piggybank.cli import complement_array_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-r|--reversed)?(?P[\d ,]+) from (?P\S+)" + argd = match(r, args) + if not argd is None: + argd = argd.groupdict() + return { + "coins": list(map(str, argd["coins"].split(", "))), + "file": argd["file"], + "reversed": argd["reversed"] is None } + + def main(): - """An entry point for a take command.""" - parser = ArgumentParser(prog="piggybank-take", - description="Take a set of coins from a piggy bank.", - epilog=EPILOGUE) - parser.add_argument("file", type=str, - help="a piggy bank file name. Missing .pb extension" - "will be added") - parser.add_argument("coins", type=int, nargs="+", metavar="COIN", - help="add a set of coins. A new file will be created" - "if it doesn't exist") + handle_default_arguments(' '.join(argv), lambda: print(USAGE_TAKE)) - parser.add_argument("-v", "--version", action="store_true", - help="show program's version and license and exit") - parser.add_argument("--list-currencies", action="store_true", - help="list all supported currencies and exit") + args = parse_take_arguments(' '.join(argv)) - parser.add_argument("-r", "--reverse", action="store_true", - help="reverse a set of coins so incomplete set" - "fills with zeros from right. E.g. '8 9' will be" - "interpreted as '8 9 0 0 0 0' instead of" - "'0 0 0 0 8 9'") - - args = parser.parse_args() - - if args.version: - print_program_version() - exit() - - if args.list_currencies: - print_supported_currencies() + if args["coins"] is None or args["file"] is None: + print(USAGE_TAKE) exit() try: - piggybank = PiggyBank.from_file(args.file) - coins = complement_array_of_coins(args.coins, piggybank.currency, - args.reverse) + piggybank = PiggyBank.from_file(args["file"]) + coins = complement_array_of_coins(args["coins"], piggybank.currency, + args["reversed"]) piggybank.transact(coins, TYPE_OUTCOME) - piggybank.save(args.file) + piggybank.save(args["file"]) except BaseCurrencyError as err: print(f"{type(err).__name__}:", err, file=stderr) except ValueError as err: diff --git a/piggybank/currencies.py b/piggybank/currencies.py index be66164..32c4447 100644 --- a/piggybank/currencies.py +++ b/piggybank/currencies.py @@ -21,9 +21,8 @@ this number by 100 to get a regular floating-point number. from typing import Dict, List, TypedDict -__all__ = ["CURRENCIES", "DEFAULT_CURRENCY", "BaseCurrencyError", - "CurrencyIsNotSupportedError", "CurrenciesCoinCountMismatchError", - "CurrencyMismatchError", "print_supported_currencies"] +__all__ = ["CURRENCIES", "BaseCurrencyError", "CurrencyIsNotSupportedError", + "CurrenciesCoinCountMismatchError", "CurrencyMismatchError"] class BaseCurrencyError(Exception): @@ -53,9 +52,6 @@ class CurrenciesCoinCountMismatchError(BaseCurrencyError): pass -DEFAULT_CURRENCY: str = "SRUB" - - class Currency(TypedDict): name: str description: str @@ -116,12 +112,3 @@ CURRENCIES: Dict[str, Currency] = { "multipliers": [1, 2, 5, 10, 20, 25, 50, 1_00, 2_00] } } - - -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", DEFAULT_CURRENCY)