From 4cbb69181c4ebbf24fadc1b993b03c80235cbca7 Mon Sep 17 00:00:00 2001 From: babaev-an Date: Sat, 4 Oct 2025 18:22:18 +0300 Subject: [PATCH] 20251004-1 --- .../enums/not_bool_action.py | 11 +- .../exceptions/wrong_type_exception.py | 6 +- .../extensions/array_extension.py | 15 +- .../extensions/bool_extension.py | 33 +++-- .../extensions/guid_extension.py | 89 ++++++------ .../extensions/string_extension.py | 105 +++++++------- .../extensions/string_extension_constant.py | 136 +++++++++--------- .../extensions/type_extension.py | 28 ++-- anb_python_components/types/__init__.py | 1 + .../{classes => types}/guid.py | 60 ++++---- 10 files changed, 247 insertions(+), 237 deletions(-) create mode 100644 anb_python_components/types/__init__.py rename anb_python_components/{classes => types}/guid.py (63%) diff --git a/anb_python_components/enums/not_bool_action.py b/anb_python_components/enums/not_bool_action.py index 42446be..4cda43c 100644 --- a/anb_python_components/enums/not_bool_action.py +++ b/anb_python_components/enums/not_bool_action.py @@ -2,7 +2,6 @@ from enum import Enum - class NotBoolAction(Enum): """ Перечисление типов действий, которые необходимо выполнить, если переменная не является булевым типом. @@ -11,15 +10,15 @@ class NotBoolAction(Enum): - IT_FALSE: Считать это утверждение ложным. - RAISE: Вызвать исключение. """ - + # Игнорировать это утверждение. IGNORE = 0 - + # Считать это утверждение истинным. IT_TRUE = 1 - + # Считать это утверждение ложным. IT_FALSE = 2 - + # Вызвать исключение - RAISE = 3 + RAISE = 3 \ No newline at end of file diff --git a/anb_python_components/exceptions/wrong_type_exception.py b/anb_python_components/exceptions/wrong_type_exception.py index fca3dc9..bb73b15 100644 --- a/anb_python_components/exceptions/wrong_type_exception.py +++ b/anb_python_components/exceptions/wrong_type_exception.py @@ -4,8 +4,8 @@ class WrongTypeException(Exception): """ Ошибка, возникающая при попытке присвоить значение другого типа данным полям. """ - - def __init__(self, message: str = None, type_name: str = None, real_type_name: str = None, var_name: str = None): + + def __init__ (self, message: str = None, type_name: str = None, real_type_name: str = None, var_name: str = None): """ Инициализация экземпляра класса WrongTypeException. :param message: Сообщение об ошибке. @@ -17,4 +17,4 @@ class WrongTypeException(Exception): self.message = message self.type_name = type_name, self.real_type_name = real_type_name, - self.var_name = var_name + self.var_name = var_name \ No newline at end of file diff --git a/anb_python_components/extensions/array_extension.py b/anb_python_components/extensions/array_extension.py index 482aff7..fb5f9d9 100644 --- a/anb_python_components/extensions/array_extension.py +++ b/anb_python_components/extensions/array_extension.py @@ -2,20 +2,19 @@ from anb_python_components.extensions.string_extension import StringExtension - class ArrayExtension: """ Класс расширения для работы с массивами. """ - - def __init__(self): + + def __init__ (self): """ Инициализация расширения. """ pass - + @staticmethod - def remove_empties(array: list[str], re_sort: bool = False) -> list[str]: + def remove_empties (array: list[str], re_sort: bool = False) -> list[str]: """ Удаляет пустые строки из массива. @@ -25,11 +24,11 @@ class ArrayExtension: """ # Удаляем пустые строки result = list(filter(lambda x: not StringExtension.is_none_or_whitespace(x), array)) - + # Если нужно пересортировать массив if re_sort: # - сортируем массив result.sort() - + # Возвращаем результат - return result + return result \ No newline at end of file diff --git a/anb_python_components/extensions/bool_extension.py b/anb_python_components/extensions/bool_extension.py index 9d26b44..caf5506 100644 --- a/anb_python_components/extensions/bool_extension.py +++ b/anb_python_components/extensions/bool_extension.py @@ -2,20 +2,19 @@ from anb_python_components.enums.not_bool_action import NotBoolAction - class BoolExtension: """ Расширение типа "правда/ложь". """ - - def __init__(self): + + def __init__ (self): """ Инициализация расширения. """ pass - + @staticmethod - def to_str(b: bool, if_true: str = "True", if_false: str = "False") -> str: + def to_str (b: bool, if_true: str = "True", if_false: str = "False") -> str: """ Конвертирует булево значение в строку. :param b: Булево значение. @@ -24,9 +23,9 @@ class BoolExtension: :return: Строка, соответствующая булевому значению. """ return if_true if b else if_false - + @staticmethod - def true_count(expressions: list[bool], if_not_bool: NotBoolAction = NotBoolAction.IGNORE) -> int: + def true_count (expressions: list[bool], if_not_bool: NotBoolAction = NotBoolAction.IGNORE) -> int: """ Возвращает количество истинных значений в списке аргументов. :param expressions: Список аргументов. @@ -35,7 +34,7 @@ class BoolExtension: """ # Создаем пустой массив для хранения проверяемых аргументов check_array = [] - + # Проверяем все входящие аргументы for expression in expressions: # - если аргумент не является типом правда/ложь @@ -45,21 +44,21 @@ class BoolExtension: case NotBoolAction.IGNORE: # - игнорируем аргумент и продолжаем цикл continue - + # -- если указано действие при не булевом значении - считать как истинное значение case NotBoolAction.IT_TRUE: # --- добавляем True в массив проверяемых аргументов check_array.append(True) # --- и продолжаем цикл continue - + # -- если указано действие при не булевом значении - считать как ложное значение case NotBoolAction.IT_FALSE: # --- добавляем False в массив проверяемых аргументов check_array.append(False) # --- и продолжаем цикл continue - + # -- если указано действие при не булевом значении - выбросить исключение case NotBoolAction.RAISE: # --- то вызываем исключение @@ -67,15 +66,15 @@ class BoolExtension: else: # - иначе добавляем аргумент в массив проверяемых аргументов check_array.append(expression) - + # Используем фильтрацию массива для получения массива только истинных значений filtered = [value for value in check_array if value] - + # Возвращаем количество истинных значений в отфильтрованном массиве return len(filtered) - + @staticmethod - def any_true(expressions: list[bool]) -> bool: + def any_true (expressions: list[bool]) -> bool: """ Проверяет, есть ли хотя бы один истинный аргумент. :param expressions: Выражения. @@ -83,6 +82,6 @@ class BoolExtension: """ # Получаем количество истинных значений true_count = BoolExtension.true_count(expressions, NotBoolAction.IGNORE) - + # Если количество истинных значений больше нуля, возвращаем True, иначе False - return True if true_count > 0 else False + return True if true_count > 0 else False \ No newline at end of file diff --git a/anb_python_components/extensions/guid_extension.py b/anb_python_components/extensions/guid_extension.py index 0aed92b..42bf0e3 100644 --- a/anb_python_components/extensions/guid_extension.py +++ b/anb_python_components/extensions/guid_extension.py @@ -1,23 +1,22 @@ # anb_python_components/extensions/guid_extension.py import secrets -from anb_python_components.classes.guid import GUID, GUID_EMPTY from anb_python_components.exceptions.wrong_type_exception import WrongTypeException - +from anb_python_components.types.guid import GUID class GUIDExtension: """ Класс GUIDExtension реализует расширение для работы с GUID. """ - - def __init__(self): + + def __init__ (self): """ Инициализация расширения. """ pass - + @staticmethod - def generate() -> GUID: + def generate () -> GUID: """ Генерирует уникальный идентификатор GUID согласно стандарту RFC 4122. """ @@ -27,56 +26,58 @@ class GUIDExtension: time_hi_and_version = ((secrets.randbits(12) << 4) | 0x4000) & 0xffff clock_seq_hi_and_reserved = ((secrets.randbits(14) << 2) | 0x8000) & 0xffff node_id = secrets.randbits(48) & 0xffffffffffff - + # Объединение компонентов в единый GUID guid_parts = [ - time_low >> 16, time_low & 0xffff, - time_mid, - time_hi_and_version, - clock_seq_hi_and_reserved, - node_id >> 32, (node_id >> 16) & 0xffff, node_id & 0xffff - ] - + time_low >> 16, time_low & 0xffff, + time_mid, + time_hi_and_version, + clock_seq_hi_and_reserved, + node_id >> 32, (node_id >> 16) & 0xffff, node_id & 0xffff + ] + # Форматируем компоненты в виде строки GUID - guid_str = "-".join([ - "%08x" % guid_parts[0], - "%04x" % guid_parts[1], - "%04x" % guid_parts[2], - "%04x" % guid_parts[3], - ("%04x%04x%04x" % tuple(guid_parts[4:])), - ]) - + guid_str = "-".join( + [ + "%08x" % guid_parts[0], + "%04x" % guid_parts[1], + "%04x" % guid_parts[2], + "%04x" % guid_parts[3], + ("%04x%04x%04x" % tuple(guid_parts[4:])), + ] + ) + # Возвращаем экземпляр GUID return GUID(guid_str) - + @staticmethod - def is_equal(guid1: str | GUID, guid2: str | GUID) -> bool: - + def is_equal (guid1: str | GUID, guid2: str | GUID) -> bool: + # Если guid1 не является GUID или строкой if not isinstance(guid1, GUID) or not isinstance(guid1, str): # - генерируем исключение - raise WrongTypeException("Неверный тип аргумента!", "GUID|str", var_name="guid1") - + raise WrongTypeException("Неверный тип аргумента!", "GUID|str", var_name = "guid1") + # Если guid2 не является GUID или строкой if not isinstance(guid2, GUID) or not isinstance(guid2, str): # - генерируем исключение - raise WrongTypeException("Неверный тип аргумента!", "GUID|str", var_name="guid2") - + raise WrongTypeException("Неверный тип аргумента!", "GUID|str", var_name = "guid2") + # Если guid1 является строкой if not isinstance(guid1, GUID): # - преобразуем её в GUID guid1 = GUID(guid1) - + # Если guid2 является строкой if not isinstance(guid2, GUID): # - преобразуем её в GUID guid2 = GUID(guid2) - + # Сравниваем GUID return guid1 == guid2 - + @staticmethod - def validate(guid: str | GUID) -> bool: + def validate (guid: str | GUID) -> bool: """ Проверка GUID на валидность. :param guid: GUID для проверки. @@ -84,12 +85,12 @@ class GUIDExtension: """ # Если guid не является строкой, то преобразуем его в неё guid = guid if isinstance(guid, str) else str(guid) - + # Проверяем GUID return bool(GUID.validate_str(guid)) - + @staticmethod - def is_invalid_or_empty(guid: str | GUID) -> bool: + def is_invalid_or_empty (guid: str | GUID) -> bool: """ Проверка GUID на валидность и не пустоту. :param guid: Класс или строка GUID для проверки. @@ -97,27 +98,27 @@ class GUIDExtension: """ # Если guid не является строкой, то преобразуем его в неё guid = guid if isinstance(guid, str) else str(guid) - + # Проверяем GUID - return not GUID.validate_str(guid) or guid == GUID_EMPTY - + return not GUID.validate_str(guid) or GUID(guid) == GUID(GUID.EMPTY) + @classmethod - def parse(cls, guid_string: str, empty_if_not_valid: bool = True) -> GUID: + def parse (cls, guid_string: str, empty_if_not_valid: bool = True) -> GUID: """ Парсинг GUID из строки. :param guid_string: Строка GUID. :param empty_if_not_valid: Если True, то возвращается пустой GUID, если GUID недействителен. """ - + # Проверяем строку на соответствие формату GUID if cls.validate(guid_string): # - если GUID действителен, возвращаем экземпляр GUID return GUID(guid_string) - + # Если же GUID недействителен и запрещено выбрасывать исключение if empty_if_not_valid: # -- то возвращаем пустой GUID - return GUID(GUID_EMPTY) + return GUID(GUID.EMPTY) else: # -- иначе выбрасываем исключение - raise WrongTypeException('Предан неверный GUID / Wrong GUID.') + raise WrongTypeException('Предан неверный GUID / Wrong GUID.') \ No newline at end of file diff --git a/anb_python_components/extensions/string_extension.py b/anb_python_components/extensions/string_extension.py index c04289b..dffea4b 100644 --- a/anb_python_components/extensions/string_extension.py +++ b/anb_python_components/extensions/string_extension.py @@ -3,58 +3,57 @@ import re from .string_extension_constant import StringExtensionConstants - class StringExtension: """ Расширение строк. """ - - def __init__(self): + + def __init__ (self): """ Конструктор. """ pass - + @staticmethod - def is_none_or_empty(text: str | None) -> bool: + def is_none_or_empty (text: str | None) -> bool: """ Проверяет, пуста ли строка. :param text: Проверяемая строка. :return: Результат проверки. """ return text is None or text == "" - + @classmethod - def is_none_or_whitespace(cls, text: str | None) -> bool: + def is_none_or_whitespace (cls, text: str | None) -> bool: """ Проверяет, пуста ли строка, содержит ли вместо текста только пробелы. :param text: Проверяемая строка. :return: Bool Результат проверки. """ return cls.is_none_or_empty(text) or text.strip() == '' - + @staticmethod - def is_russian_letter(letter: str) -> bool: + def is_russian_letter (letter: str) -> bool: """ Проверяет, является ли символ русским буквой. :param letter: Проверяемый символ. :return: Результат проверки. """ - + return letter in StringExtensionConstants.russian_letters - + @staticmethod - def get_russian_letter_transliteration(letter: str) -> bool | None: + def get_russian_letter_transliteration (letter: str) -> bool | None: """ Получаю транслитерированную букву русского алфавита. :param letter: Буква русского алфавита. :return: Транслитерированная буква. """ - + try: # Получаю транслитерированную букву transliteration = StringExtensionConstants.russian_letters[letter] - + # Если не удалось получить транслитерированную букву if transliteration is None: # - то возбуждаю исключение @@ -62,12 +61,12 @@ class StringExtension: except KeyError: # Если возбуждено исключение, то возвращаю None return None - + # Возвращаю транслитерированную букву return transliteration - + @classmethod - def convert_to_latin(cls, source: str) -> str: + def convert_to_latin (cls, source: str) -> str: """ Конвертация в латиницу. :param source: Исходная строка. @@ -75,13 +74,13 @@ class StringExtension: """ # Создаю результат result = "" - + # Получаю длину строкиДля каждой буквы или символа из слова for i, letter in enumerate(source): if cls.is_russian_letter(letter): # - транслитерирую эту букву result_transliteration = cls.get_russian_letter_transliteration(letter) - + # - если транслитерация не удалась if result_transliteration is None: # -- вывожу оригинальную букву @@ -92,12 +91,12 @@ class StringExtension: else: # - иначе вывожу букву или символ result += letter - + # Вывожу результат return result - + @classmethod - def compare(cls, str1: str | None, str2: str | None, ignore_case: bool = False) -> int: + def compare (cls, str1: str | None, str2: str | None, ignore_case: bool = False) -> int: """ Сравнивает две строки. :param str1: Первая строка. @@ -112,37 +111,37 @@ class StringExtension: if cls.is_none_or_whitespace(str1) and cls.is_none_or_whitespace(str2): # - то считаем их равными return 0 - + # Если первый из них не пуст, а второй пуст if not cls.is_none_or_whitespace(str1) and cls.is_none_or_whitespace(str2): # - то первый больше return 1 - + # Если первый из них пуст, а второй не пуст if cls.is_none_or_whitespace(str1) and not cls.is_none_or_whitespace(str2): # - то первый меньше return -1 - + # Если не нужно учитывать регистр # - преобразую (или нет) первую строку compare_str_1 = str1 if not ignore_case else str1.lower() # - преобразую (или нет) вторую строку compare_str_2 = str2 if not ignore_case else str2.lower() - + # Проверяю равенство if compare_str_1 == compare_str_2: # - и если равны, то возвращаю 0 return 0 - + # Они не равны, поэтому получим длину первого слова и второго len1 = len(compare_str_1) len2 = len(compare_str_2) - + # Если длина первого больше и равна второго, то верну 1, иначе -1 return 1 if len1 >= len2 else -1 - + @staticmethod - def get_short_text(text: str, max_length: int, end_symbols: str = '') -> str: + def get_short_text (text: str, max_length: int, end_symbols: str = '') -> str: """ Обрезает строку до указанных в параметре max_length символов. :param text: Исходный текст. @@ -154,15 +153,15 @@ class StringExtension: if len(text) <= max_length: # - то возвращаем сам текст return text - + # Если длина текста больше максимальной, то получаю длину текста без суффикса len_no_end_symbols = max_length - len(end_symbols) - + # Возвращаю обрезанный текст return text[:len_no_end_symbols] + end_symbols - + @staticmethod - def to_utf8(subject: str, encoding: str = 'UTF-8') -> str: + def to_utf8 (subject: str, encoding: str = 'UTF-8') -> str: """ Перекодирует строку в UTF-8. :param subject: Исходная строка. @@ -173,21 +172,21 @@ class StringExtension: if encoding == 'UTF-8': # - то возвращаю исходную строку return subject - + # Получаем байты оригинальной строки bytes_original = subject.encode(encoding) - + # Преобразовываем в Unicode (используя указанную кодировку) unicode_string = bytes_original.decode(encoding) - + # Кодируем в UTF-8 utf8_bytes = unicode_string.encode('UTF-8') - + # Возвращаем результат return utf8_bytes.decode('UTF-8') - + @staticmethod - def from_utf8(subject: str, to_encoding: str = 'UTF-8') -> str: + def from_utf8 (subject: str, to_encoding: str = 'UTF-8') -> str: """ Перекодирует строку из UTF-8. :param subject: Исходная строка. @@ -198,15 +197,15 @@ class StringExtension: if to_encoding == 'UTF-8': # - то возвращаю исходную строку return subject - + # Получаю байты строки target_bytes = subject.encode('UTF-8') - + # Преобразовываю в нужную кодировку и возвращаю результат return str(target_bytes.decode('UTF-8').encode(to_encoding)) - + @classmethod - def replace(cls, subject: str, search: str, replace: str, encoding: str = 'UTF-8') -> str: + def replace (cls, subject: str, search: str, replace: str, encoding: str = 'UTF-8') -> str: """ Заменяет в строке все вхождения строки поиска на строку замены. :param subject: Исходная строка. @@ -223,23 +222,23 @@ class StringExtension: replace = cls.to_utf8(replace, encoding) # - и перекодируем исходную строку в UTF-8 subject = cls.to_utf8(subject, encoding) - + # Используем re.escape для экранирования спецсимволов pattern = re.escape(search) - + # Замена всех вхождений search на replace result = re.sub(pattern, replace, subject) - + # Если кодировка не UTF-8 if encoding != 'UTF-8': # - то перекодируем результат в нужную кодировку result = cls.from_utf8(result, encoding) - + # Возвращаем результат return result - + @classmethod - def replace_all(cls, search_replace: dict[str, str], subject: str, encoding: str = 'UTF-8') -> str: + def replace_all (cls, search_replace: dict[str, str], subject: str, encoding: str = 'UTF-8') -> str: """ Заменяет в строке все вхождения строки поиска на строку замены. :param search_replace: Словарь с парами поиска и замены. Например, {'-': '#', '$': '%'} @@ -250,11 +249,11 @@ class StringExtension: """ # Создаю результат result = subject - + # Для каждой пары поиска и замены for search, replace in search_replace.items(): # - заменяю все вхождения строки поиска на строку замены в заданной строке result = cls.replace(result, search, replace, encoding) - + # Возвращаю результат - return result + return result \ No newline at end of file diff --git a/anb_python_components/extensions/string_extension_constant.py b/anb_python_components/extensions/string_extension_constant.py index 630f491..049f322 100644 --- a/anb_python_components/extensions/string_extension_constant.py +++ b/anb_python_components/extensions/string_extension_constant.py @@ -8,73 +8,73 @@ class StringExtensionConstants: Attributes: russian_letters (dict): Словарь соответствия русских букв в транслитерации. """ - + # Словарь соответствия русских букв в транслитерации russian_letters = { - 'а': 'a', - 'б': 'b', - 'в': 'v', - 'г': 'g', - 'д': 'd', - 'е': 'e', - 'ё': 'yo', - 'ж': 'zh', - 'з': 'z', - 'и': 'i', - 'й': 'j', - 'к': 'k', - 'л': 'l', - 'м': 'm', - 'н': 'n', - 'о': 'o', - 'п': 'p', - 'р': 'r', - 'с': 's', - 'т': 't', - 'у': 'u', - 'ф': 'f', - 'х': 'h', - 'ц': 'c', - 'ч': 'ch', - 'ш': 'sh', - 'щ': 'sch', - 'ъ': 'j', - 'ы': 'i', - 'ь': 'j', - 'э': 'e', - 'ю': 'yu', - 'я': 'ya', - 'А': 'A', - 'Б': 'B', - 'В': 'V', - 'Г': 'G', - 'Д': 'D', - 'Е': 'E', - 'Ё': 'Yo', - 'Ж': 'Zh', - 'З': 'Z', - 'И': 'I', - 'Й': 'J', - 'К': 'K', - 'Л': 'L', - 'М': 'M', - 'Н': 'N', - 'О': 'O', - 'П': 'P', - 'Р': 'R', - 'С': 'S', - 'Т': 'T', - 'У': 'U', - 'Ф': 'F', - 'Х': 'H', - 'Ц': 'C', - 'Ч': 'Ch', - 'Ш': 'Sh', - 'Щ': 'Sch', - 'Ъ': 'J', - 'Ы': 'I', - 'Ь': 'J', - 'Э': 'E', - 'Ю': 'Yu', - 'Я': 'Ya' - } + 'а': 'a', + 'б': 'b', + 'в': 'v', + 'г': 'g', + 'д': 'd', + 'е': 'e', + 'ё': 'yo', + 'ж': 'zh', + 'з': 'z', + 'и': 'i', + 'й': 'j', + 'к': 'k', + 'л': 'l', + 'м': 'm', + 'н': 'n', + 'о': 'o', + 'п': 'p', + 'р': 'r', + 'с': 's', + 'т': 't', + 'у': 'u', + 'ф': 'f', + 'х': 'h', + 'ц': 'c', + 'ч': 'ch', + 'ш': 'sh', + 'щ': 'sch', + 'ъ': 'j', + 'ы': 'i', + 'ь': 'j', + 'э': 'e', + 'ю': 'yu', + 'я': 'ya', + 'А': 'A', + 'Б': 'B', + 'В': 'V', + 'Г': 'G', + 'Д': 'D', + 'Е': 'E', + 'Ё': 'Yo', + 'Ж': 'Zh', + 'З': 'Z', + 'И': 'I', + 'Й': 'J', + 'К': 'K', + 'Л': 'L', + 'М': 'M', + 'Н': 'N', + 'О': 'O', + 'П': 'P', + 'Р': 'R', + 'С': 'S', + 'Т': 'T', + 'У': 'U', + 'Ф': 'F', + 'Х': 'H', + 'Ц': 'C', + 'Ч': 'Ch', + 'Ш': 'Sh', + 'Щ': 'Sch', + 'Ъ': 'J', + 'Ы': 'I', + 'Ь': 'J', + 'Э': 'E', + 'Ю': 'Yu', + 'Я': 'Ya' + } \ No newline at end of file diff --git a/anb_python_components/extensions/type_extension.py b/anb_python_components/extensions/type_extension.py index e32f061..a2594e3 100644 --- a/anb_python_components/extensions/type_extension.py +++ b/anb_python_components/extensions/type_extension.py @@ -3,21 +3,20 @@ import datetime from typing import Any - # Базовая структура для представления расширенного типа class TypeExtension: """ Класс для расширения типов. """ - - def __init__(self): + + def __init__ (self): """ Инициализирует экземпляр класса. """ pass - + @staticmethod - def to_dict(instance: Any) -> dict[str, Any]: + def to_dict (instance: Any) -> dict[str, Any]: """ Преобразует экземпляр объекта в словарь. @@ -26,7 +25,7 @@ class TypeExtension: """ # Создаём словарь result = {} - + # Перебираем поля экземпляра for key, value in vars(instance).items(): # - если значение является экземпляром datetime, преобразуем его в timestamp @@ -38,12 +37,12 @@ class TypeExtension: # - иначе просто добавляем значение else: result[key] = value - + # Возвращаем словарь return result - + @staticmethod - def from_dict(data: dict, cls=None) -> Any: + def from_dict (data: dict, cls = None) -> Any: """ Восстанавливает объект из словаря. @@ -51,15 +50,16 @@ class TypeExtension: :param cls: Класс для восстановления объекта (необязательный параметр, равный None по умолчанию). :return: Восстановленный объект. """ - + # Проверяем, что класс указан и является типом if cls is None or not isinstance(cls, type): # - если класс не указан, бросаем исключение raise TypeError('Класс для восстановления не указан.') - + # Создаём объект класса + # noinspection PyArgumentList obj = cls.__new__(cls) - + # Перебираем поля словаря for key, value in data.items(): # - если значение является словарем, вызываем рекурсивно функцию from_dict и устанавливаем результат в поле объекта @@ -70,6 +70,6 @@ class TypeExtension: setattr(obj, key, TypeExtension.from_dict(value, nested_cls)) else: setattr(obj, key, value) - + # Возвращаем восстановленный объект - return obj + return obj \ No newline at end of file diff --git a/anb_python_components/types/__init__.py b/anb_python_components/types/__init__.py new file mode 100644 index 0000000..98a58bd --- /dev/null +++ b/anb_python_components/types/__init__.py @@ -0,0 +1 @@ +# anb_python_components/types/__init__.py \ No newline at end of file diff --git a/anb_python_components/classes/guid.py b/anb_python_components/types/guid.py similarity index 63% rename from anb_python_components/classes/guid.py rename to anb_python_components/types/guid.py index ea257d0..bf63a82 100644 --- a/anb_python_components/classes/guid.py +++ b/anb_python_components/types/guid.py @@ -1,66 +1,78 @@ -# anb_python_components/classes/guid.py +# anb_python_components/types/guid.py import re from anb_python_components.exceptions.wrong_type_exception import WrongTypeException -# Константа пустого GUID -GUID_EMPTY: str = "00000000-0000-0000-0000-000000000000" - - class GUID: - - def __init__(self, guid: str = GUID_EMPTY): + """ + Тип GUID. + """ + + # Константа пустого GUID + EMPTY: str = "00000000-0000-0000-0000-000000000000" + + def __init__ (self, guid = EMPTY): """ Инициализация расширения. - :param guid: Передаваемый GUID + :param guid: str | GUID - Передаваемый GUID """ - + # Проверка типа аргумента guid + # - если аргумент не является строкой + if not isinstance(guid, str): + # -- если аргумент является экземпляром GUID + if isinstance(guid, GUID): + # - преобразуем его в строку + guid = str(guid) + else: + # -- иначе генерируем исключение + raise WrongTypeException("Неверный тип аргумента!", "GUID", str(type(guid)), "guid") + # Проверка GUID на валидность if not self.validate_str(guid): # и если GUID невалидный, то генерируем исключение raise WrongTypeException("Неверный формат GUID!", "GUID", guid, "guid") - + # Инициализируем приватный атрибут __value (текстовое представление хранящегося GUID) self.__value = guid - - def __str__(self): + + def __str__ (self): """ Переопределение метода __str__. :return: Текстовое представление GUID. """ - return self.__value if self.__value else GUID_EMPTY - - def __eq__(self, other): + return self.__value if self.__value else self.EMPTY + + def __eq__ (self, other): """ Переопределение метода __eq__. :param other: Объект для сравнения. :return: True, если GUID равны, иначе False. """ - + # Если аргумент не является экземпляром GUID if not isinstance(other, GUID): # - генерируем исключение raise WrongTypeException("Неверный тип аргумента!", "GUID", type(other), "other") - + # Преобразование второго аргумента в строку other_str = str(other) - + # Сравниваем строки return self.__value == other_str - + @staticmethod - def validate_str(guid: str | None) -> bool: + def validate_str (guid: str | None) -> bool: """ Проверка строки на валидность GUID. :return: True, если GUID валидный, иначе False. """ - + # Проверка на пустоту if not guid: return False - + # Регулярное выражение для проверки формата GUID pattern = r'^[0-9A-Fa-f]{8}-([0-9A-Fa-f]{4}-){3}[0-9A-Fa-f]{12}$' - + # Проверка на соответствие формату - return bool(re.fullmatch(pattern, guid)) + return bool(re.fullmatch(pattern, guid)) \ No newline at end of file