20251004-1

This commit is contained in:
2025-10-04 18:22:18 +03:00
parent 2d0a800598
commit 4cbb69181c
10 changed files with 247 additions and 237 deletions

View File

@@ -2,7 +2,6 @@
from enum import Enum from enum import Enum
class NotBoolAction(Enum): class NotBoolAction(Enum):
""" """
Перечисление типов действий, которые необходимо выполнить, если переменная не является булевым типом. Перечисление типов действий, которые необходимо выполнить, если переменная не является булевым типом.
@@ -11,15 +10,15 @@ class NotBoolAction(Enum):
- IT_FALSE: Считать это утверждение ложным. - IT_FALSE: Считать это утверждение ложным.
- RAISE: Вызвать исключение. - RAISE: Вызвать исключение.
""" """
# Игнорировать это утверждение. # Игнорировать это утверждение.
IGNORE = 0 IGNORE = 0
# Считать это утверждение истинным. # Считать это утверждение истинным.
IT_TRUE = 1 IT_TRUE = 1
# Считать это утверждение ложным. # Считать это утверждение ложным.
IT_FALSE = 2 IT_FALSE = 2
# Вызвать исключение # Вызвать исключение
RAISE = 3 RAISE = 3

View File

@@ -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. Инициализация экземпляра класса WrongTypeException.
:param message: Сообщение об ошибке. :param message: Сообщение об ошибке.
@@ -17,4 +17,4 @@ class WrongTypeException(Exception):
self.message = message self.message = message
self.type_name = type_name, self.type_name = type_name,
self.real_type_name = real_type_name, self.real_type_name = real_type_name,
self.var_name = var_name self.var_name = var_name

View File

@@ -2,20 +2,19 @@
from anb_python_components.extensions.string_extension import StringExtension from anb_python_components.extensions.string_extension import StringExtension
class ArrayExtension: class ArrayExtension:
""" """
Класс расширения для работы с массивами. Класс расширения для работы с массивами.
""" """
def __init__(self): def __init__ (self):
""" """
Инициализация расширения. Инициализация расширения.
""" """
pass pass
@staticmethod @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)) result = list(filter(lambda x: not StringExtension.is_none_or_whitespace(x), array))
# Если нужно пересортировать массив # Если нужно пересортировать массив
if re_sort: if re_sort:
# - сортируем массив # - сортируем массив
result.sort() result.sort()
# Возвращаем результат # Возвращаем результат
return result return result

View File

