diff --git a/.gitignore b/.gitignore index 75703f3..1df1925 100644 --- a/.gitignore +++ b/.gitignore @@ -130,3 +130,5 @@ dmypy.json .idea + +create_db.py diff --git a/CLI.py b/CLI.py new file mode 100644 index 0000000..5e1af2a --- /dev/null +++ b/CLI.py @@ -0,0 +1,43 @@ +import click + +from homework.patient import Patient, PatientCollection + + +@click.group() +def cli(): + pass + +@cli.command() +@click.argument("first_name") +@click.argument("last_name") +@click.option("--birth-date", help="Birth day") +@click.option("--phone", help="Phone") +@click.option("--document-type", help="Document type") +@click.option("--document-number", help="Document id") +def create(first_name, last_name, birth_date, phone, document_type, document_number): + par = Patient.create(first_name, last_name, birth_date, phone, document_type, document_number) + print(par.save()) + click.echo(par) + + +@cli.command() +@click.option("--val", default=10, help="limit") +def show(val): + Pc = PatientCollection() + for pat in Pc.limit(val): + click.echo(pat) + + +@cli.command() +def count(): + click.echo(PatientCollection().count()) + # print(PatientCollection().count()) +# +# +# cli.command(create) +# cli.command(show) +# cli.command(count) + +cli() +# if __name__ == 'main': +# pass diff --git a/homework/Bad_Logs.txt b/homework/Bad_Logs.txt new file mode 100644 index 0000000..e69de29 diff --git a/homework/DataIsValid.py b/homework/DataIsValid.py new file mode 100644 index 0000000..721e465 --- /dev/null +++ b/homework/DataIsValid.py @@ -0,0 +1,95 @@ +from copy import deepcopy +from re import fullmatch, sub, search +from datetime import date as dt + + +# from homework.Log import validerr + +def nameReal(name_): + pattern = "[0-9]" + name = sub(pattern, "", name_) + if len(name) == 0: + return None + return name + + +def dateIsValid(date): + pattern1 = "\d{4}.\d{2}.\d{2}" # y-m-d + pattern2 = "\d{2}.\d{2}.\d{4}" # d-m-y + match1 = fullmatch(pattern1, date) + match2 = fullmatch(pattern2, date) + + if match1: + try: + d = str(dt(int(date[:4]), int(date[5:7]), int(date[8:]))) + except: + return None + elif match2: + try: + d = dt(int(date[8:]), int(date[5:7]), int(date[:4])) + except: + return None + else: + return None + return d + + +def phoneIsValid(phone_): + pattern = "[^+,0,1,2,3,4,5,6,7,8,9]" + phone = sub(pattern, "", phone_) + if len(phone) < 10: + return None + if phone[0] == '8' or phone[0] == '7': + phone = ''.join(['+7', phone[1:]]) + elif not phone[0] == '+' or not phone[1] == '7': + # validerr.paterr.warning(["Only Russians numbers are valid. +7-xxx-xxx-xx-xx or 8-xxx-xxx-xx-xx. Your num: ", phone]) + return None + + if not len(phone) == 12: + # validerr.paterr.warning(["Only Russians numbers are valid. len !=12 . Your num: ", phone]) + return None + if not (phone[2:5] == '495' or phone[2:5] == '499' or phone[2] == '9'): + # validerr.paterr.warning(["Only Russians numbers are valid. +7-499-... or +7-495-... or +7-9..-.... Your num: ", phone]) + return None + return phone + + +def docTypeIsValid(doc_type): + if not isinstance(doc_type, str): + return None + doc_type = doc_type.lower() + + passport = "паспорт" + passportruen = "gfcgjhn" + zPassport = "загран" + zpassportruen = "pfuhfy" + prav1 = "водительск" + prav1ruen = "djlbntkmcr" + prav2 = "права" + prav2ruen = "ghfdf" + + if search(zPassport, doc_type) or search(zpassportruen, doc_type): + return "загран" + elif search(passport, doc_type) or search(passportruen, doc_type): + return "паспорт" + elif search(prav1, doc_type) or search(prav2, doc_type) or search(prav1ruen, doc_type) or search(prav2ruen, + doc_type): + return "права" + + return None + + +def docIdIsValid(id, type=None): + pattern = "[^0,1,2,3,4,5,6,7,8,9]" + id = sub(pattern, "", id) + if len(id) == 10: + if type == "паспорт" or type == "права" or not type: + return id + else: + # validerr.paterr.warning(["Zpass - len ==9. In dr and pass-10. Your type: ", type, ". Your id: ", id]) + return None + elif len(id) == 9 and (type == "загран" or not type): + # validerr.paterr.warning(["Zpass - len ==9. In dr and pass-10. Your type: ", type, ". Your id: ", id]) + return id + else: + return None diff --git a/homework/Decorators.py b/homework/Decorators.py new file mode 100644 index 0000000..136e8ad --- /dev/null +++ b/homework/Decorators.py @@ -0,0 +1,107 @@ +import os +import psycopg2 + + +def Pat_create_logs(ini): + def wrapper_pc(self, *args): + if len(args) == 0: + self.patinfo.debug("Empty Patient was created") + return + elif not len(args) == 6: + self.paterr.error( + "There should be 6 args: first_name_, last_name_, birth_date_, phone_, document_type_, document_id_. Patient wasn't created") + return + ini(self, *args) + if not ( + self.first_name or self.last_name or self.birth_date or self.phone or self.document_type or self.document_id): + self.created = False + raise AttributeError + self.patinfo.info("User was created") + + return wrapper_pc + + +def Pat_save_logs(save): + def wrapper_ps(self): + if not self.created: + self.paterr.warning("User is NONE, so it wasn't saved.") + # try: + # with open(filename, "a", newline="", encoding='utf-8') as file: + # writer = wr(file) + # except: + # raise AttributeError("Can't open csv file") + try: + save(self) + self.patinfo.info("User was saved.") + except: + self.paterr.error("User was not saved!") + raise AttributeError + + return wrapper_ps + + +def PC_create(ini): + def wrapper_pcc(self, path): + if not os.path.isfile(path): + raise ValueError("Path does exist") + ini(self, path) + + return wrapper_pcc + + +def Name_set(set): + def wrapper_ns(self, instance, val): + # raise TypeError + if not isinstance(val, str): + instance.paterr.error('Invalid name.') + instance.paterr.error("Error. User was not created.") + raise TypeError("not str") + + if instance.is_created(): + instance.paterr.error("You can't change name") + instance.paterr.error("Error. User was not created.") + raise AttributeError("can't change name") + + if not set(self, instance, val): + instance.paterr.error("Wrong name") + instance.paterr.error("Error. User was not created.") + raise ValueError("wrong name") + + instance.patinfo.debug(["name is okey:", instance.__dict__[self.name]]) + + return wrapper_ns + + +def set_descr(set): + def wrapper_sd(self, instance, val): + d_t = self.name + if not isinstance(val, str): + instance.paterr.error(['Invalid ', d_t]) + instance.paterr.error("Error. User was not created.") + raise TypeError("not str") + + if not set(self, instance, val): + instance.paterr.error(['Invalid value ', d_t]) + instance.paterr.error("Error. User was not created.") + raise ValueError([d_t, " error"]) + + instance.patinfo.debug([d_t, " is okey: ", instance.__dict__[self.name]]) + if instance.is_created(): + instance.patinfo.info([d_t, " is okey: ", instance.__dict__[self.name]]) + + return wrapper_sd + + +def PC_create_db(ini): + def wrapper_pcidb(self, db="postgres", user_="alex", password_="1234", host_="127.0.0.1", port_="5432"): + with psycopg2.connect( + database="postgres", + user="alex", + password="1234", + host="127.0.0.1", + port="5432") as con: + pass + + ini(self, db, user_, password_, host_, port_) + + return wrapper_pcidb diff --git a/homework/Descriptor.py b/homework/Descriptor.py new file mode 100644 index 0000000..936127b --- /dev/null +++ b/homework/Descriptor.py @@ -0,0 +1,89 @@ +from homework.DataIsValid import * +from homework.Decorators import Name_set, set_descr + + +class Name: + def __get__(self, instance, owner): + return instance.__dict__[self.name] + + @Name_set + def __set__(self, instance, val): + n = nameReal(val) + if not n: + return None + + instance.__dict__[self.name] = n + return n + + def __set_name__(self, owner, name): + self.name = name + + +class Phone: + def __get__(self, instance, owner): + return instance.__dict__[self.name] + + @set_descr + def __set__(self, instance, number): + prov = phoneIsValid(number) + if not prov: + return None + + instance.__dict__[self.name] = prov + return prov + + def __set_name__(self, owner, name): + self.name = name + + +class DocType(): + def __get__(self, instance, owner): + return instance.__dict__[self.name] + + @set_descr + def __set__(self, instance, type): + prov = docTypeIsValid(type) + if not prov: + return None + + instance.__dict__[self.name] = prov + return prov + + def __set_name__(self, owner, name): + self.name = name + + +class DocId: + def __get__(self, instance, owner): + return instance.__dict__[self.name] + + @set_descr + def __set__(self, instance, id): + self.type = instance.document_type + prov = docIdIsValid(id, self.type) + + if not prov: + return None + + instance.__dict__[self.name] = prov + return prov + + def __set_name__(self, owner, name): + self.name = name + self.type = None + + +class Date: + def __get__(self, instance, owner): + return instance.__dict__[self.name] + + @set_descr + def __set__(self, instance, date): + prov = dateIsValid(date) + if not prov: + return None + instance.__dict__[self.name] = prov + return prov + + def __set_name__(self, owner, name): + self.name = name diff --git a/homework/Good_Logs.txt b/homework/Good_Logs.txt new file mode 100644 index 0000000..e69de29 diff --git a/homework/PatienList.csv b/homework/PatienList.csv new file mode 100644 index 0000000..7afc531 --- /dev/null +++ b/homework/PatienList.csv @@ -0,0 +1,7 @@ +Кондрат,Рюрик,1971-01-31,+79160000000,паспорт,0228000000 +Евпатий,Коловрат,1972-01-31,+79160000001,паспорт,0228000001 +Ада,Лавлейс,1978-01-21,+79160000002,паспорт,0228000002 +Миртл,Плакса,1980-01-31,+79160000003,паспорт,0228000003 +Евлампия,Фамилия,1999-01-31,+79160000004,паспорт,0228000004 +Фёдор,Достоевский,1978-01-05,+79160000012,паспорт,0228000012 +Фёдор,Достоевский,1978-01-05,+79160000012,паспорт,0228000012 diff --git a/homework/config.py b/homework/config.py index 955b991..ac62250 100644 --- a/homework/config.py +++ b/homework/config.py @@ -1,13 +1,13 @@ -GOOD_LOG_FILE = "good_log.txt" -ERROR_LOG_FILE = "error_log.txt" -CSV_PATH = "csv.csv" -PHONE_FORMAT = "79160000000" # Здесь запишите телефон +7-916-000-00-00 в том формате, в котором вы храните телефоны +GOOD_LOG_FILE = "/home/alexsun8/kib/python_developer_hw2/homework/Good_Logs.txt" +ERROR_LOG_FILE = "/home/alexsun8/kib/python_developer_hw2/homework/Bad_Logs.txt" +CSV_PATH = "PatienList.csv" +PHONE_FORMAT = "+79160000000" # Здесь запишите телефон +7-916-000-00-00 в том формате, в котором вы храните телефоны PASSPORT_TYPE = "паспорт" # тип документа, когда он паспорт -PASSPORT_FORMAT = "0000 000000" # Здесь запишите номер парспорта 0000 000000 в том формате, в котором вы его храните +PASSPORT_FORMAT = "0000000000" # Здесь запишите номер парспорта 0000 000000 в том формате, в котором вы его храните -INTERNATIONAL_PASSPORT_TYPE = "заграничный паспорт" # тип документа, если это загран -INTERNATIONAL_PASSPORT_FORMAT = "00 0000000" # формат хранения заграна для номера 00 0000000 +INTERNATIONAL_PASSPORT_TYPE = "загран" # тип документа, если это загран +INTERNATIONAL_PASSPORT_FORMAT = "000000000" # формат хранения заграна для номера 00 0000000 -DRIVER_LICENSE_TYPE = "водительское удостоверение" # тип документа, если это водительское удостоверение -DRIVER_LICENSE_FORMAT = "00 00 000000" # формат хранения номера ВУ +DRIVER_LICENSE_TYPE = "права" # тип документа, если это водительское удостоверение +DRIVER_LICENSE_FORMAT = "0000000000" # формат хранения номера ВУ diff --git a/homework/create_db.py b/homework/create_db.py new file mode 100644 index 0000000..25e9ac9 --- /dev/null +++ b/homework/create_db.py @@ -0,0 +1,22 @@ +# import psycopg2 +# +# # +# +# # # Creating a cursor object using the cursor() method +# # cursor = con.cursor() +# # +# # # Doping EMPLOYEE table if already exists. +# # cursor.execute("DROP TABLE IF EXISTS PATIENTS") +# # +# # # Creating table as per requirement +# # sql = '''CREATE TABLE PATIENTS( +# # FIRST_NAME CHAR(20) NOT NULL, +# # LAST_NAME CHAR(20) NOT NULL, +# # BIRTH_DATE CHAR(10) NOT NULL, +# # PHONE CHAR(12) NOT NULL, +# # DOCUMENT_TYPE CHAR(20) NOT NULL, +# # DOCUMENT_ID CHAR(20) NOT NULL +# # )''' +# # cursor.execute(sql) +# # print("Table created successfully........") +# diff --git a/homework/patient.py b/homework/patient.py index dad2526..eab44d6 100644 --- a/homework/patient.py +++ b/homework/patient.py @@ -1,17 +1,142 @@ +import csv +import psycopg2 + +from homework.Descriptor import * +import logging +from homework.Decorators import Pat_create_logs, Pat_save_logs, PC_create, PC_create_db + + class Patient: - def __init__(self, *args, **kwargs): - pass + first_name = Name() + last_name = Name() + birth_date = Date() + phone = Phone() + document_type = DocType() + document_id = DocId() + created = False + + formatter = logging.Formatter("%(filename)s[LINE:%(lineno)d]# %(levelname)-8s [%(asctime)s] %(message)s") + handler = logging.FileHandler('/home/alexsun8/kib/python_developer_hw2/homework/Good_Logs.txt', 'a', 'utf-8') + handlerbad = logging.FileHandler('/home/alexsun8/kib/python_developer_hw2/homework/Bad_Logs.txt', 'a', 'utf-8') + handler.setFormatter(formatter) + # handlerbad = handler + # handlerbad = handler2 + + # logs in Patient class + patinfo = logging.getLogger("Patient info") + patinfo.setLevel(logging.INFO) + patinfo.addHandler(handler) + paterr = logging.getLogger("Patient errors") + paterr.setLevel(logging.ERROR) + paterr.addHandler(handlerbad) - def create(*args, **kwargs): - raise NotImplementedError() + @Pat_create_logs + def __init__(self, *args): + self.created = False + self.first_name = args[0] + self.last_name = args[1] + self.birth_date = args[2] + self.phone = args[3] + self.document_type = args[4] + self.document_id = args[5] + self.created = True + @staticmethod + def create(*args): + return Patient(*args) + + @Pat_save_logs def save(self): - pass + data = [self.first_name, self.last_name, self.birth_date, self.phone, self.document_type, self.document_id] + + with psycopg2.connect( + database="postgres", + user="alex", + password="1234", + host="127.0.0.1", + port="5432") as con: + with con.cursor() as cursor: + postgres_insert_query = """ INSERT INTO PATIENTS(FIRST_NAME, LAST_NAME, BIRTH_DATE, PHONE, DOCUMENT_TYPE, DOCUMENT_ID) VALUES (%s,%s,%s,%s,%s,%s)""" + cursor.execute(postgres_insert_query, data) + con.commit() + + def __str__(self): + if not self.created: + return "" + data = ' '.join( + [self.first_name, self.last_name, self.birth_date, self.phone, self.document_type, self.document_id]) + return data + + def is_created(self): + return self.created class PatientCollection: - def __init__(self, log_file): - pass + # @PC_create + # def __init__(self, path_to_file): + # self.filepath = path_to_file + + @PC_create_db + def __init__(self, db, user_, password_, host_, port_): + self.database = db + self.user = user_ + self.password = password_ + self.host = host_ + self.port = port_ + + def __iter__(self): + with psycopg2.connect( + database=self.database, + user=self.user, + password=self.password, + host=self.host, + port=self.port) as con: + with con.cursor() as cursor: + postgreSQL_select_Query = "select * from PATIENTS" + + cursor.execute(postgreSQL_select_Query) + records = cursor.fetchall() + + for row in records: + a = Patient(*row) + yield a + + def limit(self, num=-1): + if num < 1: + raise ValueError("Argument in limit should be >1.") + with psycopg2.connect( + database=self.database, + user=self.user, + password=self.password, + host=self.host, + port=self.port) as con: + with con.cursor() as cursor: + postgreSQL_select_Query = "select * from PATIENTS" + + cursor.execute(postgreSQL_select_Query) + + if num > -1: + records = cursor.fetchmany(num) + else: + records = cursor.fetchall + + + for row in records: + # print("PAT: ", row[0], row[1], row[2], row[3], row[4], row[5]) + a = Patient(*row) + yield a + + def count(self): + count = -1 + with psycopg2.connect( + database=self.database, + user=self.user, + password=self.password, + host=self.host, + port=self.port) as con: + with con.cursor() as cursor: + comm = """SELECT * FROM PATIENTS""" + cursor.execute(comm) + count = len(cursor.fetchall()) - def limit(self, n): - raise NotImplementedError() + return count diff --git a/postgres-docker/docker-compose.yml b/postgres-docker/docker-compose.yml new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_patient_collection.py b/tests/test_patient_collection.py index 9536eff..aac6400 100644 --- a/tests/test_patient_collection.py +++ b/tests/test_patient_collection.py @@ -7,14 +7,14 @@ from tests.constants import PATIENT_FIELDS GOOD_PARAMS = ( - ("Кондрат", "Рюрик", "1971-01-11", "79160000000", PASSPORT_TYPE, "0228 000000"), - ("Евпатий", "Коловрат", "1972-01-11", "79160000001", PASSPORT_TYPE, "0228 000001"), + ("Кондрат", "Рюрик", "1971-01-31", "79160000000", PASSPORT_TYPE, "0228 000000"), + ("Евпатий", "Коловрат", "1972-01-31", "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"), + ("Миртл", "Плакса", "1980-01-31", "79160000003", PASSPORT_TYPE, "0228 000003"), + ("Евлампия", "Фамилия", "1999-01-31", "79160000004", PASSPORT_TYPE, "0228 000004"), + ("Кузя", "Кузьмин", "2000-01-31", "79160000005", PASSPORT_TYPE, "0228 000005"), + ("Гарри", "Поттер", "2000-01-31", "79160000006", PASSPORT_TYPE, "0228 000006"), + ("Рон", "Уизли", "1900-04-30", "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"),