Skip to content

Commit 9b66f97

Browse files
authored
Merge pull request #7 from Hum9183/release/0.6.0
Release/0.6.0
2 parents cfa1a98 + c529a52 commit 9b66f97

17 files changed

Lines changed: 709 additions & 193 deletions

.github/workflows/test.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
pull_request:
7+
8+
jobs:
9+
test:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Set up Python 3.11
16+
uses: actions/setup-python@v5
17+
with:
18+
python-version: '3.11'
19+
20+
- name: Install dependencies
21+
run: |
22+
python -m pip install --upgrade pip
23+
pip install pytest
24+
25+
- name: Run tests
26+
run: |
27+
pytest tests/ -v

README.md

Lines changed: 128 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
1-
# deep_reloader
1+
# deep_reloader
2+
3+
[日本語版](docs/README.ja.md) | [中文版](docs/README.zh-CN.md)
24

35
> [!WARNING]
4-
> このソフトウェアは現在プレリリース版です。APIが変更される可能性があります。
6+
> This software is currently in pre-release. The API may change.
57
6-
Pythonモジュールの依存関係を解析して、再帰的にリロードを行うライブラリです。特にMayaでのスクリプト開発時に、モジュール変更を即座に反映させるために設計されています。
8+
A Python library that analyzes module dependencies and performs recursive reloading. Designed specifically for Maya script development to instantly reflect module changes.
79

8-
## 機能
10+
## Features
911

10-
- **深いリロード**: 深い階層でもリロードが可能
11-
- **AST解析**: 静的解析により from-import文 を正確に検出
12-
- **ワイルドカード対応**: `from module import *` もサポート
13-
- **相対インポート対応**: パッケージ内の相対インポートを正しく処理
14-
- **循環参照対応**: Pythonで動作する循環インポートを正しくリロード
12+
- **Deep Reload**: Reloads modules at any depth level
13+
- **AST Analysis**: Accurately detects from-import statements through static analysis
14+
- **Wildcard Support**: Supports `from module import *`
15+
- **Relative Import Support**: Properly handles relative imports within packages
16+
- **Circular Import Support**: Correctly reloads circular imports that work in Python
1517

16-
## インストール
18+
## Installation
1719

18-
Pythonパスが通っている場所であればどこでも配置可能です。
19-
本READMEでは一般的なMayaのscriptsフォルダーを例として説明します。
20+
The package can be placed anywhere in the Python path.
21+
This README uses Maya's common scripts folder as an example.
2022

2123
```
22-
~/Documents/maya/scripts/ ()
24+
~/Documents/maya/scripts/ (example)
2325
└── deep_reloader/
2426
├── __init__.py
2527
├── _metadata.py
@@ -33,156 +35,145 @@ Pythonパスが通っている場所であればどこでも配置可能です
3335
└── tests/
3436
```
3537

36-
## 使用方法
38+
## Usage
3739

38-
### 基本的な使用方法
40+
### Basic Usage
3941

4042
```python
41-
# 最もシンプルな使用例
43+
# Simplest usage example
4244
from deep_reloader import deep_reload
4345
deep_reload(your_module)
4446
```
4547

46-
### ログ設定
48+
### Logging Configuration
4749

48-
開発時やデバッグ時には、詳細なログ出力を有効にできます:
50+
For development or debugging, you can enable detailed log output:
4951

5052
```python
5153
from deep_reloader import deep_reload, setup_logging
5254
import logging
5355

54-
# ログレベルを設定(すべてのdeep_reloaderログに影響)
55-
logger = setup_logging(logging.DEBUG) # 詳細なデバッグ情報
56+
# Set log level (affects all deep_reloader logs)
57+
logger = setup_logging(logging.DEBUG) # Detailed debug information
5658

57-
# 返されたロガーを使って直接ログ出力も可能
58-
logger.info("deep_reloaderのログ設定が完了しました")
59+
# You can also use the returned logger for direct logging
60+
logger.info("deep_reloader logging configured")
5961

60-
# その後、通常通り使用
62+
# Then use normally
6163
deep_reload(your_module)
6264
```
6365

64-
**ログレベルの説明:**
65-
- `logging.DEBUG`: pycacheクリアなどの詳細情報も表示
66-
- `logging.INFO`: モジュールリロードの状況を表示(デフォルト)
67-
- `logging.WARNING`: エラーと警告のみ表示
68-
69-
## テスト実行
66+
**Log Level Descriptions:**
67+
- `logging.DEBUG`: Shows detailed information including pycache clearing
68+
- `logging.INFO`: Shows module reload status (default)
69+
- `logging.WARNING`: Shows only errors and warnings
7070

71-
**注意: テストはpytestで実行してください。Maya内部での実行はサポートしていません。**
71+
## Running Tests
7272