@@ -2,20 +2,19 @@
from anb_python_components.enums.not_bool_action import NotBoolAction from anb_python_components.enums.not_bool_action import NotBoolAction
class BoolExtension: class BoolExtension:
""" """
Расширение типа "правда/ложь". Расширение типа "правда/ложь".
""" """
def __init__(self): def __init__ (self):
""" """
Инициализация расширения. Инициализация расширения.
""" """
pass pass
@staticmethod @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: Булево значение. :param b: Булево значение.
@@ -24,9 +23,9 @@ class BoolExtension:
:return: Строка, соответствующая булевому значению. :return: Строка, соответствующая булевому значению.
""" """
return if_true if b else if_false return if_true if b else if_false
@staticmethod @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: Список аргументов. :param expressions: Список аргументов.
@@ -35,7 +34,7 @@ class BoolExtension:
""" """
# Создаем пустой массив для хранения проверяемых аргументов # Создаем пустой массив для хранения проверяемых аргументов
check_array = [] check_array = []
# Проверяем все входящие аргументы # Проверяем все входящие аргументы
for expression in expressions: for expression in expressions:
# - если аргумент не является типом правда/ложь # - если аргумент не является типом правда/ложь
@@ -45,21 +44,21 @@ class BoolExtension:
case NotBoolAction.IGNORE: case NotBoolAction.IGNORE:
# - игнорируем аргумент и продолжаем цикл # - игнорируем аргумент и продолжаем цикл
continue continue
# -- если указано действие при не булевом значении - считать как истинное значение # -- если указано действие при не булевом значении - считать как истинное значение
case NotBoolAction.IT_TRUE: case NotBoolAction.IT_TRUE:
# --- добавляем True в массив проверяемых аргументов # --- добавляем True в массив проверяемых аргументов
check_array.append(True) check_array.append(True)
# --- и продолжаем цикл # --- и продолжаем цикл
continue continue
# -- если указано действие при не булевом значении - считать как ложное значение # -- если указано действие при не булевом значении - считать как ложное значение
case NotBoolAction.IT_FALSE: case NotBoolAction.IT_FALSE:
# --- добавляем False в массив проверяемых аргументов # --- добавляем False в массив проверяемых аргументов
check_array.append(False) check_array.append(False)
# --- и продолжаем цикл # --- и продолжаем цикл
continue continue
# -- если указано действие при не булевом значении - выбросить исключение # -- если указано действие при не булевом значении - выбросить исключение
case NotBoolAction.RAISE: case NotBoolAction.RAISE:
# --- то вызываем исключение # --- то вызываем исключение
@@ -67,15 +66,15 @@ class BoolExtension:
else: else:
# - иначе добавляем аргумент в массив проверяемых аргументов # - иначе добавляем аргумент в массив проверяемых аргументов
check_array.append(expression) check_array.append(expression)
# Используем фильтрацию массива для получения массива только истинных значений # Используем фильтрацию массива для получения массива только истинных значений
filtered = [value for value in check_array if value] filtered = [value for value in check_array if value]
# Возвращаем количество истинных значений в отфильтрованном массиве # Возвращаем количество истинных значений в отфильтрованном массиве
return len(filtered) return len(filtered)
@staticmethod @staticmethod
def any_true(expressions: list[bool]) -> bool: def any_true (expressions: list[bool]) -> bool:
""" """
Проверяет, есть ли хотя бы один истинный аргумент. Проверяет, есть ли хотя бы один истинный аргумент.
:param expressions: Выражения. :param expressions: Выражения.
@@ -83,6 +82,6 @@ class BoolExtension:
""" """
# Получаем количество истинных значений # Получаем количество истинных значений
true_count = BoolExtension.true_count(expressions, NotBoolAction.IGNORE) true_count = BoolExtension.true_count(expressions, NotBoolAction.IGNORE)
# Если количество истинных значений больше нуля, возвращаем True, иначе False # Если количество истинных значений больше нуля, возвращаем True, иначе False
return True if true_count > 0 else False return True if true_count > 0 else False

View File

