1
0

Performed some refactoring on an existing code base before further work.

This commit is contained in:
Alexander "Arav" Andreev 2020-03-27 20:14:22 +04:00 committed by Alexander Arav Andreev
parent fc15b333b7
commit d9dbf0fb8d
9 changed files with 63 additions and 71 deletions

2
.gitignore vendored
View File

@ -1,6 +1,6 @@
.vscode/ .vscode/
build/ build/
dist/ dist/
piggybank.egg-info/ *.egg-info/
__pycache__ __pycache__
*.pb *.pb

View File

@ -1,2 +1,13 @@
from typing import List
from piggybank.currencies import CURRENCIES
EPILOGUE = """This program is to assist you to keep track of how much coins EPILOGUE = """This program is to assist you to keep track of how much coins
you have across your piggy banks.""" you have across your piggy banks."""
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

View File

@ -5,12 +5,10 @@ from os.path import exists
from sys import exit, stderr from sys import exit, stderr
from piggybank import print_program_version from piggybank import print_program_version
from piggybank.cli import EPILOGUE from piggybank.cli import EPILOGUE, complement_array_of_coins
from piggybank.currencies import CURRENCIES, DEFAULT_CURRENCY, \ from piggybank.currencies import CURRENCIES, DEFAULT_CURRENCY, \
BaseCurrencyError, print_supported_currencies BaseCurrencyError, print_supported_currencies
from piggybank.piggybank import PiggyBank from piggybank.piggybank import PiggyBank
from piggybank.util import add_common_arguments_to_parser, \
complement_array_of_coins
__all__ = ["main"] __all__ = ["main"]
@ -31,7 +29,16 @@ def main() -> None:
help="set currency of a piggy bank. Not applicable to" help="set currency of a piggy bank. Not applicable to"
"an existing one") "an existing one")
add_common_arguments_to_parser(parser) 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() args = parser.parse_args()

View File

@ -1,4 +1,4 @@
"""CLI: Take a set of coins from a piggy bank.""" """CLI: Show summarised information on a piggybank."""
from argparse import ArgumentParser from argparse import ArgumentParser
from os.path import exists from os.path import exists
@ -9,7 +9,6 @@ from piggybank.cli import EPILOGUE
from piggybank.currencies import CURRENCIES, DEFAULT_CURRENCY, \ from piggybank.currencies import CURRENCIES, DEFAULT_CURRENCY, \
BaseCurrencyError, print_supported_currencies BaseCurrencyError, print_supported_currencies
from piggybank.piggybank import PiggyBank from piggybank.piggybank import PiggyBank
from piggybank.util import add_common_arguments_to_parser
__all__ = ["main"] __all__ = ["main"]
@ -88,7 +87,10 @@ def main():
help="merge multiple files to show how much do you" help="merge multiple files to show how much do you"
"have across them. They all should be of same currency") "have across them. They all should be of same currency")
add_common_arguments_to_parser(parser, include_reverse_flag=False) 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() args = parser.parse_args()

View File

@ -4,13 +4,11 @@ from argparse import ArgumentParser
from sys import exit, stderr from sys import exit, stderr
from piggybank import print_program_version from piggybank import print_program_version
from piggybank.cli import EPILOGUE from piggybank.cli import EPILOGUE, complement_array_of_coins
from piggybank.currencies import CURRENCIES, DEFAULT_CURRENCY, \ from piggybank.currencies import CURRENCIES, DEFAULT_CURRENCY, \
BaseCurrencyError, print_supported_currencies BaseCurrencyError, print_supported_currencies
from piggybank.piggybank import PiggyBank from piggybank.piggybank import PiggyBank
from piggybank.transaction import TYPE_OUTCOME from piggybank.transaction import TYPE_OUTCOME
from piggybank.util import add_common_arguments_to_parser, \
complement_array_of_coins
__all__ = ["main"] __all__ = ["main"]
@ -18,16 +16,25 @@ __all__ = ["main"]
def main(): def main():
"""An entry point for a take command.""" """An entry point for a take command."""
parser = ArgumentParser(prog="piggybank-take", parser = ArgumentParser(prog="piggybank-take",
description="Take a set of coins from a coin box.", description="Take a set of coins from a piggy bank.",
epilog=EPILOGUE) epilog=EPILOGUE)
parser.add_argument("file", type=str, parser.add_argument("file", type=str,
help="a coin box file name. Missing .cb extension will" help="a piggy bank file name. Missing .pb extension"
"be added") "will be added")
parser.add_argument("coins", type=int, nargs="+", metavar="COIN", parser.add_argument("coins", type=int, nargs="+", metavar="COIN",
help="add a set of coins. A new file will be created" help="add a set of coins. A new file will be created"
"if it doesn't exist") "if it doesn't exist")
add_common_arguments_to_parser(parser) 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() args = parser.parse_args()

View File