73-
このプロジェクトのテストはpytest専用です。開発環境でpytestを使用してテストを実行してください。
73+
**Note: Tests must be run with pytest. Running within Maya is not supported.**
7474

75-
### pytest実行
75+
Tests for this project are pytest-only. Run tests using pytest in your development environment.
7676

7777
```shell
78-
# パッケージの親ディレクトリに移動 (例)
79-
cd ~/Documents/maya/scripts/
78+
# Navigate to repository root (example)
79+
cd ~/Documents/maya/scripts/deep_reloader
80+
81+
# Run all tests
82+
pytest tests/ -v
83+
84+
# Run specific test file
85+
pytest tests/integration/test_absolute_import.py -v
86+
87+
# More detailed output
88+
pytest tests/ -vv
89+
90+
# Concise output
91+
pytest tests/ -q
92+
```
93+
94+
### Verified Environment
95+
96+
**Test Development Environment (Non-Maya):**
97+
- Python 3.11.9+ (verified in current development environment)
98+
- pytest 8.4.2+ (required for running tests)
8099

81-
# 全テスト実行
82-
python -m pytest deep_reloader/tests/ -v
100+
**Note**: The above is the environment used for library testing and development. It differs from the Maya execution environment. Supported Maya versions are not yet finalized.
83101

84-
# 特定のテストファイル実行
85-
python -m pytest deep_reloader/tests/integration/test_absolute_import.py -v
102+
## Limitations and Known Issues
86103

87-
# より詳細な出力
88-
python -m pytest deep_reloader/tests/ -vv
104+
### isinstance() Failure (Python Language Constraint)
89105

90-
# 簡潔な出力
91-
python -m pytest deep_reloader/tests/ -q
106+
Instances created before reload will fail `isinstance()` checks with the reloaded class. This is a constraint of the Python language specification and a common issue with all reload systems.
107+
108+
**Cause**: After reload, the class object ID changes.
109+
110+
**Example**:
111+
```python
112+
# Before reload
113+
my_class = MyClass()
114+
isinstance(my_class, MyClass) # True
115+
116+
deep_reload(MyClass) # Reload
117+
118+
isinstance(my_class, MyClass) # False (my_class is an instance of old MyClass, MyClass is the new class)
92119
```
93120

