Poetrypoet

Теги: cli  pip  python 

Features

  • Прямое объявление задач проекта в вашем pyproject.toml (что-то вроде сценариев npm)
  • Задача запускается в виртуальной среде poetry (или в другой указанной вами среде)
  • Имена задач в shell (а также глобальные параметры для zsh)
  • Может использоваться отдельно или как плагин
  • Задачи могут быть командами (с оболочкой или без нее) или ссылками на функции Python (например, tool.poetry.scripts)
  • Короткие команды с дополнительными аргументами, переданными в пакет задач [options] task [task_args], или вы можете явно определить аргументы
  • Задачи могут указывать и ссылаться на переменные среды, как если бы они были запущены в командной облочке
  • Задачи самодокументируются, с необязательными справочными сообщениями (просто запустите poe без аргументов)
  • Задачи могут быть определены как последовательность других задач
  • Работает с файлами .env
  • Можно использовать автокомплишен по tab для bash, zsh, fish

How to use

[tool.poe.tasks]
test   = "pytest --cov=poethepoet"                                # simple command based task
serve  = { script = "my_app.service:run(debug=True)" }            # python script based task
tunnel = { shell = "ssh -N -L 0.0.0.0:8080:$PROD:8080 $PROD &" }  # (posix) shell based task

poe test просто запустить или добавить дополнительные аргументы poe test -v tests/favorite_test.py -> pytest --cov=poethepoet -v tests/favorite_test.py

Типы тасков

Command task

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

[tool.poe.tasks]
format = "black ."  # strings are interpreted as commands by default
clean = """
# Multiline commands including comments work too. Unescaped whitespace is ignored.
rm -rf .coverage
       .mypy_cache
       .pytest_cache
       dist
       ./**/__pycache__
"""
lint = { "cmd": "pylint poethepoet" }  # Inline tables with a cmd key work too
greet = "echo Hello $USER"  # Environment variables work, even though there's no shell!

Script tasks

Содержат ссылку на python, вызываемый для импорта и выполнения

[tool.poe.tasks]
fetch-assets = { "script" = "my_package.assets:fetch" }
fetch-images = { "script" = "my_package.assets:fetch(only='images', log=environ['LOG_PATH'])" }

Подмножество синтаксиса, операторов и глобальных переменных Python может использоваться встроенно для определения аргументов функции с использованием обычного синтаксиса Python, включая environ (из пакета os) для доступа к переменным среды, которые доступны для задачи. Если дополнительные аргументы передаются задаче в командной строке (и аргументы CLI не объявлены), они будут доступны в вызываемой функции python через sys.argv.

Shell task

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

[tool.poe.tasks]
pfwd = { "shell" = "ssh -N -L 0.0.0.0:8080:$STAGING:8080 $STAGING & ssh -N -L 0.0.0.0:5432:$STAGINGDB:5432 $STAGINGDB &" }
pfwdstop = { "shell" = "kill $(pgrep -f "ssh -N -L .*:(8080|5432)")" }

По умолчанию poe пытается найти в системе оболочку posix (sh, bash или zsh именно в таком порядке) и использует ее. При работе в Windows это не всегда возможно. Если bash не найден по пути в Windows, то poe будет явно искать Gitbash в обычном месте.

Можно задать другие shell-интерпретаторы через interpreter = ["posix", "pwsh"]

Кроме того, можно можно задать python код как шелл-таск.

[tool.poe.tasks.time]
shell = """
from datetime import datetime

print(datetime.now())
"""
interpreter = "python"

Composite task

Определяются как последовательность других задач в виде массива. По умолчанию содержимое массива интерпретируется как ссылки на другие задачи (фактически тип задачи ref), хотя это поведение можно изменить, установив глобальную опцию default_array_item_task_type на имя другого типа задачи, например cmd, или установив default_item_type параметр локально в задаче последовательности.

[tool.poe.tasks]

test = "pytest --cov=src"
build = "poetry build"
_publish = "poetry publish"
release = ["test", "build", "_publish"]

Префикс _ не включается в документацию и не исполняется непосредственно, а используется для ссылки на другие задачи.

Другой вариант записи:

release = [
  { cmd = "pytest --cov=src" },
  { script = "devtasks:build" },
  { ref = "_publish" },
]

Еще

[tool.poe.tasks]

  [[tool.poe.tasks.release]]
  cmd = "pytest --cov=src"

  [[tool.poe.tasks.release]]
  script = "devtasks:build"

  [[tool.poe.tasks.release]]
  ref = "_publish"

Task level configuration

Можно задавать текст подсказок

[tool.poe.tasks]
style = {cmd = "black . --check --diff", help = "Check code style"}

Переменные окружения

[tool.poe.tasks]
serve.script = "myapp:run"
serve.env = { PORT = "9001" }

Можно использовать .env файлы

