LoginSignup
8
10

More than 5 years have passed since last update.

プラグインシステム的なものについて考える ~動的import~

Last updated at Posted at 2017-06-19

MayaとかPhotoshopとかで機能を追加するための『プラグイン』システムがありますが、
そういうのを自作のツールにも設けられないか、というメモです。

importlib

具体的には「importlib」モジュールを使います。

このモジュールの「import_module」関数に モジュール名 を文字列で渡すことで、

import hogehoge

という書き方によらないモジュールのインポートができます。
文字列を受け取ってくれるので、見つけたモジュールを随時代入しながらインポートさせられそうです。

使うのは import_module だけなので、このようにインポートして使います。

from importlib import import_module

(importという文字列の登場頻度の高さ。。。)

引っ掛かりポイント

1: 絶対パスで渡そうとする

てっきりPythonファイルを渡すものだと勘違いしており、このように書いていました。

pluginPath = 'path/to/plugin'

for plugin in os.listdir(pluginPath):
    mod_path = os.path.join(pluginPath,plugin)
    mod = import_module(mod_path,)

ダメでした。
モジュール名を渡すのです。
また、そのためにはプラグイン用Pythonファイルを置いている場所を
sys.path.appendに追加しておく必要があります。
かつ、見つけたPythonファイルも拡張子は除去しておく必要があります。
渡すのはモジュール名だけです。

pluginPath = 'path/to/plugin'
sys.path.append(pluginPath)

for plugin in os.listdir(pluginPath):
    mod_name = os.path.splitext(plugin)[0]
    mod = import_module(mod_name,)

これで、プラグインフォルダにPythonファイルを追加すればインポートしてくれるようになりました。

2: pycが邪魔

インポートしてくれるようになりましたが、
インポートできたらできたで、pyc作られます。読んでほしくありません。

# 前略

for plugin in os.listdir(pluginPath):
    split_name = os.path.splitext(plugin)
    if split_name[1] == '.pyc':
        continue
    mod = import_module(split_name[0],)

見つけたプラグイン分だけボタンを増やす

あとは見つけた分だけボタンを配置します。

plugin.py の仕様

仕様というほどでもありませんが、
プラグインの機能を利用するための関数をあらかじめお約束しておきます。
exec とか doIt とか run とかが考えられます。

また、ボタンに記載するラベルもモジュールに持たせておきましょう。

plugin.py

LABEL = 'create poly sphere'

"""
some your scripts...
"""

def exec():
    pass

# or

def doIt():
    pass

# or

def run():
    pass

#-----------------------------------------------------------------------------
# EOF
#-----------------------------------------------------------------------------

module_name.exec (など)をボタンにconnectします

ボタンへconnect

QPushButtonをつくり、.clicked.connect にさっき決めた実行用関数を渡します。

btn = QtGui.QPushButton( mod.LABEL )
btn.clicked.connect(mod.exec)

これを、モジュール読んでるfor文に加えます。

まとめ

import os
import sys

from PySide import QtCore, QtGui
from importlib import import_module

pluginPath = 'path/to/plugin'
sys.path.append(pluginPath)

for plugin in os.listdir(pluginPath):
    split_name = os.path.splitext(plugin)
    if split_name[1] == '.pyc':
        continue
    mod = import_module(split_name[0],)

    btn = QtGui.QPushButton( mod.LABEL )
    btn.clicked.connect(mod.exec)

こういう感じのをGUIつくってるスクリプトのどこかにいい具合にいれます

結局一番時間かかったのは
import_moduleに絶対パス渡そうとして「通らないなー」って唸ってたあたり
とpluginを pluing とタイポしてたあたり でした…。

ドキュメントよく読もう!


GUIの部分についてはこちらもどうぞ

参考?

8
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
10