Make組ブログ

Python、Webサービスや製品開発、ライブラリー開発についてhirokikyが書きます

invokeで実行されるコマンドをプロジェクトルートから実行する方法

invoke(pyinvoke)というプロジェクト管理用のツールを使っていたときに出た疑問の解決方法を説明します。 とはいえ、私自身もまだこの方法で良いのか疑問なので、より良い方法を知っている人はぜひ教えてください。

invoke(pyinvoke)とは

プロジェクトでの開発を進める際に、よくあるコマンド操作をまとめておくことがよくあります。 例えば不要なファイルを削除したり、フォーマッターを適用したり、本番用にビルドしたりなどがあります。 invoke(pyinvoke)を使うとPythonでシェルでのコマンド操作を簡単に書けるようになります。

www.pyinvoke.org

invokeでプロジェクトルートから実行する

invoke でコマンドを実行(c.run(...))するときは、invoke ... を実行したパスでコマンドが実行されます。 invoke のタスクを定義したファイルは以下のように走査されますが、実行パスは変わりません。

docs.pyinvoke.org

ですが、例えばフォーマッターを全体に適応したいときなどはプロジェクトルートからコマンドを実行したくなります。 例えば以下のようなプロジェクト構成のとき、 mymodule 以下で invoke ... としても、 tasks.py を含むディレクトリーから実行したいときです。

+- tasks.py
+- setup.py
+- mymodule
    +- foo.py
    +- bar.py

そういう場合は、以下のように tasks.py を書くと良いでしょう。

import os

from invoke import task


HERE = os.path.dirname(__file__)


@task
def mytask(c):
    c.run("...")

こうすると、 invoke mytask はプロジェクトルート(tasks.py を含むディレクトリー)で実行されます。 私はプロジェクト全体のフォーマットを整えるタスクに活用しています。

@task
def format(c):
    c.run("black .")
    c.run("isort -rc .")

このプロジェクトルートから実行する方法については、invokeのドキュメントやIssueを調べても良い回答は見つかりませんでした。 唯一近そうなのがこのIssueでした。

github.com

もしより良い方法を知っている方がいれば教えてください。