From c06f4f76218bfcc990817f1937129e541b7d1890 Mon Sep 17 00:00:00 2001 From: babaev-an Date: Thu, 9 Oct 2025 23:25:32 +0300 Subject: [PATCH] 20251009 --- .run/Тест Directory.run.xml | 17 ++ .run/Тест File.run.xml | 17 ++ anb_python_components/classes/file.py | 60 ++++++- help/class_desc/classes/directory.md | 85 +++++++++ help/class_desc/classes/file.md | 242 ++++++++++++++++++++++++++ tests/classes/directory_test.py | 19 ++ tests/classes/file_test.py | 79 +++++++++ 7 files changed, 518 insertions(+), 1 deletion(-) create mode 100644 .run/Тест Directory.run.xml create mode 100644 .run/Тест File.run.xml create mode 100644 help/class_desc/classes/directory.md create mode 100644 help/class_desc/classes/file.md create mode 100644 tests/classes/directory_test.py create mode 100644 tests/classes/file_test.py diff --git a/.run/Тест Directory.run.xml b/.run/Тест Directory.run.xml new file mode 100644 index 0000000..7b094f1 --- /dev/null +++ b/.run/Тест Directory.run.xml @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file diff --git a/.run/Тест File.run.xml b/.run/Тест File.run.xml new file mode 100644 index 0000000..a6ada19 --- /dev/null +++ b/.run/Тест File.run.xml @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file diff --git a/anb_python_components/classes/file.py b/anb_python_components/classes/file.py index d57c2af..37ff0f6 100644 --- a/anb_python_components/classes/file.py +++ b/anb_python_components/classes/file.py @@ -1,5 +1,6 @@ # anb_python_components/classes/action_state.py import glob +import hashlib import math import os @@ -20,6 +21,15 @@ class File: # Словарь локализации размеров файлов. FILE_SIZE_UNITS: list[str] = ['байт', 'КБ', 'МБ', 'ГБ', 'ТБ'] + @staticmethod + def is_exist (file_path: str) -> bool: + """ + Проверяет, существует ли файл по указанному пути. + :param file_path: Путь к файлу. + :return: bool: True, если файл существует, False в противном случае. + """ + return True if os.path.exists(file_path) and os.path.isfile(file_path) else False + @staticmethod def find (directory: str, pattern: str = '*', exclude_list: set[str] = str()) -> list | bool: """ @@ -165,4 +175,52 @@ class File: size = round(file_size / (1024 ** power), 2) # Возвращаем преобразованное значение вместе с единицей измерения - return f"{size:,.2f} {localize_file_size[power]}".replace('.', decimal_separator) \ No newline at end of file + return f"{size:,.2f} {localize_file_size[power]}".replace('.', decimal_separator) + + @staticmethod + def hash (file_name: str, hash_algorithm: str = 'sha256') -> str: + """ + Вычисляет хэш файла. + :param file_name: Имя файла для которого нужно вычислить хэш. + :param hash_algorithm: Алгоритм хэширования. По умолчанию: 'sha256'. + :return: Строка с хэшем. + """ + # Преобразование алгоритма в нижний регистр + hash_algorithm = hash_algorithm.lower() + + # Определяем алгоритм хэширования + match hash_algorithm: + # md5 + case 'md5': + hasher = hashlib.md5() + # sha1 + case 'sha1': + hasher = hashlib.sha1() + # sha256 + case 'sha256': + hasher = hashlib.sha256() + # sha512 + case 'sha512': + hasher = hashlib.sha512() + # sha3_256 + case 'sha3_256': + hasher = hashlib.sha3_256() + # sha3_512 + case 'sha3_512': + hasher = hashlib.sha3_512() + # blake2b + case 'blake2': + hasher = hashlib.blake2b() + # по умолчанию + case _: + hasher = hashlib.sha256() + + # Открываем файл для чтения + with open(file_name, 'rb') as file: + # - читаем файл по 4096 байт, чтобы сэкономить память + while chunk := file.read(4096): + # - добавляем прочитанные данные в хэш + hasher.update(chunk) + + # Возвращаем hex-представление хэша + return hasher.hexdigest() \ No newline at end of file diff --git a/help/class_desc/classes/directory.md b/help/class_desc/classes/directory.md new file mode 100644 index 0000000..403ee4a --- /dev/null +++ b/help/class_desc/classes/directory.md @@ -0,0 +1,85 @@ +# Класс `Directory` + +Класс `Directory` предоставляет инструменты для работы с каталогами (директориями) в операционной системе. Основными +функциями класса являются проверка существования директорий и их рекурсивное удаление. Этот класс полезен для +автоматизированных задач по управлению структурой папок в приложениях. + +## Основная информация + +- **Имя файла**: anb_python_components\classes\directory.py +- **Автор**: Александр Бабаев +- **Версия**: 1.0.0 +- **Дата начала поддержки**: с версии 1.0 + +## Атрибуты и методы класса + +### Словарь `REMOVE_DIRECTORY_ERROR_MESSAGES` + +Словарь сообщений об ошибках для удаления директории. + +```python +REMOVE_DIRECTORY_ERROR_MESSAGES: dict[str, str] = { + 'directory_not_exist': "Директория не существует или нет доступа на запись!", + 'error_deleting_directory': 'Ошибка удаления каталога: %s. Код возврата: %d!', + 'unhandled_error': 'Ошибка удаления директории %s: %s!' + } +``` + +### Метод `remove` + +Удаляет директорию вместе со всеми поддиректориями и файлами. + +**Параметры**: + +- **`directory: str`**: путь к директории, которую нужно удалить. +- **`error_messages: dict[str, str] | None = None`**: словарь с сообщениями об ошибках (опционально). Если задан как + `None`, то используется словарь `Directory.REMOVE_DIRECTORY_ERROR_MESSAGES`. По умолчанию, `None`. + +**Возвращает**: + +- Объект `ActionState`, содержащий результат операции и возможные сообщения об ошибках. + +Пример использования: + +```python +from anb_python_components.classes.directory import Directory + +result = Directory.remove("/path/to/folder") +if result.is_success(): + print("Директория успешно удалена.") +else: + print("Ошибка:", result.get_string_messages()) +``` + +### Метод `is_exists` + +Проверяет существование директории и (при необходимости) права доступа к ней. + +**Параметры**: + +- **`directory: str`**: путь к директории. +- **`check_access_level: str`**: строка, содержащая комбинации символов 'r', 'w', 'x' для проверки соответствующих прав + доступа (чтение, запись, исполнение). По умолчанию, `""`. + +**Возвращает**: + +- `True`, если директория существует и доступна по указанным параметрам, иначе `False`. + +**Пример использования**: + +```python +from anb_python_components.classes.directory import Directory + +exists = Directory.is_exists("/path/to/folder", check_access_level = "rw") +if exists: + print("Директория существует и доступна для чтения и записи.") +else: + print("Проблемы с доступом к директории.") +``` + +## Заключение + +Класс `Directory` позволяет упростить управление файловой системой, особенно полезными будут методы удаления и проверки +доступности директорий, которые помогают повысить устойчивость приложений к ошибкам. + +[На главную](../../index.md) \ No newline at end of file diff --git a/help/class_desc/classes/file.md b/help/class_desc/classes/file.md new file mode 100644 index 0000000..3ae4904 --- /dev/null +++ b/help/class_desc/classes/file.md @@ -0,0 +1,242 @@ +# Класс `File` + +Класс `File` предоставляет разнообразные инструменты для работы с файлами в Python, начиная от простых операций, таких +как проверка существования файла, и заканчивая более продвинутыми возможностями, такими как поиск файлов по маске, +вычисление размера файла и его хэша. + +## Основная информация + +- **Имя файла**: anb_python_components\classes\file.py +- **Автор**: Александр Бабаев +- **Версия**: 1.0.0 +- **Дата начала поддержки**: с версии 1.0 + +## Атрибуты и методы класса + +### Словарь сообщений об ошибках (`FILE_SIZE_ERROR_MESSAGES`) + +Этот словарь используется для локализованных сообщений об ошибках, которые возникают при попытке получить размер файла. +Каждое сообщение связано с определенным видом ошибки, и его можно настроить индивидуально для нужд приложения. + +**Содержимое словаря**: + +- `'file_not_exist'`: Сообщение выдается, если файл по указанному пути отсутствует. +- `'not_a_file'`: Сообщение появляется, если путь ведет не к файлу, а к каталогу или другому ресурсу. +- `'cannot_get_size'`: Сообщается, если возникли трудности с определением размера файла (например, из-за отсутствия + разрешения на чтение). + +**Пример использования**: + +```python +from anb_python_components.classes.file import File + +error_msg = File.FILE_SIZE_ERROR_MESSAGES['file_not_exist'] +print(error_msg) # Файл не существует! +``` + +### Словарь локализации размеров файлов (`FILE_SIZE_UNITS`) + +Этот список используется для перевода единиц измерения размера файла на человеческий язык. Каждая единица измеряется +следующим образом: + +- `'байт'`: Байты. +- `'КБ'`: Килобайты. +- `'МБ'`: Мегабайты. +- `'ГБ'`: Гигабайты. +- `'ТБ'`: Терабайты. + +**Пример использования**: + +```python +from anb_python_components.classes.file import File + +units = File.FILE_SIZE_UNITS +print(units[2]) # МБ +``` + +### Метод `is_exist` + +Проверяет, существует ли файл по указанному пути. + +**Параметры**: + +- **`file_path: str`**: Путь к файлу. + +**Возвращает**: + +- `True`, если файл существует, иначе `False`. + +**Пример использования**: + +```python +from anb_python_components.classes.file import File + +if File.is_exist('/path/to/file.txt'): + print("Файл существует.") +``` + +### Метод `find` + +Рекурсивно ищет файлы по указанному шаблону в каталоге. + +Параметры: + +- **`directory`**: Каталог для поиска. +- **`pattern`**: Маска имени файла (по умолчанию `'*'`). +- **`exclude_list`**: Список директорий, которые нужно исключить из поиска. + +Возвращает: + +- Список путей к найденным файлам. + +Пример использования: + +```python +from anb_python_components.classes.file import File + +files = File.find('/home/user/', '*.txt') +for file in files: + print(file) +``` + +### Метод `extract_file_name` + +Извлекает имя файла из полного пути. + +Параметры: + +- **`file_path`**: Полный путь к файлу. + +Возвращает: + +- Имя файла. + +Пример использования: + +```python +from anb_python_components.classes.file import File + +name = File.extract_file_name('/home/user/document.txt') +print(name) # document.txt +``` + +### Метод `extract_file_extension` + +Извлекает расширение файла из полного пути. + +Параметры: + +- **`file_path`**: Полный путь к файлу. +- **`with_dot`**: Включать ли точку перед расширением (по умолчанию `True`). + +Возвращает: + +- Расширение файла. + +Пример использования: + +```python +from anb_python_components.classes.file import File + +extension = File.extract_file_extension('/home/user/image.jpg') +print(extension) # .jpg +``` + +### Метод `relative_path` + +Возвращает относительный путь к файлу относительно заданной директории. + +Параметры: + +- **`full_path`**: Полный путь к файлу. +- **`base_path`**: Базовая директория. + +Возвращает: + +- Относительный путь к файлу или **`False`**, если путь не относится к заданной директории. + +Пример использования: + +```python +from anb_python_components.classes.file import File + +rel_path = File.relative_path('/home/user/images/cat.png', '/home/user/') +print(rel_path) # images/cat.png +``` + +### Метод `size` + +Получает размер файла и сохраняет результат в объект `ActionState`. + +Параметры: + +- **`file_name`**: Путь к файлу. +- **`error_localization`**: Сообщения об ошибках (опционально). + +Возвращает: + +- Объект `ActionState`, содержащий размер файла или информацию об ошибке. + +Пример использования: + +```python +from anb_python_components.classes.file import File + +result = File.size('/path/to/file.txt') +if result.is_success(): + print("Размер файла:", result.value) +else: + print("Ошибка:", result.get_string_messages()) +``` + +### Метод `size_to_string` + +Преобразует размер файла в строку с указанием единицы измерения (байты, КБ, МБ и т.д.). + +Параметры: + +- **`file_size`**: Размер файла в байтах. +- **`localize_file_size`**: Локализация единиц измерения (опционально). +- **`decimal_separator`**: Разделитель десятичной точки (по умолчанию `.`, может быть настроен на региональный формат). + +Возвращает: + +- Форматированную строку с размером файла. + +Пример использования: + +```python +from anb_python_components.classes.file import File + +formatted_size = File.size_to_string(1024 * 1024) +print(formatted_size) # 1.00 MB +``` + +### Метод `hash` + +Вычисляет хэш файла, используя заданный алгоритм. + +Параметры: + +- **`file_name`**: Путь к файлу. +- **`hash_algorithm`**: Алгоритм хэширования (по умолчанию SHA-256). + +Возвращает: + +- Хэш файла в виде шестнадцатеричной строки. + +Пример использования: + +```python +from anb_python_components.classes.file import File + +file_hash = File.hash('/path/to/file.txt', 'sha256') +print(file_hash) +``` + +## Заключение + +Класс `File` предоставляет широкий спектр полезных методов для работы с файлами, облегчая стандартные операции с файлами +и помогая решать задачи, связанные с управлением файлами в приложениях. + +[На главную](../../index.md) \ No newline at end of file diff --git a/tests/classes/directory_test.py b/tests/classes/directory_test.py new file mode 100644 index 0000000..8527b37 --- /dev/null +++ b/tests/classes/directory_test.py @@ -0,0 +1,19 @@ +# directory_test.py + +import unittest + +from anb_python_components.classes.directory import Directory + +class DirectoryTest(unittest.TestCase): + def test_is_exists (self): + self.assertTrue(Directory.is_exists(r"C:\Windows", "r")) + self.assertFalse(Directory.is_exists(r"C:\Windows\1", "rw")) + # Создайте поддиректорию 123 в директории теста и заполните ее содержимым + self.assertTrue(Directory.is_exists(r".\123", "rwx")) + + def test_remove (self): + # Создайте поддиректорию 123 в директории теста и заполните ее содержимым + self.assertTrue(Directory.remove(r".\123")) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/tests/classes/file_test.py b/tests/classes/file_test.py new file mode 100644 index 0000000..876c23c --- /dev/null +++ b/tests/classes/file_test.py @@ -0,0 +1,79 @@ +# file_test.py + +import unittest + +from anb_python_components.classes.file import File + +class FileTest(unittest.TestCase): + def test_is_exists (self): + file_name = r"C:\Windows\explorer.exe" + dir_name = r"C:\Windows" + self.assertTrue(File.is_exist(file_name)) + self.assertFalse(File.is_exist(dir_name)) + + def test_find (self): + find_list = File.find(r"..\classes", "*.py") + result = [ + '..\\classes\\action_state_test.py', '..\\classes\\directory_test.py', '..\\classes\\file_test.py', + '..\\classes\\__init__.py' + ] + + self.assertEqual(result, find_list) + + def test_extract_file_name (self): + file_name = r"C:\Windows\explorer.exe" + result = File.extract_file_name(file_name) + expected_result = "explorer.exe" + + self.assertEqual(expected_result, result) + + def test_extract_file_extension (self): + file_name = r"C:\Windows\explorer.exe" + result = File.extract_file_extension(file_name) + expected_result = ".exe" + + self.assertEqual(expected_result, result) + + result = File.extract_file_extension(file_name, False) + expected_result = "exe" + + self.assertEqual(expected_result, result) + + def test_extract_file_name_without_extension (self): + file_name = r"C:\Windows\explorer.exe" + result = File.extract_file_name_without_extension(file_name) + expected_result = "explorer" + + self.assertEqual(expected_result, result) + + def test_relative_path (self): + file_name = r"C:\Windows\explorer.exe" + result = File.relative_path(file_name, r"C:\Windows") + expected_result = r"\explorer.exe" + + self.assertEqual(expected_result, result) + + def test_size (self): + file_name = r"C:\Windows\explorer.exe" + result = File.size(file_name).value + expected_result = 2774080 + + self.assertEqual(expected_result, result) + + def test_size_to_string (self): + file_name = r"C:\Windows\explorer.exe" + size = File.size(file_name).value + result = File.size_to_string(size) + expected_result = "2.65 МБ" + + self.assertEqual(expected_result, result) + + def test_hash (self): + file_name = r"C:\Windows\explorer.exe" + result = File.hash(file_name) + expected_result = "6345f80dd23b51d90bfdedfe03c51c9d85c5233c9fb2f2cfe9e1ac633a4895ca" + + self.assertEqual(expected_result, result) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file