[tool.poe.tasks]
serve.script  = "myapp:run"
serve.envfile = ".env"

Также можно ссылаться на существующие переменные окружения при определении новой переменной окружения для задачи.

[tool.poe.tasks.serve]
serve.cmd = "flask run"
serve.env   = { FLASK_RUN_PORT = "${TF_VAR_service_port}" }

Declaring CLI arguments

По умолчанию дополнительные аргументы, передаваемые в интерфейс командной строки poe после имени задачи, добавляются в конец задачи cmd или отображаются как sys.argv в задаче сценария (но вызовут ошибку для задач оболочки или последовательности задач). В качестве альтернативы можно определить именованные аргументы, которые должна принимать задача, которые будут задокументированы в справке для этой задачи и представлены в задаче таким образом, который наиболее целесообразен для этого типа задачи.

  • positional arguments which are provided directly following the name of the task like poe task-name <arg-value>
  • option arguments which are provided like poe task-name --option-name <arg-value>
  • flags which are either provided or not, but don’t accept a value like poe task-name --flag

Именованные аргументы настраиваются путем объявления параметра задачи args как массива или подтаблицы.

[tool.poe.tasks.serve]
cmd = "myapp:run"
args = ["host", "port"]

poe serve --host 0.0.0.0 --port 8001

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

[tool.poe.tasks.serve]
cmd = "myapp:run"
args = [{ name = "host", default = "localhost" }, { name = "port", default = "9000" }]

Можно использовать toml синтаксис

[tool.poe.tasks.serve]
cmd = "myapp:run"
help = "Run the application server"

  [[tool.poe.tasks.serve.args]]
  name = "host"
  options = ["-h", "--host"]
  help = "The host on which to expose the service"
  default = "localhost"

  [[tool.poe.tasks.serve.args]]
  name = "port"
  options = ["-p", "--port"]
  help = "The port on which to expose the service"
  default = "8000"

или так

[tool.poe.tasks.serve]
cmd = "myapp:run"
help = "Run the application server"

  [tool.poe.tasks.serve.args.host]
  options = ["-h", "--host"]
  help = "The host on which to expose the service"
  default = "localhost"

  [tool.poe.tasks.serve.args.port]
  options = ["-p", "--port"]
  help = "The port on which to expose the service"
  default = "8000"

Task args options:

  • default : Union[str, int, float, bool]
  • help : str
  • name : str
  • options : List[str]
  • positional : bool
  • required : bool
  • type : str

Для задач cmd и оболочки значения предоставляются задаче как переменные среды

[tool.poe.tasks.passby]
shell = """
echo "hello $planet";
echo "goodbye $planet";
"""
help = "Pass by a planet!"

  [[tool.poe.tasks.passby.args]]
  name = "planet"
  help = "Name of the planet to pass"
  default = "earth"
  options = ["-p", "--planet"]

poe passby --planet mars

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

[tool.poe.tasks]
build = { script = "project.util:build", args = ["dest", "version"] }
[tool.poe.tasks]
build = { script = "project.util:build(dest, build_version=version, verbose=True)", args = ["dest", "version"]

Аргументы могут быть переданы задачам, на которые ссылается задача последовательности

[tool.poe.tasks]
build = { script = "util:build_app", args = [{ name = "target", positional = true }] }

[tool.poe.tasks.check]
sequence = ["build ${target}", { script = "util:run_tests(environ['target'])" }]
args = ["target"]

Project-wide configuration options

Global environment variables

В tool.poe.env

[tool.poe.env]
VAR1 = "FOO"
VAR2 = "BAR BAR BLACK ${FARM_ANIMAL}"

Можно задать дефолт, если переменная не указана

# .env
STAGE=dev
PASSWORD='!@#$%^&*('

[tool.poe.env]
VAR1.default = "FOO"

Можно использовать .env

[tool.poe]
envfile = ".env"

Default command verbosity

Run poe from anywhere

Change the default task type

Change the executor type

  • auto: to automatically use the most appropriate of the following executors in order
  • poetry: to run tasks in the poetry managed environment
  • virtualenv: to run tasks in the indicated virtualenv (or else “./.venv” if present)
  • simple: to run tasks without doing any specific environment setup
[tool.poe.executor]
type = "virtualenv"
location = "myvenv"

Change the default shell interpreter

Load tasks from another file

В некоторых сценариях может потребоваться определить задачи вне pyproject.toml. Например, если вы хотите распределять задачи между проектами через модули git, динамически генерировать определения задач или просто иметь много задач и не хотите, чтобы pyproject.toml стал слишком большим. Этого можно достичь, создав файл toml или json в структуре каталогов вашего проекта, включая ту же структуру для задач, которая используется в pyproject.toml.

Еще:

  • Usage as a poetry plugin
  • Usage without poetry

Еще ссылки: