@@ -56,30 +56,50 @@ def test_read_files(tmp_path, monkeypatch):
56
56
expand .read_files (["../a.txt" ], tmp_path )
57
57
58
58
59
- def test_read_attr (tmp_path , monkeypatch ):
60
- files = {
61
- "pkg/__init__.py" : "" ,
62
- "pkg/sub/__init__.py" : "VERSION = '0.1.1'" ,
63
- "pkg/sub/mod.py" : (
64
- "VALUES = {'a': 0, 'b': {42}, 'c': (0, 1, 1)}\n "
65
- "raise SystemExit(1)"
66
- ),
67
- }
68
- write_files (files , tmp_path )
69
-
70
- with monkeypatch .context () as m :
71
- m .chdir (tmp_path )
72
- # Make sure it can read the attr statically without evaluating the module
73
- assert expand .read_attr ('pkg.sub.VERSION' ) == '0.1.1'
74
- values = expand .read_attr ('lib.mod.VALUES' , {'lib' : 'pkg/sub' })
75
-
76
- assert values ['a' ] == 0
77
- assert values ['b' ] == {42 }
78
-
79
- # Make sure the same APIs work outside cwd
80
- assert expand .read_attr ('pkg.sub.VERSION' , root_dir = tmp_path ) == '0.1.1'
81
- values = expand .read_attr ('lib.mod.VALUES' , {'lib' : 'pkg/sub' }, tmp_path )
82
- assert values ['c' ] == (0 , 1 , 1 )
59
+ class TestReadAttr :
60
+ def test_read_attr (self , tmp_path , monkeypatch ):
61
+ files = {
62
+ "pkg/__init__.py" : "" ,
63
+ "pkg/sub/__init__.py" : "VERSION = '0.1.1'" ,
64
+ "pkg/sub/mod.py" : (
65
+ "VALUES = {'a': 0, 'b': {42}, 'c': (0, 1, 1)}\n "
66
+ "raise SystemExit(1)"
67
+ ),
68
+ }
69
+ write_files (files , tmp_path )
70
+
71
+ with monkeypatch .context () as m :
72
+ m .chdir (tmp_path )
73
+ # Make sure it can read the attr statically without evaluating the module
74
+ assert expand .read_attr ('pkg.sub.VERSION' ) == '0.1.1'
75
+ values = expand .read_attr ('lib.mod.VALUES' , {'lib' : 'pkg/sub' })
76
+
77
+ assert values ['a' ] == 0
78
+ assert values ['b' ] == {42 }
79
+
80
+ # Make sure the same APIs work outside cwd
81
+ assert expand .read_attr ('pkg.sub.VERSION' , root_dir = tmp_path ) == '0.1.1'
82
+ values = expand .read_attr ('lib.mod.VALUES' , {'lib' : 'pkg/sub' }, tmp_path )
83
+ assert values ['c' ] == (0 , 1 , 1 )
84
+
85
+ def test_import_order (self , tmp_path ):
86
+ """
87
+ Sometimes the import machinery will import the parent package of a nested
88
+ module, which triggers side-effects and might create problems (see issue #3176)
89
+
90
+ ``read_attr`` should bypass these limitations by resolving modules statically
91
+ (via ast.literal_eval).
92
+ """
93
+ files = {
94
+ "src/pkg/__init__.py" : "from .main import func\n from .about import version" ,
95
+ "src/pkg/main.py" : "import super_complicated_dep\n def func(): return 42" ,
96
+ "src/pkg/about.py" : "version = '42'" ,
97
+ }
98
+ write_files (files , tmp_path )
99
+ attr_desc = "pkg.about.version"
100
+ pkg_dir = {"" : "src" }
101
+ # `import super_complicated_dep` should not run, otherwise the build fails
102
+ assert expand .read_attr (attr_desc , pkg_dir , tmp_path ) == "42"
83
103
84
104
85
105
def test_resolve_class ():
0 commit comments