Skip to content

Commit cbcf95f

Browse files
authored
Add context manager for adding DLL directories to the search path (#2)
The list of DLL directories is read from the specified environment variable and added to the Windows search path for DLLs. This only applies to Python 3.8+. Any values in the environment variable that are not directories are ignored. Signed-off-by: Jacob Perron <jacob@openrobotics.org>
1 parent e51fac8 commit cbcf95f

4 files changed

Lines changed: 101 additions & 0 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
# rpyutils
22
Various utility types and functions for Python
3+
4+
## API
5+
6+
- Context manager for adding DLLs to the Windows search path.
7+
Only applies to Python 3.8 or newer:
8+
- `add_dll_directories_from_env`

rpyutils/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,9 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
from .add_dll_directories import add_dll_directories_from_env
16+
17+
1518
__all__ = [
19+
'add_dll_directories_from_env',
1620
]

rpyutils/add_dll_directories.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Copyright 2020 Open Source Robotics Foundation, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from contextlib import contextmanager
16+
import os
17+
import sys
18+
19+
20+
@contextmanager
21+
def add_dll_directories_from_env(env_name: str):
22+
"""
23+
Add a list of directories from an environment variable to the DLL search path on Windows.
24+
25+
Each directory in the environment variable that exists is passed to
26+
:func:`os.add_dll_directory`.
27+
28+
If this function is called on a system other than Windows, then nothing happens and
29+
an empty list is returned.
30+
If this function is called with a version of Python less than 3.8, then nothing happens and
31+
an empty list is returned.
32+
33+
Example usage::
34+
35+
with add_dll_directories_from_env('PATH'):
36+
importlib.import_module('foo', package='bar')
37+
38+
:param env_name: The name of the environment variable with DLL search paths.
39+
:return: A list of handles to directories.
40+
"""
41+
dll_dir_handles = []
42+
# This function only makes sense on Windows and if the function 'add_dll_directory' exists
43+
if sys.platform == 'win32' and hasattr(os, 'add_dll_directory'):
44+
env_value = os.environ.get(env_name)
45+
path_list = env_value.split(os.pathsep) if env_value is not None else []
46+
for prefix_path in path_list:
47+
# Only add directories that exist
48+
if os.path.isdir(prefix_path):
49+
dll_dir_handles.append(os.add_dll_directory(prefix_path))
50+
51+
try:
52+
yield dll_dir_handles
53+
finally:
54+
for handle in dll_dir_handles:
55+
handle.close()
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright 2020 Open Source Robotics Foundation, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from rpyutils import add_dll_directories_from_env
16+
17+
18+
def test_add_dll_direcotires_from_env(monkeypatch, tmp_path):
19+
# Test with empty value
20+
monkeypatch.delenv('TEST_ENV', raising=False)
21+
with add_dll_directories_from_env('TEST_ENV'):
22+
pass
23+
24+
# Test with one path
25+
monkeypatch.setenv('TEST_ENV', tmp_path.name)
26+
with add_dll_directories_from_env('TEST_ENV'):
27+
pass
28+
29+
# Test with multiple paths
30+
dir1 = tmp_path / 'subdir1'
31+
dir2 = tmp_path / 'subdir2'
32+
dir1.mkdir()
33+
dir2.mkdir()
34+
monkeypatch.setenv('TEST_ENV', f'{dir1.name};{dir2.name}')
35+
with add_dll_directories_from_env('TEST_ENV'):
36+
pass

0 commit comments

Comments
 (0)