# Исходный код tools.fix_python_project

    #!/usr/bin/env python3
    """Модуль исправления структуры Python-проекта.

    Автоматически выполняет:
    1. Удаление BOM-маркеров из файлов
    2. Создание недостающих __init__.py
    3. Логирование всех операций

    Использование: python fix_python_project.py [путь_к_проекту]
    """

    import os
    import sys
    from typing import List, Set

    # Настройки обработки проекта
    INIT_IGNORED_DIRS: Set[str] = {'tests', '.git', '__pycache__', 'venv', 'env', '.idea', '.vscode'}
    TARGET_EXTENSIONS: tuple = ('.py', '.json', '.txt')
    INIT_TEMPLATE: str = """# Auto-generated by fix_python_project.py
    \"\"\"Package initialization.\"\"\"
    """

    class ProjectFixer:
        """Исправляет структуру Python-проекта.

        Атрибуты:
            root_dir: Корневая директория проекта.
            log: Лог выполненных операций.
        """

        def __init__(self, root_dir: str = '.'):
            """Инициализирует экземпляр ProjectFixer.

            Args:
                root_dir: Корневая директория проекта. По умолчанию '.'.
            """

            self.root_dir = os.path.abspath(root_dir)
            self.log: List[str] = []

        def remove_bom(self, filepath: str) -> bool:
            """Удаляет BOM-маркер из файла.

            Args:
                filepath: Путь к файлу.

            Returns:
                bool: True если BOM был удалён.

            Raises:
                Exception: При ошибке чтения/записи.
            """

            try:
                with open(filepath, 'rb') as f:
                    content = f.read()

                if content.startswith(b'\xEF\xBB\xBF'):
                    with open(filepath, 'wb') as f:
                        f.write(content[3:])
                    self.log.append(f"REMOVED BOM: {filepath}")
                    return True
            except Exception as e:
                self.log.append(f"ERROR processing {filepath}: {str(e)}")
            return False

        def should_skip_init(self, dir_path: str) -> bool:
            """Проверяет нужно ли пропустить директорию.

            Args:
                dir_path: Путь к директории.

            Returns:
                bool: True если директорию нужно пропустить.
            """

            dir_name = os.path.basename(dir_path)
            return (dir_name in INIT_IGNORED_DIRS or
                    dir_name.startswith('.'))

        def needs_init_py(self, dir_path: str) -> bool:
            """Проверяет нужно ли создать __init__.py.

            Args:
                dir_path: Путь к директории.

            Returns:
                bool: True если __init__.py требуется.
            """

            if self.should_skip_init(dir_path):
                return False

            try:
                items = os.listdir(dir_path)
                has_py_files = any(f.endswith('.py') and f != '__init__.py' for f in items)
                has_init = '__init__.py' in items
                return has_py_files and not has_init
            except Exception:
                return False

        def create_init_py(self, dir_path: str) -> bool:
            """Создаёт файл __init__.py.

            Args:
                dir_path: Путь к директории.

            Returns:
                bool: True если файл создан.

            Raises:
                Exception: При ошибке создания.
            """

            init_path = os.path.join(dir_path, '__init__.py')
            try:
                with open(init_path, 'w', encoding='utf-8') as f:
                    f.write(INIT_TEMPLATE)
                self.log.append(f"CREATED INIT: {init_path}")
                return True
            except Exception as e:
                self.log.append(f"ERROR creating {init_path}: {str(e)}")
                return False

        def process_directory(self):
            """Рекурсивно обрабатывает проект."""

            for root, dirs, files in os.walk(self.root_dir):
                # Обработка файлов с целевыми расширениями
                for file in files:
                    if file.endswith(TARGET_EXTENSIONS):
                        self.remove_bom(os.path.join(root, file))

                # Создание __init__.py где это необходимо
                if self.needs_init_py(root):
                    self.create_init_py(root)

        def save_log(self, log_file: str = 'project_fix.log'):
            """Сохраняет лог операций в файл.

            Args:
                log_file: Имя файла лога. По умолчанию 'project_fix.log'.
            """

            with open(log_file, 'w', encoding='utf-8') as f:
                f.write("\n".join(self.log))

    if __name__ == '__main__':
        # Обработка аргументов командной строки
        target_dir = sys.argv[1] if len(sys.argv) > 1 else '.'

        # Инициализация и запуск обработки
        fixer = ProjectFixer(target_dir)
        print(f"Исправление структуры проекта в: {fixer.root_dir}")

        fixer.process_directory()
        fixer.save_log()

        # Вывод результатов
        print(f"Готово! Внесено {len(fixer.log)} изменений.")
        print("Подробности сохранены в project_fix.log")