diff --git a/CLAUDE.md b/CLAUDE.md index a2805df..8f96628 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -23,7 +23,7 @@ ## 開発進捗 -最新: フェーズ 7(実装)— Step 8-14 の物理モデル精緻化と並行し,**[TEST_13](docs/06_TEST/TEST_13_物理モデル健全性の一括監査.md) 物理モデル健全性の一括監査**を実施.TEST_12 と同型の「無警告で結果だけが歪む」故障を横断検査し,**絶対放射量が積分球の解析解と 0.2% 一致**(単位系・反射率・光源パワー・センサ校正は健全)・シェーディング法線と幾何法線の一致(逸脱 0.044 度)・メッシュ法線の向き(裏面ヒット 0)を確認.**修正 3 件**: 片面 BSDF の脆弱性(法線裏返りで無警告の黒化 → `twosided` ラップ.実シーンには無影響)/**LLVM 初期化の順序バグでレンダテスト 8 件が長期間全滅していた**問題/ TEST_08 軸取り違えの回帰テスト欠落.**要判断**: `max_depth=16` は収束値の 90.3% しかエネルギーを拾えていない(CoV への影響は +0.35% で形状指標の過去結論は無影響.設定変更は LED radiance 再校正を伴うため保留,警告ログのみ実装).**未解決**: VTK 破損で `sm-visualize` と可視化テスト 39 件が実行不能.詳細な経緯・設計判断・失敗パターンは [docs/PROGRESS.md](docs/PROGRESS.md). +最新: フェーズ 7(実装)— Step 8-14 の物理モデル精緻化と並行し,**[TEST_13](docs/06_TEST/TEST_13_物理モデル健全性の一括監査.md) 物理モデル健全性の一括監査**を実施.TEST_12 と同型の「無警告で結果だけが歪む」故障を横断検査し,**絶対放射量が積分球の解析解と 0.2% 一致**(単位系・反射率・光源パワー・センサ校正は健全)・シェーディング法線と幾何法線の一致(逸脱 0.044 度)・メッシュ法線の向き(裏面ヒット 0)を確認.**修正 3 件**: 片面 BSDF の脆弱性(法線裏返りで無警告の黒化 → `twosided` ラップ.実シーンには無影響)/**LLVM 初期化の順序バグでレンダテスト 8 件が長期間全滅していた**問題/ TEST_08 軸取り違えの回帰テスト欠落.**要判断**: `max_depth=16` は収束値の 90.3% しかエネルギーを拾えていない(CoV への影響は +0.35% で形状指標の過去結論は無影響.設定変更は LED radiance 再校正を伴うため保留,警告ログのみ実装).**可視化の復旧**: `sm-visualize` の起動不能は VTK の破損ではなく Windows Smart App Control による DLL ブロックと判明し,`vtk==9.4.2` への固定で解消(可視化テスト 54 件が全て通過).再破損を即検知する import 監視テストを通常実行に常設.詳細な経緯・設計判断・失敗パターンは [docs/PROGRESS.md](docs/PROGRESS.md). 実装済みモジュール: - `src/sm_tias_lightsim/uniformity.py` — Rec.709 輝度変換 + CoV/std/max-min(SmTIAS-Evaluation コピー) diff --git "a/docs/02_ENV/ENV_01_\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.md" "b/docs/02_ENV/ENV_01_\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.md" index fdaed37..3ce46d0 100644 --- "a/docs/02_ENV/ENV_01_\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.md" +++ "b/docs/02_ENV/ENV_01_\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.md" @@ -81,7 +81,7 @@ | 画像 I/O(RAW) | `rawpy` | DNG(RAW)読み込み.linear raw を保ったまま実測リファレンスを取得(`evaluation/dng_loader.py`) | | 可視化(2D) | `matplotlib` | 輝度マップ・ヒストグラム・放射状プロファイル等 | | 画像処理(指標) | `scikit-image` | 構造的類似度 SSIM の算出(形状評価指標,`evaluation/shape_metrics.py`) | -| 可視化(3D) | `pyvista` | 照度ベイク結果のインタラクティブ 3D ビューア(`sm-visualize`) | +| 可視化(3D) | `pyvista` + `vtk==9.4.2` | 照度ベイク結果のインタラクティブ 3D ビューア(`sm-visualize`).vtk はバージョン固定(9.6.1 は Smart App Control に DLL をブロックされる.TEST_13 検査 8) | | 画像処理(GUI) | `opencv-python` | 実測 PNG での白色板境界選択 GUI(`scripts/select_white_board.py`) | | 表データ | `pandas` | 均一性指標 CSV の生成・統計集計 | | テスト | `pytest` | 単体テスト | diff --git "a/docs/02_ENV/ENV_04_\351\226\213\347\231\272\343\202\263\343\203\236\343\203\263\343\203\211.md" "b/docs/02_ENV/ENV_04_\351\226\213\347\231\272\343\202\263\343\203\236\343\203\263\343\203\211.md" index 8194471..27898c3 100644 --- "a/docs/02_ENV/ENV_04_\351\226\213\347\231\272\343\202\263\343\203\236\343\203\263\343\203\211.md" +++ "b/docs/02_ENV/ENV_04_\351\226\213\347\231\272\343\202\263\343\203\236\343\203\263\343\203\211.md" @@ -40,9 +40,11 @@ uv run pytest -m "" # slow を含む全テスト.シーン幾何を変えた後は一度通す ``` -> ⚠ 既知の問題: `slow` 層のうち `tests/visualize/` と `tests/cli/test_visualize_cli.py` は -> VTK のインストール破損により失敗する(`import pyvista` 単体で再現).`sm-visualize` も -> 同じ理由で実行できない.依存関係の修復が必要. +> ⚠ `vtk` は `pyproject.toml` で **9.4.2 に固定**している.9.6.1 では Windows の +> Smart App Control が 14 個の DLL をレピュテーション判定でブロックし,`sm-visualize` が +> 起動できなくなる([TEST_13](../06_TEST/TEST_13_物理モデル健全性の一括監査.md) 検査 8). +> バージョンを上げるときは必ず `sm-visualize` の起動確認を行うこと. +> `tests/visualize/test_vtk_import_guard.py` が通常実行で import 可否を常時検査している. ## Lint / フォーマット (Lint & Format) diff --git "a/docs/06_TEST/TEST_13_\347\211\251\347\220\206\343\203\242\343\203\207\343\203\253\345\201\245\345\205\250\346\200\247\343\201\256\344\270\200\346\213\254\347\233\243\346\237\273.md" "b/docs/06_TEST/TEST_13_\347\211\251\347\220\206\343\203\242\343\203\207\343\203\253\345\201\245\345\205\250\346\200\247\343\201\256\344\270\200\346\213\254\347\233\243\346\237\273.md" index d4e683b..fa58cb5 100644 --- "a/docs/06_TEST/TEST_13_\347\211\251\347\220\206\343\203\242\343\203\207\343\203\253\345\201\245\345\205\250\346\200\247\343\201\256\344\270\200\346\213\254\347\233\243\346\237\273.md" +++ "b/docs/06_TEST/TEST_13_\347\211\251\347\220\206\343\203\242\343\203\207\343\203\253\345\201\245\345\205\250\346\200\247\343\201\256\344\270\200\346\213\254\347\233\243\346\237\273.md" @@ -27,7 +27,7 @@ | 5 | 多重反射の打ち切り(`max_depth`) | **問題あり**(基準設計シーンで **9.7% のエネルギー欠損**) | 警告を実装.設定変更は要判断 | | 6 | 面光源のサイズ→軸マッピング(TEST_08 の再発) | **健全**だが**テストが存在しなかった** | 実効的な回帰テストを追加 | | 7 | レンダ経路のテスト(`slow` 層) | **長期間全滅していた** | LLVM 初期化順序のバグを修正 | -| 8 | 3D 可視化のテスト(`slow` 層) | **全滅**(VTK 環境破損) | 環境側の対応が必要(未着手) | +| 8 | 3D 可視化のテスト(`slow` 層) | **全滅**(Smart App Control が VTK の DLL をブロック) | `vtk==9.4.2` に固定して解消.import 監視テストを常設 | ## 検査 1・3 — 法線の健全性 (Normals) @@ -166,15 +166,91 @@ > 本監査で追加した積分球テストは 1 本 0.2 秒(32x32 / spp=128)で合計 1.5 秒程度なので, > `slow` を付けず通常実行に含めている. -## 検査 8 — 3D 可視化テストの全滅(未解決) (Broken Visualization Tests) +## 検査 8 — 3D 可視化テストの全滅 (Broken Visualization Tests) 残る `slow` 失敗 39 件は全て `tests/visualize/` と `tests/cli/test_visualize_cli.py` で, -原因は **VTK のインストール破損**である(`ImportError: Failed to load vtkCommonMath: -No module named vtkmodules.vtkCommonCore`.`import pyvista` 単体で再現,mitsuba とは無関係). +`sm-visualize` も実行できない状態だった. -現在 **`sm-visualize` は実行できない状態**.[CLAUDE.md](../../CLAUDE.md) の -「幾何を変えるシーンは本番レンダ前に必ず 3D で配置確認する」運用が塞がっているため, -依存関係の修復が必要(`vtk 9.6.1` / `pyvista 0.48.0`).本監査では未着手. +### 原因 — Windows Smart App Control による DLL のブロック + +**依存関係の破損ではなく,OS のアプリケーション制御ポリシーが VTK の DLL を弾いていた.** + +```text +DLL load failed while importing vtkRenderingVolume: +アプリケーション制御ポリシーによってこのファイルがブロックされました。 +``` + +開発機の Smart App Control が**オン(強制モード)**になっていた. + +| 確認項目 | 値 | +| --- | --- | +| `HKLM:\SYSTEM\CurrentControlSet\Control\CI\Policy\VerifiedAndReputablePolicyState` | 1(オン・強制) | +| `Win32_DeviceGuard.UsermodeCodeIntegrityPolicyEnforcementStatus` | 2(強制中) | + +Smart App Control は署名の有無ではなく**ファイル単位のクラウドレピュテーション**で判定する. +そのため vtk 9.6.1 では **209 個の DLL のうち 14 個だけ**がブロックされ,残りは通るという +状態になっていた.ブロックされたのは以下(`vtkRenderingAnnotation` はスカラーバー・座標軸, +`vtkInteractionWidgets` はウィジェットを担い,どちらも PyVista の描画に必須). + +```text +vtkRenderingVolume vtkRenderingVolumeOpenGL2 vtkRenderingVolumeAMR +vtkRenderingAnnotation vtkInteractionWidgets vtkInteractionImage +vtkImagingColor vtkRenderingVR vtkRenderingOpenXR +vtkRenderingOpenXRRemoting vtkTestingRendering vtkViewsInfovis +vtkWebCore vtkWebGLExporter +``` + +依存の破損でないことの根拠: + +- VTK の 153 モジュール分の `.pyd` はすべて正しく存在していた +- 通った `vtkRenderingCore` も弾かれた `vtkRenderingVolume` も**どちらも未署名** + (`Get-AuthenticodeSignature`).署名の有無は判定基準ではない +- `uv.lock` の vtk 9.6.1 は Step 7(2026-05-17)から変わっておらず, + Dependabot による更新も入っていない + +### 症状のメッセージが 2 通りあったことについて + +最初に観測した症状は +`ImportError: Failed to load vtkCommonMath: No module named vtkmodules.vtkCommonCore` +で,上記のアプリケーション制御エラーとは別のメッセージだった.両者の関係は完全には +確定していない.事実として確認できたのは以下である. + +- `vtkCommonCore` はブロックされた 14 個に含まれず,単独では import できた +- 同一環境で `import pyvista` が一度失敗し,のちに成功した(判定に揺れがある) +- 一貫して再現したのはアプリケーション制御によるブロックの方 + +`vtkmodules` は独自のローダ(`vtkmodules/__init__.py` の `exec_module`)で依存モジュールを +読み込むため,**DLL がブロックされた事実を握りつぶして「モジュールが無い」という +誤解を招くメッセージに化けさせた二次症状**と推定しているが,機構までは確認していない. +最初の切り分けで「VTK のインストール破損」と誤診したのはこのメッセージが原因であり, +**ネイティブ拡張の ImportError は表示されたメッセージを額面どおり受け取らない**という +教訓として記録しておく. + +### 対処 — vtk を 9.4.2 に固定 + +より長く配布されレピュテーションが確立しているバージョンへ下げる方針を採った +(pyvista 0.48.0 の要求は `vtk>=9.2.2, <9.7.0, !=9.4.1`). + +`vtk==9.4.2` では **147 モジュール全てが読み込め,ブロック 0 件**.`sm-visualize` の +3D 表示(筐体・LED マーカー 18 個・センサマーカー・座標軸)も復旧し, +`slow` の可視化テスト 54 件が全て通るようになった. + +`pyproject.toml` に固定理由をコメントで残している(`/deps-update` や Dependabot が +9.6 系へ戻して静かに再破損するのを防ぐため). + +> Smart App Control の無効化は**一度オフにすると Windows を再インストールしない限り +> 再びオンにできない**ため採用しなかった.可視化ツール 1 本のために恒久的に +> マルウェア保護を手放すのは釣り合わない. + +### 再発を即座に検知する仕組み + +破損は 2026-08-17 から 8-30 まで約 2 週間気づかれなかった.**可視化テストが全て +`slow` マークで通常実行から外れていたことが原因**であり,検査 7(LLVM 初期化バグで +レンダテストが長期間全滅していた件)とまったく同じ構図である. + +そこで `tests/visualize/test_vtk_import_guard.py` を **`slow` を付けずに**追加した. +pyvista とブロック実績のあるモジュールの import,および固定バージョンの確認のみを行い, +レンダリングはしないので 1 秒未満で完了する. ## 採用を見送った検査 (Rejected Checks) @@ -214,5 +290,4 @@ ## 次にやること (Next Steps) 1. `max_depth` を 32〜64 に引き上げるかの判断(引き上げる場合は LED radiance の再校正が必要) -2. VTK の修復(`sm-visualize` の復旧) -3. 残る差分=「形」(実機の斜め構造・相補性の振幅)の切り分けへ復帰 +2. 残る差分=「形」(実機の斜め構造・相補性の振幅)の切り分けへ復帰 diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 39b3caa..a9eb8e6 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -79,3 +79,4 @@ - **TEST_12 追補 — 単灯再検証で TEST_09 中核結論「3 灯同形」を撤回・非対称相補性の部分再現を確認 (2026-08-18)**: 基準単灯 3 灯(blend w0.05_a0.1)を修正版で再レンダ(ロフト w1p4 系はユーザー判断でスキップ).灯間 NCC(平滑)は修正前 0.99 均等 → **修正後 0.85/0.93/0.73 の非対称**=「シミュは 3 灯ほぼ同形で非対称相補性を再現できない → B1 非対称幾何が唯一の候補」(TEST_09)はアーティファクトが作った見かけと判明し撤回(TEST_09 冒頭に BEFORE FIX 注記).修正後シミュは「left-right が最も異なる」点で実機(0.92/0.66/0.44)と一致するが,差の振幅は弱く最類似ペアは不一致=実験4(漏れ点検)の主動機は大幅に弱まり,残る課題は相補性の振幅・並びと実機の斜め構造の切り分けに再設定.計測上の学び: 単灯 spp=1024 はノイズ 5.3% > 構造振幅 4% で raw 指標(特に peak/mean・NCC)はノイズ支配 → 灯間 NCC は raw/smooth 併記とし解釈は smooth を正(`pairwise_ncc.csv`),以後の単灯実験は spp≥4096 推奨.成果物: `output/singles_fix/`,`scripts/build_singles_fix_summary.py`,図 `output/_slide_panels/singles_fix_shape_roi.png`,記録 [TEST_12 §追補](06_TEST/TEST_12_シェーディング法線アーティファクトの発見と修正.md). - **TEST_12 追補 2 — ロフト w1.4 の修正後再検証で TEST_10 の判定を確定 (2026-08-18)**: ロフト w1.4(全灯 1+単灯 3)を修正版で再レンダ.**④「全灯に実質不感」は維持**(CoV 0.0610→0.0605,全指標差 ≈1%=実機 w1.4 測定への予測「従来筐体とほぼ同じ」も不変).**③「対称拡大は 3 灯を同形化」も維持・明確化**(灯間 NCC 平滑 0.85/0.93/0.73→0.91/0.96/0.84 で実機の非対称から遠ざかる).一方 **①「bottom 単灯の平ら化=幾何レバー初実証」は撤回相当に弱まる**(平滑 p/m 変化 -0.9% のみ.TEST_10 の raw -10% はアーティファクト期の見かけが大半.修正後 raw p/m はヘビーテイルノイズの最大値ゆらぎで不採用).②「left/right 不動」維持.TEST_10 冒頭に BEFORE FIX 注記(結論の生死を明記).成果物: `output/full_w1p4_fix/`・`output/singles_fix/*_w1p4/`,summary/pairwise CSV と 3×4 パネル更新,記録 [TEST_12 §ロフト再検証](06_TEST/TEST_12_シェーディング法線アーティファクトの発見と修正.md). - **TEST_13 物理モデル健全性の一括監査 — 潜在バグ 3 件を修正し再発防止テストを常設 (2026-08-30)**: TEST_12 と同じ「エラーも警告も出ないまま結果だけが歪む」故障モードが他に残っていないかを横断監査(動機: 同型のバグが TEST_08 でも起きており,そのとき TEST_07 が誤出力を「物理的に正しい」と一度正当化している=3 度目を防ぐ).**健全と確認**: シェーディング法線 == 幾何法線(実測逸脱 0.044 度)・メッシュ法線の向き(裏面ヒット 0・全 15 STL 巻き順一貫)・**絶対放射量(積分球の解析解と 0.2% 一致=単位系/反射率/光源パワー/センサ校正が正しい)**・面光源の軸マッピング.**修正した問題 3 件**: ① 片面 BSDF の脆弱性(法線が裏返ると無警告で真っ黒.`twosided` ラップで恒久修正.実シーンでは mean +0.015%=無影響を確認)/ ② **LLVM 初期化の順序バグで `slow` レンダテスト 8 件が長期間全滅**(`scene/lights.py` がモジュール import 時に mitsuba を読むため `runner.py` の自動探索が手遅れ.開発機は環境変数が永続設定済みで症状が隠れていた)/ ③ TEST_08 の軸取り違えに実効的な回帰テストが無かった.**要判断の発見**: `max_depth=16` は収束値の **90.3%** しかエネルギーを拾えていない(間接照明のみの構成のため.ただし CoV への影響は +0.35% で形状指標の過去結論は無影響.設定変更は LED radiance 再校正を伴うため未実施,警告ログのみ実装).**未解決**: VTK 破損で `sm-visualize` と可視化テスト 39 件が実行不能(依存関係の修復が必要).設計判断: 対称性テストは負のコントロールが発火せず(立方体では平滑法線でも象限比 1.002 vs 1.003)検出力を実証できなかったため**常設テストに含めない**(検出できない検査は「検査済み」という誤った安心を与える).積分球テストは 1.5 秒と軽量なので `slow` を付けず通常実行に含めた(`slow` 隔離が ② の全滅を見逃した原因のため).記録 [TEST_13](06_TEST/TEST_13_物理モデル健全性の一括監査.md). +- **sm-visualize の起動不能を解消 — 原因は VTK 破損ではなく Smart App Control (2026-08-30)**: TEST_13 で唯一未解決だった 3D 可視化の全滅(可視化テスト 39 件・`sm-visualize` 実行不能)を解決.**当初「VTK のインストール破損」と誤診していたが,真因は Windows Smart App Control(強制モード)が vtk 9.6.1 の DLL 209 個のうち 14 個をレピュテーション判定でブロックしていたこと**.署名の有無は判定基準ではなく(通った DLL も弾かれた DLL も未署名),`.pyd` は全て正常に存在し `uv.lock` も 5/17 から不変だったため,`uv sync` や同一バージョン再インストールでは直らない種類だった.誤診の原因は最初に観測したメッセージが `No module named vtkmodules.vtkCommonCore` という二次症状だったこと=**ネイティブ拡張の ImportError は表示メッセージを額面どおり受け取らない**という教訓.対処は `vtk==9.4.2` への固定(より長く配布されレピュテーションが確立したバージョン.pyvista 0.48.0 の制約 `>=9.2.2,<9.7.0,!=9.4.1` 内)で,全 147 モジュールがブロック 0 件で読み込め可視化テスト 54 件が全通過.設計判断: Smart App Control の無効化は**一度オフにすると Windows 再インストールなしに戻せない**ため不採用(可視化ツール 1 本のために恒久的にマルウェア保護を手放すのは釣り合わない).WSL2 への切り出しは環境二重管理の負債を負うため次善策として保留.**再発防止**: 破損が 8/17〜8/30 の約 2 週間気づかれなかった原因は可視化テストが全て `slow` 隔離されていたことで,TEST_13 検査 7(LLVM 初期化バグでレンダテストが長期間全滅)とまったく同じ構図.import 可否だけを見る軽量テスト(1 秒未満)を `slow` 無しで常設し,`pyproject.toml` の固定にも理由をコメントで残した(Dependabot / `/deps-update` による静かな再破損を防ぐため).判断は `/consult`(advisor: Fable)に諮り,A(ダウングレード)→ B(WSL2)の順・C(SAC 無効化)不採用・import 監視テスト常設という助言に沿って実施.記録 [TEST_13 検査 8](06_TEST/TEST_13_物理モデル健全性の一括監査.md). diff --git a/pyproject.toml b/pyproject.toml index b2230de..cb07826 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,13 @@ "pillow>=12.2.0", "pydantic>=2.13.3", "pyvista>=0.45", + # vtk は 9.4.2 に固定する.9.6.1 では Windows の Smart App Control が + # vtkRenderingAnnotation・vtkInteractionWidgets 等 14 個の DLL を + # レピュテーション判定でブロックし,sm-visualize が起動できなくなる + # (docs/06_TEST/TEST_13 検査 8).9.4.2 は全 147 モジュールが読み込める. + # バージョンを上げる際は必ず sm-visualize の起動確認を行うこと + # (tests/visualize/test_vtk_import_guard.py が常時検査している). + "vtk==9.4.2", "pyyaml>=6.0.3", "rawpy>=0.21.0", "scikit-image>=0.21.0", diff --git a/tests/visualize/test_vtk_import_guard.py b/tests/visualize/test_vtk_import_guard.py new file mode 100644 index 0000000..5ddf081 --- /dev/null +++ b/tests/visualize/test_vtk_import_guard.py @@ -0,0 +1,102 @@ +"""VTK / PyVista が実際に読み込めることを常時検査する軽量テスト. + +仕様出典: +- docs/06_TEST/TEST_13_物理モデル健全性の一括監査.md(検査 8) + +2026-08-17 から 8-30 の間に,Windows の Smart App Control が VTK 9.6.1 の +DLL 14 個(`vtkRenderingAnnotation`・`vtkInteractionWidgets` 等)を +レピュテーション判定でブロックし,`sm-visualize` が起動できなくなった. +`vtk==9.4.2` への固定で解消したが,**破損に約 2 週間気づかなかった**. + +気づけなかった理由は,可視化テストが全て `slow` マークで通常実行から +外れていたこと.TEST_13 検査 7(LLVM 初期化バグでレンダテストが長期間 +全滅していた件)とまったく同じ構図である. + +そこで本モジュールは **`slow` を付けず**,import が通るかだけを検査する. +レンダリングを行わないので 1 秒未満で完了し,通常実行に含めても負担にならない. +`sm-visualize` の実際の描画は `tests/visualize/test_viewer.py` 等の +`slow` テストが受け持つ. + +依存を上げたときにここが落ちたら,まず `sm-visualize` の起動確認を行うこと. +""" + +from __future__ import annotations + +import pytest + +# Smart App Control にブロックされた実績のあるモジュール. +# 特に vtkRenderingAnnotation(スカラーバー・座標軸)と +# vtkInteractionWidgets は PyVista の描画に必須で,これが欠けると起動できない. +_PREVIOUSLY_BLOCKED_MODULES = [ + "vtkmodules.vtkImagingColor", + "vtkmodules.vtkInteractionImage", + "vtkmodules.vtkInteractionWidgets", + "vtkmodules.vtkRenderingAnnotation", + "vtkmodules.vtkRenderingVolume", + "vtkmodules.vtkRenderingVolumeOpenGL2", + "vtkmodules.vtkViewsInfovis", +] + +# 描画経路の中核.これらが欠けると PyVista は何も表示できない. +_CORE_RENDERING_MODULES = [ + "vtkmodules.vtkCommonCore", + "vtkmodules.vtkRenderingCore", + "vtkmodules.vtkRenderingOpenGL2", +] + + +def test_pyvista_imports(): + """pyvista が import できること. + + 3D 配置確認(CLAUDE.md「シミュレーション実験の進め方」)の前提. + """ + import pyvista + + assert pyvista.__version__ + + +@pytest.mark.parametrize("module_name", _CORE_RENDERING_MODULES) +def test_core_rendering_module_imports(module_name): + """描画経路の中核モジュールが import できること.""" + import importlib + + assert importlib.import_module(module_name) is not None + + +@pytest.mark.parametrize("module_name", _PREVIOUSLY_BLOCKED_MODULES) +def test_previously_blocked_module_imports(module_name): + """過去に Smart App Control でブロックされたモジュールが import できること. + + 失敗した場合は依存の破損ではなく,OS のアプリケーション制御ポリシーが + 当該 DLL を弾いている可能性が高い(エラーメッセージを確認すること). + """ + import importlib + + assert importlib.import_module(module_name) is not None + + +def test_vtk_version_is_pinned_to_a_loadable_release(): + """vtk が読み込み実績のあるバージョンに固定されていること. + + pyproject.toml で `vtk==9.4.2` に固定している.9.6.1 では + Smart App Control が 14 個の DLL をブロックする(TEST_13 検査 8). + バージョンを上げるときは sm-visualize の起動確認を必ず行うこと. + """ + import vtk + + assert vtk.VTK_VERSION == "9.4.2" + + +def test_plotter_can_be_constructed_off_screen(): + """オフスクリーンの Plotter を構築できること. + + import が通っても描画クラスの初期化で落ちる場合があるため, + レンダリングは行わずに構築だけを確認する(軽量に保つ). + """ + import pyvista + + plotter = pyvista.Plotter(off_screen=True) + try: + assert plotter is not None + finally: + plotter.close() diff --git a/uv.lock b/uv.lock index fdcbd37..29a64cd 100644 --- a/uv.lock +++ b/uv.lock @@ -1215,6 +1215,7 @@ { name = "rawpy" }, { name = "scikit-image" }, { name = "trimesh" }, + { name = "vtk" }, ] [package.dev-dependencies] @@ -1237,6 +1238,7 @@ { name = "rawpy", specifier = ">=0.21.0" }, { name = "scikit-image", specifier = ">=0.21.0" }, { name = "trimesh", specifier = ">=4.12.1" }, + { name = "vtk", specifier = "==9.4.2" }, ] [package.metadata.requires-dev] @@ -1310,27 +1312,18 @@ [[package]] name = "vtk" -version = "9.6.1" +version = "9.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "matplotlib" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/95/89/c274101ec7b9bf7356333fdacf5e634803fe6b40f776e82c6ce9d941e0ad/vtk-9.6.1-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:b8125e3e3bc3160e18853a15be98101d0efe662c16036179ab15ddf1669b32af", size = 114729308, upload-time = "2026-03-27T13:50:37.547Z" }, - { url = "https://files.pythonhosted.org/packages/9d/1a/ecbebaf31724a00f85fc4dbf95992b507328f615362ee8fa5ea1a38cf9d6/vtk-9.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:956d05b8c53c6a9eba569de244e9c8229815bbb3e024bb9954fafe163407e66d", size = 106814956, upload-time = "2026-03-27T13:51:24.324Z" }, - { url = "https://files.pythonhosted.org/packages/46/66/ba3c8b277cfa8058e982bfbd47875d9c6b4c06e65f98d577c69a2628f8d4/vtk-9.6.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9728e8d41889a0f105b5d20a73a4da80f398b2cfe6057fa7a94cd61128c3ceb4", size = 145920093, upload-time = "2026-03-27T13:53:12.49Z" }, - { url = "https://files.pythonhosted.org/packages/f5/cb/0bbf91cd45a8d8f5453fe01cddf44c913db6316b3a2b15f41893ae0ca9ad/vtk-9.6.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3b5ec2e56bd6165189aa2e6e896edda29460e63040f897e1a123a1592810266d", size = 135683842, upload-time = "2026-03-27T13:52:15.218Z" }, - { url = "https://files.pythonhosted.org/packages/08/c0/653c94939498a3976157f054b830ade5c1da48ae288a23547f55fc25a262/vtk-9.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:4022fda8af46636f74c3c1932c2365da13a1dc8779a6b1ea4b13dc5bbcdb729f", size = 81262921, upload-time = "2026-03-27T13:53:50.192Z" }, - { url = "https://files.pythonhosted.org/packages/a8/8d/16e597f86241772fe188bbdd86a74ce48eadd2dd9513e2410b4ea07f78aa/vtk-9.6.1-cp313-cp313-macosx_10_10_x86_64.whl", hash = "sha256:88983bce26f7665ac6e4fb7de16cf53b896140a1a6cadd942d3c13e7c74a8530", size = 114747320, upload-time = "2026-03-27T13:54:33.138Z" }, - { url = "https://files.pythonhosted.org/packages/63/ca/8f0c19bded437423479d0d3ff0b7457cf6ef68def322666df867e6dacc0f/vtk-9.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:94ed369a54c6cfacea0b34f42d7d3ef41fa06c1aabfc75d93cabdc9047454293", size = 106817051, upload-time = "2026-03-27T13:55:21.903Z" }, - { url = "https://files.pythonhosted.org/packages/82/22/c1d98e6e191481af1e5c82ae3fa750798d868aa442a76db027f6a7901b95/vtk-9.6.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:deeb86794cd42f922ea75711b9717e45841777624203727eb84595b709af1382", size = 145920554, upload-time = "2026-03-27T13:57:14.258Z" }, - { url = "https://files.pythonhosted.org/packages/16/5d/658f60209de7b41b634178aee1f458bcad149aa2654d16bd023c09afd29c/vtk-9.6.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:fef8abc33168ad38b2622cf29048b7d5fe48a45789bf0a0421781f5cafa1e554", size = 135686060, upload-time = "2026-03-27T13:56:23.89Z" }, - { url = "https://files.pythonhosted.org/packages/f0/31/e4eb318901a8e736c936491e759ce03a1656792f728ae912db0e20997e9a/vtk-9.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:a5db7b2ff8fc3f56b547c8b9b7bc117a869c902683c86ef5cd6197c087f66183", size = 81264861, upload-time = "2026-03-27T13:57:47.164Z" }, - { url = "https://files.pythonhosted.org/packages/43/de/ad1ccb188681d51b5e5621f383afa0a1dd8711ff8f3dcba4ff950f758cbb/vtk-9.6.1-cp314-cp314-macosx_10_10_x86_64.whl", hash = "sha256:91257894723dfced8be264915d81ba418d08e5bbdb4873da0f12b02c1e21f244", size = 114382745, upload-time = "2026-03-27T13:58:30.592Z" }, - { url = "https://files.pythonhosted.org/packages/59/21/7bb2bd61b4ae05db79e2f40df452a6dbcd3bb66c259fd2043aaf60bbe5b7/vtk-9.6.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e119721774418fba34e95852efaefe5ac4156a4a270362fef06894cdc1377b6e", size = 106826433, upload-time = "2026-03-27T13:59:22.109Z" }, - { url = "https://files.pythonhosted.org/packages/fc/e4/5317afdeaa4a66fe037e1fedcb6bde86b888b8227c89aba6c8ad2946e380/vtk-9.6.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98df48bcd630a4ffa71ac09d6aebb69c628925902920419e3db838dc7f7ce0ed", size = 145936133, upload-time = "2026-03-27T14:01:19.29Z" }, - { url = "https://files.pythonhosted.org/packages/67/7f/f1375aa3ef1835e39b4bea978da06d4985bc1407e3e91384dfaabf5e09d0/vtk-9.6.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:3ea3c3e466a4a9cd8fa7e5b64595215467a7936c9f0fd61ec3275954c122a79c", size = 135710278, upload-time = "2026-03-27T14:00:19.358Z" }, - { url = "https://files.pythonhosted.org/packages/91/25/7ff877a0d4f3e848d994d3a774d5a8e4495681ed26c32eb9dbb2a86b50e5/vtk-9.6.1-cp314-cp314-win_amd64.whl", hash = "sha256:a05e12ab8c82e81b225feee5ca08fda5fff814520a11c2941cc866335d990e03", size = 83197720, upload-time = "2026-03-27T14:01:53.313Z" }, - { url = "https://files.pythonhosted.org/packages/0a/ae/f621aaed0a36c99ba3c1b2f2593386094222132a8396f21c616adffacaaf/vtk-9.6.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:043fb013a2669180180bd0ab667f318f2e1f14da69ae943192a7443f5ce3721a", size = 145557875, upload-time = "2026-03-27T14:03:45.531Z" }, - { url = "https://files.pythonhosted.org/packages/e1/d5/41edd3f8b38ad45b8fb30d12ef35be3d62e1221e455722a5d7d103ca2f0d/vtk-9.6.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:d08b3760cbd8bffdbb4551033c4c9d87afe30e9e9d4c0e5cad29cbe7107c9af7", size = 135524312, upload-time = "2026-03-27T14:02:46.035Z" }, + { url = "https://files.pythonhosted.org/packages/59/df/6c04941922986d2af611e9c7ea289ea1922295455ea08536b8fb9f104664/vtk-9.4.2-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:5482c147e36490a90fadf01333b8b06f2a88659a9cb012523603697e7de37dc7", size = 82686355, upload-time = "2025-03-28T20:17:37.753Z" }, + { url = "https://files.pythonhosted.org/packages/4c/6b/fce6a0040cc877324e5dc8191407a9ab73b7da65c88403d173f834052f70/vtk-9.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ac03471cada196b9465305336649cd502ce4796ee5006eade2cdaf7f2b5b593b", size = 76541862, upload-time = "2025-03-28T20:17:45.559Z" }, + { url = "https://files.pythonhosted.org/packages/9f/61/e998f3d118aa4e70d4cc8549dc0b67acfa138936ef9da896cbf87da21f7b/vtk-9.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef81842d151312b52455b2b613871c57ca7323c2f901914e13fc750b74ce3fd2", size = 105054000, upload-time = "2025-03-28T20:17:55.285Z" }, + { url = "https://files.pythonhosted.org/packages/35/a1/5df9de36c17c42269ae85b4435d346bf38d106b25e9b98c6db6cc2f8ac5f/vtk-9.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:fded22d5bc8cd2193ef27214efb63e1db5318f566fb64f2cf31332b820ece6ac", size = 58482099, upload-time = "2025-03-28T20:18:02.399Z" }, + { url = "https://files.pythonhosted.org/packages/22/30/5df46c3d90267f5b3efb6c8ac91c1014ef3532df2342aa53bd2ebed196e8/vtk-9.4.2-cp313-cp313-macosx_10_10_x86_64.whl", hash = "sha256:ec8c4258ceb9b3eb9c8101e1db1cca16825f0c0daa891ae4d85cd2ae9ec7681c", size = 82708428, upload-time = "2025-03-28T20:18:09.633Z" }, + { url = "https://files.pythonhosted.org/packages/2d/a1/34f61fe0ab3735d9f9127b7be186add12b481251601a1fde564fb08294bc/vtk-9.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1e291fc1a0c6a8432185abd9265d44fc7822b39325dc8e81d01b798858b68733", size = 76553587, upload-time = "2025-03-28T20:18:17.61Z" }, + { url = "https://files.pythonhosted.org/packages/8b/b1/f0deed70f4a72a0c42cf9a0120a0a92bbd1eac37090b501144e39c4792ad/vtk-9.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c6d15129443eb950b8faf127b67935a680533aa08ad832b9137889543084ddd", size = 105054339, upload-time = "2025-03-28T20:18:26.878Z" }, + { url = "https://files.pythonhosted.org/packages/99/52/2f49d4b73ed019b20f4bbbcf1b5f3a371d76af951688f6f70e79ff44fd14/vtk-9.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:5be5096e8c247c1ae151cc68121fbb0b6c5c76217e69d9600e4b8ba0c1c53c9f", size = 58482778, upload-time = "2025-03-28T20:18:33.653Z" }, ]