Skip to content

PDM Plugins#

PDMは、コミュニティ主導のパッケージマネージャを目指しています。 フル機能のプラグインシステムとともに出荷され、次のことが可能です。

  • PDMの新しいコマンドの開発
  • 既存のPDMコマンドに追加オプションの追加
  • 追加の構成項目を読み込んでPDMの動作の変更
  • 依存関係の解決またはインストールのプロセスの制御

What should a plugin do#

コアPDMプロジェクトは、依存関係の管理とパッケージの公開に重点を置いています。PDMと統合したいその他の機能は、独自のプラグインに配置し、スタンドアロンのPyPIプロジェクトとしてリリースすることをお勧めします。プラグインがコアプロジェクトの優れた補足と見なされる場合は、PDMに吸収される可能性があります。

Write your own plugin#

以下のセクションでは、hello.nameconfigを読み取る新しいコマンドhelloを追加する例を示します。

Write the command#

PDMのCLIモジュールは、ユーザーが簡単に"継承および変更"できるように設計されています。新しいコマンドを記述するには、次の手順に従います。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from pdm.cli.commands.base import BaseCommand

class HelloCommand(BaseCommand):
    """Say hello to the specified person.
    If none is given, will read from "hello.name" config.
    """

    def add_arguments(self, parser):
        parser.add_argument("-n", "--name", help="the person's name to whom you greet")

    def handle(self, project, options):
        if not options.name:
            name = project.config["hello.name"]
        else:
            name = options.name
        print(f"Hello, {name}")

まず、pdm.cli.commands.base.BaseCommandから継承する新しいHelloCommandクラスを作成しましょう。これには2つの主要な機能があります。

  • add_arguments()は、唯一の引数として渡された引数パーサーを操作します。このパーサーには、追加のコマンドライン引数を追加できます。
  • handle()は、サブコマンドが一致したときに何かを実行しますが、単一のpassステートメントを記述しても何も実行できません。2つの引数を受け入れます。最初の引数としてpdm.project.Projectオブジェクト、2番目の引数として解析されたargparse.Namespaceオブジェクトです。

ドキュメント文字列は、pdm--helpに表示されるコマンドのヘルプテキストとして機能します。

If you don't want these default options, override the arguments class attribute to a list of pdm.cli.options.Option objects, or assign it to an empty list to have no default options:

さらに、PDMのサブコマンドには2つのデフォルトオプションがあります。冗長性レベルを変更するための-v/--verboseと、グローバルプロジェクトを有効にするための-g/--globalです。これらのデフォルトオプションが不要な場合は、argumentsクラス属性をpdm.cli.options.Optionオブジェクトのリストにオーバーライドするか、デフォルトオプションを持たないように空のリストに割り当てます。

1
2
3
class HelloCommand(BaseCommand):

    arguments = []

Note

最初にデフォルトのオプションがロードされてからadd_arguments()が呼び出されます。

Register the command to the core object#

プラグインプロジェクトのどこかに関数を記述します。関数の名前に制限はありませんが、引数は1つだけ(PDMコアオブジェクト)です。

1
2
def hello_plugin(core):
    core.register_command(HelloCommand, "hello")

Call core.register_command() to register the command. The second argument as the name of the subcommand is optional. PDM will look for the HelloCommand's name attribute if the name is not passed.

Add a new config item#

コマンドを登録するにはcore.register_command()を呼び出してください。サブコマンドの名前としての2番目の引数はオプションです。名前が渡されない場合、PDMはHelloCommandname属性を検索します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class HelloCommand(BaseCommand):
    """Say hello to the specified person.
    If none is given, will read from "hello.name" config.
    """

    def add_arguments(self, parser):
        parser.add_argument("-n", "--name", help="the person's name to whom you greet")

    def handle(self, project, options):
        if not options.name:
            name = project.config["hello.name"]
        else:
            name = options.name
        print(f"Hello, {name}")

You need to register the config item, too:

これまでは、pdm config get hello.nameで構成値を照会すると、有効な構成キーではないというエラーがポップアップ表示されていました。構成項目も登録する必要があります。

1
2
3
4
5
from pdm.project.config import ConfigItem

def hello_plugin(core):
    core.register_command(HelloCommand, "hello")
    core.add_config("hello.name", ConfigItem("The person's name", "John"))

