--- vocab: developer-facing --- (command-text)= # コードの入力と実行 PME のコード欄へ Python を書くときの前提と、入力・実行の仕様をまとめています。対象は PME 2.1 です。 :::{important} 最初に:PME のコード欄は1行で書きます - **通常の Command / Custom とメニューの Poll は、1行のコードを入力します。** 短い処理には `;` や条件式を使います。 - **長い処理や再利用する処理は、外部の Python ファイルへ分けます。** PME の欄には `execute_script("scripts/my_action.py")` のような短い呼び出しを書きます。 AI がコードを生成する場合も、外部ファイルの複数行コードと、PME に貼る1行は分けて示してください。 ::: (code-input-limit)= AI 向け:通常スロットの Command / Custom は UTF-8 で1,024バイトまでです。超える処理は外部ファイルへ分けてください(Context Router の専用 Custom 欄は32,768文字まで)。 関数・変数と引数の仕様は [API リファレンス](scripting.rst)、メニューの利用条件は [Poll Method](poll_method.md) を参照してください。 (code-one-line)= ## コード欄には貼り付け用の1行を用意する 通常の Command / Custom とメニューの Poll には、短い処理を1行にして入力します。説明用に改行した Python を、そのまま貼り付ける形式にはしません。 | 書きたい処理 | 1行の形 | 注意点 | |---|---|---| | 単純な文を順番に実行 | `x = 1; print(x)` | `;` は実行順を作る。対話操作の終了待ちにはならない | | 条件によって値を選ぶ | `value_if_true if condition else value_if_false` | 各名前を実際の式に置き換える | | 条件を満たすときだけ実行 | `condition and action()` | 左側が真のときだけ右側を評価する | | Poll の結果を返す | `return C.mode == 'OBJECT'` | メニューの Poll 用。Command では使わない | `if` / `for` / `def` のブロックを、改行から `;` への置換だけで変換することはできません。処理が長い、ネストが深い、繰り返しや関数が必要な場合は {ref}`外部ファイル `へ分けます。 :::{dropdown} 複数行の操作履歴を取り込む場合 操作記録の取り込みには、オペレーター呼び出しや代入を抽出して1行にまとめる経路があります。任意の Python スクリプトをそのまま保存する機能ではありません。取り込み後の内容も確認してください。 ::: ## 設定先と実行タイミング | 設定先 | 評価されるとき | 書く内容 | |---|---|---| | Command | 項目を実行したとき | オペレーターの呼び出し、値の変更 | | Custom | UI を描画するとき。再描画で繰り返す | `L` を使う UI の配置。描画そのものではデータを変更しない | | メニューの Poll | メニューが利用できるかを調べるとき | 条件を読み、`return` で判定結果を返す。データを変更しない | | Property の Getter / Setter / Update | 値の取得・書き込み・更新時 | 役割ごとの処理。{ref}`コールバックの仕様 `を参照 | | `execute_script()` で呼ぶファイル | 呼び出し元が評価されたとき | 呼び出し元の役割に応じた処理。Custom から呼べば描画時に実行される | たとえば Custom に `bpy.ops.mesh.primitive_cube_add()` と書くと、描画時に追加処理を実行してしまいます。ボタンを置くなら `L.operator("mesh.primitive_cube_add")` を使います。 ## PME が用意する名前と、自分で用意する名前 PME のコード欄には便利な名前が用意されています。ただし、すべての設定先で 同じ値が揃うわけではありません。次の表は、Command / Custom と、そこから `execute_script()` で呼ぶファイルを読むための入口です。 | 名前 | 用途 | 前提・注意点 | |---|---|---| | `C` / `context` | その実行・描画で PME が提供するコンテキストを読む | `bpy.context` と同じオブジェクトとは限らない。対象のないメンバーは `None` の場合がある | | `bpy` | Blender の API を使う | 描画経路によって `bpy.context` の見え方を PME が調整する場合がある | | `D` | Blender のデータへのアクセス | `bpy.data` のショートカット。特定オブジェクトが存在する保証はない | | `O` | Blender のオペレーターを呼ぶ | `bpy.ops` のショートカット。呼び出し条件は省略されない | | `T` | Blender の型へのアクセス | `bpy.types` のショートカット | | `L` | 現在のレイアウトに UI 部品を描く | Custom など、レイアウトを受け取る描画時に使う。Command 用の操作対象ではない | | `E` | その処理に渡された入力イベントを調べる | イベントのない評価では名前自体が提供されない場合がある | | `U` | PME のセッション内で一時的な値を共有する | 保存先ではない。PME の再登録や Blender の再起動をまたぐ値に使わない | `pm`、`pmi`、`menu` などの名前は、設定先ごとの意味を確認してください。 たとえば Property のコールバックでの `menu` は Property ID です。 別のスロットの例をそのまま流用せず、[Property のコールバック](../editors/property_editor.md) の説明を使います。 外部ファイルで独自の関数、`mathutils.Vector`、他のモジュールを使う場合は、 そのファイル自身で定義・インポートします。PME が現在提供する名前と、 以前 Python Console に入力した変数を混同しないでください。 (external-command-script)= ## 外部ファイルを実行する 長い処理は通常の Python ファイルへ書き、PME から `execute_script()` で呼びます。次は、選択中のオブジェクト数を表示する例です。 **1. ファイルを置く** — [保存先とフォルダ構成](file_locations.md)にあるユーザースクリプトのフォルダへ、`selection_report.py` を保存します。 **ファイル本文(複数行):** ```python return_value = False def build_report(context, prefix): objects = getattr(context, "selected_objects", ()) or () return f"{prefix}: {len(objects)}" report = build_report(C, str(kwargs.get("prefix", "Selection"))) message_box(report) return_value = report ``` **2. 呼び出しを設定する** — パイメニューのスロット → **Command** に、次の1行を貼り付けます。 ```python execute_script("scripts/selection_report.py", prefix="Selected objects") ``` **3. 確認する** — 3D Viewport の Object Mode でオブジェクトを選び、この項目を実行します。選択数のメッセージが出ます。選択を外して実行すると `0` と表示されます。 ### ファイルの場所と引数 | 項目 | 意味 | |---|---| | `scripts/selection_report.py` | ユーザースクリプトのフォルダを先に検索し、なければ PME 付属のスクリプトを検索 | | その他の相対パス | アドオンのフォルダが基準。絶対パスも使用可能 | | `kwargs` | 呼び出しで渡した引数の辞書。`prefix` という変数が自動で作られるわけではない | | `__file__` | 実際に読み込んだファイルのパス | | `return_value` | `execute_script()` の戻り値。ファイル直下では `return` 文を使わず、これに代入する | 戻り値を使う場合は呼び出し側で変数へ代入します。戻り値は自動表示されないため、上の例では `message_box()` を呼んでいます。PME 2.1 ではファイル先頭のインポートや定義を、同じ実行で定義した関数からも参照できます。 外部ファイルに移しても、呼び出し元のコンテキストや評価タイミングは変わりません。設定をほかの環境へ渡す場合は、ファイルも一緒に用意します。 :::{dropdown} 戻り値を成功判定に使うとき `return_value` の既定値は `True` です。例外を捕捉した経路でもその値が返る場合があり、戻り値だけを汎用的な成功判定にはできません。例では冒頭に `False`、処理の最後に結果を設定しています。エラー出力と実際の結果も確認してください。この代入は、途中まで行ったデータ変更を取り消す仕組みではありません。 ::: (code-operator-context)= ## オペレーターの実行場所とタイミング `bpy.ops` の呼び出しには、引数だけでなく実行場所の条件があります。 同じ文字列でも、3D Viewport からの実行と Preferences 上のボタンでは結果が異なり得ます。 - 必要なエディターとリージョンにいるか。 - 必要なモードか。アクティブな対象と選択対象は揃っているか。 - 引数名と値が、使っている Blender のバージョンに存在するか。 - 操作をその場で確定するのか、マウスで調整する操作を始めるのか。 `EXEC_DEFAULT` は指定した値で実行する経路、`INVOKE_DEFAULT` はオペレーターの 開始処理を呼ぶ経路です。後者はダイアログやマウス操作に進む場合がありますが、 すべてのオペレーターが両方の使い方を提供するわけではありません。 詳しくは [Blender の Operator API](https://docs.blender.org/api/current/bpy.ops.html)を参照してください。 オペレーターが `RUNNING_MODAL` を返すと、ユーザーによる操作がまだ続いています。 その呼び出しの後ろに `;` で書いた Python が、操作の確定まで待つとは考えないでください。 ユーザーの調整を挟む手順には [Macro Operator](../editors/macro_operator_editor.md)も検討します。 コンテキストエラーのたびに、見つかった最初のエリアへ切り替えるコードを足すと、 意図しないビューで動く原因になります。まず本来のエディターから呼び出し、 ホットキーの範囲を確認します。別エリアを対象にする必要がある場合だけ、 対象の選び方と、見つからないときの動作を決めます。 ## エラーを切り分ける Blender の Python Console に入力したコードの結果と、PME の `print()` の出力先は 同じとは限りません。`print()` や Python の例外は、Blender の標準出力・エラー出力を 確認します。macOS では Blender を起動したターミナルなどが出力先になります。 | 症状 | 最初に確認すること | |---|---| | `NameError` | 必要な名前を、そのファイル内でインポート・定義しているか。`L` や `E` を使える設定先か | | `ModuleNotFoundError` | 依存モジュールが Blender の Python に存在するか。システムの Python に入れただけではないか | | `AttributeError` / `NoneType` | 対象なしの状態、オブジェクト型、プロパティ名、Blender のバージョン | | `poll() failed` | Blender オペレーターが要求するエディター、リージョン、モード、選択状態 | | コード末尾の構文エラー | 貼り付けたコードが元の内容と一致しているか | | Text Editor では動くが PME では動かない | 不足しているインポート、別の実行で残った変数、実行場所の違い | | 処理は進むが期待した結果にならない | `CANCELLED` などのオペレーター結果、対象の選び方、非同期の操作が続いていないか | 対象の状態だけを出力する短い Command を、本来使うエディターから呼ぶと、 エラーの起きる状態を絞れます。 ```python print("PME context:", getattr(C.area, "type", None), C.mode, C.active_object) ``` まず一つの処理で結果を確かめてから、分岐や連続操作を追加します。 データ変更を伴う場合は、対象がある場合・ない場合の両方と、Undo / Redo を確認します。 `;` で連続させたことや `EXEC_DEFAULT` を使ったことだけでは、 一つの Undo にまとまるとは限りません。履歴を見ずに `bpy.ops.ed.undo_push()` を 機械的に追加しないでください。 ## 関連するリファレンス - [コード例](scripting_workflow.md):設定先と貼り付けるコードから選ぶ。 - [API リファレンス](scripting.rst):関数・変数の仕様を調べる。 - [Public API](public_api.md):外部アドオンなどから PME を利用する。 - {ref}`一時的な値の共有 `:`U` と永続保存の使い分け。