diff --git a/.mysql/root.crt b/.mysql/root.crt new file mode 100644 index 0000000..cd9e9e3 --- /dev/null +++ b/.mysql/root.crt @@ -0,0 +1,59 @@ +-----BEGIN CERTIFICATE----- +MIIE3TCCAsWgAwIBAgIKPxb5sAAAAAAAFzANBgkqhkiG9w0BAQ0FADAfMR0wGwYD +VQQDExRZYW5kZXhJbnRlcm5hbFJvb3RDQTAeFw0xNzA2MjAxNjQ0MzdaFw0yNzA2 +MjAxNjU0MzdaMFUxEjAQBgoJkiaJk/IsZAEZFgJydTEWMBQGCgmSJomT8ixkARkW +BnlhbmRleDESMBAGCgmSJomT8ixkARkWAmxkMRMwEQYDVQQDEwpZYW5kZXhDTENB +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqgNnjk0JKPcbsk1+KG2t +eM1AfMnEe5RkAJuBBuwVV49snhcvO1jhKBx/pCnjr6biICc1/oAFDVgU8yVYYPwp +WZ2vH3ZtscjJ/RAT/NS9OKKG7kKknhFhVYxua5xhoIQmm6usBNYYiTcWoFm1eHC8 +I9oddOLSscZYbh3unVRvt+3V+drVmUx9oSUKpqMgfysiv1MN6zB3vq9TFkbhz53E +k0tEcV+W2NnDaeFhLKy284FDKLvOdTDj1EDsSAihxl7sNEKpupNuhgyy2siOqUb+ +d5mO/CRfaAKGg3E6hDM3pEi48E506dJdjPXWfHKSvuguMLRlb2RWdVocRZuyWxOh +0QIDAQABo4HkMIHhMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRMU5uItjx+ +TOicX1+ovC1Xq2PSnzAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8E +BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSrucX/oe/mUx0zOSKE +0XbUN04tajBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vY3Jscy55YW5kZXgucnUv +WWFuZGV4SW50ZXJuYWxSb290Q0EvWWFuZGV4SW50ZXJuYWxSb290Q0EuY3JsMA0G +CSqGSIb3DQEBDQUAA4ICAQAsR5Lb4Pv2FD0Kk+4oc1GEOnehxKLsQtdV81nrU+IV +l9pr2oNMdi8lwIolvHZRllLM4Ba5AcRH6YJ5fe7AjKm+5EdSkhqVWo2UOllRCbtS +wmL50+erOAkxstSlRkO6b8x1L0MOBKv54E5YcQ/Wwt27ldSb6RkEmJBGvmxObAaf +5zc51pqSqao9tnldYaCblEQ/Zmy43FliIpa2eUJoh8DqK8bVo2gcI3wbQ32tWs9u +wvKk8fo4lAdhCwhv+QHuqau1VAY9hPU106bsFIDUmijTMxjAobKBi6CkIX6EbNHU +Jv4DzYVLlDd2y0CADdn2F6I70xpCBn5cquSGuvFbqZjQDmIHwb7WQSxadkiGRWfc +zVTnmiHjJONJJIpE2t+FOV3hc+8o98OzOtNaH2QQ9j6dnKvtIGKGFeNSDp0vXPOi +QhHiIyuB7eWx+g2whktQ74UCpGDSXYnEW3s8w5wezVWIEmouq7q4rCEkTNvJ7Ico +43AgUdPzAFS2zYktw1C+cbUALM8smvXbXrXOBzMmscjIhtXvLMrpPeh23VfdJfQB +0rN2BmRCLUE8JOV+o0k98XMm83oN+lGkL1l+hyoj3ok1uI3JrsWOcDyjOds3ptcN +KimJLm27ndjcxDNo/iA6gefMJuCxFRaqI+eF4P0jSkMgnnQqZkvLGFuHCw8eRDhm +bw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFGTCCAwGgAwIBAgIQJMM7ZIy2SYxCBgK7WcFwnjANBgkqhkiG9w0BAQ0FADAf +MR0wGwYDVQQDExRZYW5kZXhJbnRlcm5hbFJvb3RDQTAeFw0xMzAyMTExMzQxNDNa +Fw0zMzAyMTExMzUxNDJaMB8xHTAbBgNVBAMTFFlhbmRleEludGVybmFsUm9vdENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAgb4xoQjBQ7oEFk8EHVGy +1pDEmPWw0Wgw5nX9RM7LL2xQWyUuEq+Lf9Dgh+O725aZ9+SO2oEs47DHHt81/fne +5N6xOftRrCpy8hGtUR/A3bvjnQgjs+zdXvcO9cTuuzzPTFSts/iZATZsAruiepMx +SGj9S1fGwvYws/yiXWNoNBz4Tu1Tlp0g+5fp/ADjnxc6DqNk6w01mJRDbx+6rlBO +aIH2tQmJXDVoFdrhmBK9qOfjxWlIYGy83TnrvdXwi5mKTMtpEREMgyNLX75UjpvO +NkZgBvEXPQq+g91wBGsWIE2sYlguXiBniQgAJOyRuSdTxcJoG8tZkLDPRi5RouWY +gxXr13edn1TRDGco2hkdtSUBlajBMSvAq+H0hkslzWD/R+BXkn9dh0/DFnxVt4XU +5JbFyd/sKV/rF4Vygfw9ssh1ZIWdqkfZ2QXOZ2gH4AEeoN/9vEfUPwqPVzL0XEZK +r4s2WjU9mE5tHrVsQOZ80wnvYHYi2JHbl0hr5ghs4RIyJwx6LEEnj2tzMFec4f7o +dQeSsZpgRJmpvpAfRTxhIRjZBrKxnMytedAkUPguBQwjVCn7+EaKiJfpu42JG8Mm ++/dHi+Q9Tc+0tX5pKOIpQMlMxMHw8MfPmUjC3AAd9lsmCtuybYoeN2IRdbzzchJ8 +l1ZuoI3gH7pcIeElfVSqSBkCAwEAAaNRME8wCwYDVR0PBAQDAgGGMA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFKu5xf+h7+ZTHTM5IoTRdtQ3Ti1qMBAGCSsGAQQB +gjcVAQQDAgEAMA0GCSqGSIb3DQEBDQUAA4ICAQAVpyJ1qLjqRLC34F1UXkC3vxpO +nV6WgzpzA+DUNog4Y6RhTnh0Bsir+I+FTl0zFCm7JpT/3NP9VjfEitMkHehmHhQK +c7cIBZSF62K477OTvLz+9ku2O/bGTtYv9fAvR4BmzFfyPDoAKOjJSghD1p/7El+1 +eSjvcUBzLnBUtxO/iYXRNo7B3+1qo4F5Hz7rPRLI0UWW/0UAfVCO2fFtyF6C1iEY +/q0Ldbf3YIaMkf2WgGhnX9yH/8OiIij2r0LVNHS811apyycjep8y/NkG4q1Z9jEi +VEX3P6NEL8dWtXQlvlNGMcfDT3lmB+tS32CPEUwce/Ble646rukbERRwFfxXojpf +C6ium+LtJc7qnK6ygnYF4D6mz4H+3WaxJd1S1hGQxOb/3WVw63tZFnN62F6/nc5g +6T44Yb7ND6y3nVcygLpbQsws6HsjX65CoSjrrPn0YhKxNBscF7M7tLTW/5LK9uhk +yjRCkJ0YagpeLxfV1l1ZJZaTPZvY9+ylHnWHhzlq0FzcrooSSsp4i44DB2K7O2ID +87leymZkKUY6PMDa4GkDJx0dG4UXDhRETMf+NkYgtLJ+UIzMNskwVDcxO4kVL+Hi +Pj78bnC5yCw8P5YylR45LdxLzLO68unoXOyFz1etGXzszw8lJI9LNubYxk77mK8H +LpuQKbSbIERsmR+QqQ== +-----END CERTIFICATE----- diff --git a/homework/.mysql/root.crt b/homework/.mysql/root.crt new file mode 100644 index 0000000..cd9e9e3 --- /dev/null +++ b/homework/.mysql/root.crt @@ -0,0 +1,59 @@ +-----BEGIN CERTIFICATE----- +MIIE3TCCAsWgAwIBAgIKPxb5sAAAAAAAFzANBgkqhkiG9w0BAQ0FADAfMR0wGwYD +VQQDExRZYW5kZXhJbnRlcm5hbFJvb3RDQTAeFw0xNzA2MjAxNjQ0MzdaFw0yNzA2 +MjAxNjU0MzdaMFUxEjAQBgoJkiaJk/IsZAEZFgJydTEWMBQGCgmSJomT8ixkARkW +BnlhbmRleDESMBAGCgmSJomT8ixkARkWAmxkMRMwEQYDVQQDEwpZYW5kZXhDTENB +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqgNnjk0JKPcbsk1+KG2t +eM1AfMnEe5RkAJuBBuwVV49snhcvO1jhKBx/pCnjr6biICc1/oAFDVgU8yVYYPwp +WZ2vH3ZtscjJ/RAT/NS9OKKG7kKknhFhVYxua5xhoIQmm6usBNYYiTcWoFm1eHC8 +I9oddOLSscZYbh3unVRvt+3V+drVmUx9oSUKpqMgfysiv1MN6zB3vq9TFkbhz53E +k0tEcV+W2NnDaeFhLKy284FDKLvOdTDj1EDsSAihxl7sNEKpupNuhgyy2siOqUb+ +d5mO/CRfaAKGg3E6hDM3pEi48E506dJdjPXWfHKSvuguMLRlb2RWdVocRZuyWxOh +0QIDAQABo4HkMIHhMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRMU5uItjx+ +TOicX1+ovC1Xq2PSnzAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8E +BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSrucX/oe/mUx0zOSKE +0XbUN04tajBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vY3Jscy55YW5kZXgucnUv +WWFuZGV4SW50ZXJuYWxSb290Q0EvWWFuZGV4SW50ZXJuYWxSb290Q0EuY3JsMA0G +CSqGSIb3DQEBDQUAA4ICAQAsR5Lb4Pv2FD0Kk+4oc1GEOnehxKLsQtdV81nrU+IV +l9pr2oNMdi8lwIolvHZRllLM4Ba5AcRH6YJ5fe7AjKm+5EdSkhqVWo2UOllRCbtS +wmL50+erOAkxstSlRkO6b8x1L0MOBKv54E5YcQ/Wwt27ldSb6RkEmJBGvmxObAaf +5zc51pqSqao9tnldYaCblEQ/Zmy43FliIpa2eUJoh8DqK8bVo2gcI3wbQ32tWs9u +wvKk8fo4lAdhCwhv+QHuqau1VAY9hPU106bsFIDUmijTMxjAobKBi6CkIX6EbNHU +Jv4DzYVLlDd2y0CADdn2F6I70xpCBn5cquSGuvFbqZjQDmIHwb7WQSxadkiGRWfc +zVTnmiHjJONJJIpE2t+FOV3hc+8o98OzOtNaH2QQ9j6dnKvtIGKGFeNSDp0vXPOi +QhHiIyuB7eWx+g2whktQ74UCpGDSXYnEW3s8w5wezVWIEmouq7q4rCEkTNvJ7Ico +43AgUdPzAFS2zYktw1C+cbUALM8smvXbXrXOBzMmscjIhtXvLMrpPeh23VfdJfQB +0rN2BmRCLUE8JOV+o0k98XMm83oN+lGkL1l+hyoj3ok1uI3JrsWOcDyjOds3ptcN +KimJLm27ndjcxDNo/iA6gefMJuCxFRaqI+eF4P0jSkMgnnQqZkvLGFuHCw8eRDhm +bw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFGTCCAwGgAwIBAgIQJMM7ZIy2SYxCBgK7WcFwnjANBgkqhkiG9w0BAQ0FADAf +MR0wGwYDVQQDExRZYW5kZXhJbnRlcm5hbFJvb3RDQTAeFw0xMzAyMTExMzQxNDNa +Fw0zMzAyMTExMzUxNDJaMB8xHTAbBgNVBAMTFFlhbmRleEludGVybmFsUm9vdENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAgb4xoQjBQ7oEFk8EHVGy +1pDEmPWw0Wgw5nX9RM7LL2xQWyUuEq+Lf9Dgh+O725aZ9+SO2oEs47DHHt81/fne +5N6xOftRrCpy8hGtUR/A3bvjnQgjs+zdXvcO9cTuuzzPTFSts/iZATZsAruiepMx +SGj9S1fGwvYws/yiXWNoNBz4Tu1Tlp0g+5fp/ADjnxc6DqNk6w01mJRDbx+6rlBO +aIH2tQmJXDVoFdrhmBK9qOfjxWlIYGy83TnrvdXwi5mKTMtpEREMgyNLX75UjpvO +NkZgBvEXPQq+g91wBGsWIE2sYlguXiBniQgAJOyRuSdTxcJoG8tZkLDPRi5RouWY +gxXr13edn1TRDGco2hkdtSUBlajBMSvAq+H0hkslzWD/R+BXkn9dh0/DFnxVt4XU +5JbFyd/sKV/rF4Vygfw9ssh1ZIWdqkfZ2QXOZ2gH4AEeoN/9vEfUPwqPVzL0XEZK +r4s2WjU9mE5tHrVsQOZ80wnvYHYi2JHbl0hr5ghs4RIyJwx6LEEnj2tzMFec4f7o +dQeSsZpgRJmpvpAfRTxhIRjZBrKxnMytedAkUPguBQwjVCn7+EaKiJfpu42JG8Mm ++/dHi+Q9Tc+0tX5pKOIpQMlMxMHw8MfPmUjC3AAd9lsmCtuybYoeN2IRdbzzchJ8 +l1ZuoI3gH7pcIeElfVSqSBkCAwEAAaNRME8wCwYDVR0PBAQDAgGGMA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFKu5xf+h7+ZTHTM5IoTRdtQ3Ti1qMBAGCSsGAQQB +gjcVAQQDAgEAMA0GCSqGSIb3DQEBDQUAA4ICAQAVpyJ1qLjqRLC34F1UXkC3vxpO +nV6WgzpzA+DUNog4Y6RhTnh0Bsir+I+FTl0zFCm7JpT/3NP9VjfEitMkHehmHhQK +c7cIBZSF62K477OTvLz+9ku2O/bGTtYv9fAvR4BmzFfyPDoAKOjJSghD1p/7El+1 +eSjvcUBzLnBUtxO/iYXRNo7B3+1qo4F5Hz7rPRLI0UWW/0UAfVCO2fFtyF6C1iEY +/q0Ldbf3YIaMkf2WgGhnX9yH/8OiIij2r0LVNHS811apyycjep8y/NkG4q1Z9jEi +VEX3P6NEL8dWtXQlvlNGMcfDT3lmB+tS32CPEUwce/Ble646rukbERRwFfxXojpf +C6ium+LtJc7qnK6ygnYF4D6mz4H+3WaxJd1S1hGQxOb/3WVw63tZFnN62F6/nc5g +6T44Yb7ND6y3nVcygLpbQsws6HsjX65CoSjrrPn0YhKxNBscF7M7tLTW/5LK9uhk +yjRCkJ0YagpeLxfV1l1ZJZaTPZvY9+ylHnWHhzlq0FzcrooSSsp4i44DB2K7O2ID +87leymZkKUY6PMDa4GkDJx0dG4UXDhRETMf+NkYgtLJ+UIzMNskwVDcxO4kVL+Hi +Pj78bnC5yCw8P5YylR45LdxLzLO68unoXOyFz1etGXzszw8lJI9LNubYxk77mK8H +LpuQKbSbIERsmR+QqQ== +-----END CERTIFICATE----- diff --git a/homework/cli.py b/homework/cli.py new file mode 100644 index 0000000..1fab0f0 --- /dev/null +++ b/homework/cli.py @@ -0,0 +1,85 @@ +import click +from patient import Patient, PatientCollection +from connection_config import config +import mysql.connector + + +class GetAllOption(click.Option): + def __init__(self, *args, **kwargs): + self.save_other_options = kwargs.pop('save_other_options', True) + nargs = kwargs.pop('nargs', -1) + assert nargs == -1, 'nargs, if set, must be -1 not {}'.format(nargs) + super(GetAllOption, self).__init__(*args, **kwargs) + self._previous_parser_process = None + self._eat_all_parser = None + + def add_to_parser(self, parser, ctx): + def parser_process(value, state): + done = False + value = [value] + if self.save_other_options: + # grab everything up to the next option + while state.rargs and not done: + for prefix in self._eat_all_parser.prefixes: + if state.rargs[0].startswith(prefix): + done = True + if not done: + value.append(state.rargs.pop(0)) + else: + value += state.rargs + state.rargs[:] = [] + value = tuple(value) + self._previous_parser_process(value, state) + res = super(GetAllOption, self).add_to_parser(parser, ctx) + for name in self.opts: + our_parser = parser._long_opt.get(name) or parser._short_opt.get(name) + if our_parser: + self._eat_all_parser = our_parser + self._previous_parser_process = our_parser.process + our_parser.process = parser_process + break + return res + +@click.group() +def cli(): + pass + + +@cli.command('create') +@click.argument("first_name") +@click.argument("last_name") +@click.option('--birth-date', prompt='Birth date') +@click.option('--phone', cls=GetAllOption, prompt='Phone number') +@click.option('--document-type', cls=GetAllOption, + prompt='Document type (паспор/водительское удостоверение/заграничный паспорт)') +@click.option('--document-number', cls=GetAllOption, prompt='Document id') +def create(first_name, last_name, birth_date, phone, document_type, document_number): + try: + Patient(*[first_name, last_name, birth_date, ' '.join(phone), ' '.join(document_type), + ''.join(document_number)]).save() + except ValueError: + click.echo('Creation aborted, wrong data format') + else: + click.echo('Patient created') + + +@cli.command('show') +@click.argument('num', default=10, type=int) +def show(num): + click.echo(PatientCollection(num)) + + +@cli.command('count') +def count(): + res = len(PatientCollection()) + add = 's' if res > 1 or res == 0 else '' + click.echo(f'{res} patient{add} in the table') + + +cli.add_command(create) +cli.add_command(show) +cli.add_command(count) + + +if __name__ == '__main__': + cli() \ No newline at end of file diff --git a/homework/config.py b/homework/config.py index 955b991..093bc24 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 = "good_log.log" +ERROR_LOG_FILE = "error_log.log" +CSV_PATH = "data.csv" +PHONE_FORMAT = "9160000000" # Здесь запишите телефон +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_FORMAT = "000000000" # формат хранения заграна для номера 00 0000000 DRIVER_LICENSE_TYPE = "водительское удостоверение" # тип документа, если это водительское удостоверение -DRIVER_LICENSE_FORMAT = "00 00 000000" # формат хранения номера ВУ +DRIVER_LICENSE_FORMAT = "0000000000" # формат хранения номера ВУ diff --git a/homework/log.py b/homework/log.py new file mode 100644 index 0000000..c71ed3d --- /dev/null +++ b/homework/log.py @@ -0,0 +1,54 @@ +import logging + +# info_logger_setup +info_logger = logging.getLogger('Info_Logger') +info_logger.setLevel(logging.INFO) +fh_info = logging.FileHandler('good_log.log', encoding='utf-8') +fh_info.setLevel(logging.INFO) +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +fh_info.setFormatter(formatter) +info_logger.addHandler(fh_info) + +# error_logger_setup +error_logger = logging.getLogger('Error_Logger') +error_logger.setLevel(logging.ERROR) +fh_error = logging.FileHandler('error_log.log', encoding='utf-8') +fh_error.setLevel(logging.ERROR) +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +fh_error.setFormatter(formatter) +error_logger.addHandler(fh_error) + + +def set_logger(func): + def wrapper(self, instance, value): + new_value = value + try: + func(self, instance, value) + except TypeError: + instance.error_logger.error(f'{value} must be a string') + raise TypeError + except ValueError: + instance.error_logger.error(f'Wrong format : {value}') + raise ValueError + except AttributeError: + instance.error_logger.error(f'Try to set {self.name} of {instance}') + raise AttributeError + return wrapper + + +def save_logger(func): + def wrapper(self, *args, **kwargs): + try: + func(self, *args, **kwargs) + except FileExistsError: + self.error_logger.error(f'Raise FileExistsError in save() with {self}') + except FileNotFoundError: + self.error_logger.error(f'Raise FileNotFoundError in save() with {self}') + except IsADirectoryError: + self.error_logger.error(f'Raise IsADirectoryError in save() with {self}') + except PermissionError: + self.error_logger.error(f'Raise PermissionError in save() with {self}') + else: + self.info_logger.info(f'patient {self} was successfully added to file') + + return wrapper \ No newline at end of file diff --git a/homework/patient.py b/homework/patient.py index dad2526..bbb3a75 100644 --- a/homework/patient.py +++ b/homework/patient.py @@ -1,17 +1,164 @@ -class Patient: - def __init__(self, *args, **kwargs): +from itertools import islice +import vald_values as valid +import logging +from log import set_logger, save_logger +import mysql.connector +from connection_config import config + +csv_path = 'data.csv' + +class BasicDescriptor: + def __init__(self, name): + self.name = name + + def __get__(self, instance, owner): + return instance.__dict__[self.name] + + def __set__(self, instance, value): pass - def create(*args, **kwargs): - raise NotImplementedError() + @staticmethod + def check_type(val): + if not isinstance(val, str): + s = f'{val} must be a string not {type(val)}' + logging.getLogger('Error_Logger').error(s) + raise TypeError(s) + + +class ImmutableData(BasicDescriptor): + @set_logger + def __set__(self, instance, value): + self.check_type(value) + if self.name not in instance.__dict__: + if value.isalpha(): + instance.__dict__[self.name] = value + else: + s = f'{value} must be an alpha' + raise ValueError(s) + else: + s = 'Name changes are forbidden' + raise AttributeError(s) + + +class MutableData(BasicDescriptor): + def __init__(self, name): + super().__init__(name) + if self.name == 'phone': + self.validate = valid.valid_phone + elif self.name == 'birth_date': + self.validate = valid.valid_date + elif self.name == 'document_type': + self.validate = valid.valid_document_type + else: + self.validate = valid.valid_document + + @set_logger + def __set__(self, instance, value): + self.check_type(value) + new_val = self.validate(value) + if new_val: + if self.name in instance.__dict__: + logging.getLogger('Info_Logger').info(f'{self.name} set to {new_val}') + instance.__dict__[self.name] = new_val + else: + s = f'{value} invalid data format' + raise ValueError(s) + + +class DocDescriptor(BasicDescriptor): + @set_logger + def __set__(self, instance, value): + if self.name == "document_id": + self.check_type(value) + new_doc = valid.valid_document((instance.document_type, value)) + if new_doc: + if self.name in instance.__dict__: + logging.getLogger('Info_Logger').info(f'{self.name} set to {new_doc}') + instance.__dict__[self.name] = new_doc + else: + s = 'Invalid document id' + raise ValueError(s) + elif self.name == "document_type": + self.check_type(value) + new_type = valid.valid_document_type(value) + if new_type: + if self.name in instance.__dict__: + logging.getLogger('Info_Logger').info("Type was changed") + instance.__dict__[self.name] = value + else: + raise ValueError("Invalid document type") + +class Patient: + first_name = ImmutableData('first_name') + last_name = ImmutableData('last_name') + birth_date = MutableData('birth_date') + phone = MutableData('phone') + document_id = DocDescriptor('document_id') + document_type = DocDescriptor('document_type') + + def __init__(self, first_name, last_name, birth_date, phone, document_type, document_id): + self.info_logger = logging.getLogger('Info_Logger') + self.error_logger = logging.getLogger('Error_Logger') + 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.info_logger.info(f'{first_name} {last_name} patient created') + + @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) + + @save_logger def save(self): - pass + cnx = mysql.connector.connect(**config) + cur = cnx.cursor(buffered=True) + cur.execute('SELECT MAX(id) FROM covid LIMIT 1') + num = cur.fetchone()[0] + 1 if cur.fetchone()[0] else 0 + cur.execute('INSERT INTO covid (id, first_name, last_name, ' + 'birth_date, phone, document_type, document_id) VALUES(%s, %s, %s, %s, %s, %s, %s)', (num, + self.first_name, self.last_name, self.birth_date, self.phone, self.document_type, self.document_id)) + cnx.commit() + cur.close() + cnx.close() + + def __str__(self): + return ' '.join([self.first_name, self.last_name, self.phone, self.birth_date, + self.document_type, self.document_id]) + + def __repr__(self): + return self.__str__() class PatientCollection: - def __init__(self, log_file): - pass + def __init__(self, num=None): + cnx = mysql.connector.connect(**config) + cur = cnx.cursor(buffered=True) + if not num or num <= 0: + cur.execute('Select * FROM covid') + else: + cur.execute(f'SELECT * FROM covid LIMIT {num}') + self.data = [Patient(*human[1:]) for human in cur.fetchall()] + cur.close() + cnx.close() def limit(self, n): - raise NotImplementedError() + return islice(self, n) + + def __iter__(self): + cnx = mysql.connector.connect(**config) + cur = cnx.cursor(buffered=True) + cur.execute('SELECT * FROM covid') + for human in cur.fetchall(): + yield Patient(*human[1:]) + cur.close() + cnx.close() + + def __str__(self): + return '\n'.join([str(patient) for patient in self.data]) + + def __len__(self): + return len(self.data) diff --git a/homework/table_creation.py b/homework/table_creation.py new file mode 100644 index 0000000..eb229be --- /dev/null +++ b/homework/table_creation.py @@ -0,0 +1,18 @@ +import mysql.connector + +config = { + 'user': 'xxx', + 'password': 'xx', + 'database': 'xxx', + 'host': 'xxx.net', + 'port': '3306', + 'ssl_ca': '.mysql/root.crt', +} + +cnx = mysql.connector.connect(**config) +cur = cnx.cursor(buffered=True) +cur.execute('CREATE TABLE covid (id int(11), first_name varchar(128), last_name varchar(128), ' + 'birth_date varchar(64), phone varchar(64), document_type varchar(64), document_id varchar(64))') +cnx.commit() +cur.close() +cnx.close() \ No newline at end of file diff --git a/homework/vald_values.py b/homework/vald_values.py new file mode 100644 index 0000000..8cb0611 --- /dev/null +++ b/homework/vald_values.py @@ -0,0 +1,39 @@ +def valid_date(date): + import time + try: + time.strptime(date, '%Y-%m-%d') + res = '-' + except ValueError: + try: + time.strptime(date, '%Y.%m.%d') + res = '.' + except ValueError: + return None + return '-'.join(date.split(res)) + + +def valid_phone(phone): + res = phone.replace('+', '').replace('-', '').replace('(', '').replace(')', '').replace(' ', '') + if len(res) == 11 and res[0] in {'7', '8'}: + res = res[1:] + return res + if len(res) == 10: + return res + return None + + +def valid_document(document): + document_id = document[1].replace(' ', '').replace('-', '').replace('/', '') + if not document_id.isdigit(): + return None + if document[0] in {'водительское удостоверение', 'паспорт'} and len(document_id) == 10: + return document_id + if document[0] == 'заграничный паспорт' and len(document_id) == 9: + return document_id + return None + + +def valid_document_type(document_type): + if document_type in {'водительское удостоверение', 'паспорт', 'заграничный паспорт'}: + return document_type + return None diff --git a/tests/test_patient.py b/tests/test_patient.py index 125bd59..f811c96 100644 --- a/tests/test_patient.py +++ b/tests/test_patient.py @@ -31,15 +31,18 @@ def wrapper(*args, **kwargs): return deco -def setup(): +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(): +def teardown_module(__name__): for file in [GOOD_LOG_FILE, ERROR_LOG_FILE, CSV_PATH]: - os.remove(file) + try: + os.remove(file) + except: + print('Error access') @check_log_size("error") @@ -180,7 +183,7 @@ def test_wrong_type_assignment(patient, field, param): )) @check_log_size("error", increased=True) @check_log_size("good") -def test_wrong_type_assignment(patient, field, param): +def test_wrong_value_assignment(patient, field, param): try: setattr(patient, field, param) assert False, f"ValueError for {field} assignment not invoked" diff --git a/tests/test_patient_collection.py b/tests/test_patient_collection.py index d1036e5..9536eff 100644 --- a/tests/test_patient_collection.py +++ b/tests/test_patient_collection.py @@ -7,17 +7,17 @@ from tests.constants import PATIENT_FIELDS GOOD_PARAMS = ( - ("Кондрат", "Рюрик", "1971-01-31", "79160000000", PASSPORT_TYPE, "0228 000000"), - ("Евпатий", "Коловрат", "1972-01-31", "79160000001", PASSPORT_TYPE, "0228 000001"), + ("Кондрат", "Рюрик", "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-31", "79160000003", PASSPORT_TYPE, "0228 000003"), - ("Евлампия", "Фамилия", "1999-01-31", "79160000004", PASSPORT_TYPE, "0228 000004"), - ("Кузя", "Кузьмин", "2000-01-31", "79160000005", PASSPORT_TYPE, "0228 000005"), - ("Гарри", "Поттер", "2020-01-31", "79160000006", PASSPORT_TYPE, "0228 000006"), - ("Рон", "Уизли", "1900-04-31", "79160000007", PASSPORT_TYPE, "0228 000007"), + ("Миртл", "Плакса", "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-31", "79160000010", PASSPORT_TYPE, "0228 000010"), + ("Вован", "ДеМорт", "1978-11-30", "79160000010", PASSPORT_TYPE, "0228 000010"), ("Гопник", "Районный", "1978-01-25", "79160000011", PASSPORT_TYPE, "0228 000011"), ("Фёдор", "Достоевский", "1978-01-05", "79160000012", PASSPORT_TYPE, "0228 000012"), )