Skip to content

refactor: ID 型ターゲットのパラメータ化(宣言テーブル化) - #6

Merged
Pluglug merged 2 commits into
mainfrom
refactor/id-target-parameterization
Jul 2, 2026
Merged

refactor: ID 型ターゲットのパラメータ化(宣言テーブル化)#6
Pluglug merged 2 commits into
mainfrom
refactor/id-target-parameterization

Conversation

@Pluglug

@Pluglug Pluglug commented Jun 12, 2026

Copy link
Copy Markdown
Owner

発注書 #3(dev-note/orders/2026-06-13-id-target-parameterization.md)の成果物。

結果サマリー

識別子6個以外完全同一だった ID 型ターゲット10ファイル(material / mesh / armature / action / camera / light / curve / scene / texture / image、各60行 = 600行)を targets/id_datablock.py 1ファイルに畳んだ。

  • 同一クラスタ: 600行 → 189行(id_datablock.py 178行 = 共通基底 IDDatablockTarget 約68行 + 宣言テーブル(属性6個だけの class 文10連)約110行、material.py 互換シム 11行)。targets/ 全体で -413行(284 insertions / 697 deletions)
  • 型判定の三重化を1箇所に集約: 判定の情報源はクラス属性(ol_type / ol_idcode)のみ。can_create_from_scope が唯一の判定実装で、create_from_scope はそこへ委譲。10ファイルにあった TSE_SOME_ID / ID_MA 等のリテラル再出現はゼロに
  • object / collectionIDDatablockTarget を継承して create_namespace を共通化しつつ、固有の収集経路(VIEW3D 選択 / View Layer フォールバック)を持つスコープ判定2メソッドは verbatim に保持
  • 挙動同一性の実証: レジストリの3インデックス(bl_type / ol_type / ol_idcode)+ 登録順 + namespace_key を実機 Blender 5.0.1 でダンプし、main とこのブランチで byte 同一 を確認

新 ID タイプの追加手順(実演 — 実際には追加していない)

例として World を追加する場合:

  1. targets/id_datablock.py 末尾に1エントリ追加:
    class WorldRenameTarget(IDDatablockTarget):
        """ワールドのリネームターゲット"""
    
        bl_type = "WORLD"
        ol_idcode = BID.ID_WO
        namespace_key = "worlds"
        collection_type = bpy.types.World
        display_name = "World"
        icon = "WORLD"
  2. targets/__init__.py の import と target_classes に1行ずつ追加

メソッド実装はゼロ。発注書の文言「テーブルに1行」に対して実態は「テーブルに1エントリ(属性6行の class 文)」 — これは設計比較の帰結(下記)で、文字どおりの1行(タプル+globals 注入)は静的解析と引き換えになるため見送った。

設計比較と採用理由

実装前に2視点(リロード安全性・レジストリ共生 / 可読性・保守性)の独立判定エージェントで3案を比較した。

リロード安全性視点 可読性視点 判定
A: ファクトリ関数(MaterialRenameTarget = make_id_target("MaterialRenameTarget", ...)) 9/10(1位) 6/10(2位) 不採用
B改: 共通基底 + 単一モジュールに通常 class 文10連 7/10(2位)※ 8/10(1位) 採用
C: spec テーブル + 生成ループ + globals() 注入 3/10 3/10 失格

※ B の減点理由は「安全性は満点だが10ファイル分散が目的未達」のみ → 単一モジュール統合(B改)で解消。

決め手: 共通基底がメソッド3つを吸収した時点で、class 文も属性6行だけになりファクトリの「短さ」優位が消える(black の line-length 88 ではファクトリ呼び出しも7〜8行に展開される)。残るのはクラス名文字列の二重化(__name__ ベースのレジストリ重複排除が強制)と、grep "class MaterialRenameTarget" の不発・IDE 定義ジャンプの劣化だけ。素の class 文なら __name__ は自然に正しく、リロード時のレジストリ共生(__name__ 文字列比較での重複排除)も無条件に成立する。

案 C は加えて、targets パッケージ本体だけがローダーのリロード対象であるため、毎リロードでクラスが再生成され module dict に幽霊クラスが残存する非対称を生む。

その他の設計判断:

  • ol_type = OT.TSE_SOME_ID は全 ID 型で共通のため基底に1回だけ宣言
  • create_namespacegetattr(data, cls.namespace_key) に一般化(namespace_key と bpy.data の属性名は全12タイプで一致 — 乖離する型が現れたらその時に属性を分離する。YAGNI)
  • material.py は targets.material の import パスをテストが参照するため互換 re-export シムとして残置。他9ファイルは参照ゼロを確認のうえ削除
  • __init_subclass__ による属性検証・自動登録は発注書どおり見送り。宣言テーブル(id_datablock.py)と明示リスト(init.py)が並んだ「景色」ができたので、自動登録の採否はこの2つを見比べて判断できる状態

