Как сделать ваши программы модульными

Итак, вы прочитали несколько руководств по созданию CLI в python. Вы загрузили Click, создали несколько групп и теперь у вас есть рабочий интерфейс командной строки!

Затем вы начинаете думать о дополнительных командах и понимаете, что это не масштабируется. Добавление всего в один файл приводит к беспорядку, а мысль о том, что над ним работают несколько команд, вызывает мурашки по коже. В этой статье мы сосредоточимся на двух подходах к масштабированию вашего интерфейса командной строки, чтобы сделать его более модульным и простым в управлении. Включен репозиторий Github с первоначальным проектом и различными рефакторингами.

В этом руководстве предполагается, что вы понимаете, как работает Click, но если вы этого не понимаете, вы можете прочитать следующие три статьи, чтобы освоиться:

Наш интерфейс командной строки

Тестовый cli, который мы будем создавать, будет содержать три действия:

  • Создайте
  • Удалить
  • получить

Каждое действие может быть выполнено на двух целях:

  • файл
  • каталог

Макет проекта V1

Чтобы создать нашу первую версию cli, мы следовали руководству и поместили все в один файл. Не лучшая практика… но это сработало! Наш проект выглядит так.

├── main.py
├── setup.py

Вы можете найти код в папке V1 репозитория github. Мы используем групповые декораторы для структурирования нашей иерархии, как показано ниже.

Это работает, и мы можем скомпилировать наш CLI, но добавление дополнительных функций становится более загроможденным, поэтому мы пытаемся реорганизовать код, чтобы сделать его более модульным.

V1.5 Пытаясь быть модульным

Мы рефакторим наш код и добавляем файлы file.py и directory.py. Мы копируем и вставляем в них наши функции с декораторами, но теперь сталкиваемся с проблемой, как нам структурировать импорт?

Мы пытаемся импортировать нашу группу CLI верхнего уровня в подмодули и таким образом добавлять команды, но получаем пустые подкоманды. Пришло время пересмотреть наши возможности.

Схема модульного проекта V2

Чтобы помочь создать более масштабируемый подход, мы собираемся добавить модули Python в наш каталог. Наш макет проекта будет отражать наши категории (существительные) с папкой верхнего уровня, содержащей точку входа cli, два модуля и установочный файл.

├── main.py
├── setup.py
└── src
    ├── directories
    │   └── directory.py
    └── files
        └── file.py

Теперь у нас есть выбор того, как мы хотели бы, чтобы наши пользователи взаимодействовали с нашим cli, либо структурируя его так, чтобы команды шли сначала глаголом, либо существительным, то есть cli create file или cli file create.. В следующем разделе мы обсудим некоторые плюсы и минусы каждого из них. подход.

Структурирование ваших команд

В зависимости от того, с какими CLI вы работали, естественная иерархия для вашего cli может быть cli create file или cli file create. Первый называется иерархией глагол-существительное с клисом, таким как Powershell. Эти структуры хороши, когда команды имеют похожие действия, которые можно выполнить, и более точно отражают английский язык.

Второй тип существительного-глагола clis имеет больше примеров, включая AWS CLI и команды linux bash. В случае AWS каждая служба является второй частью каждой команды cli, такой как aws ec2 describe instances и aws s3 ls..

Основное преимущество этой структуры cli заключается в том, что она позволяет командам вносить свой вклад в более крупный cli без изменения действий верхнего уровня, которые могут быть предприняты. Команды могут работать более автономно, а пользователи могут выбирать, какие подмодули загружать. Он также более точно следует хорошим принципам объектно-ориентированного программирования, не слишком полагаясь на общие методы в подклассах (группах), когда они не нужны.

Другие интерфейсы командной строки смешивают и сопоставляют структуру «существительное-глагол» и «глагол-существительное», например, kubectl с такими командами, как

kubectl config get-contexts
kubectl config view

А также такие команды, как

kubectl get pods
kubectl get services

Сегодня в следующем разделе мы расскажем, как выполнить обе настройки, и вам предлагается реализовать предпочтительный подход для вашего проекта.

Сначала имя существительное — Cli File Create

Сначала мы начнем с существительного, потому что это упрощает нашу настройку. В нашем main.py в папке Noun First вы заметите, как мы структурируем наш проект, мы импортируем каждую группу из наших подкаталогов и добавляем их как команду.

Это было довольно легко! Следует отметить, что я помещаю все в папку src, а затем в свой setup.py импортирую все в src как pymodule.

├── main.py
├── setup.py
└── src
├── каталоги
│ └── directory.py
└── файлы
└── file.py

Когда мы запустим cli, мы должны увидеть что-то вроде этого.

cli file
Usage: cli file [OPTIONS] COMMAND [ARGS]...
Options:
  --help  Show this message and exit.
Commands:
  create
  delete
  get

Глагол первый — Cli Создать файл

Наш второй подход заключается в том, чтобы наш глагол cli был первым, например cli create file .

Этот подход немного сложнее, потому что мы не можем просто добавить команду create в нашу группу верхнего уровня cli, нам нужно их объединить. По этой причине мы можем написать вспомогательную функцию для команд слияния.

def merge_commands(group, command_collection:CommandCollection):
    """ Set the group's commands to those in the collection"""
    new_commands = {}
    command_sources = command_collection.sources
    for group in command_sources:
        for command_name,command in group.commands.items():
            new_commands[command_name] = command

    group.commands = new_commands
    return group

Для каждой команды верхнего уровня мы создадим набор команд, а затем передадим нашу группу, чтобы переопределить ее пустые команды.

Всякий раз, когда мы хотим добавить новый модуль (существительное) для команды, мы можем добавить его в наш параметр sources в CommandCollection init, а наша программа позаботится обо всем остальном! Команда cli для создания будет выглядеть примерно так.

cli create
Usage: cli create [OPTIONS] COMMAND [ARGS]...
Options:
  --help  Show this message and exit.
Commands:
  directory  Create directory
  file       Create file

Примечание. Вам необходимо создать группы глаголов (создать, получить, удалить) в main.py и подмодулях!

Вывод

И вот оно. В этом руководстве мы узнали, как масштабировать наш Python Click cli, разбив наши группы на модули и поддерживая два типа структур cli. По мере дальнейшего масштабирования вы столкнетесь с более интересными проблемами, и мне было бы интересно узнать о них по ходу дела.