忘却まとめ

Blenderの中級者・上級者向けの踏み込んだ情報や、アドオン・3DCGに関する情報を記事にします

【Blender】複数ファイル構成のアドオン開発での注意点【デバッグ用の再読み込み・アドオン設定の参照など】

Python

更新日:

アドオンを複数ファイル構成にする際の注意点をいくつか紹介する。

アドオンファイルは単一ファイル構成だとファイルの取り扱いが楽だが、膨大な行になってくると管理が大変になる。 ファイルを複数に分けると管理が楽になる。

メインのファイル以外の構成ファイルは、サブモジュールという模様。

メインのファイル名は __init__.py にする

最初に読み込まれるファイルの名前は、__init__.py にする。
これがメインのファイルになる。
ここにサブモジュールのインポートなどを書く。

分類する

構成は明確に分類できるならした方がよいが、扱いやすさも考慮する。
少ないファイル数でフォルダ分けしてもしょうがない。
下記のようなフォルダー分類は一般的な模様。

  • icons
  • operators
  • ui
  • utils

サブモジュールをインポートする

__init__.pyファイルの先頭付近で、サブモジュールをインポートする。

■ 例 下記のようなファイル構成の場合

  • __init__.py
  • hoge.py
  • boo.py
  • operatorsフォルダー
    • op_moge.py
    • op_goo.py
from .hoge import *
from .boo import *
from .operators.op_moge import *
from .operators.op_goo import *
  • . が階層を表す。
  • 最初の . は、__init__.py ファイル直下の意味。
  • * は、サブモジュール内すべての要素を読み込む。これを使わずに特定の項目のみをインポートすることもできる。

サブモジュールは再読み込みできない

複数ファイル構成のアドオンは、設定 → アドオン → 再読み込み や、アドオンのチェックボックスのオンオフでは、サブモジュールを再読み込みできない。
そのため、毎回再起動する必要がある

デバッグ作業が非常に手間になってしまう。

アドオン再読み込みでサブモジュールも更新するようにするには、アドオン側に読み込み方法を付け加える必要がある。

解決法 - 既にサブモジュールがロードされていれば、再読み込みさせる

importlib.reload() を使い、[script.reload] のオペレーターを実行すると、再読み込みすることができる。

importlib.reload() は、サブモジュールがロードされていれば再ロードする設定する、という読み込み方にする。

このオペレーターは、Blender2.8でも実行はできるが、キー設定されておらず、メニューからも実行できない隠されたものになったので注意。

注意点

このコードでは、深いフォルダー階層のファイルまでロードすることができない問題がある。
すべてルート階層に置けば正常に使用できる。

if "bpy" in locals():
	import importlib
	reloadable_modules = [ # リストに読み込むものをまとめる
	"keymap",
	"op_main",
	"ui_panel",
	"property",
	]
	for module in reloadable_modules: # リスト内のものがすでにあれば、reloadを発動する
		if module in locals():
			importlib.reload(locals()[module])

初回時に普通に読み込む
from .keymap import *
from .op_main import *
from .ui_panel import *
from .property import *

再読み込み実行時にエラーが出る場合

1つのアドオンでエラーが出ると、全てのアドオンの再読み込みが失敗する。
問題が出たら1つ1つ修正すること。
修正して再読み込みすれば、他のアドオンも読み込むことができる。

インデントや文法ミスの場合

アドオン設定から有効・無効のチェックをオン・オフすることで、上記のエラーの場合は確認することができる。

特定ファイルが読み込めない場合

特定ファイルに何らかの原因があり、読み込み失敗する場合がある。
この問題があるかどうかを確認するには、class読み込みを一旦全てコメントアウトし、半分ずつサブモジュール読み込みをコメントアウトして原因を探る。

参考

Pythonモジュールがインポートされると、ソースファイルが変更されたときにインタープリターによって(つまり、自動的に)再ロードされることはありません。

Blenderには、F8ショートカット(デフォルトのキーマップ内)によってトリガーされる、すべてのpyスクリプトをリロードするオペレーターがあります。

これで、登録済みのアドオン(およびスタートアップ/ UIスクリプト)のみがリロードされます。アドオンに__init__.pyアドオンファイルでそのような構成を使用して、自分でリロードを処理する必要があるサブモジュールがいくつか含まれている場合:

BlenderはPythonスクリプトの変更を無視します - stackovernet
https://blender.stackovernet.com/ja/q/6802

アドオン設定が参照できない

アドオン設定のプロパティを参照する時に、一般的には下記のようにするが、これをサブモジュールでやろうとするとエラーを吐いてしまう。
これは、__name__ が参照できないことが原因。

bpy.context.preferences.preferences.addons[__name__].preferences

解決法1 __package__ を使う

そのため、__name__の代わりに__package__を使う。
AddonPreferences クラス内での bl_idnameを、__package__にすること。

class HOGE_MT_preferences(bpy.types.AddonPreferences):
  bl_idname = __package__
bpy.context.preferences.preferences.addons[__package__].preferences

解決法2 name.partition(".")[0]

下記のようにする。
こちらはAddonPreferences クラス内で、 __name__から変える必要はない。

bpy.context.preferences.preferences.addons[__name__.partition(".")[0]].preferences

-Python
-, ,

Copyright© 忘却まとめ , 2019 All Rights Reserved Powered by STINGER.