発見事項(修正せず記録のみ)

  1. object.py の create_from_scope は OUTLINER 経路で idcode を検査しない(TSE_SOME_ID のみ確認)— 自身の can_create_from_scope とは非対称で、ID 型クラスタの「正しい形」より緩い。現状はレジストリ/コレクタがクラス選定済みのため実害はないが、共通実装(can_create 委譲)に乗せると挙動が変わるため、今回は verbatim 保持した。統一するなら別 PR で判断
  2. 旧ターゲットファイル群は CRLF 改行だった(object.py / material.py 等)。書き直したファイルは LF に正規化された(リポジトリの他ファイルと同じ)。diff が全行置換に見えるのはこのため(git diff --ignore-cr-at-eol で実質差分を確認可能)
  3. pointer_cache 引数の型注釈が旧コードでは PointerCache(非 Optional)だったが、コレクタは VIEW3D 経路で実際に None を渡している。今回触った3ファイルはインターフェース(Optional[PointerCache] = None)に合わせ、None ガードを追加した(当該経路は OUTLINER では到達不能のため挙動同一 — 独立検証でも確認済み)。他のターゲット(bone / node / strip 等)には同じ型の嘘が残っている

受け入れ条件チェックリスト

  • 既存テストが無変更で全緑(git diff main...HEAD -- tests/ は空。Tier 1: uv run pytest = 166 passed + 6 xfailed、Tier 2: tests/blender/run.sh = 39 passed — いずれもベースラインと同一)
  • CI(unit + blender)が PR 上で緑(unit 13s / blender 27s、両ジョブ pass)
  • 実機で enable/disable がエラーなし(Blender 5.0.1、--factory-startup + BLENDER_USER_SCRIPTSdefault_set=True で enable → disable、トレースバックなし)
  • 行数の前後を PR 本文に記載(上記サマリー)
  • 新 ID タイプの追加手順を実演(上記、実際の追加はなし)
  • xfail 6件不変(166 passed + 6 xfailed)
  • dev-note/plans/2026-06-12-milestone.md §3 の該当項目を実績更新
  • 納品前にフレッシュコンテキストの検証エージェントでレビュー(判定: 合格。指摘は milestone の行数 -1 ずれ(訂正済み)と「テーブルに1行」の文言乖離(本文で明示)のみ)

🤖 Generated with Claude Code

Pluglug and others added 2 commits June 13, 2026 05:49
Collapse the ten copy-pasted ID-datablock target files (60 lines each,
differing only in six identifiers) into targets/id_datablock.py: a shared
IDDatablockTarget base implementing create_namespace /
can_create_from_scope / create_from_scope once, followed by ten
attribute-only subclasses that form a declarative table.

- Type judgment now lives in one place: can_create_from_scope reads the
  ol_type/ol_idcode class attributes, and create_from_scope delegates
  to it (previously triplicated per file).
- object.py and collection.py keep their unique scope methods (VIEW3D
  path, View Layer fallback) verbatim but inherit the shared base and
  drop their duplicated create_namespace.
- material.py remains as a one-line compatibility re-export because
  tests import the targets.material module path; the other nine files
  are deleted.
- Public class names, registration order, and registry index contents
  are unchanged (verified by dumping all registry indexes in Blender
  5.0.1 before/after: byte-identical).

Cluster size: 600 lines -> 189 (178 base+table, 11 shim).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 90406f40a0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines -1 to -3
"""
Mesh リネームターゲット
"""

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep compatibility shims for deleted target modules

When any existing script, test, or add-on integration imports a per-target module such as from structured_renamer.targets.mesh import MeshRenameTarget, this deletion now raises ModuleNotFoundError; only material.py kept a re-export shim. Since these modules were importable package members before the refactor, keep lightweight shims for the deleted ID target modules or this becomes a breaking change unrelated to the intended behavior-preserving refactor.

Useful? React with 👍 / 👎.

@Pluglug

Pluglug commented Jul 2, 2026

Copy link
Copy Markdown
Owner Author

司令塔レビュー(独立検証)— 合格

発注書 #3 の受け入れ条件を、請負の報告値を使わず手元で再測定して確認した。

検証項目 方法 結果
テスト無変更 git diff origin/main...HEAD -- tests/ 空 ✓
Tier 1 uv run pytest を手元で実行 166 passed / 6 xfailed ✓
Tier 2 tests/blender/run.sh(実 Blender 5.0.1) 39 passed ✓
CI unit / blender 両ジョブ 緑 ✓
挙動同一性 レジストリ3インデックス+登録順+全19クラスの識別子6属性を実機で独自ダンプし、main と diff 56行 byte 同一
enable/disable ダンプスクリプト自体が enable→disable を実行 トレースバックなし ✓
公開クラス名 ダンプの登録順に旧名が全て出現、targets.material シム経由 import も動作 維持 ✓
固有ロジック保持 object / collection の diff を --ignore-cr-at-eol で精読 スコープ判定2メソッド verbatim(None ガード追加のみ、OUTLINER 経路では到達不能なので挙動同一)✓
milestone §3 実績追記を確認

所見

  • 設計判断は支持する。特に「共通基底がメソッド3つを吸収した時点でファクトリの短さ優位が消える」という比較の帰結は、判定パネルの点数を鵜呑みにせず統合した良い判断
  • 発見事項3件(object の idcode 非対称 / CRLF→LF 正規化 / pointer_cache 型の嘘)はいずれも妥当な記録。object の非対称は別 PR 判断としてバックログへ
  • 「テーブルに1行」→「テーブルに1エントリ」の文言乖離は本文で明示されており、globals 注入(文字どおりの1行)を静的解析と引き換えに見送った理由も妥当

同一 GitHub アカウントのため approve は不可。本コメントをレビュー記録としてマージする。

@Pluglug
Pluglug merged commit dee5cf1 into main Jul 2, 2026
4 checks passed
@Pluglug
Pluglug deleted the refactor/id-target-parameterization branch July 2, 2026 07:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant