diff --git a/src/rpdk/core/test.py b/src/rpdk/core/test.py index b7e24993..d2ea8f80 100644 --- a/src/rpdk/core/test.py +++ b/src/rpdk/core/test.py @@ -77,14 +77,27 @@ def empty_hook_override(): return {"CREATE_PRE_PROVISION": {}} +# As per Python docs NamedTemporaryFile does NOT work the same in Windows. Setting delete=False as workaround. +# +# Temporary file must be explicitly cleaned up after temporary_ini_file() is called! +# +# "Whether the name can be used to open the file a second time, while the named temporary file is still open, +# varies across platforms (it can be so used on Unix; it cannot on Windows)." +# https://docs.python.org/3.9/library/tempfile.html#tempfile.NamedTemporaryFile +# +# Fix being tracked here https://github.com/python/cpython/issues/58451 + + @contextmanager def temporary_ini_file(): with NamedTemporaryFile( - mode="w", encoding="utf-8", prefix="pytest_", suffix=".ini" + mode="w", encoding="utf-8", prefix="pytest_", suffix=".ini", delete=False ) as temp: LOG.debug("temporary pytest.ini path: %s", temp.name) path = Path(temp.name).resolve(strict=True) copy_resource(__name__, "data/pytest-contract.ini", path) + # Close temporary file for other processes to use, needed on Windows + temp.close() yield str(path) @@ -394,6 +407,11 @@ def invoke_test(args, project, overrides, inputs): pytest_args.extend(args.passed_to_pytest) LOG.debug("pytest args: %s", pytest_args) ret = pytest.main(pytest_args, plugins=[plugin]) + # Manually clean up temporary file before exiting - issue with NamedTemporaryFile method on Windows + try: + os.unlink(path) + except FileNotFoundError: + pass if ret: raise SysExitRecommendedError("One or more contract tests failed") diff --git a/tests/test_test.py b/tests/test_test.py index e8ad173a..66eaaad2 100644 --- a/tests/test_test.py +++ b/tests/test_test.py @@ -337,6 +337,11 @@ def test_temporary_ini_file(): with path.open("r", encoding="utf-8") as f: assert "[pytest]" in f.read() + # Manually clean up temporary file before exiting - issue with NamedTemporaryFile method on Windows + try: + os.unlink(path_str) + except FileNotFoundError: + pass def test_get_overrides_no_root():