@ -1,20 +1,22 @@
"""Here is a dictionary of supported currencies defined. Which could be easily """Here is a dictionary of supported currencies defined. Which could be easily
extended with new ones. extended with new ones.
Each dictionary entry has an ISO code of a currency as its key. Or it can Each entry is a dictionary that has an ISO code of a currency as its key. Or it
slightly differ from an ISO to represent a modified version of a currency. An can be slightly differ from an ISO code to represent a modified version of a
example is SRUB entry for shortened version of RUB where coins of 1 and 5 kopek currency.
value were removed. And value is an another dictionary consists of following
fields: Each entry consists of following fields:
name -- a full name of a currency; name -- a full name of a currency;
description -- usually a country where this currency is used is being description -- usually a country where this currency is used is being
mentioned. Plus additional information; mentioned. Plus additional information;
count -- a number of coins in a currency; count -- a number of coins in a currency;
names -- an array of names for each coins' face values; names -- an array of names for each coins' face values;
multipliers -- an array of multipliers for each face value in a decimal multipliers -- an array of multipliers for each face value in a decimal*
format. Decimal is used to avoid problems of rounding float numbers. format.
So first two digits are used to store a fraction part. You can simply
divide this number by 100 to get a regular floating-point number. * - Decimal is used to avoid problems of rounding float numbers. So first two
digits to the right are used to store a fraction part. You can simply divide
this number by 100 to get a regular floating-point number.
""" """
from typing import Dict, List, TypedDict from typing import Dict, List, TypedDict

View File

@ -1,4 +1,4 @@
"""Implementation of the piggy bank itself.""" """PiggyBank implementation."""
from __future__ import annotations from __future__ import annotations
from os.path import exists from os.path import exists
@ -14,8 +14,7 @@ __all__ = ["PiggyBank"]
class PiggyBank: class PiggyBank:
"""This class stores transactions and do file I/O on piggy bank """This class stores array of transactions and perform some actions on it."""
.pb files."""
def __init__(self, currency: str = DEFAULT_CURRENCY) -> None: def __init__(self, currency: str = DEFAULT_CURRENCY) -> None:
if currency.upper() in CURRENCIES: if currency.upper() in CURRENCIES:
self._currency = currency.upper() self._currency = currency.upper()
@ -28,7 +27,7 @@ class PiggyBank:
"""Make a transaction.""" """Make a transaction."""
if len(coins) != CURRENCIES[self.currency]["count"]: if len(coins) != CURRENCIES[self.currency]["count"]:
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"!= {CURRENCIES[self.currency]['count']})")
self._transactions.append(Transaction(coins, direction)) self._transactions.append(Transaction(coins, direction))
@ -41,7 +40,7 @@ class PiggyBank:
@property @property
def count(self) -> List[int]: def count(self) -> List[int]:
"""Returns a list of counts for each face value.""" """Returns a list of counts for each face value in total."""
count = [0] * CURRENCIES[self.currency]["count"] count = [0] * CURRENCIES[self.currency]["count"]
for tr in self.transactions: for tr in self.transactions:
count = [x + y if tr.direction == TYPE_INCOME count = [x + y if tr.direction == TYPE_INCOME
@ -123,6 +122,3 @@ class PiggyBank:
new = PiggyBank(self.currency) new = PiggyBank(self.currency)
new._transactions = self.transactions + piggybank._transactions new._transactions = self.transactions + piggybank._transactions
return new return new
def __repr__(self) -> str:
return f"PiggyBank(currency={self.currency!r})"

View File

@ -1,4 +1,4 @@
"""Implementation of Transaction class.""" """Transaction class implementation."""
from __future__ import annotations from __future__ import annotations
from time import strftime, strptime, gmtime from time import strftime, strptime, gmtime
@ -12,8 +12,9 @@ TIME_FORMAT = "%Y-%m-%dT%H:%M:%S"
class Transaction: class Transaction:
"""Represents a single transaction. """Transaction consists of a timestamp, a direction
Consists of array of coins' list, direction and timestamp.""" and an array of coins. It doesn't depend on a currency. Only coins count is
stored."""
def __init__(self, coins, direction: str = TYPE_INCOME, def __init__(self, coins, direction: str = TYPE_INCOME,
timestamp: Optional[str] = None) -> None: timestamp: Optional[str] = None) -> None:
self.coins = coins self.coins = coins
@ -29,7 +30,7 @@ class Transaction:
strptime(timestamp, TIME_FORMAT) strptime(timestamp, TIME_FORMAT)
except ValueError: except ValueError:
raise ValueError(f"Timestamp {timestamp} has wrong format. " raise ValueError(f"Timestamp {timestamp} has wrong format. "
f"The right one is {TIME_FORMAT}") f"The right one is '{TIME_FORMAT}''")
self.timestamp = timestamp self.timestamp = timestamp
@staticmethod @staticmethod

View File

@ -1,34 +0,0 @@
"""Utility functions."""
from argparse import ArgumentParser
from typing import List
from piggybank import __version__, __copyright__, __license__
from piggybank.currencies import CURRENCIES, DEFAULT_CURRENCY
__all__ = ["add_common_arguments_to_parser", "complement_array_of_coins"]
def add_common_arguments_to_parser(parser: ArgumentParser,
include_reverse_flag: bool = True) -> None:
"""Extends ArgumentParser with a common set of arguments that are shared
amongst all parsers in CLI module."""
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")
if include_reverse_flag:
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'")
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