Skip to content

Commit b3d2954

Browse files
committed
test: namespace packageサポートの検証を追加
- test_namespace_package.pyを追加し、__init__.pyなしのnamespace packageでdeep_reloaderが正常に動作することを検証 - test_utils.pyのcreate_test_modules()にcreate_initパラメータを追加し、namespace packageのテスト作成を可能に
1 parent 502dc0c commit b3d2954

2 files changed

Lines changed: 113 additions & 3 deletions

File tree

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
"""
2+
namespace package(__init__.pyなし)でのdeep_reload動作テスト
3+
4+
Python 3.3以降(PEP 420)では__init__.pyなしでもパッケージとして機能します。
5+
このテストはdeep_reloaderがそのようなnamespace packageを正しく扱えるかを検証します。
6+
"""
7+
8+
import textwrap
9+
10+
from deep_reloader import deep_reload
11+
12+
from ..test_utils import create_test_modules, update_module
13+
14+
15+
def test_namespace_package_without_init(tmp_path):
16+
"""
17+
__init__.pyなしのnamespace packageでリロードできるか
18+
"""
19+
# __init__.pyなしでパッケージを作成
20+
modules_dir = create_test_modules(
21+
tmp_path,
22+
{
23+
'a.py': textwrap.dedent(
24+
"""
25+
x = 1
26+
"""
27+
),
28+
'b.py': textwrap.dedent(
29+
"""
30+
from .a import x
31+
"""
32+
),
33+
},
34+
package_name='namespace_pkg',
35+
create_init=False, # namespace packageとして作成
36+
)
37+
38+
# __init__.pyが存在しないことを確認
39+
assert not (modules_dir / '__init__.py').exists()
40+
41+
import namespace_pkg.b # type: ignore
42+
43+
assert namespace_pkg.b.x == 1
44+
45+
# a.pyを書き換えて値を変更
46+
update_module(modules_dir, 'a.py', 'x = 999')
47+
48+
# deep reloadを実行
49+
deep_reload(namespace_pkg.b)
50+
51+
# 更新された値を確認
52+
assert namespace_pkg.b.x == 999
53+
54+
55+
def test_namespace_package_relative_import(tmp_path):
56+
"""
57+
__init__.pyなしのnamespace packageで相対インポートが動作するか
58+
"""
59+
modules_dir = create_test_modules(
60+
tmp_path,
61+
{
62+
'utils.py': textwrap.dedent(
63+
"""
64+
def helper():
65+
return "original"
66+
"""
67+
),
68+
'main.py': textwrap.dedent(
69+
"""
70+
from .utils import helper
71+
72+
def process():
73+
return helper()
74+
"""
75+
),
76+
},
77+
package_name='namespace_app',
78+
create_init=False, # namespace packageとして作成
79+
)
80+
81+
# __init__.pyが存在しないことを確認
82+
assert not (modules_dir / '__init__.py').exists()
83+
84+
import namespace_app.main # type: ignore
85+
86+
assert namespace_app.main.process() == "original"
87+
88+
# utils.pyを書き換え
89+
update_module(
90+
modules_dir,
91+
'utils.py',
92+
textwrap.dedent(
93+
"""
94+
def helper():
95+
return "updated"
96+
"""
97+
),
98+
)
99+
100+
# deep reloadを実行
101+
deep_reload(namespace_app.main)
102+
103+
# 更新された値を確認
104+
assert namespace_app.main.process() == "updated"

tests/test_utils.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,12 @@ def add_temp_path_to_sys(tmp_path: Path) -> None:
7676
sys.path.insert(0, tmp_path_str)
7777

7878

79-
def create_test_modules(tmp_path: Path, structure: Dict[str, str], package_name: Optional[str] = None) -> Path:
79+
def create_test_modules(
80+
tmp_path: Path,
81+
structure: Dict[str, str],
82+
package_name: Optional[str] = None,
83+
create_init: bool = True,
84+
) -> Path:
8085
"""
8186
辞書で定義されたテストモジュール構造を一括作成し、sys.pathに自動追加
8287
@@ -87,6 +92,7 @@ def create_test_modules(tmp_path: Path, structure: Dict[str, str], package_name:
8792
値: ファイルの内容
8893
例: {'__init__.py': '', 'module_a.py': 'x=1', 'sub/mod.py': 'y=2'}
8994
package_name: パッケージ名。Noneの場合はtmp_path直下にファイルを作成(パッケージなし)
95+
create_init: __init__.pyを自動作成するか(デフォルトTrue)。Falseの場合はnamespace package
9096
9197
Returns:
9298
パッケージディレクトリのPath(package_nameがNoneの場合はtmp_path)
@@ -135,8 +141,8 @@ def create_test_modules(tmp_path: Path, structure: Dict[str, str], package_name:
135141
file_path.write_text(content, encoding='utf-8')
136142

137143
# __init__.pyが明示的に指定されていない場合、空の__init__.pyを作成
138-
# ただし、package_nameがNoneの場合(パッケージなし)は作成しない
139-
if package_name is not None:
144+
# ただし、package_nameがNoneの場合(パッケージなし)またはcreate_init=Falseの場合は作成しない
145+
if create_init and package_name is not None:
140146
init_file = modules_dir / '__init__.py'
141147
if '__init__.py' not in structure and not init_file.exists():
142148
init_file.write_text('', encoding='utf-8')

0 commit comments

Comments
 (0)