Skip to content

Commit b59bf65

Browse files
committed
Unify temporary directory allocation strategy in tests
This package was previously using three different temporary directory allocation strategies: - Manual `TemporaryDirectory` management - pytest `tmpdir` fixture - pytest `tmp_path` fixture This commit changes all temporary directory allocation in tests to use the `tmp_path` fixture, and includes a compatibility definition of that fixture so that the tests will continue to work properly on RHEL 8.
1 parent aee8364 commit b59bf65

24 files changed

Lines changed: 850 additions & 935 deletions

test/conftest.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Copyright 2026 Open Source Robotics Foundation, Inc.
2+
# Licensed under the Apache License, Version 2.0
3+
4+
from pathlib import Path
5+
6+
import pytest
7+
8+
9+
if getattr(pytest, 'version_tuple', ()) < (3, 9):
10+
@pytest.fixture
11+
def tmp_path(tmpdir):
12+
"""
13+
Compatibility fixture for temporary directory allocation.
14+
15+
This can be removed when we drop support for platforms with Pytest
16+
versions older than 3.9 (namely Enterprise Linux 8).
17+
"""
18+
return Path(tmpdir)

test/spell_check.words

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ asyncio
66
autouse
77
backend
88
backported
9-
basepath
109
bazqux
1110
blocklist
1211
callables

test/test_build_python.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import asyncio
55
from contextlib import suppress
66
from pathlib import Path
7-
from tempfile import TemporaryDirectory
87
from types import SimpleNamespace
98

