Performed some refactoring on an existing code base before further work.
This commit is contained in:
parent
fc15b333b7
commit
d9dbf0fb8d
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,6 @@
|
|||||||
.vscode/
|
.vscode/
|
||||||
build/
|
build/
|
||||||
dist/
|
dist/
|
||||||
piggybank.egg-info/
|
*.egg-info/
|
||||||
__pycache__
|
__pycache__
|
||||||
*.pb
|
*.pb
|
||||||
|
@ -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
|
@ -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()
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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})"
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
|
Loading…
Reference in New Issue
Block a user