diff --git a/HW3.py b/HW3.py new file mode 100644 index 0000000..5a789b8 --- /dev/null +++ b/HW3.py @@ -0,0 +1,263 @@ +import logging +import re +import psycopg2 +from log import logging_decor +from conf import DATA_BASE, LOGIN, PASSWD, HST, NPORT + +conn = psycopg2.connect(database=DATA_BASE, user=LOGIN, + password=PASSWD, host=HST, port=NPORT) + +cur = conn.cursor() +# cur.execute("DROP TABLE IF EXISTS patients") +cur.execute("CREATE TABLE IF NOT EXISTS patients (patient_id SERIAL PRIMARY KEY,first_name VARCHAR(64), " + "last_name VARCHAR(64), birth_date VARCHAR(64), phone VARCHAR(64), " +"document_type VARCHAR(64), document_id VARCHAR(64))") +conn.commit() + + + +class LogAndChange(object): + """Дескриптор данных, в котором организована проверка полей + из конструктора объекта Patient а также их изменение + и логирование(логгер определим вне классов)""" + + # Проверка даты + def _check_date(self, val): + if len(val) == 10: # Количество символов, включая знаки препинания и цифры, в верном формате равно 10 + if not re.match('(\d{4})-(\d{2})-(\d{2})', val): # проверка на НЕсоответсвие паттерну 1994-10-12 + new_date = re.split('\.|/|-', val) # Сформируем список из чисел по разделителям . / - + if len(new_date[2]) == 4: # если год стоит на последнем месте + new_date = new_date[::-1] # исправим это + new_string = '-'.join(new_date) # соберем все вместе в правильно формате 1994-10-12 + val = new_string + else: + # self._error_logger.error('Неверный формат даты') + raise ValueError('Неверный формат даты') + return val + + # Проверка типа документа + def _check_document_type(self, val): + _valid_document_types = { + 'Паспорт': ['Паспорт', 'паспорт'], + 'Водительские права': ['Водительские права', 'водительские права', 'права'], + 'Заграничный паспорт': ['Заграничный паспорт', 'заграничный паспорт', 'загран'], + } + found = False # флаг найденного значения + for key, valid_list in _valid_document_types.items(): + if val in valid_list: # Проверка нахождения подаваемого значения в списке допустимых значений + val = key # В случае успеха приведем значение к человеческому виду + found = True # соответственно флаг теперь тру + if not found: # Если подаваемого значения в списке нет, то исключение + # self._error_logger.error('Неверный тип документа') + raise ValueError('Неверный тип документа') + return val + + # Проверка номера телефона + def _check_phone(self, val): + val = re.sub(r'[^0-9]+', r'', val) # для начала удалим все лишнее(все то, что не цифра) + if len(val) != 11: # количество цифр вместе с восьмеркой или семеркой + # self._error_logger.error('Неверное количество цифр в номере телефона') + raise ValueError('Неверное количество цифр в номере телефона') + return val + + # Проверка номера документа + def _check_doc_id(self, val, obj): # в doc_type будем передавать значение из dict объекта по ключу document_type + _valid_len = { + 'Паспорт': 10, + 'Водительские права': 10, + 'Заграничный паспорт': 9, + } + doc_type = obj.__dict__.get('document_type') + v_len = _valid_len[doc_type] # Получим валидную длину указанного(doc_type) документа + val = re.sub(r'[^0-9]+', r'', val) # удалим все лишнее и непонятное + + if len(val) != v_len: + # self._error_logger.error('Неверное количество цифр в номере документа') + raise ValueError('Неверное количество цифр в номере документа ') + return val + + def _check_name(self, val, obj): + if not val.isalpha(): + # self._error_logger.error(f'Невалидное {self.name} {val}') + raise ValueError(f'Невалидное {self.name} {val}') + if self.name in obj.__dict__: # Если такое имя уже существует у объекта (позволяет избежать записи + # self._error_logger.error(f'Попытка изменить {self.name}') # о смене фамилии или имени с None на текущую) + raise AttributeError(f'Попытка изменить {self.name}') + return val + + def __init__(self, name='название_атрибута'): + # self._info_logger = logging.getLogger('info_logger') + # self._error_logger = logging.getLogger('error_logger') + self.name = name + + def __get__(self, obj, objtype): + return obj.__dict__[self.name] # вернем значение атрибута по ключу(названию атрибута) + + @logging_decor + def __set__(self, obj, val): + if not isinstance(val, str): # + # self._error_logger.error(f'Неверный тип {val} - {type(val)}') + raise TypeError(f'Неверный тип {val} - {type(val)}') + + if self.name in ['first_name', 'last_name']: + val = self._check_name(val, obj) + elif self.name == 'birth_date': + val = self._check_date(val) + elif self.name == 'phone': + val = self._check_phone(val) + elif self.name == 'document_type': + val = self._check_document_type(val) + elif self.name == 'document_id': + val = self._check_doc_id(val, obj) # передаем объект для получения типа документа + + if self.name in obj.__dict__: # изменяем только в том случае, когда объект существует + pass + # self._info_logger.info( + # f"Изменяю {self.name} у пациента {obj.first_name} {obj.last_name} c {obj.__dict__.get(self.name)} на {val}") + obj.__dict__[self.name] = val + + +class Patient: + first_name = LogAndChange('first_name') + last_name = LogAndChange('last_name') + birth_date = LogAndChange('birth_date') + phone = LogAndChange('phone') + document_type = LogAndChange('document_type') + document_id = LogAndChange('document_id') + current_row_idx = 1 # указатель на текущую строку + + @logging_decor + def __init__(self, first_name, last_name, birth_date, phone, document_type, document_id): + # self._info_logger = logging.getLogger('info_logger') + + if not (first_name and last_name and birth_date + and phone and document_type and document_id): + raise TypeError('Заполнены не все поля') + + self.first_name = first_name + self.last_name = last_name + self.birth_date = birth_date + self.phone = phone + self.document_type = document_type + self.document_id = document_id + + self._saved = False # флаг, позволяющий узнать сохранен ли объект + # в начале объектов у нас нет + self._row_idx = None # индекс объекта + # self._info_logger.info(f'Создан объект {self.first_name} {self.last_name} ' + # f'{self.birth_date} {self.phone} {self.document_type} {self.document_id}') + #ретурн строка выше + + @staticmethod + def create(first_name, last_name, birth_date, phone, document_type, document_id): + return Patient(first_name, last_name, birth_date, phone, document_type, document_id) + + # Сохраняем пациента в csv таблицу + + def save(self): + data = [self.first_name, + self.last_name, + self.birth_date, + self.phone, + self.document_type, + self.document_id] + if self._saved: # Если пациент уже существует + #получаем его индекс cur.fetchall()[self._row_idx][0] и меняем данные пациента + + # + # cur.execute("SELECT * FROM patients") #смотрим на пациентов + # cur.fetchall()[self._row_idx][0] # индекс пациента + # где-нибудь здесь получим индекс и сделаем UPDATE распакуем пациента в БД + cur.execute(f"UPDATE patients SET first_name = '{self.first_name}', last_name = '{self.last_name}'," + f" birth_date = '{self.birth_date}'," + f"phone = '{self.phone}', document_type = '{self.document_type}'," + f" document_id = '{self.document_id}' WHERE patient_id = {self._row_idx}") + conn.commit() + + # элементу списка со всеми пациентами присваются данные конкретного пациента + + else: + self._saved = True # Теперь пациент существует + self._row_idx = Patient.current_row_idx # конкретном объекту присвается номер строки в файле + Patient.current_row_idx += 1 # после этого для следующего объекта счетчик +1 + + # БД covid + cur.execute("INSERT INTO patients (first_name, last_name, birth_date, " + "phone, document_type, document_id) VALUES (%s, %s, %s, %s, %s, %s)", + (self.first_name, + self.last_name, + self.birth_date, + self.phone, + self.document_type, + self.document_id)) # распакуем пациента + conn.commit() + def __str__(self): + return (f'{self.first_name} {self.last_name} {self.birth_date} ' + f'{self.phone} {self.document_type} {self.document_id}') + + +class PatientCollection: + # def __init__(self, path_to_file): + # self.path_to_file = path_to_file + + + def __iter__(self): + #создать курсор, установить размер буфера на одну запись и итерироваться по курсору + cur.execute("SELECT * FROM patients ORDER BY patient_id") + for i in cur.fetchall(): + # print(i) + row = [i[1], i[2], i[3], i[4], i[5], i[6]] + p = Patient(*row) + # p._saved = True # пациент сохранен + # p._row_idx = i # в строке i + yield p + + def limit(self, num): + cur.execute("SELECT * FROM patients ORDER BY patient_id") + for i in cur.fetchall(): + # print(i) + if i[0]> num: + break + + row = [i[1], i[2], i[3], i[4], i[5], i[6]] + p = Patient(*row) + # p._saved = True # пациент сохранен + # p._row_idx = i # в строке i + yield p + + # def __str__(self): + # return (f'{Patient.first_name} {Patient.last_name} {Patient.birth_date} ' + # f'{Patient.phone} {Patient.document_type} {Patient.document_id}') + + +if __name__ == "__main__": + + + # p = Patient('Vasya', 'Pupkin','08-04-1994','89126116381','паспорт','5162333666') + # p.save() + # p.birth_date = '12-10-1994' + # p.save() + # + # p = Patient('Pip', 'Lil','08-04-1995','89126116456','паспорт','5162444666') + # p.save() + # p = Patient('Lil', 'Nas','08-04-1984','89126456891','паспорт','5162555666') + # p.save() + # + p = Patient('kek', 'shpek', '08-04-1995', '89126116456', 'паспорт', '5162444666') + p.save() + p = Patient('mem', 'kekov', '08-04-1984', '89126456891', 'паспорт', '5162555666') + p.save() + + p = Patient('Peton', 'ivanov', '08-04-1984', '89126456891', 'паспорт', '5162555666') + p.save() + p = Patient('Vasiliii', 'Petrov', '08-04-1984', '89126456891', 'паспорт', '5162555666') + p.save() + # p = Patient('Bill', 'Gates', '08-04-1984', '89126456891', 'паспорт', '51555666') + # p.save() + + # pc = PatientCollection() + # for i in pc: + # print(i) + # print() + # + # + # for x in pc.limit(5): + # print(x) diff --git a/README.md b/README.md index 316aa05..ab58471 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,31 @@ -# python_developer_hw2 -Репозиторий для проверки домашки №2 по курсу "Разработчик Python" + Для работы необходимо в файле conf.py заменить данные на свои + + Запуск из консоли: + +Создание python cli.py create Имя Фамилия --birth-date 1990-01-01 --phone +7-916-000-00-00 --document-type паспорт --document-number 0000000000 -## Проверка ДЗ +Вывод на экран первых 10 пользователей: python cli.py show -1. В файле homework/config.py заполняете все константы своими значениями -2. Размещаете классы Patient и PatientCollection в файле homework/patient.py -3. ```pytest tests``` +Вывод на экран произвольного количества пользователей: python cli.py show 8 -Если всё ок, то Pull-request в этот репозиторий \ No newline at end of file +Вывод на экран количества сохраненных пользователей: python cli.py count + +P.S. + Перед созданием пациента логируется изменение полей, как сделать в декораторе так, чтобы логирование шло именно при реальном изменении, пока не придумал. + +P.P.S так же необходимо проделать: + +pip3 install psycopg2-binary + +В Linux может потребоваться sudo apt install libpq-dev + +Ну и сам postgres: + +Create the file /etc/apt/sources.list.d/pgdg.list and add a line for the repository + +deb http://apt.postgresql.org/pub/repos/apt/ YOUR_UBUNTU_VERSION_HERE-pgdg main + +Import the repository signing key, and update the package lists + +wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - +sudo apt-get update diff --git a/cli.py b/cli.py new file mode 100644 index 0000000..65088c1 --- /dev/null +++ b/cli.py @@ -0,0 +1,45 @@ +import click +from HW3 import Patient, PatientCollection + +@click.group() +def cli(): + """Создаем пациентов через консоль""" +@click.command('create') +@click.argument('first-name') +@click.argument('last-name') +@click.option('--birth-date', help='The birth date format "yyyy-mm-dd"') +@click.option('--phone', help='The phone format "8-ddd-ddd-dd-dd"') +@click.option('--document-type', help='The document type must be "Паспорт", "Заграничный паспорт",' + ' "Водительские права"') +@click.option('--document-number', help='The document id must have 10 digits for russian passport or driving licence' + 'or 9 digits for international passport') + +def create_patient(first_name, last_name, birth_date, phone, document_type, document_number): + p = Patient(first_name, last_name, birth_date, phone, document_type, document_number) + p.save() + + +@click.command('show') +@click.argument('num', default=10) +def show_patients(num): + pc = PatientCollection() + for m in pc.limit(num): + click.echo(m) + + +@click.command('count') +# @click.argument('num', default=10) +def count_patients(): + pc = PatientCollection() + count=0 + for m in pc: + count+=1 + click.echo(count) + + + +cli.add_command(create_patient) +cli.add_command(show_patients) +cli.add_command(count_patients) +cli() + diff --git a/conf.py b/conf.py new file mode 100644 index 0000000..85f680c --- /dev/null +++ b/conf.py @@ -0,0 +1,8 @@ +DATA_BASE = 'covid' +LOGIN = 'aleksandrskiba' +PASSWD = '31471' +HST = 'localhost' +NPORT = 5432 + + + diff --git a/homework/__init__.py b/homework/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/homework/config.py b/homework/config.py deleted file mode 100644 index 955b991..0000000 --- a/homework/config.py +++ /dev/null @@ -1,13 +0,0 @@ -GOOD_LOG_FILE = "good_log.txt" -ERROR_LOG_FILE = "error_log.txt" -CSV_PATH = "csv.csv" -PHONE_FORMAT = "79160000000" # Здесь запишите телефон +7-916-000-00-00 в том формате, в котором вы храните телефоны - -PASSPORT_TYPE = "паспорт" # тип документа, когда он паспорт -PASSPORT_FORMAT = "0000 000000" # Здесь запишите номер парспорта 0000 000000 в том формате, в котором вы его храните - -INTERNATIONAL_PASSPORT_TYPE = "заграничный паспорт" # тип документа, если это загран -INTERNATIONAL_PASSPORT_FORMAT = "00 0000000" # формат хранения заграна для номера 00 0000000 - -DRIVER_LICENSE_TYPE = "водительское удостоверение" # тип документа, если это водительское удостоверение -DRIVER_LICENSE_FORMAT = "00 00 000000" # формат хранения номера ВУ diff --git a/homework/patient.py b/homework/patient.py deleted file mode 100644 index dad2526..0000000 --- a/homework/patient.py +++ /dev/null @@ -1,17 +0,0 @@ -class Patient: - def __init__(self, *args, **kwargs): - pass - - def create(*args, **kwargs): - raise NotImplementedError() - - def save(self): - pass - - -class PatientCollection: - def __init__(self, log_file): - pass - - def limit(self, n): - raise NotImplementedError() diff --git a/log.py b/log.py new file mode 100644 index 0000000..8653b02 --- /dev/null +++ b/log.py @@ -0,0 +1,38 @@ +import logging +import functools + +# Определим логгер +def setup_logger(logger_name, log_file, level=logging.INFO): + l = logging.getLogger(logger_name) + formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') + fileHandler = logging.FileHandler(log_file, 'w') + fileHandler.setFormatter(formatter) + + l.setLevel(level) + l.addHandler(fileHandler) + + +setup_logger('info_logger', 'info.log', logging.INFO) +setup_logger('error_logger', 'error.log', logging.ERROR) + +logger_info = logging.getLogger('info_logger') +logger_error = logging.getLogger('error_logger') + +def logging_decor(func): + @functools.wraps(func) + def decorated(self,*args): + try: + result = func(self, *args) + except TypeError as ex: + logger_error.error("TypeError {0}".format(ex)) + raise ex + except ValueError as ex: + logger_error.error("ValueError {0}".format(ex)) + raise ex + except AttributeError as ex: + logger_error.error("Попытка изменить имя или фамилию {0}".format(ex)) + raise ex + names_dict = {'__init__': 'Создан объект','__set__':'Изменено' } + logger_info.info(f'{names_dict[func.__name__]} {args}') + return result + return decorated diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/constants.py b/tests/constants.py deleted file mode 100644 index 6107319..0000000 --- a/tests/constants.py +++ /dev/null @@ -1,6 +0,0 @@ -from homework.config import PHONE_FORMAT, DRIVER_LICENSE_TYPE, DRIVER_LICENSE_FORMAT, PASSPORT_TYPE - -GOOD_PARAMS = ("Кондрат", "Коловрат", "1978-01-31", PHONE_FORMAT, DRIVER_LICENSE_TYPE, DRIVER_LICENSE_FORMAT) -OTHER_GOOD_PARAMS = ("Нурсултан", "Назарбаев", "1900-01-01", "+7-916-111-11-11", PASSPORT_TYPE, "1111 111111") -WRONG_PARAMS = ("098098", "56876576558", "ABCDEF", "sdfsdfsdf", "sdfsdfsdfs", "sdflsdfiuh") -PATIENT_FIELDS = ("first_name", "last_name", "birth_date", "phone", "document_type", "document_id") \ No newline at end of file diff --git a/tests/test_patient.py b/tests/test_patient.py deleted file mode 100644 index a442599..0000000 --- a/tests/test_patient.py +++ /dev/null @@ -1,195 +0,0 @@ -import functools -import os -from datetime import datetime -import itertools - -import pytest - -from homework.config import GOOD_LOG_FILE, ERROR_LOG_FILE, CSV_PATH, PHONE_FORMAT, PASSPORT_TYPE, PASSPORT_FORMAT, \ - INTERNATIONAL_PASSPORT_FORMAT, INTERNATIONAL_PASSPORT_TYPE, DRIVER_LICENSE_TYPE, DRIVER_LICENSE_FORMAT -from homework.patient import Patient -from tests.constants import GOOD_PARAMS, OTHER_GOOD_PARAMS, WRONG_PARAMS, PATIENT_FIELDS - - -def get_len(file): - with open(file, encoding='utf-8') as f: - return len(f.readlines()) - - -def check_log_size(log, increased=False): - def deco(func): - log_map = {"error": ERROR_LOG_FILE, "good": GOOD_LOG_FILE, "csv": CSV_PATH} - log_path = log_map.get(log, log) - @functools.wraps(func) - def wrapper(*args, **kwargs): - log_len = get_len(log_path) - result = func(*args, **kwargs) - new_len = get_len(log_path) - assert new_len > log_len if increased else new_len == log_len, f"Wrong {log} file length" - return result - return wrapper - return deco - - -def setup_module(__main__): - for file in [GOOD_LOG_FILE, ERROR_LOG_FILE, CSV_PATH]: - with open(file, 'w', encoding='utf-8') as f: - f.write('') - - -def teardown_module(__name__): - for file in [GOOD_LOG_FILE, ERROR_LOG_FILE, CSV_PATH]: - os.remove(file) - - -@check_log_size("error") -@check_log_size("good", increased=True) -def test_creation_all_good_params(): - patient = Patient("Кондрат", "Коловрат", "1978-01-31", PHONE_FORMAT, PASSPORT_TYPE, PASSPORT_FORMAT) - assert patient.first_name == "Кондрат", "Wrong attribute first_name" - assert patient.last_name == "Коловрат", "Wrong attribute last_name" - assert patient.birth_date == "1978-01-31" or patient.birth_date == datetime(1978, 1, 31), \ - "Wrong attribute birth_date" - assert patient.phone == PHONE_FORMAT, "Wrong attribute phone" - assert patient.document_type == PASSPORT_TYPE, "Wrong attribute document_type" - assert patient.document_id == PASSPORT_FORMAT, "Wrong attribute document_id" - - patient = Patient("Кондрат", "Коловрат", "1978-01-31", PHONE_FORMAT, INTERNATIONAL_PASSPORT_TYPE, - INTERNATIONAL_PASSPORT_FORMAT) - assert patient.document_type == INTERNATIONAL_PASSPORT_TYPE, "Wrong attribute document_type" - assert patient.document_id == INTERNATIONAL_PASSPORT_FORMAT, "Wrong attribute document_id" - - patient = Patient("Кондрат", "Коловрат", "1978-01-31", PHONE_FORMAT, DRIVER_LICENSE_TYPE, DRIVER_LICENSE_FORMAT) - assert patient.document_type == DRIVER_LICENSE_TYPE, "Wrong attribute document_type" - assert patient.document_id == DRIVER_LICENSE_FORMAT, "Wrong attribute document_id" - - -@pytest.mark.parametrize('default,new', itertools.permutations(["(916)", "916", "-916-"], 2)) -@check_log_size("error") -@check_log_size("good", increased=True) -def test_creation_acceptable_phone(default, new): - patient = Patient("Кондрат", "Коловрат", "1978-01-31", PHONE_FORMAT.replace(default, new), - PASSPORT_TYPE, PASSPORT_FORMAT) - assert patient.phone == PHONE_FORMAT, "Wrong attribute phone" - - -@pytest.mark.parametrize('passport', ("00 00 000 000", "0000-000000", "0 0 0 0 0 0 0 0 0 0", "0000/000-000")) -@check_log_size("error") -@check_log_size("good", increased=True) -def test_creation_acceptable_passport(passport): - patient = Patient("Кондрат", "Коловрат", "1978-01-31", PHONE_FORMAT, PASSPORT_TYPE, passport) - assert patient.document_id == PASSPORT_FORMAT, "Wrong attribute document_id" - - -@pytest.mark.parametrize('passport', ("00 0000000", "00-0000000", "0 0 0 0 0 0 0 0 0", "00/000-0000")) -@check_log_size("error") -@check_log_size("good", increased=True) -def test_creation_acceptable_international_passport(passport): - patient = Patient("Кондрат", "Коловрат", "1978-01-31", PHONE_FORMAT, INTERNATIONAL_PASSPORT_TYPE, passport) - assert patient.document_id == INTERNATIONAL_PASSPORT_FORMAT, "Wrong attribute document_id" - - -@pytest.mark.parametrize('driver_license', ("00 00 000 000", "0000-000000", "0 0 0 0 0 0 0 0 0 0", "0000/000000")) -@check_log_size("error") -@check_log_size("good", increased=True) -def test_creation_acceptable_driver_license(driver_license): - patient = Patient("Кондрат", "Коловрат", "1978-01-31", PHONE_FORMAT, DRIVER_LICENSE_TYPE, driver_license) - assert patient.document_id == DRIVER_LICENSE_FORMAT, "Wrong attribute document_id" - - -# неверный тип -@pytest.mark.parametrize("i", list(range(len(GOOD_PARAMS)))) -@check_log_size("error", increased=True) -@check_log_size("good") -def test_creation_wrong_type_params(i): - try: - Patient(*GOOD_PARAMS[:i], 1.8, *GOOD_PARAMS[i+1:]) - assert False, f"TypeError for {PATIENT_FIELDS[i]} not invoked" - except TypeError: - assert True - - -# неверные значения -@pytest.mark.parametrize("i", list(range(len(GOOD_PARAMS)))) -@check_log_size("error", increased=True) -@check_log_size("good") -def test_creation_wrong_params(i): - try: - Patient(*GOOD_PARAMS[:i], WRONG_PARAMS[i], *GOOD_PARAMS[i+1:]) - assert False, f"ValueError for {PATIENT_FIELDS[i]} not invoked" - except ValueError: - assert True - - -# метод create -@check_log_size("error") -@check_log_size("good", increased=True) -def test_create_method_good_params(): - patient = Patient.create(*GOOD_PARAMS) - for param, field in zip(GOOD_PARAMS, PATIENT_FIELDS): - assert getattr(patient, field) in (param, datetime(1978, 1, 31)), f"Wrong attribute {field}" - - -# обновление параметров -@pytest.mark.parametrize("patient,field,param", zip( - [Patient(*OTHER_GOOD_PARAMS)] * len(PATIENT_FIELDS[:2]), - PATIENT_FIELDS[:2], - GOOD_PARAMS[:2] -)) -@check_log_size("error", increased=True) -@check_log_size("good") -def test_names_assignment(patient, field, param): - try: - setattr(patient, field, param) - assert False, f"Attribute error should be invoked for {field} changing" - except AttributeError: - assert True - - -@pytest.mark.parametrize("patient,field,param", zip( - [Patient(*OTHER_GOOD_PARAMS)] * len(PATIENT_FIELDS[2:]), - PATIENT_FIELDS[2:], - GOOD_PARAMS[2:] -)) -@check_log_size("error") -@check_log_size("good", increased=True) -def test_good_params_assignment(patient, field, param): - setattr(patient, field, param) - assert getattr(patient, field) == param, f"Attribute {field} did not change" - - -@pytest.mark.parametrize("patient,field,param", zip( - [Patient(*OTHER_GOOD_PARAMS)] * len(PATIENT_FIELDS[2:]), - PATIENT_FIELDS[2:], - [1.4] * len(PATIENT_FIELDS[2:]) -)) -@check_log_size("error", increased=True) -@check_log_size("good") -def test_wrong_type_assignment(patient, field, param): - try: - setattr(patient, field, param) - assert False, f"TypeError for {field} assignment not invoked" - except TypeError: - assert True - - -@pytest.mark.parametrize("patient,field,param", zip( - [Patient(*OTHER_GOOD_PARAMS)] * len(PATIENT_FIELDS[2:]), - PATIENT_FIELDS[2:], - WRONG_PARAMS[2:] -)) -@check_log_size("error", increased=True) -@check_log_size("good") -def test_wrong_value_assignment(patient, field, param): - try: - setattr(patient, field, param) - assert False, f"ValueError for {field} assignment not invoked" - except ValueError: - assert True - - -# метод save -@check_log_size("csv", increased=True) -def test_save(): - patient = Patient(*GOOD_PARAMS) - patient.save() diff --git a/tests/test_patient_collection.py b/tests/test_patient_collection.py deleted file mode 100644 index 9536eff..0000000 --- a/tests/test_patient_collection.py +++ /dev/null @@ -1,78 +0,0 @@ -import os - -import pytest - -from homework.config import PASSPORT_TYPE, CSV_PATH -from homework.patient import PatientCollection, Patient -from tests.constants import PATIENT_FIELDS - -GOOD_PARAMS = ( - ("Кондрат", "Рюрик", "1971-01-11", "79160000000", PASSPORT_TYPE, "0228 000000"), - ("Евпатий", "Коловрат", "1972-01-11", "79160000001", PASSPORT_TYPE, "0228 000001"), - ("Ада", "Лавлейс", "1978-01-21", "79160000002", PASSPORT_TYPE, "0228 000002"), - ("Миртл", "Плакса", "1880-01-11", "79160000003", PASSPORT_TYPE, "0228 000003"), - ("Евлампия", "Фамилия", "1999-01-21", "79160000004", PASSPORT_TYPE, "0228 000004"), - ("Кузя", "Кузьмин", "2000-01-21", "79160000005", PASSPORT_TYPE, "0228 000005"), - ("Гарри", "Поттер", "2020-01-11", "79160000006", PASSPORT_TYPE, "0228 000006"), - ("Рон", "Уизли", "1900-04-20", "79160000007", PASSPORT_TYPE, "0228 000007"), - ("Билл", "Гейтс", "1978-12-31", "79160000008", PASSPORT_TYPE, "0228 000008"), - ("Владимир", "Джугашвили", "1912-01-31", "79160000009", PASSPORT_TYPE, "0228 000009"), - ("Вован", "ДеМорт", "1978-11-30", "79160000010", PASSPORT_TYPE, "0228 000010"), - ("Гопник", "Районный", "1978-01-25", "79160000011", PASSPORT_TYPE, "0228 000011"), - ("Фёдор", "Достоевский", "1978-01-05", "79160000012", PASSPORT_TYPE, "0228 000012"), -) - - -@pytest.fixture() -def prepare(): - with open(CSV_PATH, 'w', encoding='utf-8') as f: - f.write('') - for params in GOOD_PARAMS: - Patient(*params).save() - yield - os.remove(CSV_PATH) - - -@pytest.mark.usefixtures('prepare') -def test_collection_iteration(): - collection = PatientCollection(CSV_PATH) - for i, patient in enumerate(collection): - true_patient = Patient(*GOOD_PARAMS[i]) - for field in PATIENT_FIELDS: - assert getattr(patient, field) == getattr(true_patient, field), f"Wrong attr {field} for {GOOD_PARAMS[i]}" - - -@pytest.mark.usefixtures('prepare') -def test_limit_usual(): - collection = PatientCollection(CSV_PATH) - try: - len(collection.limit(8)) - assert False, "Iterator should not have __len__ method" - except (TypeError, AttributeError): - assert True - for i, patient in enumerate(collection.limit(8)): - true_patient = Patient(*GOOD_PARAMS[i]) - for field in PATIENT_FIELDS: - assert getattr(patient, field) == getattr(true_patient, field), f"Wrong attr {field} for {GOOD_PARAMS[i]} in limit" - - -@pytest.mark.usefixtures('prepare') -def test_limit_add_record(): - collection = PatientCollection(CSV_PATH) - limit = collection.limit(len(GOOD_PARAMS) + 10) - for _ in range(len(GOOD_PARAMS)): - next(limit) - new_patient = Patient("Митрофан", "Космодемьянский", "1999-10-15", "79030000000", PASSPORT_TYPE, "4510 000444") - new_patient.save() - last_patient = next(limit) - for field in PATIENT_FIELDS: - assert getattr(new_patient, field) == getattr(last_patient, field), f"Wrong attr {field} for changed limit" - - -@pytest.mark.usefixtures('prepare') -def test_limit_remove_records(): - collection = PatientCollection(CSV_PATH) - limit = collection.limit(4) - with open(CSV_PATH, 'w', encoding='utf-8') as f: - f.write('') - assert len([_ for _ in limit]) == 0, "Limit works wrong for empty file"