1
0
PiggyBank/piggybank/piggybank.py

129 lines
4.7 KiB
Python
Raw Normal View History

"""Implementation of the piggy bank itself."""
from __future__ import annotations
from os.path import exists
from typing import List
from piggybank import PIGGYBANK_FILE_EXTENSION
from piggybank.currencies import CURRENCIES, DEFAULT_CURRENCY, \
CurrencyIsNotSupportedError, CurrenciesCoinCountMismatchError, \
CurrencyMismatchError
from piggybank.transaction import Transaction, TYPE_INCOME
__all__ = ["PiggyBank"]
class PiggyBank:
"""This class stores transactions and do file I/O on piggy bank
.pb files."""
def __init__(self, currency: str = DEFAULT_CURRENCY) -> None:
if currency.upper() in CURRENCIES:
self._currency = currency.upper()
else:
raise CurrencyIsNotSupportedError
self._transactions = []
def transact(self, coins: List[int], direction: str = TYPE_INCOME) -> None:
"""Make a transaction."""
if len(coins) != CURRENCIES[self.currency]["count"]:
raise ValueError("Length of passed coins list doesn't match the "
f"currency's coins count ({len(coins)} "
f"!= {CURRENCIES[self.currency]['count']})")
self._transactions.append(Transaction(coins, direction))
for coin_count in self.count:
if coin_count < 0:
del self._transactions[-1]
raise ValueError(
"You can't take out more than you have.")
@property
def count(self) -> List[int]:
"""Returns a list of counts for each face value."""
count = [0] * CURRENCIES[self.currency]["count"]
for tr in self.transactions:
count = [x + y if tr.direction == TYPE_INCOME
else x - y for x, y in zip(count, tr.coins)]
return count
@property
def sum(self) -> List[int]:
"""Returns a list of sums for each face value multiplied by its
currency's multipilers."""
return [x * y for x, y
in zip(self.count, CURRENCIES[self.currency]["multipliers"])]
@property
def total(self) -> int:
"""Returns a total amount of money stored in a PiggyBank."""
return sum(self.sum)
@staticmethod
def from_file(filename: str) -> PiggyBank:
"""Returns a PiggyBank object loaded from a file with name
`filename`."""
piggybank = PiggyBank()
piggybank.load(filename)
return piggybank
def save(self, filename: str) -> None:
"""Writes a PiggyBank object to a file with name `filename`."""
if not filename.endswith(PIGGYBANK_FILE_EXTENSION):
filename += PIGGYBANK_FILE_EXTENSION
with open(filename, 'w') as _file:
_file.write(f"{self.currency}\n")
for transaction in self.transactions:
_file.write(f"{str(transaction)}\n")
def load(self, filename: str) -> None:
"""Loads a PiggyBank from a file with name `filename`."""
if not filename.endswith(PIGGYBANK_FILE_EXTENSION):
filename += PIGGYBANK_FILE_EXTENSION
if not exists(filename):
raise FileNotFoundError(filename)
with open(filename, 'r') as _file:
currency = _file.readline()[:-1]
if currency not in CURRENCIES:
raise CurrencyIsNotSupportedError
else:
self.currency = currency
for transaction in _file:
self._transactions.append(Transaction.from_string(transaction))
@property
def currency(self) -> str:
"""Returns a currency of a PiggyBank."""
return self._currency
@currency.setter
def currency(self, currency: str) -> None:
"""Sets a currency of a PiggyBank with check for support. And if count
of coins doesn't match the old currency it won't set a new one."""
currency = currency.upper()
if currency not in CURRENCIES:
raise CurrencyIsNotSupportedError
if CURRENCIES[currency]["count"] != CURRENCIES[self.currency]["count"]:
raise CurrenciesCoinCountMismatchError
self._currency = currency
@property
def transactions(self) -> List[Transaction]:
"""Returns a list of transactions."""
return self._transactions
def __eq__(self, piggybank: PiggyBank) -> str:
"""It compares only currency."""
return self.currency == piggybank._currency
def __add__(self, piggybank: PiggyBank) -> PiggyBank:
if self != piggybank:
raise CurrencyMismatchError
new = PiggyBank(self.currency)
new._transactions = self.transactions + piggybank._transactions
return new
def __repr__(self) -> str:
return f"PiggyBank(currency={self.currency!r})"