22#
33# SPDX-License-Identifier: MIT
44
5+ import io
56import os
67import pathlib
78import pkgutil
89import sys
910
11+ from contextlib import redirect_stdout
12+
1013import pytest
1114
1215import mesonpy
@@ -66,10 +69,10 @@ def test_mesonpy_meta_finder(package_complex, tmp_path):
6669 mesonpy .Project (package_complex , tmp_path )
6770
6871 # 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' ])
7073
7174 # check repr
72- assert repr (finder ) == f'MesonpyMetaFinder({ str (tmp_path )!r} )'
75+ assert repr (finder ) == f'MesonpyMetaFinder(\' complex \' , { str (tmp_path )!r} )'
7376
7477 # verify that we can look up a pure module in the source directory
7578 spec = finder .find_spec ('complex' )
@@ -130,7 +133,7 @@ def test_resources(tmp_path):
130133 mesonpy .Project (package_path , tmp_path )
131134
132135 # 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' ])
134137
135138 # verify that we can look up resources
136139 spec = finder .find_spec ('simple' )
@@ -149,7 +152,7 @@ def test_importlib_resources(tmp_path):
149152 mesonpy .Project (package_path , tmp_path )
150153
151154 # 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' ])
153156
154157 try :
155158 # install the finder in the meta path
@@ -198,7 +201,7 @@ def test_editable_pkgutils_walk_packages(package_complex, tmp_path):
198201 # build a package in a temporary directory
199202 mesonpy .Project (package_complex , tmp_path )
200203
201- finder = _editable .MesonpyMetaFinder ({'complex' }, os .fspath (tmp_path ), ['ninja' ])
204+ finder = _editable .MesonpyMetaFinder ('complex' , {'complex' }, os .fspath (tmp_path ), ['ninja' ])
202205
203206 try :
204207 # install editable hooks
@@ -230,10 +233,64 @@ def test_editable_pkgutils_walk_packages(package_complex, tmp_path):
230233
231234def test_custom_target_install_dir (package_custom_target_dir , tmp_path ):
232235 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' ])
234237 try :
235238 sys .meta_path .insert (0 , finder )
236239 import package .generated .one
237240 import package .generated .two # noqa: F401
238241 finally :
239242 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