+ 1from functools import wraps
+ 2from time import time
+ 3from typing import Any, Optional
+ 4
+ 5
+ 6def log(predicate: Any, error_message: str, filename: Optional[str] = None) -> Any:
+ 7 """
+ 8 Декоратор для логирования функций!
+ 9 :param predicate:
+ 10 :param error_message:
+ 11 :param filename:
+ 12 :return:
+ 13 """
+ 14
+ 15 def wrapper(function: Any) -> Any:
+ 16
+ 17 @wraps(function)
+ 18 def inner(*args: Any) -> Any:
+ 19
+ 20 if not predicate(*args):
+ 21 error_txt: str = f"{function.__name__} error: {error_message}, Inputs: {args}\n"
+ 22 """Переменная выводит сообщение о некорректной работе функции!"""
+ 23 if filename:
+ 24 with open(filename, "a", encoding="utf-8") as file:
+ 25 file.write(error_txt)
+ 26 else:
+ 27 print(error_txt)
+ 28 raise ValueError(error_message)
+ 29
+ 30 time_start = time()
+ 31 """Начало работы функции"""
+ 32
+ 33 result = function(*args)
+ 34 """Результат работы функции"""
+ 35
+ 36 time_end = time()
+ 37 """Конец работы функции"""
+ 38
+ 39 exec_time = time_end - time_start
+ 40 """Рассчитанное время работы функции"""
+ 41
+ 42 success_message: str = f"{function.__name__}, Ok \nWork time: {exec_time: 4f} seconds \n"
+ 43 """Переменная выводит сообщение о корректной работе функции!"""
+ 44
+ 45 if filename:
+ 46 with open(filename, "a", encoding="utf-8") as file:
+ 47 file.write(success_message)
+ 48 else:
+ 49 print(success_message)
+ 50
+ 51 return result
+ 52
+ 53 return inner
+ 54
+ 55 return wrapper
+ 56
+ 57
+ 58def predicate_param(start: int, end: int) -> bool:
+ 59 # return type(start) == int and type(end) == int and start > 0 and end > 0 and start <= end
+ 60 return isinstance(start, int) and isinstance(end, int) and start > 0 and end > 0 and start <= end
+
+
+ 1from typing import Dict, Generator
+ 2
+ 3from src.decorators import log, predicate_param
+ 4
+ 5
+ 6def filter_by_currency(date_list: list, currency: str = "USD") -> Generator[Dict, str, None]:
+ 7 """
+ 8 принимает на вход список словарей, представляющих транзакции.
+ 9 Функция должна возвращать итератор, который поочередно выдает транзакции,
+ 10 где валюта операции соответствует заданной (например, USD).
+ 11
+ 12 :param date_list:
+ 13 :param currency:
+ 14 :return:
+ 15 """
+ 16 if not date_list or currency is None:
+ 17 return # если список отсутствует - выходим из функции
+ 18
+ 19 normalized_currency = currency.strip().upper()
+ 20 """ currency надлежащего вида без пробелов и в верхнем регистре """
+ 21
+ 22 for transaction in date_list:
+ 23 transaction_temp = transaction.get("operationAmount").get("currency")
+ 24 """ данную переменную завел на случай, если понадобится определять валюту не по коду а по имени """
+ 25 if transaction_temp.get("code") is not None and transaction_temp.get("code") == normalized_currency:
+ 26 yield transaction
+ 27
+ 28
+ 29def transaction_descriptions(date_list: list) -> Generator[str]:
+ 30 """
+ 31 Принимает список словарей с транзакциями
+ 32 и возвращает описание каждой операции по очереди
+ 33
+ 34 :param date_list:
+ 35 :return:
+ 36 """
+ 37 if not date_list:
+ 38 yield "Нет доступных транзакций"
+ 39 return # если список отсутствует - выходим из функции
+ 40
+ 41 for transaction in date_list:
+ 42 description = str(transaction.get("description", "")).strip()
+ 43 """ описание транзакции если она имеется """
+ 44 if description is not None:
+ 45 yield description
+ 46
+ 47
+ 48def card_number_generator(start_value: int = 1, end_value: int = 5) -> Generator[str]:
+ 49 """
+ 50 Генерирует номера карт
+ 51 от 0000 0000 0000 0001 до 9999 9999 9999 9999
+ 52
+ 53 :param start_value: - начальное значение.
+ 54 Если стартовое значение <= 0 тогда оно автоматом приравнивается к 1
+ 55 :param end_value: - конечное значение
+ 56 :return:
+ 57 """
+ 58
+ 59 zero_card = "0" * 16
+ 60 """ исходная пустая карта """
+ 61
+ 62 current_number_card_integer = start_value if start_value > 0 else 1
+ 63 """ текущий номер карты """
+ 64
+ 65 while True:
+ 66 current_number_card_str = str(current_number_card_integer)
+ 67 """ текущий номер карты в строковом эквиваленте """
+ 68 current_number_card_len = len(current_number_card_str)
+ 69 """ длинна сгенерированного номера в символах """
+ 70 zero_card = zero_card[:-current_number_card_len] + current_number_card_str
+ 71 yield f"{zero_card[0:4]} {zero_card[4:8]} {zero_card[8:12]} {zero_card[12:16]}"
+ 72 current_number_card_integer += 1
+ 73 if current_number_card_integer > end_value or current_number_card_integer > 9999999999999999:
+ 74 break # raise "Out of range!"
+ 75
+ 76
+ 77@log(predicate_param, "Не корректные входные данные!", "mylog.txt")
+ 78def card_num_gen(start_value: int = 1, end_value: int = 5) -> Generator[str]:
+ 79 return card_number_generator(start_value, end_value)
+ 80
+ 81
+ 82@log(predicate_param, "Не корректные входные данные!")
+ 83def card_num_gen_console(start_value: int = 1, end_value: int = 5) -> Generator[str]:
+ 84 return card_number_generator(start_value, end_value)
+
+