Skip to content

Commit 1123dce

Browse files
emersonknappmergify[bot]
authored andcommitted
Allow Path in substitutions, instead of requiring cast to str (#873)
Signed-off-by: Emerson Knapp <[email protected]> (cherry picked from commit 49bcf2d)
1 parent f080a39 commit 1123dce

File tree

17 files changed

+56
-48
lines changed

17 files changed

+56
-48
lines changed

launch/launch/launch_description_sources/python_launch_file_utilities.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
from importlib.machinery import SourceFileLoader
1818
from importlib.util import module_from_spec
1919
from importlib.util import spec_from_loader
20+
from pathlib import Path
2021
from types import ModuleType
2122
from typing import Text
23+
from typing import Union
2224

2325
from ..launch_description import LaunchDescription
2426

@@ -29,9 +31,9 @@ class InvalidPythonLaunchFileError(Exception):
2931
...
3032

3133

32-
def load_python_launch_file_as_module(python_launch_file_path: Text) -> ModuleType:
34+
def load_python_launch_file_as_module(python_launch_file_path: Union[Text, Path]) -> ModuleType:
3335
"""Load a given Python launch file (by path) as a Python module."""
34-
loader = SourceFileLoader('python_launch_file', python_launch_file_path)
36+
loader = SourceFileLoader('python_launch_file', str(python_launch_file_path))
3537
spec = spec_from_loader(loader.name, loader)
3638
if spec is None:
3739
raise RuntimeError('Failed to load module spec!')
@@ -41,7 +43,7 @@ def load_python_launch_file_as_module(python_launch_file_path: Text) -> ModuleTy
4143

4244

4345
def get_launch_description_from_python_launch_file(
44-
python_launch_file_path: Text
46+
python_launch_file_path: Union[Text, Path]
4547
) -> LaunchDescription:
4648
"""
4749
Load a given Python launch file (by path), and return the launch description from it.

launch/launch/some_substitutions_type.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"""Module for SomeSubstitutionsType type."""
1616

1717
import collections.abc
18+
from pathlib import Path
1819
from typing import Iterable
1920
from typing import Text
2021
from typing import Union
@@ -23,12 +24,14 @@
2324

2425
SomeSubstitutionsType = Union[
2526
Text,
27+
Path,
2628
Substitution,
27-
Iterable[Union[Text, Substitution]],
29+
Iterable[Union[Text, Path, Substitution]],
2830
]
2931

3032
SomeSubstitutionsType_types_tuple = (
3133
str,
34+
Path,
3235
Substitution,
3336
collections.abc.Iterable,
3437
)

launch/launch/substitutions/path_join_substitution.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
"""Module for the PathJoinSubstitution substitution."""
1616

17-
import os
17+
from pathlib import Path
1818
from typing import Iterable
1919
from typing import List
2020
from typing import Text
@@ -90,7 +90,7 @@ def perform(self, context: LaunchContext) -> Text:
9090
perform_substitutions(context, component_substitutions)
9191
for component_substitutions in self.substitutions
9292
]
93-
return os.path.join(*path_components)
93+
return str(Path(*path_components))
9494

9595
def __truediv__(self, additional_path: SomeSubstitutionsType) -> 'PathJoinSubstitution':
9696
"""Join path substitutions using the / operator, mimicking pathlib.Path operation."""

launch/launch/substitutions/python_expression.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import collections.abc
1818
import importlib
19+
from pathlib import Path
1920
from typing import List
2021
from typing import Sequence
2122
from typing import Text
@@ -72,6 +73,7 @@ def parse(cls, data: Sequence[SomeSubstitutionsType]):
7273
# Check if we got empty list from XML
7374
# Ensure that we got a list!
7475
assert not isinstance(data[1], str)
76+
assert not isinstance(data[1], Path)
7577
assert not isinstance(data[1], Substitution)
7678
# Modules
7779
modules = list(data[1])

launch/launch/utilities/normalize_to_list_of_substitutions_impl.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
"""Module for the normalize_to_list_of_substitutions() utility function."""
1616

17+
from pathlib import Path
1718
from typing import cast
1819
from typing import Iterable
1920
from typing import List
@@ -31,14 +32,14 @@ def normalize_to_list_of_substitutions(subs: SomeSubstitutionsType) -> List[Subs
3132
def normalize(x):
3233
if isinstance(x, Substitution):
3334
return x
34-
if isinstance(x, str):
35-
return TextSubstitution(text=x)
35+
if isinstance(x, (str, Path)):
36+
return TextSubstitution(text=str(x))
3637
raise TypeError(
3738
"Failed to normalize given item of type '{}', when only "
3839
"'str' or 'launch.Substitution' were expected.".format(type(x)))
3940

40-
if isinstance(subs, str):
41-
return [TextSubstitution(text=subs)]
41+
if isinstance(subs, (str, Path)):
42+
return [TextSubstitution(text=str(subs))]
4243
if is_a_subclass(subs, Substitution):
4344
return [cast(Substitution, subs)]
4445
return [normalize(y) for y in cast(Iterable, subs)]

launch/launch/utilities/typing_file_path.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
# limitations under the License.
1414

1515
import os
16+
from pathlib import Path
1617
import typing
1718

1819
# Type of a filesystem path
19-
FilePath = typing.TypeVar('FilePath', str, bytes, os.PathLike)
20+
FilePath = typing.TypeVar('FilePath', str, bytes, os.PathLike, Path)

launch/test/launch/actions/test_include_launch_description.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
"""Tests for the IncludeLaunchDescription action class."""
1616

17-
import os
17+
from pathlib import Path
1818

1919
from launch import LaunchContext
2020
from launch import LaunchDescription
@@ -74,7 +74,7 @@ def test_include_launch_description_launch_file_location():
7474
assert lc1.locals.current_launch_file_directory == '<script>'
7575
assert action.get_asyncio_future() is None
7676

77-
this_file = os.path.abspath(__file__)
77+
this_file = Path(__file__).absolute()
7878
ld2 = LaunchDescription()
7979
action2 = IncludeLaunchDescription(LaunchDescriptionSource(ld2, this_file))
8080
assert 'IncludeLaunchDescription' in action2.describe()
@@ -83,7 +83,7 @@ def test_include_launch_description_launch_file_location():
8383
lc2 = LaunchContext()
8484
# Result should only contain the launch description as there are no launch arguments.
8585
assert action2.visit(lc2) == [ld2]
86-
assert lc2.locals.current_launch_file_directory == os.path.dirname(this_file)
86+
assert lc2.locals.current_launch_file_directory == str(this_file.parent)
8787
assert action2.get_asyncio_future() is None
8888

8989

@@ -209,11 +209,8 @@ def test_include_launch_description_launch_arguments():
209209

210210
def test_include_python():
211211
"""Test including Python, with and without explicit PythonLaunchDescriptionSource."""
212-
this_dir = os.path.dirname(os.path.abspath(__file__))
213-
simple_launch_file_path = os.path.join(this_dir,
214-
'..',
215-
'launch_description_source',
216-
'simple.launch.py')
212+
this_dir = Path(__file__).parent
213+
simple_launch_file_path = this_dir.parent / 'launch_description_source' / 'simple.launch.py'
217214

218215
# Explicitly construct with PythonLaunchDescriptionSource
219216
plds = PythonLaunchDescriptionSource(simple_launch_file_path)
@@ -232,4 +229,4 @@ def test_include_python():
232229
assert action.get_asyncio_future() is None
233230
assert len(action.launch_arguments) == 0
234231

235-
assert action.launch_description_source.location == simple_launch_file_path
232+
assert action.launch_description_source.location == str(simple_launch_file_path)

launch/test/launch/launch_description_source/test_python_launch_description_source.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
"""Tests for the PythonLaunchDescriptionSource class."""
1616

17-
import os
17+
from pathlib import Path
1818

1919
from launch import LaunchContext
2020
from launch.launch_description_sources import InvalidPythonLaunchFileError
@@ -25,17 +25,17 @@
2525

2626
def test_python_launch_description_source():
2727
"""Test the PythonLaunchDescriptionSource class."""
28-
this_dir = os.path.dirname(os.path.abspath(__file__))
29-
simple_launch_file_path = os.path.join(this_dir, 'simple.launch.py')
28+
this_dir = Path(__file__).parent
29+
simple_launch_file_path = this_dir / 'simple.launch.py'
3030
plds = PythonLaunchDescriptionSource(simple_launch_file_path)
3131
assert 'python launch file' in plds.method
3232
assert 'launch.substitutions.text_substitution.TextSubstitution' in plds.location
3333
ld = plds.get_launch_description(LaunchContext())
34-
assert plds.location == simple_launch_file_path
34+
assert plds.location == str(simple_launch_file_path)
3535
assert 0 == len(ld.entities)
3636

3737
with pytest.raises(InvalidPythonLaunchFileError):
38-
plds = PythonLaunchDescriptionSource(os.path.join(this_dir, 'loadable_python_module.py'))
38+
plds = PythonLaunchDescriptionSource(this_dir / 'loadable_python_module.py')
3939
ld = plds.get_launch_description(LaunchContext())
4040

4141
with pytest.raises(FileNotFoundError):

launch/test/launch/launch_description_source/test_python_launch_file_utilities.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
"""Tests for the Python launch file utility functions."""
1616

17-
import os
17+
from pathlib import Path
1818
import sys
1919

2020
from launch.launch_description_sources import get_launch_description_from_python_launch_file
@@ -26,8 +26,8 @@
2626

2727
def test_load_python_launch_file_as_module():
2828
"""Test load_python_launch_file_as_module()."""
29-
this_dir = os.path.dirname(os.path.abspath(__file__))
30-
module = load_python_launch_file_as_module(os.path.join(this_dir, 'loadable_python_module.py'))
29+
this_dir = Path(__file__).parent
30+
module = load_python_launch_file_as_module(this_dir / 'loadable_python_module.py')
3131
assert sys.executable == module.some_function()
3232

3333
with pytest.raises(FileNotFoundError):
@@ -36,13 +36,12 @@ def test_load_python_launch_file_as_module():
3636

3737
def test_get_launch_description_from_python_launch_file():
3838
"""Test get_launch_description_from_python_launch_file()."""
39-
this_dir = os.path.dirname(os.path.abspath(__file__))
40-
ld = get_launch_description_from_python_launch_file(os.path.join(this_dir, 'simple.launch.py'))
39+
this_dir = Path(__file__).parent
40+
ld = get_launch_description_from_python_launch_file(this_dir / 'simple.launch.py')
4141
assert 0 == len(ld.entities)
4242

4343
with pytest.raises(InvalidPythonLaunchFileError):
44-
ld = get_launch_description_from_python_launch_file(
45-
os.path.join(this_dir, 'loadable_python_module.py'))
44+
ld = get_launch_description_from_python_launch_file(this_dir / 'loadable_python_module.py')
4645

4746
with pytest.raises(FileNotFoundError):
4847
ld = get_launch_description_from_python_launch_file('does_not_exist')

launch/test/launch/substitutions/test_command.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ def commands():
2929
this_dir = pathlib.Path(__file__).parent
3030

3131
commands = {
32-
'normal': str(this_dir / 'test_command' / 'normal_command.bash'),
33-
'failing': str(this_dir / 'test_command' / 'failing_command.bash'),
34-
'with_stderr': str(this_dir / 'test_command' / 'command_with_stderr.bash')
32+
'normal': this_dir / 'test_command' / 'normal_command.bash',
33+
'failing': this_dir / 'test_command' / 'failing_command.bash',
34+
'with_stderr': this_dir / 'test_command' / 'command_with_stderr.bash'
3535
}
3636

3737
if os.name == 'nt':
3838
for key, value in commands.items():
39-
commands[key] = value.replace('bash', 'bat')
39+
commands[key] = value.with_suffix('.bat')
4040
return commands
4141

4242

0 commit comments

Comments
 (0)