Как правильно написать код на Python?

У меня есть вопрос на тему написания скрипта. <br/> Предположим, у нас есть дерево директорий, содержащее файлы на Python, которые могут иметь произвольную вложенность. <br/> В каждом из этих файлов определена переменная CMDS, содержащая список shell команд `echo`, которые необходимо выполнить. <br/> Я хочу разработать скрипт, который будет извлекать переменную CMDS из всех файлов в дереве директорий и выполнять указанные команды поочередно, сортируя их в алфавитном порядке по именам файлов. Команды, находящиеся в одном файле, должны выполняться в порядке их указания в переменной. <br/> <br/> Каждая команда должна выполниться только один раз. Если команда уже была выполнена, скрипт должен выводить сообщение об этом и пропускать её выполнение. <br/> Если для реализации решения предполагается использование сторонних библиотек, опишите зависимости в формате requirements.txt. <br/> <br/> Как правильно организовать этот процесс?
  • 21 сентября 2024 г. 8:43
Ответы на вопрос 1
Для реализации описанного вами функционала можно создать Python-скрипт, который будет рекурсивно проходить по дереву директорий, извлекать переменные `CMDS` из файлов Python, а затем выполнять уникальные команды в алфавитном порядке. Вот пример того, как можно организовать этот процесс:

```python
import os
import importlib.util
import subprocess

def find_py_files(directory):
    """Рекурсивно находит все файлы .py в заданной директории."""
    py_files = []
    for root, _, files in os.walk(directory):
        for file in files:
            if file.endswith('.py'):
                py_files.append(os.path.join(root, file))
    return py_files

def extract_cmds(file_path):
    """Извлекает переменную CMDS из указанного файла Python."""
    try:
        spec = importlib.util.spec_from_file_location("module.name", file_path)
        module = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(module)
        return getattr(module, 'CMDS', [])
    except Exception as e:
        print(f"Ошибка при извлечении CMDs из {file_path}: {e}")
        return []

def execute_commands(commands):
    """Выполняет команды поочередно, избегая дублирования."""
    executed_commands = set()
    for command in sorted(commands):
        if command not in executed_commands:
            print(f"Выполнение команды: {command}")
            subprocess.run(command, shell=True)
            executed_commands.add(command)
        else:
            print(f"Команда уже выполнена: {command}")

def main(directory):
    py_files = find_py_files(directory)
    all_cmds = []
    
    # Извлекаем команды из всех файлов
    for file_path in py_files:
        cmds = extract_cmds(file_path)
        if cmds:
            all_cmds.extend(cmds)

    # Выполняем уникальные команды
    execute_commands(all_cmds)

if __name__ == "__main__":
    main('/path/to/your/directory')  # Замените на ваш путь
```

### Объяснение кода:

1. **find_py_files(directory)** - Функция для поиска всех файлов `.py` в заданной директории и её поддиректориях.
2. **extract_cmds(file_path)** - Функция для импорта файла Python и извлечения списка команд из переменной `CMDS`. Если возникают ошибки, выводится сообщение об ошибке.
3. **execute_commands(commands)** - Функция для выполнения команд. Она отслеживает уже выполненные команды с помощью множества `executed_commands` и выполняет только уникальные команды.
4. **main(directory)** - Основная функция, которая координирует процесс: находит файлы, извлекает команды и выполняет их.

### Зависимости:
В этом коде используются только стандартные библиотеки Python, поэтому вам не нужно устанавливать дополнительных зависимостей. Однако если вам необходимо создать файл `requirements.txt`, просто создайте его пустым, или добавьте следующие строки:

```
# requirements.txt
# Для этого скрипта дополнительные зависимости не требуются
```

### Запуск кода:
Не забудьте изменить `'/path/to/your/directory'` на реальный путь к вашей директории, содержащей Python файлы. 

Ваш скрипт теперь готов для использования!
Похожие вопросы