ここで、ConfigItemクラスは次の順序で4つのパラメータを取ります。:

  • description:config項目の説明
  • default:config項目のデフォルト値
  • global_only:configがホームconfigにのみ設定できるかどうか
  • env_var:config値として読み込まれる環境変数の名前

Other plugin points#

コマンドと設定に加えて、coreオブジェクトはオーバーライドするための他のメソッドと属性を公開します。PDMには、聴くことができるいくつかのシグナルも用意されています。詳細については、API referenceを参照してください。

Tips about developing a PDM plugin#

プラグインを開発する場合、開発中にプラグインを有効にし、コードが変更されたときに更新されることを期待します。

これは、プラグインを編集可能モードでインストールすることで実現できます。これを行うには、tool.pdm.plugins配列で依存関係を指定します。:

1
2
3
4
[tool.pdm]
plugins = [
    "-e file:///${PROJECT_ROOT}"
]

次のようにしてインストールします。:

1
pdm install --plugins

その後、プラグイン自体を含むすべての依存関係がプロジェクトプラグインライブラリで編集可能モードで使用できるようになります。これは、コードベースへの変更が再インストールなしですぐに有効になることを意味します。pdm実行可能ファイルも内部でPythonインタプリタを使用するので、プラグインプロジェクト内からpdmを実行すると、開発中のプラグインが自動的にアクティブになり、その動作を確認するためのテストを行うことができます。

Testing your plugin#

PDMは、pdm.pytestモジュールのプラグインとして、いくつかのpytestフィクスチャを公開しています。これらを利用するには、テスト依存関係としてpdm[pytest]を追加する必要があります。

テストでそれらを有効にするには、プラグインとしてpdm.pytestを追加します。これは、ルートconftest.pyで行うことができます。

conftest.py
1
2
3
4
5
6
7
8
9
# single plugin
pytest_plugins = "pytest.plugin"

# many plugins
pytest_plugins = [
    ...
    "pdm.pytest",
    ...
]

PDM独自のtests、特に設定用のconftest.py fileの使用例を見ることができます。

詳細については、pytest fixtures documentationを参照してください。

Publish your plugin#

プラグインをすでに定義したので、PyPIに配布しましょう。PDMのプラグインは、エントリポイントのタイプによって検出されます。pdmエントリポイントを作成し、プラグインの呼び出し可能なオブジェクトを指定します(関数である必要はありません。呼び出し可能なオブジェクトであれば動作します)。

PEP 621:

1
2
3
4
# pyproject.toml

[project.entry-points.pdm]
hello = "my_plugin:hello_plugin"

setuptools:

1
2
3
4
5
6
7
# setup.py

setup(
    ...
    entry_points={"pdm": ["hello = my_plugin:hello_plugin"]}
    ...
)

Activate the plugin#

プラグインはエントリポイントを介してロードされるため、プラグインをインストールするだけでアクティブ化できます。PDMには、プラグインを管理するためのpluginコマンドグループが用意されています。

プラグインがpdm-helloとして公開されていると仮定します。:

1
pdm self add pdm-hello

ターミナルでpdm --helpと入力すると、新しく追加されたhelloコマンドが表示され、それを使用します。

1
2
$ pdm hello Jack
Hello, Jack

端末でpdm self --helpと入力して、プラグイン管理サブコマンドを表示します。

Specify the plugins in project#

プロジェクトに必要なプラグインを指定するには、pyproject.tomlファイルのtool.pdm.plugins構成を使用します。これらの依存関係は、pdm install --pluginsを実行してプロジェクトプラグインライブラリにインストールできます。プロジェクトプラグインライブラリは、後続のPDMコマンドでロードされます。

これは、同じプラグインセットをコントリビュータと共有する場合に便利です。

1
2
3
4
5
# pyproject.toml
[tool.pdm]
plugins = [
    "pdm-packer"
]

プラグインをインストールしてアクティブにするには、pdm install --pluginsを実行します。

または、編集可能なローカル依存関係を使用して、PyPIにパブリッシュされないプロジェクトローカルプラグインを作成することもできます。:

1
2
3
4
5
# pyproject.toml
[tool.pdm]
plugins = [
    "-e file:///${PROJECT_ROOT}/plugins/my_plugin"
]