忘却まとめ

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

. が階層を表す。
最初の . は、__init__.py ファイル直下の意味。

* は、サブモジュール内すべての要素を読み込む。これを使わずに特定の項目のみをインポートすることもできる。

from .hoge import *
from .boo import *
from .operators.op_moge import *
from .operators.op_goo import *

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

Blenderでは、サブモジュールは自動的に再読み込みできないため、毎回再起動する必要がある。
Blenderからのアドオン再読み込みでサブモジュールも更新するようにするには、アドオン側で読み込み方を変更する必要がある。

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

サブモジュールがロードされていれば再ロードする設定する、という読み込み方にする。
最後のelse で、最初の読み込ができるはずなのだが、うまくできないので、最初にアドオンを読み込むimportも書く。

# 普通に読み込む
from .hoge import *

if "bpy" in locals():
    import importlib
    if "hoge" in locals(): # hoge が既に読み込まれている場合、hogeを再読み込みする
        importlib.reload(hoge)

else:
    from .hoge import *

参考

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

-未分類
-, ,

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