109
from colcon_core.package_descriptor import PackageDescriptor
@@ -179,15 +178,16 @@ def _test_build_package(
179178
@pytest.mark.parametrize(
180179
'symlink_first',
181180
[False, True])
182-
def test_build_package(symlink_first, setup_cfg, libexec_pattern, data_files):
183-
with TemporaryDirectory(prefix='test_colcon_') as tmp_path_str:
184-
_test_build_package(
185-
tmp_path_str, symlink_install=symlink_first,
186-
setup_cfg=setup_cfg, libexec_pattern=libexec_pattern,
187-
data_files=data_files)
188-
189-
# Test again with the symlink flag inverted to validate cleanup
190-
_test_build_package(
191-
tmp_path_str, symlink_install=not symlink_first,
192-
setup_cfg=setup_cfg, libexec_pattern=libexec_pattern,
193-
data_files=data_files)
181+
def test_build_package(
182+
symlink_first, setup_cfg, libexec_pattern, data_files, tmp_path,
183+
):
184+
tmp_path_str = str(tmp_path)
185+
186+
_test_build_package(
187+
tmp_path_str, symlink_install=symlink_first, setup_cfg=setup_cfg,
188+
libexec_pattern=libexec_pattern, data_files=data_files)
189+
190+
# Test again with the symlink flag inverted to validate cleanup
191+
_test_build_package(
192+
tmp_path_str, symlink_install=not symlink_first, setup_cfg=setup_cfg,
193+
libexec_pattern=libexec_pattern, data_files=data_files)

test/test_command.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import signal
77
import sys
88
from tempfile import mkdtemp
9-
from tempfile import TemporaryDirectory
109
from unittest.mock import Mock
1110
from unittest.mock import patch
1211

@@ -234,20 +233,19 @@ def test_prog_name_not_a_file():
234233

235234

236235
@pytest.mark.skipif(sys.platform == 'win32', reason='Symlinks not supported.')
237-
def test_prog_name_symlink():
236+
def test_prog_name_symlink(tmp_path):
238237
# use __file__ since we know it exists
239-
with TemporaryDirectory(prefix='test_colcon_') as temp_dir:
240-
linked_file = os.path.join(temp_dir, 'test_command.py')
241-
os.symlink(__file__, linked_file)
242-
243-
argv = [linked_file]
244-
with patch('colcon_core.command.sys.argv', argv):
245-
with patch(
246-
'colcon_core.command.shutil.which',
247-
return_value=__file__
248-
):
249-
# prog should be shortened to the basename
250-
assert get_prog_name() == 'test_command.py'
238+
linked_file = tmp_path / 'test_command.py'
239+
linked_file.symlink_to(__file__)
240+
241+
argv = [str(linked_file)]
242+
with patch('colcon_core.command.sys.argv', argv):
243+
with patch(
244+
'colcon_core.command.shutil.which',
245+
return_value=__file__
246+
):
247+
# prog should be shortened to the basename
248+
assert get_prog_name() == 'test_command.py'
251249

252250

253251
@pytest.mark.skipif(sys.platform != 'win32', reason='Only valid on Windows.')

test/test_environment.py

Lines changed: 50 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
# Copyright 2016-2018 Dirk Thomas
22
# Licensed under the Apache License, Version 2.0
33

4-
import os
54
from pathlib import Path
6-
from tempfile import TemporaryDirectory
75
from unittest.mock import Mock
86
from unittest.mock import patch
97

@@ -51,66 +49,60 @@ class Extension4(ShellExtensionPoint):
5149
pass
5250

5351

54-
def test_create_environment_scripts():
55-
with TemporaryDirectory(prefix='test_colcon_') as basepath:
56-
pkg = Mock()
57-
pkg.name = 'name'
58-
pkg.dependencies = {}
59-
pkg.hooks = []
60-
args = Mock()
61-
args.install_base = basepath
52+
def test_create_environment_scripts(tmp_path):
53+
pkg = Mock()
54+
pkg.name = 'name'
55+
pkg.dependencies = {}
56+
pkg.hooks = []
57+
args = Mock()
58+
args.install_base = str(tmp_path)
6259

63-
# no hooks at all
60+
# no hooks at all
61+
with patch(
62+
'colcon_core.environment.create_environment_hooks', return_value=[],
63+
):
6464
with patch(
65-
'colcon_core.environment.create_environment_hooks', return_value=[]
65+
'colcon_core.environment.get_shell_extensions', return_value={},
6666
):
67-
with patch(
68-
'colcon_core.environment.get_shell_extensions', return_value={}
69-
):
70-
create_environment_scripts(pkg, args)
71-
72-
pkg.hooks = [os.path.join(basepath, 'subA')]
73-
with ExtensionPointContext(
74-
extension3=Extension3, extension4=Extension4
75-
):
76-
extensions = get_shell_extensions()
77-
# one invalid return value, one check correct hooks argument
78-
extensions[100]['extension3'].create_package_script = Mock()
79-
extensions[100]['extension4'].create_package_script = Mock(
80-
return_value=None)
81-
with patch('colcon_core.environment.logger.error') as error:
82-
create_environment_scripts(
83-
pkg, args, default_hooks=[('subB', )],
84-
additional_hooks=[['subC', 'arg1', 'arg2']])
85-
# the raised exception is catched and results in an error message
86-
assert error.call_count == 1
87-
assert len(error.call_args[0]) == 1
88-
assert error.call_args[0][0].startswith(
89-
"Exception in shell extension 'extension3': "
90-
'create_package_script() should return a list\n')
91-
# check for correct hooks argument
92-
mock = extensions[100]['extension4'].create_package_script
93-
assert mock.call_count == 1
94-
assert len(mock.call_args[0]) == 3
95-
assert mock.call_args[0][0] == Path(args.install_base)
96-
assert mock.call_args[0][1] == pkg.name
97-
hook_tuples = mock.call_args[0][2]
98-
assert len(hook_tuples) == 3
99-
assert hook_tuples[0] == ('subB', ())
100-
assert hook_tuples[1] == ('subC', ['arg1', 'arg2'])
101-
assert hook_tuples[2] == ('subA', [])
102-
103-
104-
def test_create_environment_hooks():
105-
with TemporaryDirectory(prefix='test_colcon_') as basepath:
106-
with ExtensionPointContext(
107-
extension1=Extension1, extension2=Extension2
108-
):
109-
with patch('colcon_core.environment.logger.error') as error:
110-
hooks = create_environment_hooks(basepath, 'pkg_name')
67+
create_environment_scripts(pkg, args)
68+
69+
pkg.hooks = [str(tmp_path / 'subA')]
70+
with ExtensionPointContext(extension3=Extension3, extension4=Extension4):
71+
extensions = get_shell_extensions()
72+
# one invalid return value, one check correct hooks argument
73+
extensions[100]['extension3'].create_package_script = Mock()
74+
extensions[100]['extension4'].create_package_script = Mock(
75+
return_value=None)
76+
with patch('colcon_core.environment.logger.error') as error:
77+
create_environment_scripts(
78+
pkg, args, default_hooks=[('subB', )],
79+
additional_hooks=[['subC', 'arg1', 'arg2']])
80+
# the raised exception is catched and results in an error message
81+
assert error.call_count == 1
82+
assert len(error.call_args[0]) == 1
83+
assert error.call_args[0][0].startswith(
84+
"Exception in shell extension 'extension3': "
85+
'create_package_script() should return a list\n')
86+
# check for correct hooks argument
87+
mock = extensions[100]['extension4'].create_package_script
88+
assert mock.call_count == 1
89+
assert len(mock.call_args[0]) == 3
90+
assert mock.call_args[0][0] == Path(args.install_base)
91+
assert mock.call_args[0][1] == pkg.name
92+
hook_tuples = mock.call_args[0][2]
93+
assert len(hook_tuples) == 3
94+
assert hook_tuples[0] == ('subB', ())
95+
assert hook_tuples[1] == ('subC', ['arg1', 'arg2'])
96+
assert hook_tuples[2] == ('subA', [])
97+
98+
99+
def test_create_environment_hooks(tmp_path):
100+
with ExtensionPointContext(extension1=Extension1, extension2=Extension2):
101+
with patch('colcon_core.environment.logger.error') as error:
102+
hooks = create_environment_hooks(str(tmp_path), 'pkg_name')
111103
assert len(hooks) == 2
112-
assert hooks[0] == f'{basepath}/share/pkg_name/hook/one.ext'
113-
assert hooks[1] == f'{basepath}/share/pkg_name/hook/two.ext'
104+
assert hooks[0] == f'{tmp_path}/share/pkg_name/hook/one.ext'
105+
assert hooks[1] == f'{tmp_path}/share/pkg_name/hook/two.ext'
114106
# the raised exception is catched and results in an error message
115107
assert error.call_count == 1
116108
assert len(error.call_args[0]) == 1

test/test_environment_path.py

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,38 @@
11
# Copyright 2016-2018 Dirk Thomas
22
# Licensed under the Apache License, Version 2.0
33

4-
from pathlib import Path
5-
from tempfile import TemporaryDirectory
64
from unittest.mock import patch
75

86
from colcon_core.environment.path import PathEnvironment
97

108

11-
def test_path():
9+
def test_path(tmp_path):
1210
extension = PathEnvironment()
1311

14-
with TemporaryDirectory(prefix='test_colcon_') as prefix_path:
15-
prefix_path = Path(prefix_path)
16-
with patch(
17-
'colcon_core.shell.create_environment_hook',
18-
return_value=['/some/hook', '/other/hook']
19-
):
20-
# bin directory does not exist
21-
hooks = extension.create_environment_hooks(prefix_path, 'pkg_name')
22-
assert len(hooks) == 0
23-
24-
# bin directory exists, but empty
25-
(prefix_path / 'bin').mkdir()
26-
hooks = extension.create_environment_hooks(prefix_path, 'pkg_name')
27-
assert len(hooks) == 0
28-
29-
# bin directory exists, but only subdirectories
30-
(prefix_path / 'bin' / 'subdir').mkdir()
31-
hooks = extension.create_environment_hooks(prefix_path, 'pkg_name')
32-
assert len(hooks) == 0
33-
34-
# bin directory exists, with file
35-
(prefix_path / 'bin' / 'hook').write_text('')
36-
hooks = extension.create_environment_hooks(prefix_path, 'pkg_name')
37-
assert len(hooks) == 2
38-
39-
# bin directory exists, with files
40-
(prefix_path / 'bin' / 'hook2').write_text('')
41-
hooks = extension.create_environment_hooks(prefix_path, 'pkg_name')
42-
assert len(hooks) == 2
12+
with patch(
13+
'colcon_core.shell.create_environment_hook',
14+
return_value=['/some/hook', '/other/hook']
15+
):
16+
# bin directory does not exist
17+
hooks = extension.create_environment_hooks(tmp_path, 'pkg_name')
18+
assert len(hooks) == 0
19+
20+
# bin directory exists, but empty
21+
(tmp_path / 'bin').mkdir()
22+
hooks = extension.create_environment_hooks(tmp_path, 'pkg_name')
23+
assert len(hooks) == 0
24+
25+
# bin directory exists, but only subdirectories
26+
(tmp_path / 'bin' / 'subdir').mkdir()
27+
hooks = extension.create_environment_hooks(tmp_path, 'pkg_name')
28+
assert len(hooks) == 0
29+
30+
# bin directory exists, with file
31+
(tmp_path / 'bin' / 'hook').write_text('')
32+
hooks = extension.create_environment_hooks(tmp_path, 'pkg_name')
33+
assert len(hooks) == 2
34+
35+
# bin directory exists, with files
36+
(tmp_path / 'bin' / 'hook2').write_text('')
37+
hooks = extension.create_environment_hooks(tmp_path, 'pkg_name')
38+
assert len(hooks) == 2
Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,25 @@
11
# Copyright 2016-2018 Dirk Thomas
22
# Licensed under the Apache License, Version 2.0
33

4-
from pathlib import Path
5-
from tempfile import TemporaryDirectory
64
from unittest.mock import patch
75

86
from colcon_core.environment.pythonpath import PythonPathEnvironment
97
from colcon_core.python_install_path import get_python_install_path
108

119

12-
def test_pythonpath():
10+
def test_pythonpath(tmp_path):
1311
extension = PythonPathEnvironment()
1412

15-
with TemporaryDirectory(prefix='test_colcon_') as prefix_path:
16-
prefix_path = Path(prefix_path)
17-
with patch(
18-
'colcon_core.shell.create_environment_hook',
19-
return_value=['/some/hook', '/other/hook']
20-
):
21-
# Python path does not exist
22-
hooks = extension.create_environment_hooks(prefix_path, 'pkg_name')
23-
assert len(hooks) == 0
13+
with patch(
14+
'colcon_core.shell.create_environment_hook',
15+
return_value=['/some/hook', '/other/hook'],
16+
):
17+
# Python path does not exist
18+
hooks = extension.create_environment_hooks(tmp_path, 'pkg_name')
19+
assert len(hooks) == 0
2420

25-
# Python path exists
26-
python_path = get_python_install_path(
27-
'purelib', {'base': prefix_path})
28-
python_path.mkdir(parents=True)
29-
hooks = extension.create_environment_hooks(prefix_path, 'pkg_name')
30-
assert len(hooks) == 2
21+
# Python path exists
22+
python_path = get_python_install_path('purelib', {'base': tmp_path})
23+
python_path.mkdir(parents=True)
24+
hooks = extension.create_environment_hooks(tmp_path, 'pkg_name')
25+
assert len(hooks) == 2

0 commit comments

Comments
 (0)