@@ -1,23 +1,22 @@
# anb_python_components/extensions/guid_extension.py # anb_python_components/extensions/guid_extension.py
import secrets 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.exceptions.wrong_type_exception import WrongTypeException
from anb_python_components.types.guid import GUID
class GUIDExtension: class GUIDExtension:
""" """
Класс GUIDExtension реализует расширение для работы с GUID. Класс GUIDExtension реализует расширение для работы с GUID.
""" """
def __init__(self): def __init__ (self):
""" """
Инициализация расширения. Инициализация расширения.
""" """
pass pass
@staticmethod @staticmethod
def generate() -> GUID: def generate () -> GUID:
""" """
Генерирует уникальный идентификатор GUID согласно стандарту RFC 4122. Генерирует уникальный идентификатор GUID согласно стандарту RFC 4122.
""" """
@@ -27,56 +26,58 @@ class GUIDExtension:
time_hi_and_version = ((secrets.randbits(12) << 4) | 0x4000) & 0xffff time_hi_and_version = ((secrets.randbits(12) << 4) | 0x4000) & 0xffff
clock_seq_hi_and_reserved = ((secrets.randbits(14) << 2) | 0x8000) & 0xffff clock_seq_hi_and_reserved = ((secrets.randbits(14) << 2) | 0x8000) & 0xffff
node_id = secrets.randbits(48) & 0xffffffffffff node_id = secrets.randbits(48) & 0xffffffffffff
# Объединение компонентов в единый GUID # Объединение компонентов в единый GUID
guid_parts = [ guid_parts = [
time_low >> 16, time_low & 0xffff, time_low >> 16, time_low & 0xffff,
time_mid, time_mid,
time_hi_and_version, time_hi_and_version,
clock_seq_hi_and_reserved, clock_seq_hi_and_reserved,
node_id >> 32, (node_id >> 16) & 0xffff, node_id & 0xffff node_id >> 32, (node_id >> 16) & 0xffff, node_id & 0xffff
] ]
# Форматируем компоненты в виде строки GUID # Форматируем компоненты в виде строки GUID
guid_str = "-".join([ guid_str = "-".join(
"%08x" % guid_parts[0], [
"%04x" % guid_parts[1], "%08x" % guid_parts[0],
"%04x" % guid_parts[2], "%04x" % guid_parts[1],
"%04x" % guid_parts[3], "%04x" % guid_parts[2],
("%04x%04x%04x" % tuple(guid_parts[4:])), "%04x" % guid_parts[3],
]) ("%04x%04x%04x" % tuple(guid_parts[4:])),
]
)
# Возвращаем экземпляр GUID # Возвращаем экземпляр GUID
return GUID(guid_str) return GUID(guid_str)
@staticmethod @staticmethod
def is_equal(guid1: str | GUID, guid2: str | GUID) -> bool: def is_equal (guid1: str | GUID, guid2: str | GUID) -> bool:
# Если guid1 не является GUID или строкой # Если guid1 не является GUID или строкой
if not isinstance(guid1, GUID) or not isinstance(guid1, str): 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 или строкой # Если guid2 не является GUID или строкой
if not isinstance(guid2, GUID) or not isinstance(guid2, str): 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 является строкой # Если guid1 является строкой
if not isinstance(guid1, GUID): if not isinstance(guid1, GUID):
# - преобразуем её в GUID # - преобразуем её в GUID
guid1 = GUID(guid1) guid1 = GUID(guid1)
# Если guid2 является строкой # Если guid2 является строкой
if not isinstance(guid2, GUID): if not isinstance(guid2, GUID):
# - преобразуем её в GUID # - преобразуем её в GUID
guid2 = GUID(guid2) guid2 = GUID(guid2)
# Сравниваем GUID # Сравниваем GUID
return guid1 == guid2 return guid1 == guid2
@staticmethod @staticmethod
def validate(guid: str | GUID) -> bool: def validate (guid: str | GUID) -> bool:
""" """
Проверка GUID на валидность. Проверка GUID на валидность.
:param guid: GUID для проверки. :param guid: GUID для проверки.
@@ -84,12 +85,12 @@ class GUIDExtension:
""" """
# Если guid не является строкой, то преобразуем его в неё # Если guid не является строкой, то преобразуем его в неё
guid = guid if isinstance(guid, str) else str(guid) guid = guid if isinstance(guid, str) else str(guid)
# Проверяем GUID # Проверяем GUID
return bool(GUID.validate_str(guid)) return bool(GUID.validate_str(guid))
@staticmethod @staticmethod
def is_invalid_or_empty(guid: str | GUID) -> bool: def is_invalid_or_empty (guid: str | GUID) -> bool:
""" """
Проверка GUID на валидность и не пустоту. Проверка GUID на валидность и не пустоту.
:param guid: Класс или строка GUID для проверки. :param guid: Класс или строка GUID для проверки.
@@ -97,27 +98,27 @@ class GUIDExtension:
""" """
# Если guid не является строкой, то преобразуем его в неё # Если guid не является строкой, то преобразуем его в неё
guid = guid if isinstance(guid, str) else str(guid) guid = guid if isinstance(guid, str) else str(guid)
# Проверяем 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 @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 из строки. Парсинг GUID из строки.
:param guid_string: Строка GUID. :param guid_string: Строка GUID.
:param empty_if_not_valid: Если True, то возвращается пустой GUID, если GUID недействителен. :param empty_if_not_valid: Если True, то возвращается пустой GUID, если GUID недействителен.
""" """
# Проверяем строку на соответствие формату GUID # Проверяем строку на соответствие формату GUID
if cls.validate(guid_string): if cls.validate(guid_string):
# - если GUID действителен, возвращаем экземпляр GUID # - если GUID действителен, возвращаем экземпляр GUID
return GUID(guid_string) return GUID(guid_string)
# Если же GUID недействителен и запрещено выбрасывать исключение # Если же GUID недействителен и запрещено выбрасывать исключение
if empty_if_not_valid: if empty_if_not_valid:
# -- то возвращаем пустой GUID # -- то возвращаем пустой GUID
return GUID(GUID_EMPTY) return GUID(GUID.EMPTY)
else: else:
# -- иначе выбрасываем исключение # -- иначе выбрасываем исключение
raise WrongTypeException('Предан неверный GUID / Wrong GUID.') raise WrongTypeException('Предан неверный GUID / Wrong GUID.')

