Рубрики
Без рубрики

Инструменты командной строки в Python с Typer и Pytest: подсказки типа полезны

С Typer вы можете написать инструменты командной строки в Python интуитивно и легко. В то же время, введите … с меткой Python, Pytest, Typer, командной строкой.

С Тайпер , вы можете написать инструменты командной строки в Python, интуитивно и легко. В то же время Тайпер достаточно гибкий, чтобы справиться с сложности, брошенной на него.

Тип подсказки

Среди командной линии помощников библиотеки для Python (например, argparse и Нажмите ), Тайпер уникален в использовании Тип подсказки Анкет

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

Несмотря на необязательное, Python поддерживает подсказки статического типа. Другими словами, я могу написать my_variable: Намекнуть на это my_variable Всегда должно быть целым числом. Как это использовать? Инструмент mypy Можно запустить на модулях и пакетах Python, чтобы выручить проблемы или подтвердить вашу удивительность.

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

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

Создайте проект и добавьте модуль

Чтобы управлять проектом, я использую поэзию. Поэзия является зрелым и современным инструментом для управления проектом Python и его зависимостей. Вам может понравиться чтение Мое введение в поэзию а также краткое Объяснение использования поэзии для разоблачения сценариев командной строки в вашем проекте.

Вам, конечно, не нужно использовать поэзию для построения и поддержания проекта. Я рекомендую рассматривать ваш проект как пакет Python и использовать виртуальные среды. Не стесняйтесь просматривать мой Демонстрация и обзор инструментов для управления виртуальными средами Анкет Что касается упаковки проекта Python традиционным способом, используя setup.py , не поэзия, вам может понравиться Моя среда Python Dev Intro Анкет

Чтобы создать проект с поэзией, что -то подобное должно работать:

poetry new --name greet --src typergreet
cd typergreet

Обратите внимание, что в этом случае я называю внутренний пакет приветствовать Но каталог проектов назван Typergreet Анкет

Вам не нужно использовать SRC Структура для вашего пакета, но я использую его по причинам Анкет

Затем я добавляю файл с именем Greet.py в SRC/Greet подкаталог со следующим содержанием:

"""Send greetings."""

import time

import arrow  # type: ignore


def greet(tz: str, repeat: int = 1, interval: int = 3) -> None:
    """Parse a timezone and greet a location a number of times."""
    for i in range(repeat):
        if i > 0:  # no delay needed on first round
            time.sleep(interval)
        now = arrow.now(tz)
        friendly_time = now.format("h:mm a")
        seconds = now.format("s")
        location = tz.split("/")[-1].replace("_", " ")
        print(f"Hello, {location}!")
        print(f"The time is {friendly_time} and {seconds} seconds.\n")

Обратите внимание на подсказки типа по каждому параметру функции, а также возвращаемое значение. Потому что в этой функции нет возврата (позор!) Возвратный тип Нет Анкет

Установить зависимости

Нам нужно Стрелка и будет использовать Тайпер , поэтому они должны быть добавлены сейчас:

poetry add arrow typer[all]

Это даст нам стрелу, плюс Тайпер со всеми наворотами. Если вы не хотите расцветать вывод и обнаружение оболочки, вы можете опустить [Все] Анкет

Мы используем подсказки типа, поэтому мы также хотим mypy , но как Развитие зависимость. С Поэзия добавить , это означает передачу флаг:

poetry add -D mypy

Проверьте подсказки типа

Чтобы убедиться, что у нас есть правильные подсказки типа, и код считает их, запустите mypy :

poetry run mypy src/greet/greet.py

Проблемы не обнаружено? Превосходно.

При импорте этого пакета, даже при проведении тестов позже, мы захотим знать, что это тип намекает. Для этого создайте пустой py.typed Файл в пакете. Есть много способов сделать это (даже с вашим текстовым редактором). Это работает в Bash и PowerShell:

echo "" | tee ./src/greet/py.typed

Добавить конечную точку сценария в pyproject.toml

Разоблачить Приветствую Функция как сценарий командной строки, добавьте Tool.poetry.scripts раздел к pyproject.toml Анкет

[tool.poetry.scripts]
greet = "greet.greet:greet"

Это устанавливает приветствовать (скрипт), чтобы посмотреть в Приветствую (пакет) для Приветствую (модуль) и используйте приветствовать (функция). Если у вас больше творчества для именования, сделайте это.

Теперь, когда сценарий настроен, установите пакет и сценарий с помощью

poetry install

Теперь давайте запустим недавно установленный скрипт:

$ poetry run greet
Traceback (most recent call last):
  File "", line 1, in 
