@@ -1106,22 +1106,21 @@ def test_ternary_display():
1106
1106
1107
1107
1108
1108
class TestIssue2121 :
1109
- def test_simple (self , testdir ):
1110
- testdir .tmpdir .join ("tests/file.py" ).ensure ().write (
1111
- """
1112
- def test_simple_failure():
1113
- assert 1 + 1 == 3
1114
- """
1115
- )
1116
- testdir .tmpdir .join ("pytest.ini" ).write (
1117
- textwrap .dedent (
1109
+ def test_rewrite_python_files_contain_subdirs (self , testdir ):
1110
+ testdir .makepyfile (
1111
+ ** {
1112
+ "tests/file.py" : """
1113
+ def test_simple_failure():
1114
+ assert 1 + 1 == 3
1118
1115
"""
1119
- [pytest]
1120
- python_files = tests/**.py
1121
- """
1122
- )
1116
+ }
1117
+ )
1118
+ testdir .makeini (
1119
+ """
1120
+ [pytest]
1121
+ python_files = tests/**.py
1122
+ """
1123
1123
)
1124
-
1125
1124
result = testdir .runpytest ()
1126
1125
result .stdout .fnmatch_lines ("*E*assert (1 + 1) == 3" )
1127
1126
@@ -1153,3 +1152,83 @@ def spy_write_pyc(*args, **kwargs):
1153
1152
hook = AssertionRewritingHook (pytestconfig )
1154
1153
assert hook .find_module ("test_foo" ) is not None
1155
1154
assert len (write_pyc_called ) == 1
1155
+
1156
+
1157
+ class TestEarlyRewriteBailout (object ):
1158
+ @pytest .fixture
1159
+ def hook (self , pytestconfig , monkeypatch , testdir ):
1160
+ """Returns a patched AssertionRewritingHook instance so we can configure its initial paths and track
1161
+ if imp.find_module has been called.
1162
+ """
1163
+ import imp
1164
+
1165
+ self .find_module_calls = []
1166
+ self .initial_paths = set ()
1167
+
1168
+ class StubSession (object ):
1169
+ _initialpaths = self .initial_paths
1170
+
1171
+ def isinitpath (self , p ):
1172
+ return p in self ._initialpaths
1173
+
1174
+ def spy_imp_find_module (name , path ):
1175
+ self .find_module_calls .append (name )
1176
+ return imp .find_module (name , path )
1177
+
1178
+ hook = AssertionRewritingHook (pytestconfig )
1179
+ # use default patterns, otherwise we inherit pytest's testing config
1180
+ hook .fnpats [:] = ["test_*.py" , "*_test.py" ]
1181
+ monkeypatch .setattr (hook , "_imp_find_module" , spy_imp_find_module )
1182
+ hook .set_session (StubSession ())
1183
+ testdir .syspathinsert ()
1184
+ return hook
1185
+
1186
+ def test_basic (self , testdir , hook ):
1187
+ """
1188
+ Ensure we avoid calling imp.find_module when we know for sure a certain module will not be rewritten
1189
+ to optimize assertion rewriting (#3918).
1190
+ """
1191
+ testdir .makeconftest (
1192
+ """
1193
+ import pytest
1194
+ @pytest.fixture
1195
+ def fix(): return 1
1196
+ """
1197
+ )
1198
+ testdir .makepyfile (test_foo = "def test_foo(): pass" )
1199
+ testdir .makepyfile (bar = "def bar(): pass" )
1200
+ foobar_path = testdir .makepyfile (foobar = "def foobar(): pass" )
1201
+ self .initial_paths .add (foobar_path )
1202
+
1203
+ # conftest files should always be rewritten
1204
+ assert hook .find_module ("conftest" ) is not None
1205
+ assert self .find_module_calls == ["conftest" ]
1206
+
1207
+ # files matching "python_files" mask should always be rewritten
1208
+ assert hook .find_module ("test_foo" ) is not None
1209
+ assert self .find_module_calls == ["conftest" , "test_foo" ]
1210
+
1211
+ # file does not match "python_files": early bailout
1212
+ assert hook .find_module ("bar" ) is None
1213
+ assert self .find_module_calls == ["conftest" , "test_foo" ]
1214
+
1215
+ # file is an initial path (passed on the command-line): should be rewritten
1216
+ assert hook .find_module ("foobar" ) is not None
1217
+ assert self .find_module_calls == ["conftest" , "test_foo" , "foobar" ]
1218
+
1219
+ def test_pattern_contains_subdirectories (self , testdir , hook ):
1220
+ """If one of the python_files patterns contain subdirectories ("tests/**.py") we can't bailout early
1221
+ because we need to match with the full path, which can only be found by calling imp.find_module.
1222
+ """
1223
+ p = testdir .makepyfile (
1224
+ ** {
1225
+ "tests/file.py" : """
1226
+ def test_simple_failure():
1227
+ assert 1 + 1 == 3
1228
+ """
1229
+ }
1230
+ )
1231
+ testdir .syspathinsert (p .dirpath ())
1232
+ hook .fnpats [:] = ["tests/**.py" ]
1233
+ assert hook .find_module ("file" ) is not None
1234
+ assert self .find_module_calls == ["file" ]
0 commit comments