View File

@@ -3,58 +3,57 @@ import re
from .string_extension_constant import StringExtensionConstants from .string_extension_constant import StringExtensionConstants
class StringExtension: class StringExtension:
""" """
Расширение строк. Расширение строк.
""" """
def __init__(self): def __init__ (self):
""" """
Конструктор. Конструктор.
""" """
pass pass
@staticmethod @staticmethod
def is_none_or_empty(text: str | None) -> bool: def is_none_or_empty (text: str | None) -> bool:
""" """
Проверяет, пуста ли строка. Проверяет, пуста ли строка.
:param text: Проверяемая строка. :param text: Проверяемая строка.
:return: Результат проверки. :return: Результат проверки.
""" """
return text is None or text == "" return text is None or text == ""
@classmethod @classmethod
def is_none_or_whitespace(cls, text: str | None) -> bool: def is_none_or_whitespace (cls, text: str | None) -> bool:
""" """
Проверяет, пуста ли строка, содержит ли вместо текста только пробелы. Проверяет, пуста ли строка, содержит ли вместо текста только пробелы.
:param text: Проверяемая строка. :param text: Проверяемая строка.
:return: Bool Результат проверки. :return: Bool Результат проверки.
""" """
return cls.is_none_or_empty(text) or text.strip() == '' return cls.is_none_or_empty(text) or text.strip() == ''
@staticmethod @staticmethod
def is_russian_letter(letter: str) -> bool: def is_russian_letter (letter: str) -> bool:
""" """
Проверяет, является ли символ русским буквой. Проверяет, является ли символ русским буквой.
:param letter: Проверяемый символ. :param letter: Проверяемый символ.
:return: Результат проверки. :return: Результат проверки.
""" """
return letter in StringExtensionConstants.russian_letters return letter in StringExtensionConstants.russian_letters
@staticmethod @staticmethod
def get_russian_letter_transliteration(letter: str) -> bool | None: def get_russian_letter_transliteration (letter: str) -> bool | None:
""" """
Получаю транслитерированную букву русского алфавита. Получаю транслитерированную букву русского алфавита.
:param letter: Буква русского алфавита. :param letter: Буква русского алфавита.
:return: Транслитерированная буква. :return: Транслитерированная буква.
""" """
try: try:
# Получаю транслитерированную букву # Получаю транслитерированную букву
transliteration = StringExtensionConstants.russian_letters[letter] transliteration = StringExtensionConstants.russian_letters[letter]
# Если не удалось получить транслитерированную букву # Если не удалось получить транслитерированную букву
if transliteration is None: if transliteration is None:
# - то возбуждаю исключение # - то возбуждаю исключение
@@ -62,12 +61,12 @@ class StringExtension:
except KeyError: except KeyError:
# Если возбуждено исключение, то возвращаю None # Если возбуждено исключение, то возвращаю None
return None return None
# Возвращаю транслитерированную букву # Возвращаю транслитерированную букву
return transliteration return transliteration
@classmethod @classmethod
def convert_to_latin(cls, source: str) -> str: def convert_to_latin (cls, source: str) -> str:
""" """
Конвертация в латиницу. Конвертация в латиницу.
:param source: Исходная строка. :param source: Исходная строка.
@@ -75,13 +74,13 @@ class StringExtension:
""" """
# Создаю результат # Создаю результат
result = "" result = ""
# Получаю длину строкиДля каждой буквы или символа из слова # Получаю длину строкиДля каждой буквы или символа из слова
for i, letter in enumerate(source): for i, letter in enumerate(source):
if cls.is_russian_letter(letter): if cls.is_russian_letter(letter):
# - транслитерирую эту букву # - транслитерирую эту букву
result_transliteration = cls.get_russian_letter_transliteration(letter) result_transliteration = cls.get_russian_letter_transliteration(letter)
# - если транслитерация не удалась # - если транслитерация не удалась
if result_transliteration is None: if result_transliteration is None:
# -- вывожу оригинальную букву # -- вывожу оригинальную букву
@@ -92,12 +91,12 @@ class StringExtension:
else: else:
# - иначе вывожу букву или символ # - иначе вывожу букву или символ
result += letter result += letter
# Вывожу результат # Вывожу результат
return result return result
@classmethod @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: Первая строка. :param str1: Первая строка.
@@ -112,37 +111,37 @@ class StringExtension:
if cls.is_none_or_whitespace(str1) and cls.is_none_or_whitespace(str2): if cls.is_none_or_whitespace(str1) and cls.is_none_or_whitespace(str2):
# - то считаем их равными # - то считаем их равными
return 0 return 0
# Если первый из них не пуст, а второй пуст # Если первый из них не пуст, а второй пуст
if not cls.is_none_or_whitespace(str1) and cls.is_none_or_whitespace(str2): if not cls.is_none_or_whitespace(str1) and cls.is_none_or_whitespace(str2):
# - то первый больше # - то первый больше
return 1 return 1
# Если первый из них пуст, а второй не пуст # Если первый из них пуст, а второй не пуст
if cls.is_none_or_whitespace(str1) and not cls.is_none_or_whitespace(str2): if cls.is_none_or_whitespace(str1) and not cls.is_none_or_whitespace(str2):
# - то первый меньше # - то первый меньше
return -1 return -1
# Если не нужно учитывать регистр # Если не нужно учитывать регистр
# - преобразую (или нет) первую строку # - преобразую (или нет) первую строку
compare_str_1 = str1 if not ignore_case else str1.lower() compare_str_1 = str1 if not ignore_case else str1.lower()
# - преобразую (или нет) вторую строку # - преобразую (или нет) вторую строку
compare_str_2 = str2 if not ignore_case else str2.lower() compare_str_2 = str2 if not ignore_case else str2.lower()
# Проверяю равенство # Проверяю равенство
if compare_str_1 == compare_str_2: if compare_str_1 == compare_str_2:
# - и если равны, то возвращаю 0 # - и если равны, то возвращаю 0
return 0 return 0
# Они не равны, поэтому получим длину первого слова и второго # Они не равны, поэтому получим длину первого слова и второго
len1 = len(compare_str_1) len1 = len(compare_str_1)
len2 = len(compare_str_2) len2 = len(compare_str_2)
# Если длина первого больше и равна второго, то верну 1, иначе -1 # Если длина первого больше и равна второго, то верну 1, иначе -1
return 1 if len1 >= len2 else -1 return 1 if len1 >= len2 else -1
@staticmethod @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 символов. Обрезает строку до указанных в параметре max_length символов.
:param text: Исходный текст. :param text: Исходный текст.
@@ -154,15 +153,15 @@ class StringExtension:
if len(text) <= max_length: if len(text) <= max_length:
# - то возвращаем сам текст # - то возвращаем сам текст
return text return text
# Если длина текста больше максимальной, то получаю длину текста без суффикса # Если длина текста больше максимальной, то получаю длину текста без суффикса
len_no_end_symbols = max_length - len(end_symbols) len_no_end_symbols = max_length - len(end_symbols)
# Возвращаю обрезанный текст # Возвращаю обрезанный текст
return text[:len_no_end_symbols] + end_symbols return text[:len_no_end_symbols] + end_symbols
@staticmethod @staticmethod
def to_utf8(subject: str, encoding: str = 'UTF-8') -> str: def to_utf8 (subject: str, encoding: str = 'UTF-8') -> str:
""" """
Перекодирует строку в UTF-8. Перекодирует строку в UTF-8.
:param subject: Исходная строка. :param subject: Исходная строка.
@@ -173,21 +172,21 @@ class StringExtension:
if encoding == 'UTF-8': if encoding == 'UTF-8':
# - то возвращаю исходную строку # - то возвращаю исходную строку
return subject return subject
# Получаем байты оригинальной строки # Получаем байты оригинальной строки
bytes_original = subject.encode(encoding) bytes_original = subject.encode(encoding)
# Преобразовываем в Unicode (используя указанную кодировку) # Преобразовываем в Unicode (используя указанную кодировку)
unicode_string = bytes_original.decode(encoding) unicode_string = bytes_original.decode(encoding)
# Кодируем в UTF-8 # Кодируем в UTF-8
utf8_bytes = unicode_string.encode('UTF-8') utf8_bytes = unicode_string.encode('UTF-8')
# Возвращаем результат # Возвращаем результат
return utf8_bytes.decode('UTF-8') return utf8_bytes.decode('UTF-8')
@staticmethod @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. Перекодирует строку из UTF-8.
:param subject: Исходная строка. :param subject: Исходная строка.
@@ -198,15 +197,15 @@ class StringExtension:
if to_encoding == 'UTF-8': if to_encoding == 'UTF-8':
# - то возвращаю исходную строку # - то возвращаю исходную строку
return subject return subject
# Получаю байты строки # Получаю байты строки
target_bytes = subject.encode('UTF-8') target_bytes = subject.encode('UTF-8')
# Преобразовываю в нужную кодировку и возвращаю результат # Преобразовываю в нужную кодировку и возвращаю результат
return str(target_bytes.decode('UTF-8').encode(to_encoding)) return str(target_bytes.decode('UTF-8').encode(to_encoding))
@classmethod @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: Исходная строка. :param subject: Исходная строка.
@@ -223,23 +222,23 @@ class StringExtension:
replace = cls.to_utf8(replace, encoding) replace = cls.to_utf8(replace, encoding)
# - и перекодируем исходную строку в UTF-8 # - и перекодируем исходную строку в UTF-8
subject = cls.to_utf8(subject, encoding) subject = cls.to_utf8(subject, encoding)
# Используем re.escape для экранирования спецсимволов # Используем re.escape для экранирования спецсимволов
pattern = re.escape(search) pattern = re.escape(search)
# Замена всех вхождений search на replace # Замена всех вхождений search на replace
result = re.sub(pattern, replace, subject) result = re.sub(pattern, replace, subject)
# Если кодировка не UTF-8 # Если кодировка не UTF-8
if encoding != 'UTF-8': if encoding != 'UTF-8':
# - то перекодируем результат в нужную кодировку # - то перекодируем результат в нужную кодировку
result = cls.from_utf8(result, encoding) result = cls.from_utf8(result, encoding)
# Возвращаем результат # Возвращаем результат
return result return result
@classmethod @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: Словарь с парами поиска и замены. Например, {'-': '#', '$': '%'} :param search_replace: Словарь с парами поиска и замены. Например, {'-': '#', '$': '%'}
@@ -250,11 +249,11 @@ class StringExtension:
""" """
# Создаю результат # Создаю результат
result = subject result = subject
# Для каждой пары поиска и замены # Для каждой пары поиска и замены
for search, replace in search_replace.items(): for search, replace in search_replace.items():
# - заменяю все вхождения строки поиска на строку замены в заданной строке # - заменяю все вхождения строки поиска на строку замены в заданной строке
result = cls.replace(result, search, replace, encoding) result = cls.replace(result, search, replace, encoding)
# Возвращаю результат # Возвращаю результат
return result return result