94-
### 動作確認済み環境
95-
96-
**テスト開発環境(Maya以外):**
97-
- Python 3.11.9+(現在の開発環境で検証済み)
98-
- pytest 8.4.2+(テスト実行に必須)
99-
100-
**注意**: 上記はライブラリのテスト・開発で使用している環境です。Maya内での実行環境とは異なります。Mayaのサポートバージョンはまだ確定していません。
101-
102-
## 制限事項・既知の問題
103-
104-
- **isinstance()チェックの失敗**(Python言語仕様の制約 - 解決不可能)
105-
- リロード前に作成したインスタンスは、リロード後のクラスで`isinstance()`チェックが失敗します
106-
- これはPython言語仕様の制約であり、すべてのリロードシステムが抱える共通の問題です
107-
- **原因**: リロード後、クラスオブジェクトのIDが変わるため、リロード前のインスタンスは古いクラスを参照し続けます
108-
- ****:
109-
```python
110-
# リロード前
111-
obj = MyClass()
112-
isinstance(obj, MyClass) # True
113-
114-
# deep_reload後
115-
isinstance(obj, MyClass) # False(objは古いMyClassのインスタンス、MyClassは新しいクラス)
116-
```
117-
- **回避策**:
118-
- リロード後にインスタンスを再作成する
119-
- クラス名での文字列比較を使用する(`type(obj).__name__ == 'MyClass'`
120-
- アプリケーションを再起動する
121-
122-
- **デコレーターのクロージャ問題**(Python言語仕様の制約 - 解決不可能)
123-
- デコレーター内で例外クラスをキャッチする場合、リロード後に正しくキャッチできません
124-
- これはPython言語仕様の制約であり、すべてのリロードシステム(`importlib.reload()`, IPythonの`%autoreload`等)が抱える共通の問題です
125-
- **原因**: デコレーターのクロージャは定義時にクラスオブジェクトへの参照を保持し、リロード後も古いクラスオブジェクトを参照し続けます
126-
- ****:
127-
```python
128-
# custom_error.py
129-
class CustomError(Exception):
130-
@staticmethod
131-
def catch(function):
132-
@functools.wraps(function)
133-
def wrapper(*args, **kwargs):
134-
try:
135-
return function(*args, **kwargs)
136-
except CustomError as e: # ←デコレーター定義時のCustomErrorを保持
137-
return f"Caught: {e}"
138-
return wrapper
139-
140-
# main.py
141-
@CustomError.catch # ←リロード後、このクロージャは古いCustomErrorを参照
142-
def risky_function():
143-
raise CustomError("Error") # ←新しいCustomErrorを投げる
144-
```
145-
- **回避策**:
146-
- デコレーターを使用せず、直接`try-except`で例外をキャッチする
147-
- 例外クラスをリロード対象から除外する
148-
- アプリケーションを再起動する
149-
150-
- **import文非対応**(将来的に対応予定)
151-
- `import module` 形式の依存関係は現在は解析対象外です
152-
- 現在対応しているのはfrom-import形式のみです:
153-
- `from xxx import yyy` 形式
154-
- `from .xxx import yyy` 形式
155-
- `from . import yyy` 形式
156-
157-
- **現状の推奨**:
158-
- from-import を使用してください(例: `from deep_reloader import deep_reload`
159-
- `import xxx` 形式は将来のバージョンで対応予定です
160-
161-
- **将来の対応予定**:
162-
- `import mypackage` のような同一パッケージ内のモジュールインポートを検出し、依存関係として追跡
163-
- 標準ライブラリや外部ライブラリは引き続き除外
164-
165-
- **単一パッケージのみリロード**(仕様)
166-
- `deep_reload()`は、指定されたモジュールと同じパッケージに属するモジュールのみをリロードします
167-
- **理由**: 組み込みモジュール(`sys`等)やサードパーティライブラリ(`maya.cmds`, `PySide2`等)のリロードを防ぎ、システムの安定性を保つため
168-
- ****: `deep_reload(myutils)` を実行すると、`myutils`パッケージ内のモジュールのみがリロードされます
169-
- **複数の自作パッケージを開発している場合**:
170-
```python
171-
# myutils と myfunctions の両方を開発中の場合
172-
deep_reload(myutils.helper) # myutilsパッケージをリロード
173-
deep_reload(myfunctions.main) # myfunctionsパッケージをリロード
174-
```
175-
176-
### リリース状況
177-
- ✅ コア機能実装完了(from-import対応)
178-
- ✅ テストスイート
179-
- ✅ ドキュメント整備
180-
- ✅ Maya環境での動作検証
181-
- ✅ 循環インポート対応
182-
- 🔄 APIの安定化作業中
183-
- 📋 デバッグログの強化
184-
- 📋 パフォーマンス最適化とキャッシュ機能
185-
186-
## ライセンス
187-
188-
MIT License - 詳細は[LICENSE](LICENSE)ファイルを参照してください。
121+
**Workarounds**:
122+
- Recreate instances after reload
123+
- Use string comparison with class name (`type(my_class).__name__ == 'MyClass'`)
124+
- Restart Maya
125+
126+
### import Statement Not Supported (By Design)
127+
128+
`import xxx` style dependencies are not supported.
129+
130+
**Reason**: Restoring attributes automatically added to parent modules during reload adds complexity.
131+
132+
**Supported Forms**: from-import only
133+
- `from xxx import yyy` style
134+
- `from .xxx import yyy` style
135+
- `from . import yyy` style
136+
137+
### Single Package Reload Only (By Design)
138+
139+
`deep_reload()` only reloads modules that belong to the same package as the passed module.
140+
141+
**Reason**: Prevents reloading of built-in modules (`sys`, etc.) and third-party libraries (`maya.cmds`, `PySide2`, etc.) to maintain system stability.
142+
143+
**Example**: Running `deep_reload(myutils)` will reload only modules in the package that `myutils` belongs to.
144+
145+
**When developing multiple custom packages**:
146+
If there are dependencies between packages, reloading may not work correctly. It is recommended to use a single package.
147+
If absolutely necessary, call `deep_reload()` multiple times considering dependency order.
148+
```python
149+
# When you need to reload multiple packages (not recommended)
150+
deep_reload(myutils)
151+
deep_reload(mytools)
152+
```
153+
154+
### Package Structure Required (By Design)
155+
156+
`deep_reload()` only supports packaged modules.
157+
158+
**Reason**: Standalone modules cannot distinguish between standard library and user code, risking accidental system module reloads.
159+
160+
**Not Supported**: Standalone `.py` files (e.g., `~/maya/scripts/my_tool.py`)
161+
162+
**For standalone modules**: Use standard `importlib.reload()`.
163+
164+
**When using multiple modules**: Package them (directory structure with `__init__.py` recommended).
165+
166+
## Release Status
167+
168+
- ✅ Core functionality complete (from-import support)
169+
- ✅ Test suite
170+
- ✅ Documentation
171+
- ✅ Maya environment verification
172+
- ✅ Circular import support
173+
- 🔄 API stabilization in progress
174+
- 📋 Enhanced debug logging
175+
- 📋 Performance optimization and caching
176+
177+
## License
178+
179+
MIT License - See [LICENSE](LICENSE) file for details.

0 commit comments

Comments
 (0)