TypeError: greet() missing 1 required positional argument: 'tz'

Неудача – это путь к обучению. И мы учимся.

Использование аргументов командной строки Typer для анализа командной строки

Нам нужен способ проанализировать аргументы командной строки и передать их в качестве параметров функции. Тайпер Обнаружает типовые подсказки и выясняет аргументы и параметры командной строки соответственно.

Вот исходная функция, с добавлением Тайпера:

"""Send greetings."""

import time

import arrow  # type: ignore
import typer

app = typer.Typer()


@app.command()
def greet(tz: str, repeat: int = 1, interval: int = 3) -> None:
    """Parse a timezone and greet a location a number of times."""
    for i in range(repeat):
        if i > 0:  # no delay needed on first round
            time.sleep(interval)
        now = arrow.now(tz)
        friendly_time = now.format("h:mm a")
        seconds = now.format("s")
        location = tz.split("/")[-1].replace("_", " ")
        print(f"Hello, {location}!")
        print(f"The time is {friendly_time} and {seconds} seconds.\n")


def run() -> None:
    """Run commands."""
    app()

Что изменилось? Мы создали создание приложения Typer во всем мире с приложение. Typer () Анкет Таким образом, мы можем украсить любую функцию, которую мы хотим вызывать из командной строки, используя @app.command () декоратор.

Затем нам нужно было добавить командный бегун, чтобы выполнить приложение Typer. Это то, что run () функция выполняет.

Учитывая, что мы изменили точку записи сценария с Приветствую к запустить , это должно быть уточнено в pyproject.toml Анкет Итак, необходимо следующее изменение:

[tool.poetry.scripts]
greet = "greet.greet:run"

Теперь запустить это функция, которую Приветствую Команда будет указывать, а не Приветствую Анкет

Со всем этим на месте у нас есть интерфейс рабочей командной строки.

$ poetry run greet --help
Usage: greet [OPTIONS] TZ

  Parse a timezone and greet a location a number of times.

Arguments:
  TZ  [required]

Options:
  --repeat INTEGER      [default: 1]
  --interval INTEGER    [default: 3]
  --install-completion  Install completion for the current shell.
  --show-completion     Show completion for the current shell, to copy it or
                        customize the installation.

  --help                Show this message and exit.
$
$ poetry run greet --repeat 2 --interval 1 Africa/Johannesburg
Hello, Johannesburg!
The time is 1:06 pm and 38 seconds.

Hello, Johannesburg!
The time is 1:06 pm and 39 seconds.

Какой у нас вежливый и информированный инструмент командной строки.

Примечание. Дополнительные функции Typer добавляет по умолчанию: -Хельп С описаниями, детализирующими аргументы и параметры, и возможность добавлять завершение оболочки, если пользователь желает.

Тестирование интерфейсов Typer с pytest

Интерфейсы тестирования командной строки могут потребовать небольшого творчества. К счастью, Тайпер предоставляет Clirunner , бегун командной строки для тестирования. Если вы знакомы с Нажмите , он очень похож на Clirunner’s Clirunner. (Не удивительно, так как клик является зависимостью Тайпера.)

Поместите следующее в файле tests/test_greet.py

from typer.testing import CliRunner

from greet.greet import app


def test_greet_cli():
    runner = CliRunner()
    result = runner.invoke(app, ["Europe/Madrid"])
    assert result.exit_code == 0
    assert "Hello, Madrid!" in result.output

Запустите вышеприведенное с Поэзия запустить pytest Анкет

Тест проходит?

Счастье.

Альтернативы и дальнейшее чтение

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

  • Можно проанализировать ваши собственные аргументы командной строки через Список предоставил sys.argv , как мы делали в ранее упомянутых Поэзия/CLI статья Анкет
  • Тем не менее, собственная библиотека Python’s Standard Argparse обеспечивает гораздо лучшую функциональность, простоту и эффективность. Я написал статью, похожую на эту, о Использование поэзии, Argparse и Pytest Анкет
  • Я также написал краткие введения в следующие библиотеки командной строки:
    • Питон Огнен
    • Нажимать
  • Я слышал отличные отзывы о Plumbum и Клео , но еще не попробовали их
  • Для совершенно другого способа определения интерфейсов командной строки попробуйте docopt Анкет Определите интерфейсы в ваших докторах. Это не часто поддерживается, так что есть вилка docopt-ng .

Наслаждайтесь командной строкой!

Оригинал: “https://dev.to/bowmanjd/command-line-tools-in-python-with-typer-and-pytest-type-hints-are-useful-khg”