View File

@@ -8,73 +8,73 @@ class StringExtensionConstants:
Attributes: Attributes:
russian_letters (dict): Словарь соответствия русских букв в транслитерации. russian_letters (dict): Словарь соответствия русских букв в транслитерации.
""" """
# Словарь соответствия русских букв в транслитерации # Словарь соответствия русских букв в транслитерации
russian_letters = { russian_letters = {
'а': 'a', 'а': 'a',
'б': 'b', 'б': 'b',
'в': 'v', 'в': 'v',
'г': 'g', 'г': 'g',
'д': 'd', 'д': 'd',
'е': 'e', 'е': 'e',
'ё': 'yo', 'ё': 'yo',
'ж': 'zh', 'ж': 'zh',
'з': 'z', 'з': 'z',
'и': 'i', 'и': 'i',
'й': 'j', 'й': 'j',
'к': 'k', 'к': 'k',
'л': 'l', 'л': 'l',
'м': 'm', 'м': 'm',
'н': 'n', 'н': 'n',
'о': 'o', 'о': 'o',
'п': 'p', 'п': 'p',
'р': 'r', 'р': 'r',
'с': 's', 'с': 's',
'т': 't', 'т': 't',
'у': 'u', 'у': 'u',
'ф': 'f', 'ф': 'f',
'х': 'h', 'х': 'h',
'ц': 'c', 'ц': 'c',
'ч': 'ch', 'ч': 'ch',
'ш': 'sh', 'ш': 'sh',
'щ': 'sch', 'щ': 'sch',
'ъ': 'j', 'ъ': 'j',
'ы': 'i', 'ы': 'i',
'ь': 'j', 'ь': 'j',
'э': 'e', 'э': 'e',
'ю': 'yu', 'ю': 'yu',
'я': 'ya', 'я': 'ya',
'А': 'A', 'А': 'A',
'Б': 'B', 'Б': 'B',
'В': 'V', 'В': 'V',
'Г': 'G', 'Г': 'G',
'Д': 'D', 'Д': 'D',
'Е': 'E', 'Е': 'E',
'Ё': 'Yo', 'Ё': 'Yo',
'Ж': 'Zh', 'Ж': 'Zh',
'З': 'Z', 'З': 'Z',
'И': 'I', 'И': 'I',
'Й': 'J', 'Й': 'J',
'К': 'K', 'К': 'K',
'Л': 'L', 'Л': 'L',
'М': 'M', 'М': 'M',
'Н': 'N', 'Н': 'N',
'О': 'O', 'О': 'O',
'П': 'P', 'П': 'P',
'Р': 'R', 'Р': 'R',
'С': 'S', 'С': 'S',
'Т': 'T', 'Т': 'T',
'У': 'U', 'У': 'U',
'Ф': 'F', 'Ф': 'F',
'Х': 'H', 'Х': 'H',
'Ц': 'C', 'Ц': 'C',
'Ч': 'Ch', 'Ч': 'Ch',
'Ш': 'Sh', 'Ш': 'Sh',
'Щ': 'Sch', 'Щ': 'Sch',
'Ъ': 'J', 'Ъ': 'J',
'Ы': 'I', 'Ы': 'I',
'Ь': 'J', 'Ь': 'J',
'Э': 'E', 'Э': 'E',
'Ю': 'Yu', 'Ю': 'Yu',
'Я': 'Ya' 'Я': 'Ya'
} }

