From f58b675107752d362225e8cb91ac49a08c5d14a4 Mon Sep 17 00:00:00 2001 From: "Alexander \"Arav\" Andreev" Date: Thu, 4 Jun 2020 05:11:29 +0400 Subject: [PATCH] argparse package was thrown the heck out and replaced with regexp. It has resulted in change of arguments' structure. Configuration class put in action. All these changes are to be tested. --- piggybank/cli/__init__.py | 61 +++++++++++++++++++++++++++-- piggybank/cli/main.py | 70 --------------------------------- piggybank/cli/put.py | 81 +++++++++++++++++---------------------- piggybank/cli/show.py | 71 +++++++++++++--------------------- piggybank/cli/take.py | 68 +++++++++++++++----------------- piggybank/currencies.py | 17 +------- 6 files changed, 152 insertions(+), 216 deletions(-) delete mode 100644 piggybank/cli/main.py 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)