diff --git a/anb_python_components/classes/directory.py b/anb_python_components/classes/directory.py new file mode 100644 index 0000000..7e55642 --- /dev/null +++ b/anb_python_components/classes/directory.py @@ -0,0 +1,115 @@ +# anb_python_components/classes/directory.py +import os +import platform +import subprocess + +from anb_python_components.classes.action_state import ActionState + +class Directory: + """ + Класс для работы с директориями. + """ + + # Словарь сообщений об ошибках для удаления директории + REMOVE_DIRECTORY_ERROR_MESSAGES: dict[str, str] = { + 'directory_not_exist': "Директория не существует или нет доступа на запись!", + 'error_deleting_directory': 'Ошибка удаления каталога: %s. Код возврата: %d!', + 'unhandled_error': 'Ошибка удаления директории %s: %s!' + } + + @staticmethod + def remove (directory: str, error_messages: dict[str, str] | None = None) -> ActionState[bool]: + """ + Рекурсивно удаляет директорию с соответствующим результатом. + + :param directory: Путь к директории. + :param error_messages: Слова для отображения ошибок. По умолчанию используются сообщения из REMOVE_DIRECTORY_ERROR_MESSAGES. + :return: Объект ActionState с информацией о результате. + """ + # Создаем объект ActionState для хранения результата + result = ActionState[bool](False) + + # Если не заданы сообщения об ошибках + if error_messages is None: + # - устанавливаем сообщения по умолчанию + error_messages = Directory.REMOVE_DIRECTORY_ERROR_MESSAGES + + try: + # Проверяем существование директории + if not Directory.is_exists(directory): + # - если директория не существует, добавляем ошибку + result.add_error(error_messages['directory_not_exist']) + # - возвращаем результат + return result + + # Определяем текущую операционную систему + system_os = platform.system().lower() + + # Проверяем операционную систему. Если это Windows + if system_os == 'windows': + # - задаем команду для Windows + command = ['cmd.exe', '/C', 'rd', '/S', '/Q', directory] + else: + # - иначе задаем команду для Unix-подобных систем + command = ['rm', '-rf', directory] + + # Запуск команды с безопасностью (используется subprocess.run) + process = subprocess.run(command, capture_output = True, text = True) + + # Анализируем код возврата процесса и если он не равен 0 + if process.returncode != 0: + # - добавляем ошибку + result.add_error(error_messages['error_deleting_directory'] % (directory, process.returncode)) + # - возвращаем результат + return result + + # Установка успешного результата + result.value = True + + # Возвращаем результат + return result + + except Exception as ex: + # Обработка необработанных исключений + result.add_error(error_messages['unhandled_error'] % (directory, str(ex))) + return result + + @staticmethod + def is_exists (directory: str, check_access_level: str = '') -> bool: + """ + Проверяет существование директории и доступность по правам доступа. + + :param directory: Путь к директории. + :param check_access_level: Строка, содержащая символы 'r', 'w' и 'x', которые указывают на необходимость проверки прав доступа на чтение, запись и исполнение соответственно. Если строка пустая, проверка прав доступа не выполняется. Если нет какого-либо символа, проверка прав доступа не выполняется для этого типа прав. По умолчанию: ''. + :return: True, если директория существует и доступна, иначе False. + """ + # Проверяем существование директории + if not os.path.exists(directory): + # - и если директория не существует, возвращаем False + return False + + # Проверяем, что это именно директория, а не файл + if not os.path.isdir(directory): + # - если это не директория, возвращаем False + return False + + # Задаем флаги проверки прав доступа + access_level_check = check_access_level.lower() + + # Проверяем права на чтение, если это требуется + if 'r' in access_level_check and not os.access(directory, os.R_OK): + # - если нет прав на чтение, возвращаем False + return False + + # Проверяем права на запись, если это требуется + if 'w' in access_level_check and not os.access(directory, os.W_OK): + # - если нет прав на запись, возвращаем False + return False + + # Проверяем права на исполнение, если это требуется + if 'x' in access_level_check and not os.access(directory, os.X_OK): + # - если нет прав на запись, возвращаем False + return False + + # Если все проверки успешны, возвращаем True + return True \ No newline at end of file diff --git a/anb_python_components/classes/file.py b/anb_python_components/classes/file.py index 749ed24..d57c2af 100644 --- a/anb_python_components/classes/file.py +++ b/anb_python_components/classes/file.py @@ -2,8 +2,6 @@ import glob import math import os -import platform -import subprocess from anb_python_components.classes.action_state import ActionState @@ -12,13 +10,6 @@ class File: Класс для работы с файлами. """ - # Словарь сообщений об ошибках для удаления директории - REMOVE_DIRECTORY_ERROR_MESSAGES: dict[str, str] = { - 'directory_not_exist': "Директория не существует или нет доступа на запись!", - 'error_deleting_directory': 'Ошибка удаления каталога: %s. Код возврата: %d!', - 'unhandled_error': 'Ошибка удаления директории %s: %s!' - } - # Словарь сообщений об ошибках для получения размера файла FILE_SIZE_ERROR_MESSAGES: dict[str, str] = { 'file_not_exist': 'Файл не существует!', @@ -30,7 +21,7 @@ class File: FILE_SIZE_UNITS: list[str] = ['байт', 'КБ', 'МБ', 'ГБ', 'ТБ'] @staticmethod - def find_files (directory: str, pattern: str = '*', exclude_list: set[str] = str()) -> list | bool: + def find (directory: str, pattern: str = '*', exclude_list: set[str] = str()) -> list | bool: """ Ищет файлы, удовлетворяющие заданному паттерну, рекурсивно проходя по указанным директориям. :param directory: Директория, в которой производится поиск. @@ -105,104 +96,7 @@ class File: return full_path[len(base_path):] if base_path.lower() in full_path.lower() else False @staticmethod - def remove_dir (directory: str, error_messages: dict[str, str] | None = None) -> ActionState[bool]: - """ - Рекурсивно удаляет директорию с соответствующим результатом. - - :param directory: Путь к директории. - :param error_messages: Слова для отображения ошибок. По умолчанию используются сообщения из REMOVE_DIRECTORY_ERROR_MESSAGES. - :return: Объект ActionState с информацией о результате. - """ - # Создаем объект ActionState для хранения результата - result = ActionState[bool](False) - - # Если не заданы сообщения об ошибках - if error_messages is None: - # - устанавливаем сообщения по умолчанию - error_messages = File.REMOVE_DIRECTORY_ERROR_MESSAGES - - try: - # Проверяем существование директории - if not File.directory_exists(directory): - # - если директория не существует, добавляем ошибку - result.add_error(error_messages['directory_not_exist']) - # - возвращаем результат - return result - - # Определяем текущую операционную систему - system_os = platform.system().lower() - - # Проверяем операционную систему. Если это Windows - if system_os == 'windows': - # - задаем команду для Windows - command = ['cmd.exe', '/C', 'rd', '/S', '/Q', directory] - else: - # - иначе задаем команду для Unix-подобных систем - command = ['rm', '-rf', directory] - - # Запуск команды с безопасностью (используется subprocess.run) - process = subprocess.run(command, capture_output = True, text = True) - - # Анализируем код возврата процесса и если он не равен 0 - if process.returncode != 0: - # - добавляем ошибку - result.add_error(error_messages['error_deleting_directory'] % (directory, process.returncode)) - # - возвращаем результат - return result - - # Установка успешного результата - result.value = True - - # Возвращаем результат - return result - - except Exception as ex: - # Обработка необработанных исключений - result.add_error(error_messages['unhandled_error'] % (directory, str(ex))) - return result - - @staticmethod - def directory_exists (directory: str, check_access_level: str = '') -> bool: - """ - Проверяет существование директории и доступность по правам доступа. - - :param directory: Путь к директории. - :param check_access_level: Строка, содержащая символы 'r', 'w' и 'x', которые указывают на необходимость проверки прав доступа на чтение, запись и исполнение соответственно. Если строка пустая, проверка прав доступа не выполняется. Если нет какого-либо символа, проверка прав доступа не выполняется для этого типа прав. По умолчанию: ''. - :return: True, если директория существует и доступна, иначе False. - """ - # Проверяем существование директории - if not os.path.exists(directory): - # - и если директория не существует, возвращаем False - return False - - # Проверяем, что это именно директория, а не файл - if not os.path.isdir(directory): - # - если это не директория, возвращаем False - return False - - # Задаем флаги проверки прав доступа - access_level_check = check_access_level.lower() - - # Проверяем права на чтение, если это требуется - if 'r' in access_level_check and not os.access(directory, os.R_OK): - # - если нет прав на чтение, возвращаем False - return False - - # Проверяем права на запись, если это требуется - if 'w' in access_level_check and not os.access(directory, os.W_OK): - # - если нет прав на запись, возвращаем False - return False - - # Проверяем права на исполнение, если это требуется - if 'x' in access_level_check and not os.access(directory, os.X_OK): - # - если нет прав на запись, возвращаем False - return False - - # Если все проверки успешны, возвращаем True - return True - - @staticmethod - def file_size (file_name: str, error_localization: dict[str, str] | None = None) -> ActionState[int]: + def size (file_name: str, error_localization: dict[str, str] | None = None) -> ActionState[int]: """ Получает размер файла и формирует результат с возможными ошибками. @@ -245,7 +139,7 @@ class File: return result @staticmethod - def file_size_to_string ( + def size_to_string ( file_size: int, localize_file_size: dict[str, str] | None = None, decimal_separator: str = '.' ) -> str: """