2
2
#
3
3
# SPDX-License-Identifier: MIT
4
4
5
+ import io
5
6
import os
6
7
import pathlib
7
8
import pkgutil
8
9
import sys
9
10
11
+ from contextlib import redirect_stdout
12
+
10
13
import pytest
11
14
12
15
import mesonpy
@@ -66,10 +69,10 @@ def test_mesonpy_meta_finder(package_complex, tmp_path):
66
69
mesonpy .Project (package_complex , tmp_path )
67
70
68
71
# point the meta finder to the build directory
69
- finder = _editable .MesonpyMetaFinder ({'complex' }, os .fspath (tmp_path ), ['ninja' ])
72
+ finder = _editable .MesonpyMetaFinder ('complex' , {'complex' }, os .fspath (tmp_path ), ['ninja' ])
70
73
71
74
# check repr
72
- assert repr (finder ) == f'MesonpyMetaFinder({ str (tmp_path )!r} )'
75
+ assert repr (finder ) == f'MesonpyMetaFinder(\' complex \' , { str (tmp_path )!r} )'
73
76
74
77
# verify that we can look up a pure module in the source directory
75
78
spec = finder .find_spec ('complex' )
@@ -130,7 +133,7 @@ def test_resources(tmp_path):
130
133
mesonpy .Project (package_path , tmp_path )
131
134
132
135
# point the meta finder to the build directory
133
- finder = _editable .MesonpyMetaFinder ({'simple' }, os .fspath (tmp_path ), ['ninja' ])
136
+ finder = _editable .MesonpyMetaFinder ('simple' , {'simple' }, os .fspath (tmp_path ), ['ninja' ])
134
137
135
138
# verify that we can look up resources
136
139
spec = finder .find_spec ('simple' )
@@ -149,7 +152,7 @@ def test_importlib_resources(tmp_path):
149
152
mesonpy .Project (package_path , tmp_path )
150
153
151
154
# point the meta finder to the build directory
152
- finder = _editable .MesonpyMetaFinder ({'simple' }, os .fspath (tmp_path ), ['ninja' ])
155
+ finder = _editable .MesonpyMetaFinder ('simple' , {'simple' }, os .fspath (tmp_path ), ['ninja' ])
153
156
154
157
try :
155
158
# install the finder in the meta path
@@ -198,7 +201,7 @@ def test_editable_pkgutils_walk_packages(package_complex, tmp_path):
198
201
# build a package in a temporary directory
199
202
mesonpy .Project (package_complex , tmp_path )
200
203
201
- finder = _editable .MesonpyMetaFinder ({'complex' }, os .fspath (tmp_path ), ['ninja' ])
204
+ finder = _editable .MesonpyMetaFinder ('complex' , {'complex' }, os .fspath (tmp_path ), ['ninja' ])
202
205
203
206
try :
204
207
# install editable hooks
@@ -230,10 +233,64 @@ def test_editable_pkgutils_walk_packages(package_complex, tmp_path):
230
233
231
234
def test_custom_target_install_dir (package_custom_target_dir , tmp_path ):
232
235
mesonpy .Project (package_custom_target_dir , tmp_path )
233
- finder = _editable .MesonpyMetaFinder ({'package' }, os .fspath (tmp_path ), ['ninja' ])
236
+ finder = _editable .MesonpyMetaFinder ('package' , {'package' }, os .fspath (tmp_path ), ['ninja' ])
234
237
try :
235
238
sys .meta_path .insert (0 , finder )
236
239
import package .generated .one
237
240
import package .generated .two # noqa: F401
238
241
finally :
239
242
del sys .meta_path [0 ]
243
+
244
+
245
+ @pytest .mark .parametrize ('verbose' , [False , True ], ids = ('' , 'verbose' ))
246
+ @pytest .mark .parametrize ('args' , [[], ['-j1' ]], ids = ('' , '-Ccompile-args=-j1' ))
247
+ def test_editable_rebuild (package_purelib_and_platlib , tmp_path , verbose , args ):
248
+ with mesonpy ._project ({'builddir' : os .fspath (tmp_path ), 'compile-args' : args }) as project :
249
+
250
+ finder = _editable .MesonpyMetaFinder (
251
+ project ._metadata .name , {'plat' , 'pure' },
252
+ os .fspath (tmp_path ), project ._build_command ,
253
+ verbose = verbose ,
254
+ )
255
+
256
+ try :
257
+ # Install editable hooks
258
+ sys .meta_path .insert (0 , finder )
259
+
260
+ # Import module and trigger rebuild. Importing any module in the
261
+ # Python package triggers the build. Use the the pure Python one as
262
+ # Cygwin is not happy when reloading an extension module.
263
+ stdout = io .StringIO ()
264
+ with redirect_stdout (stdout ):
265
+ import pure
266
+ assert not verbose or stdout .getvalue ().startswith ('meson-python: building ' )
267
+
268
+ # Reset state.
269
+ del sys .modules ['pure' ]
270
+ finder ._rebuild .cache_clear ()
271
+
272
+ # Importing again should result in no output.
273
+ stdout = io .StringIO ()
274
+ with redirect_stdout (stdout ):
275
+ import pure # noqa: F401, F811
276
+ assert stdout .getvalue () == ''
277
+
278
+ finally :
279
+ del sys .meta_path [0 ]
280
+ sys .modules .pop ('pure' , None )
281
+
282
+
283
+ def test_editable_verbose (venv , package_complex , editable_complex , monkeypatch ):
284
+ monkeypatch .setenv ('MESONPY_EDITABLE_VERBOSE' , '1' )
285
+ venv .pip ('install' , os .fspath (editable_complex ))
286
+
287
+ # Importing the module should not result in any output since the project has already been built
288
+ assert venv .python ('-c' , 'import complex' ).strip () == ''
289
+
290
+ # Touch a compiled source file and make sure that the build info is output on import
291
+ package_complex .joinpath ('test.pyx' ).touch ()
292
+ output = venv .python ('-c' , 'import complex' ).strip ()
293
+ assert output .startswith ('meson-python: building complex: ' )
294
+
295
+ # Another import without file changes should not show any output
296
+ assert venv .python ('-c' , 'import complex' ) == ''
0 commit comments