[python] invokeのtasks.pyをVSCodeでデバッグする
invokeのタスク(tasks.py
)をVSCodeでデバッグしたかったのでやりかたの備忘録
参考:
最初にかんたんまとめ
- 必要な拡張機能入れる(Python拡張入れとけば十分)
- launch.jsonの
module
にinvoke
を記述する, argsで呼び出したいtask名を指定するlaunch.json{ "version": "0.2.0", "configurations": [ { "name": "Debug invoke task: my-task", "type": "debugpy", "request": "launch", "module": "invoke", "args": ["my-task"], "cwd": "${workspaceFolder}" } ] }
- パラメータを可変にしたければ
inputs
をlaunch.jsonに定義する
debugpy使ってデバッグ
debugpyを起動しておいて、VSCodeのデバッガを起動するとdbugpyにアタッチするような構成にする
0. 準備
- VSCodeでPython Debugger拡張入れておく
- python拡張を入れるとPylanceと一緒に自動でインストールされる
- debugpyとinvokeをインストール
pip install debugpy invoke
1. launch.jsonに構成追加
launch.json
に以下を追記
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug invoke task",
"type": "debugpy",
"request": "attach",
"connect": {
"host": "localhost",
"port": 5678
},
}
]
}
2. debugpy起動してinvoke呼び出す
$ python -m debugpy --wait-for-client --listen 5678 -m invoke my-task
--wait-for-client
でVSCodeがattachするのを待ってくれる
3. VSCodeのデバッグを実行
VSCodeの「実行とデバッグ」から前段で作った構成("Debug invoke task")を選択してデバッグを開始(F5)すると
3で起動したdebugpyのプロセスにアタッチされる
invokeのtask.pyでブレークポイントが設定されていればそこで止まってくれる
改良
まいどCLIでdebugpyを呼び出すのは大変。なので,VSCodeのTaskでdebugpyを起動させ、その後デバッグを自動で実行させる
tasks.json
{
"version": "2.0.0",
"tasks": [
{
"label": "pre launch: invoke my-task",
"type": "shell",
"command": "python -m debugpy --wait-for-client --log-to-stderr --listen 5678 -m invoke my-task",
"isBackground": true,
"problemMatcher": {
"owner": "custom",
"pattern": {
"regexp": "^$"
},
"background": {
"activeOnStart": true,
"beginsPattern": ".*",
"endsPattern": "wait_for_client()"
}
}
}
]
}
--log-to-stderr
をつけておくとログ出力をしてくれて、クライアントの呼び出し準備が完了すると末尾に"wait_for_client()"と出力されるのでそれを機にバックグラウンドに移行するようにする
launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug invoke task: my-task",
"type": "debugpy",
"request": "attach",
"connect": {
"host": "localhost",
"port": 5678
},
"preLaunchTask": "pre launch: invoke my-task", // これを追記
}
]
}
preLaunchTask
で作成したタスクを指定する。
これでデバッグ実行するとまずタスクが呼び出されてdebugpy起動した後にデバッグ実行がアタッチしてくれる
最終形
こんなことしなくとも launch.jsonでmodule
を指定すればよかった
Provides the ability to specify the name of a module to be debugged, similarly to the -m argument when run at the command line. For more information, see Python.org
要するにlaunch.jsonでmodule
にinvoke
と指定すればdebugpy -m invoke
と同等のことをVSCode側が良しなにやってくれる
これによりpreLaunchTask
でtaskを実行する必要がなくなった
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug invoke task: my-task",
"type": "debugpy",
"request": "launch",
"module": "invoke",
"args": ["my-task"],
"cwd": "${workspaceFolder}"
}
]
}
さらに任意のinvoke taskやパラメータを指定できるようにする
tasks.pyは以下のように書くとする
from invoke.collection import Collection
from invoke.tasks import task
@task
def my_task_a(c):
print("my task a")
@task
def my_task_b(c):
print("my task b")
@task
def my_task_c(c, name):
print(f"my task c with {name}")
@task
def main(c, task_name, param=None):
if task_name == "my-task-a":
my_task_a(c)
elif task_name == "my-task-b":
my_task_b(c)
elif task_name == "my-task-c" and param:
my_task_c(c, name=param)
else:
print(f"No idea what '{task_name}' is!")
namespace = Collection()
namespace.add_task(main) # type: ignore
my-task-a
~my-task-c
を指定して実行するのではなく、常にmain
タスクを呼び出して
その引数で個別のどのタスクを実行するのか指定する
{
// IntelliSense を使用して利用可能な属性を学べます。
// 既存の属性の説明をホバーして表示します。
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python デバッガー: モジュール",
"type": "debugpy",
"request": "launch",
"module": "invoke",
"args": ["main", "--task-name=${input:task_name}", "--param=${input:any_param}"],
"cwd": "${workspaceFolder}"
}
],
"inputs": [
{
"type": "pickString",
"description": "select task",
"id": "task_name",
"options": [
"my-task-a",
"my-task-b",
"my-task-c"
]
},
{
"type": "promptString",
"description": "any parameter",
"id": "any_param",
"default": ""
}
]
}
共通のtask main
を先にかましてるのはパラメータを統一しとかないと呼びわけが難しそうだったから
まとめ
- VSCodeがdebugpyを使って裏でよしなにやってくれてる流れが理解できた
- ちなみにpytest使ってるときにデバッグするときはカバレッジ計測オフにしないとブレークポイント止まってくれないので注意
Discussion