View File

@@ -3,21 +3,20 @@
import datetime import datetime
from typing import Any from typing import Any
# Базовая структура для представления расширенного типа # Базовая структура для представления расширенного типа
class TypeExtension: class TypeExtension:
""" """
Класс для расширения типов. Класс для расширения типов.
""" """
def __init__(self): def __init__ (self):
""" """
Инициализирует экземпляр класса. Инициализирует экземпляр класса.
""" """
pass pass
@staticmethod @staticmethod
def to_dict(instance: Any) -> dict[str, Any]: def to_dict (instance: Any) -> dict[str, Any]:
""" """
Преобразует экземпляр объекта в словарь. Преобразует экземпляр объекта в словарь.
@@ -26,7 +25,7 @@ class TypeExtension:
""" """
# Создаём словарь # Создаём словарь
result = {} result = {}
# Перебираем поля экземпляра # Перебираем поля экземпляра
for key, value in vars(instance).items(): for key, value in vars(instance).items():
# - если значение является экземпляром datetime, преобразуем его в timestamp # - если значение является экземпляром datetime, преобразуем его в timestamp
@@ -38,12 +37,12 @@ class TypeExtension:
# - иначе просто добавляем значение # - иначе просто добавляем значение
else: else:
result[key] = value result[key] = value
# Возвращаем словарь # Возвращаем словарь
return result return result
@staticmethod @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 по умолчанию). :param cls: Класс для восстановления объекта (необязательный параметр, равный None по умолчанию).
:return: Восстановленный объект. :return: Восстановленный объект.
""" """
# Проверяем, что класс указан и является типом # Проверяем, что класс указан и является типом
if cls is None or not isinstance(cls, type): if cls is None or not isinstance(cls, type):
# - если класс не указан, бросаем исключение # - если класс не указан, бросаем исключение
raise TypeError('Класс для восстановления не указан.') raise TypeError('Класс для восстановления не указан.')
# Создаём объект класса # Создаём объект класса
# noinspection PyArgumentList
obj = cls.__new__(cls) obj = cls.__new__(cls)
# Перебираем поля словаря # Перебираем поля словаря
for key, value in data.items(): for key, value in data.items():
# - если значение является словарем, вызываем рекурсивно функцию from_dict и устанавливаем результат в поле объекта # - если значение является словарем, вызываем рекурсивно функцию from_dict и устанавливаем результат в поле объекта
@@ -70,6 +70,6 @@ class TypeExtension:
setattr(obj, key, TypeExtension.from_dict(value, nested_cls)) setattr(obj, key, TypeExtension.from_dict(value, nested_cls))
else: else:
setattr(obj, key, value) setattr(obj, key, value)
# Возвращаем восстановленный объект # Возвращаем восстановленный объект
return obj return obj

