From 532c532fb9312fda0e00f9cd13c9006614969053 Mon Sep 17 00:00:00 2001 From: Kosarew Konstantin Date: Sun, 15 Jun 2025 20:25:16 +0300 Subject: [PATCH 1/7] =?UTF-8?q?=D0=B4=D0=BE=D0=BC=D0=B0=D1=88=D0=BD=D0=B5?= =?UTF-8?q?=D0=B5=20=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD=D0=B8=D0=B5=2011.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 26 +++- src/generators.py | 72 ++++++++++ test/main.py | 180 +++++++++++++++++++++++++ tests/conftest.py | 3 +- tests/test_generators.py | 274 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 551 insertions(+), 4 deletions(-) create mode 100644 src/generators.py create mode 100644 tests/test_generators.py diff --git a/README.md b/README.md index dd9bb19..ff45014 100644 --- a/README.md +++ b/README.md @@ -98,8 +98,8 @@ print(get_date("2024-03-11T02:26:18.671407")) ``` -### proctssing.py -proctssing.py так же содержит две функции как и предыдущие модули: +### processing.py +processing.py так же содержит две функции как и предыдущие модули: *filter_by_state* - Функция возвращает новый список словарей, содержащий только те словари, у которых ключ state соответствует указанному значению. @@ -154,8 +154,22 @@ sort [{'id': 41428829, 'state': 'EXECUTED', 'date': '2019-07-03T18:35:29.512364 {'id': 594226727, 'state': 'CANCELED', 'date': '2018-09-12T21:27:25.241689'}, {'id': 939719570, 'state': 'EXECUTED', 'date': '2018-06-30T02:08:58.425572'}] ``` + +## generators.py +generatrors.py - добавлены новые функции + +filter_by_currency(date_list: list, currency: str) +transaction_descriptions(date_list: list) +card_number_generator(start_value: int, end_value: int) + +filter_by_currency - фильтрует выводимые данные по коду валюты +transaction_descriptions - выводит поочереди все транзакции из списка +card_number_generator - генерирует номера кредитных карт в указанном диапазоне + + + ## Тесты -Добавлены тестовые файлы test_widget.py, test_masks.pym test_processing.py +Добавлены тестовые файлы test_widget.py, test_masks.py, test_processing.py, test_generators.py которые проверяют ранее написанные функции. В них реализованы функции: 1. test_mask_account_card, @@ -165,6 +179,12 @@ sort [{'id': 41428829, 'state': 'EXECUTED', 'date': '2019-07-03T18:35:29.512364 5. test_sort_by_date, 6. test_get_mask_card_number, 7. test_get_mask_account +8. test_filter_by_currency_valid +9. test_empty_input +10. test_transaction_descriptions +11. test_transaction_descriptions_empty +12. test_card_number_generator + Тест запускается из командной строки, командой **pytest** diff --git a/src/generators.py b/src/generators.py new file mode 100644 index 0000000..14a7862 --- /dev/null +++ b/src/generators.py @@ -0,0 +1,72 @@ +from typing import Dict, Generator + + +def filter_by_currency(date_list: list, currency: str = "USD") -> Generator[Dict, str, None]: + """ + принимает на вход список словарей, представляющих транзакции. + Функция должна возвращать итератор, который поочередно выдает транзакции, + где валюта операции соответствует заданной (например, USD). + + :param date_list: + :param currency: + :return: + """ + if not date_list or currency is None: + return # если список отсутствует - выходим из функции + + normalized_currency = currency.strip().upper() + """ currency надлежащего вида без пробелов и в верхнем регистре """ + + for transaction in date_list: + transaction_temp = transaction.get("operationAmount").get("currency") + """ данную переменную завел на случай, если понадобится определять валюту не по коду а по имени """ + if transaction_temp.get("code") is not None and transaction_temp.get("code") == normalized_currency: + yield transaction + + +def transaction_descriptions(date_list: list) -> Generator[str]: + """ + Принимает список словарей с транзакциями + и возвращает описание каждой операции по очереди + + :param date_list: + :return: + """ + if not date_list: + yield "Нет доступных транзакций" + return # если список отсутствует - выходим из функции + + for transaction in date_list: + description = str(transaction.get("description", "")).strip() + """ описание транзакции если она имеется """ + if description is not None: + yield description + + +def card_number_generator(start_value: int = 1, end_value: int = 5) -> Generator[str]: + """ + Генерирует номера карт + от 0000 0000 0000 0001 до 9999 9999 9999 9999 + + :param start_value: - начальное значение. + Если стартовое значение <= 0 тогда оно автоматом приравнивается к 1 + :param end_value: - конечное значение + :return: + """ + + zero_card = "0" * 16 + """ исходная пустая карта """ + + current_number_card_integer = start_value if start_value > 0 else 1 + """ текущий номер карты """ + + while True: + current_number_card_str = str(current_number_card_integer) + """ текущий номер карты в строковом эквиваленте """ + current_number_card_len = len(current_number_card_str) + """ длинна сгенерированного номера в символах """ + zero_card = zero_card[:-current_number_card_len] + current_number_card_str + yield f"{zero_card[0:4]} {zero_card[4:8]} {zero_card[8:12]} {zero_card[12:16]}" + current_number_card_integer += 1 + if current_number_card_integer > end_value or current_number_card_integer > 9999999999999999: + break # raise "Out of range!" diff --git a/test/main.py b/test/main.py index b0e7323..0f81af0 100644 --- a/test/main.py +++ b/test/main.py @@ -1,6 +1,138 @@ +from src.generators import card_number_generator, filter_by_currency, transaction_descriptions from src.processing import filter_by_state, sort_by_date from src.widget import get_date, mask_account_card +transactions_2 = [ + { + "id": 939719570, + "state": "EXECUTED", + "date": "2018-06-30T02:08:58.425572", + "operationAmount": {"amount": "9824.07", "currency": {"name": "USD", "code": "USD"}}, + #"description": "Перевод организации", + #"from": "Счет 75106830613657916952", + #"to": "Счет 11776614605963066702", + }, + { + "id": 142264268, + "state": "EXECUTED", + "date": "2019-04-04T23:20:05.206878", + "operationAmount": {"amount": "79114.93", "currency": {"name": "USD", "code": "USD"}}, + #"description": "Перевод со счета на счет", + #"from": "Счет 19708645243227258542", + #"to": "Счет 75651667383060284188", + }, + { + "id": 873106923, + "state": "EXECUTED", + "date": "2019-03-23T01:09:46.296404", + "operationAmount": {"amount": "43318.34", "currency": {"name": "руб.", "code": "RUB"}}, + #"description": "Перевод со счета на счет", + #"from": "Счет 44812258784861134719", + #"to": "Счет 74489636417521191160", + }, + { + "id": 895315941, + "state": "EXECUTED", + "date": "2018-08-19T04:27:37.904916", + "operationAmount": {"amount": "56883.54", "currency": {"name": "USD", "code": "USD"}}, + #"description": "Перевод с карты на карту", + #"from": "Visa Classic 6831982476737658", + #"to": "Visa Platinum 8990922113665229", + }, + { + "id": 594226727, + "state": "CANCELED", + "date": "2018-09-12T21:27:25.241689", + "operationAmount": {"amount": "67314.70", "currency": {"name": "руб.", "code": "RUB"}}, + #"description": "Перевод организации", + #"from": "Visa Platinum 1246377376343588", + #"to": "Счет 14211924144426031657", + }, +] + + +transactions = ( + [ + { + "id": 939719570, + "state": "EXECUTED", + "date": "2018-06-30T02:08:58.425572", + "operationAmount": { + "amount": "9824.07", + "currency": { + "name": "USD", + "code": "USD" + } + }, + "description": "Перевод организации", + "from": "Счет 75106830613657916952", + "to": "Счет 11776614605963066702" + }, + { + "id": 142264268, + "state": "EXECUTED", + "date": "2019-04-04T23:20:05.206878", + "operationAmount": { + "amount": "79114.93", + "currency": { + "name": "USD", + "code": "USD" + } + }, + "description": "Перевод со счета на счет", + "from": "Счет 19708645243227258542", + "to": "Счет 75651667383060284188" + }, + { + "id": 873106923, + "state": "EXECUTED", + "date": "2019-03-23T01:09:46.296404", + "operationAmount": { + "amount": "43318.34", + "currency": { + "name": "руб.", + "code": "RUB" + } + }, + "description": "Перевод со счета на счет", + "from": "Счет 44812258784861134719", + "to": "Счет 74489636417521191160" + }, + { + "id": 895315941, + "state": "EXECUTED", + "date": "2018-08-19T04:27:37.904916", + "operationAmount": { + "amount": "56883.54", + "currency": { + "name": "USD", + "code": "USD" + } + }, + "description": "Перевод с карты на карту", + "from": "Visa Classic 6831982476737658", + "to": "Visa Platinum 8990922113665229" + }, + { + "id": 594226727, + "state": "CANCELED", + "date": "2018-09-12T21:27:25.241689", + "operationAmount": { + "amount": "67314.70", + "currency": { + "name": "руб.", + "code": "RUB" + } + }, + "description": "Перевод организации", + "from": "Visa Platinum 1246377376343588", + "to": "Счет 14211924144426031657" + } + ] +) + + + if __name__ == "__main__": # Проверочные вызовы print(mask_account_card("Счет 73654108430535874307")) @@ -78,3 +210,51 @@ ) +#for card_number in card_number_generator(9999_2310_0990_0000,9999_2310_0992_3200): +for card_number in card_number_generator(): + print(mask_account_card(card_number)) +print() + +for card_number in card_number_generator(-100, 15): + print(card_number) + +for card_number in card_number_generator(1, -15): + print(card_number, "Ok") + +usd_transactions = filter_by_currency(transactions, "USD") +for usd_trans in usd_transactions: + print(usd_trans) + + +descriptions = transaction_descriptions(transactions) +for descript in descriptions: + print(descript) + + + + + +def t_filter_by_currency_valid(transactions_d: list, expect: list) -> None: + result = list(filter_by_currency(transactions_d, "USD")) + result_ids = [t["id"] for t in result] + + print(result_ids) + assert(result_ids == expect) + +t_filter_by_currency_valid(transactions, [939719570, 142264268, 895315941]) + + +def t_transaction_descriptions(card_input: list, excepted: list) -> None: + result = list(transaction_descriptions(transactions)) + #result = list(filter_by_currency(transactions, "USD")) + print(result) + #result_id_num = [t["id"] for t in result] + """оставляем только id номера, что бы облегчить себе жизнь при проверке""" + #assert result_id_num == excepted #ну и собственно проверяем + +t_transaction_descriptions(transactions,[939719570, 142264268, 895315941]) + +print("Okey") +descriptions = transaction_descriptions(transactions_2) +for descript in descriptions: + print(descript, "/") \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index 0dae911..d196598 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,5 @@ from datetime import datetime - +from typing import Generator, Dict import pytest @@ -17,3 +17,4 @@ def error_data_message() -> str: def current_data() -> str: now_time = datetime.now() return str(now_time.isoformat()) + diff --git a/tests/test_generators.py b/tests/test_generators.py new file mode 100644 index 0000000..f8355ab --- /dev/null +++ b/tests/test_generators.py @@ -0,0 +1,274 @@ +import pytest + +from src.generators import card_number_generator, filter_by_currency, transaction_descriptions + +transactions = [ + { + "id": 939719570, + "state": "EXECUTED", + "date": "2018-06-30T02:08:58.425572", + "operationAmount": {"amount": "9824.07", "currency": {"name": "USD", "code": "USD"}}, + "description": "Перевод организации", + "from": "Счет 75106830613657916952", + "to": "Счет 11776614605963066702", + }, + { + "id": 142264268, + "state": "EXECUTED", + "date": "2019-04-04T23:20:05.206878", + "operationAmount": {"amount": "79114.93", "currency": {"name": "USD", "code": "USD"}}, + "description": "Перевод со счета на счет", + "from": "Счет 19708645243227258542", + "to": "Счет 75651667383060284188", + }, + { + "id": 873106923, + "state": "EXECUTED", + "date": "2019-03-23T01:09:46.296404", + "operationAmount": {"amount": "43318.34", "currency": {"name": "руб.", "code": "RUB"}}, + "description": "Перевод со счета на счет", + "from": "Счет 44812258784861134719", + "to": "Счет 74489636417521191160", + }, + { + "id": 895315941, + "state": "EXECUTED", + "date": "2018-08-19T04:27:37.904916", + "operationAmount": {"amount": "56883.54", "currency": {"name": "USD", "code": "USD"}}, + "description": "Перевод с карты на карту", + "from": "Visa Classic 6831982476737658", + "to": "Visa Platinum 8990922113665229", + }, + { + "id": 594226727, + "state": "CANCELED", + "date": "2018-09-12T21:27:25.241689", + "operationAmount": {"amount": "67314.70", "currency": {"name": "руб.", "code": "RUB"}}, + "description": "Перевод организации", + "from": "Visa Platinum 1246377376343588", + "to": "Счет 14211924144426031657", + }, +] + +transactions_2 = [ + { + "id": 342264269, + "state": "EXECUTED", + "date": "2019-04-04T23:20:05.206878", + "operationAmount": {"amount": "79114.93", "currency": {"name": "USD", "code": "USD"}}, + "description": "Вывод средств со счёта", + "from": "Счет 19708645243227258542", + "to": "Счет 75651667383060284188", + }, + { + "id": 773106921, + "state": "EXECUTED", + "date": "2019-03-23T01:09:46.296404", + "operationAmount": {"amount": "43318.34", "currency": {"name": "руб.", "code": "RUB"}}, + "description": "Перевод со счета на счет злоумышленника", + "from": "Счет 44812258784861134719", + "to": "Счет 74489636417521191160", + }, + { + "id": 194226722, + "state": "CANCELED", + "date": "2018-09-12T21:27:25.241689", + "operationAmount": {"amount": "67314.70", "currency": {"name": "руб.", "code": "RUB"}}, + "description": "Перевод кому то в организации", + "from": "Visa Platinum 1246377376343588", + "to": "Счет 14211924144426031657", + }, +] + +transactions_3 = [ + { + "id": 939719570, + "state": "EXECUTED", + "date": "2018-06-30T02:08:58.425572", + "operationAmount": {"amount": "9824.07", "currency": {"name": "USD", "code": "USD"}}, + }, + { + "id": 142264268, + "state": "EXECUTED", + "date": "2019-04-04T23:20:05.206878", + "operationAmount": {"amount": "79114.93", "currency": {"name": "USD", "code": "USD"}}, + }, + { + "id": 873106923, + "state": "EXECUTED", + "date": "2019-03-23T01:09:46.296404", + "operationAmount": {"amount": "43318.34", "currency": {"name": "руб.", "code": "RUB"}}, + }, + { + "id": 895315941, + "state": "EXECUTED", + "date": "2018-08-19T04:27:37.904916", + "operationAmount": {"amount": "56883.54", "currency": {"name": "USD", "code": "USD"}}, + }, + { + "id": 594226727, + "state": "CANCELED", + "date": "2018-09-12T21:27:25.241689", + "operationAmount": {"amount": "67314.70", "currency": {"name": "руб.", "code": "RUB"}}, + }, +] + +valid_cards = [ + ( + 1, + 5, + [ + "0000 0000 0000 0001", + "0000 0000 0000 0002", + "0000 0000 0000 0003", + "0000 0000 0000 0004", + "0000 0000 0000 0005", + ], + ), + (100, 103, ["0000 0000 0000 0100", "0000 0000 0000 0101", "0000 0000 0000 0102", "0000 0000 0000 0103"]), + # Если имеются начальные значения меньше минимального + ( + -100, + 5, + [ + "0000 0000 0000 0001", + "0000 0000 0000 0002", + "0000 0000 0000 0003", + "0000 0000 0000 0004", + "0000 0000 0000 0005", + ], + ), + ( + 1, + -5, + [ + "0000 0000 0000 0001", + ], + ), + # Если значения находятся в пределах допуска + ( + 1432_4321_5678_7654, + 1432_4321_5678_7659, + [ + "1432 4321 5678 7654", + "1432 4321 5678 7655", + "1432 4321 5678 7656", + "1432 4321 5678 7657", + "1432 4321 5678 7658", + "1432 4321 5678 7659", + ], + ), + # Если конечное значение выходит за предел допустимых значений + ( + 9999_9999_9999_9998, + 19999_4321_5678_7659, + [ + "9999 9999 9999 9998", + "9999 9999 9999 9999", + ], + ), +] + + +@pytest.mark.parametrize( + "trans, currency, excepted", + [ + (transactions, "USD", [939719570, 142264268, 895315941]), + (transactions, "RUB", [873106923, 594226727]), + (transactions, "UsD", [939719570, 142264268, 895315941]), + (transactions, "usd", [939719570, 142264268, 895315941]), + (transactions, "", []), + (transactions, "набор неподходящих символов", []), + (transactions, None, []), + ], +) +def test_filter_by_currency_valid(trans: list, currency: str, excepted: list) -> None: + """ + Проверяем filter_by_currency на работу с корректными значениями + :param trans: - данные на входе, которые нужно обработать + :param currency: - валюта + :param excepted: - данные для проверки + :return: + """ + result = list(filter_by_currency(trans, currency)) + """список с отфильтрованными данными""" + result_id_num = [transactions_id["id"] for transactions_id in result] + """оставляем только id номера, что бы облегчить себе жизнь при проверке""" + assert result_id_num == excepted # ну и собственно проверяем + + +def test_empty_input() -> None: + """ + Проверяем filter_by_currency на работу с пустым списком транзакций + """ + result = list(filter_by_currency([])) + assert result == [] + + +@pytest.mark.parametrize( + "trans, excepted", + [ + ( + transactions, + [ + "Перевод организации", + "Перевод со счета на счет", + "Перевод со счета на счет", + "Перевод с карты на карту", + "Перевод организации", + ], + ), + ( + transactions_2, + [ + "Вывод средств со счёта", + "Перевод со счета на счет злоумышленника", + "Перевод кому то в организации", + ], + ), + ], +) +def test_transaction_descriptions(trans: list, excepted: list) -> None: + """ + Проверяем функцию с корректными данными на входе + :param trans: - список транзакций + :param excepted: - список данных на выходе + """ + result = list(transaction_descriptions(trans)) + assert result == excepted # ну и собственно проверяем + + +@pytest.mark.parametrize( + "trans, excepted", [([], ["Нет доступных транзакций"]), (transactions_3, ["", "", "", "", ""])] +) +def test_transaction_descriptions_empty(trans: list, excepted: list) -> None: + """ + Проверка функции при некорректных входных данных + :param trans: - список транзакций + :param excepted: - варианты проверочных данных + :return: + """ + result = list(transaction_descriptions(trans)) + assert result == excepted # ну и собственно проверяем + + +@pytest.mark.parametrize("start_value, end_value, expected", valid_cards) +def test_card_number_generator(start_value: int, end_value: int, expected: list) -> None: + """ + Проверяем функцию, которая генерирует новые номера карт в заданном диапазоне + :param start_value: - начальное значение + :param end_value: - конечное значение + :param expected: - список для проверки сгенерированных значений + :return: + """ + gen_card = list() + # пустой список для последовательной записи сгенерированных карт + expected_card = list() + # попутно создаем пустой список, куда будем последовательно класть варианты из expected + + for i in card_number_generator(start_value, end_value): + gen_card.append(i) + expected_card.append(expected) + + # после того как оба списка созданы, сравниваем их + assert gen_card == expected From 85e2fc3aba65624b88f19027b571f2f787d4edd8 Mon Sep 17 00:00:00 2001 From: Kosarew Konstantin Date: Sun, 15 Jun 2025 23:46:22 +0300 Subject: [PATCH 2/7] =?UTF-8?q?=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B4=D0=BE=D0=BC=D0=B0=D1=88=D0=BA=D1=83=20=D1=84?= =?UTF-8?q?=D0=B8=D0=BA=D1=81=D1=82=D1=83=D1=80=D0=BE=D0=B9=20=D0=B8=20cov?= =?UTF-8?q?erage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .coverage | Bin 53248 -> 53248 bytes htmlcov/class_index.html | 18 +- htmlcov/function_index.html | 42 ++++- htmlcov/index.html | 17 +- htmlcov/status.json | 2 +- htmlcov/z_145eef247bfb46b6_generators_py.html | 169 ++++++++++++++++++ test/main.py | 62 +++---- tests/conftest.py | 62 ++++++- tests/test_generators.py | 60 +------ 9 files changed, 317 insertions(+), 115 deletions(-) create mode 100644 htmlcov/z_145eef247bfb46b6_generators_py.html diff --git a/.coverage b/.coverage index a16cae0103b9c72267eef17a814e74bbc6f90252..d00a799663263b01534fe19f3f3dad9d607407c4 100644 GIT binary patch delta 343 zcmYL?JxfAi7>3`k$2fw|T@qP~=ntr=HE@bhIENO8hQdOkq7Ss8(805|o;Ao{V9|kS z%&CSP9NGe#w4sI|glMSuMA>rlTySwcjizoi^@YhXaZTV7>qzk}*TRYMEmnC7I&OiC z5q>u4x(mUI$D}Q#BI4arb*DOaaO|o-!PzYDl`Eyg{YudCindu72(f`_zT>)WZgX(I zT8NQn{H**fCSoRU{L~MQl6qwPC&SiSF~fwmzz3f3h%VZ;d5&c!Bb_wm#p%iXqI!a3 zEKeG>lv8nS&ncZ0v+@Ya-Wip=89LXVxcZVLjpMM43n2(Sfls{S6@Bz{|B4-4OE2L4U_>HOk+r#A}4&t%oCKhK;UgsYM)Om)1e=~muzXabIpw2yflWXF<*;xEp8WkC#`gqxxy;vH> z!CbJ$&FkXB6nI$pFEQ}{;KvSLp&A7%t`Tl&?&9CQ6f{cFy elKRH~k^c=)>JGmMGYc~VFEcZUU;+`0Kmq_~QbDr- diff --git a/htmlcov/class_index.html b/htmlcov/class_index.html index 49b84d7..26718b4 100644 --- a/htmlcov/class_index.html +++ b/htmlcov/class_index.html @@ -11,7 +11,7 @@

Coverage report: - 98% + 99%

@@ -80,6 +80,14 @@

0 100% + + src\generators.py + (no class) + 35 + 0 + 0 + 100% + src\masks.py (no class) @@ -109,10 +117,10 @@

Total   - 41 + 76 1 0 - 98% + 99% @@ -124,7 +132,7 @@

coverage.py v7.8.2, - created at 2025-06-06 00:06 +0300 + created at 2025-06-15 23:42 +0300