View File

@@ -0,0 +1 @@
# anb_python_components/types/__init__.py

View File

@@ -1,66 +1,78 @@
# anb_python_components/classes/guid.py # anb_python_components/types/guid.py
import re import re
from anb_python_components.exceptions.wrong_type_exception import WrongTypeException from anb_python_components.exceptions.wrong_type_exception import WrongTypeException
# Константа пустого GUID
GUID_EMPTY: str = "00000000-0000-0000-0000-000000000000"
class GUID: 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 на валидность # Проверка GUID на валидность
if not self.validate_str(guid): if not self.validate_str(guid):
# и если GUID невалидный, то генерируем исключение # и если GUID невалидный, то генерируем исключение
raise WrongTypeException("Неверный формат GUID!", "GUID", guid, "guid") raise WrongTypeException("Неверный формат GUID!", "GUID", guid, "guid")
# Инициализируем приватный атрибут __value (текстовое представление хранящегося GUID) # Инициализируем приватный атрибут __value (текстовое представление хранящегося GUID)
self.__value = guid self.__value = guid
def __str__(self): def __str__ (self):
""" """
Переопределение метода __str__. Переопределение метода __str__.
:return: Текстовое представление GUID. :return: Текстовое представление GUID.
""" """
return self.__value if self.__value else GUID_EMPTY return self.__value if self.__value else self.EMPTY
def __eq__(self, other): def __eq__ (self, other):
""" """
Переопределение метода __eq__. Переопределение метода __eq__.
:param other: Объект для сравнения. :param other: Объект для сравнения.
:return: True, если GUID равны, иначе False. :return: True, если GUID равны, иначе False.
""" """
# Если аргумент не является экземпляром GUID # Если аргумент не является экземпляром GUID
if not isinstance(other, GUID): if not isinstance(other, GUID):
# - генерируем исключение # - генерируем исключение
raise WrongTypeException("Неверный тип аргумента!", "GUID", type(other), "other") raise WrongTypeException("Неверный тип аргумента!", "GUID", type(other), "other")
# Преобразование второго аргумента в строку # Преобразование второго аргумента в строку
other_str = str(other) other_str = str(other)
# Сравниваем строки # Сравниваем строки
return self.__value == other_str return self.__value == other_str
@staticmethod @staticmethod
def validate_str(guid: str | None) -> bool: def validate_str (guid: str | None) -> bool:
""" """
Проверка строки на валидность GUID. Проверка строки на валидность GUID.
:return: True, если GUID валидный, иначе False. :return: True, если GUID валидный, иначе False.
""" """
# Проверка на пустоту # Проверка на пустоту
if not guid: if not guid:
return False return False
# Регулярное выражение для проверки формата GUID # Регулярное выражение для проверки формата GUID
pattern = r'^[0-9A-Fa-f]{8}-([0-9A-Fa-f]{4}-){3}[0-9A-Fa-f]{12}$' 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))