Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
from importlib.machinery import SourceFileLoader
from importlib.util import module_from_spec
from importlib.util import spec_from_loader
from pathlib import Path
from types import ModuleType
from typing import Text
from typing import Union

from ..launch_description import LaunchDescription

Expand All @@ -29,17 +31,17 @@ class InvalidPythonLaunchFileError(Exception):
...


def load_python_launch_file_as_module(python_launch_file_path: Text) -> ModuleType:
def load_python_launch_file_as_module(python_launch_file_path: Union[Text, Path]) -> ModuleType:
"""Load a given Python launch file (by path) as a Python module."""
loader = SourceFileLoader('python_launch_file', python_launch_file_path)
loader = SourceFileLoader('python_launch_file', str(python_launch_file_path))
spec = spec_from_loader(loader.name, loader)
mod = module_from_spec(spec)
loader.exec_module(mod)
return mod


def get_launch_description_from_python_launch_file(
python_launch_file_path: Text
python_launch_file_path: Union[Text, Path]
) -> LaunchDescription:
"""
Load a given Python launch file (by path), and return the launch description from it.
Expand Down
5 changes: 4 additions & 1 deletion launch/launch/some_substitutions_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"""Module for SomeSubstitutionsType type."""

import collections.abc
from pathlib import Path
from typing import Iterable
from typing import Text
from typing import Union
Expand All @@ -23,12 +24,14 @@

SomeSubstitutionsType = Union[
Text,
Path,
Substitution,
Iterable[Union[Text, Substitution]],
Iterable[Union[Text, Path, Substitution]],
]

SomeSubstitutionsType_types_tuple = (
str,
Path,
Substitution,
collections.abc.Iterable,
)
4 changes: 2 additions & 2 deletions launch/launch/substitutions/path_join_substitution.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

"""Module for the PathJoinSubstitution substitution."""

import os
from pathlib import Path
from typing import Iterable
from typing import List
from typing import Text
Expand Down Expand Up @@ -86,7 +86,7 @@ def perform(self, context: LaunchContext) -> Text:
perform_substitutions(context, component_substitutions)
for component_substitutions in self.substitutions
]
return os.path.join(*path_components)
return str(Path(*path_components))

def __truediv__(self, additional_path: SomeSubstitutionsType) -> 'PathJoinSubstitution':
"""Join path substitutions using the / operator, mimicking pathlib.Path operation."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

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

from pathlib import Path
from typing import cast
from typing import Iterable
from typing import List
Expand All @@ -31,14 +32,14 @@ def normalize_to_list_of_substitutions(subs: SomeSubstitutionsType) -> List[Subs
def normalize(x):
if isinstance(x, Substitution):
return x
if isinstance(x, str):
return TextSubstitution(text=x)
if isinstance(x, (str, Path)):
return TextSubstitution(text=str(x))
raise TypeError(
"Failed to normalize given item of type '{}', when only "
"'str' or 'launch.Substitution' were expected.".format(type(x)))

if isinstance(subs, str):
return [TextSubstitution(text=subs)]
if isinstance(subs, (str, Path)):
return [TextSubstitution(text=str(subs))]
if is_a_subclass(subs, Substitution):
return [cast(Substitution, subs)]
return [normalize(y) for y in cast(Iterable, subs)]
3 changes: 2 additions & 1 deletion launch/launch/utilities/typing_file_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
# limitations under the License.

import os
from pathlib import Path
import typing

# Type of a filesystem path
FilePath = typing.TypeVar('FilePath', str, bytes, os.PathLike)
FilePath = typing.TypeVar('FilePath', str, bytes, os.PathLike, Path)
15 changes: 6 additions & 9 deletions launch/test/launch/actions/test_include_launch_description.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

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

import os
from pathlib import Path

from launch import LaunchContext
from launch import LaunchDescription
Expand Down Expand Up @@ -74,7 +74,7 @@ def test_include_launch_description_launch_file_location():
assert lc1.locals.current_launch_file_directory == '<script>'
assert action.get_asyncio_future() is None

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


Expand Down Expand Up @@ -209,11 +209,8 @@ def test_include_launch_description_launch_arguments():

def test_include_python():
"""Test including Python, with and without explicit PythonLaunchDescriptionSource."""
this_dir = os.path.dirname(os.path.abspath(__file__))
simple_launch_file_path = os.path.join(this_dir,
'..',
'launch_description_source',
'simple.launch.py')
this_dir = Path(__file__).parent
simple_launch_file_path = this_dir.parent / 'launch_description_source' / 'simple.launch.py'

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

assert action.launch_description_source.location == simple_launch_file_path
assert action.launch_description_source.location == str(simple_launch_file_path)
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

"""Tests for the PythonLaunchDescriptionSource class."""

import os
from pathlib import Path

from launch import LaunchContext
from launch.launch_description_sources import InvalidPythonLaunchFileError
Expand All @@ -25,17 +25,17 @@

def test_python_launch_description_source():
"""Test the PythonLaunchDescriptionSource class."""
this_dir = os.path.dirname(os.path.abspath(__file__))
simple_launch_file_path = os.path.join(this_dir, 'simple.launch.py')
this_dir = Path(__file__).parent
simple_launch_file_path = this_dir / 'simple.launch.py'
plds = PythonLaunchDescriptionSource(simple_launch_file_path)
assert 'python launch file' in plds.method
assert 'launch.substitutions.text_substitution.TextSubstitution' in plds.location
ld = plds.get_launch_description(LaunchContext())
assert plds.location == simple_launch_file_path
assert plds.location == str(simple_launch_file_path)
assert 0 == len(ld.entities)

with pytest.raises(InvalidPythonLaunchFileError):
plds = PythonLaunchDescriptionSource(os.path.join(this_dir, 'loadable_python_module.py'))
plds = PythonLaunchDescriptionSource(this_dir / 'loadable_python_module.py')
ld = plds.get_launch_description(LaunchContext())

with pytest.raises(FileNotFoundError):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

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

import os
from pathlib import Path
import sys

from launch.launch_description_sources import get_launch_description_from_python_launch_file
Expand All @@ -26,8 +26,8 @@

def test_load_python_launch_file_as_module():
"""Test load_python_launch_file_as_module()."""
this_dir = os.path.dirname(os.path.abspath(__file__))
module = load_python_launch_file_as_module(os.path.join(this_dir, 'loadable_python_module.py'))
this_dir = Path(__file__).parent
module = load_python_launch_file_as_module(this_dir / 'loadable_python_module.py')
assert sys.executable == module.some_function()

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

def test_get_launch_description_from_python_launch_file():
"""Test get_launch_description_from_python_launch_file()."""
this_dir = os.path.dirname(os.path.abspath(__file__))
ld = get_launch_description_from_python_launch_file(os.path.join(this_dir, 'simple.launch.py'))
this_dir = Path(__file__).parent
ld = get_launch_description_from_python_launch_file(this_dir / 'simple.launch.py')
assert 0 == len(ld.entities)

with pytest.raises(InvalidPythonLaunchFileError):
ld = get_launch_description_from_python_launch_file(
os.path.join(this_dir, 'loadable_python_module.py'))
ld = get_launch_description_from_python_launch_file(this_dir / 'loadable_python_module.py')

with pytest.raises(FileNotFoundError):
ld = get_launch_description_from_python_launch_file('does_not_exist')
8 changes: 4 additions & 4 deletions launch/test/launch/substitutions/test_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ def commands():
this_dir = pathlib.Path(__file__).parent

commands = {
'normal': str(this_dir / 'test_command' / 'normal_command.bash'),
'failing': str(this_dir / 'test_command' / 'failing_command.bash'),
'with_stderr': str(this_dir / 'test_command' / 'command_with_stderr.bash')
'normal': this_dir / 'test_command' / 'normal_command.bash',
'failing': this_dir / 'test_command' / 'failing_command.bash',
'with_stderr': this_dir / 'test_command' / 'command_with_stderr.bash'
}

if os.name == 'nt':
for key, value in commands.items():
commands[key] = value.replace('bash', 'bat')
commands[key] = value.with_suffix('.bat')
return commands


Expand Down
4 changes: 2 additions & 2 deletions launch/test/launch/substitutions/test_file_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ def files():
this_dir = pathlib.Path(__file__).parent

files = {
'foo': str(this_dir / 'test_file_content' / 'foo.txt'),
'bar': str(this_dir / 'test_file_content' / 'bar.txt'),
'foo': this_dir / 'test_file_content' / 'foo.txt',
'bar': this_dir / 'test_file_content' / 'bar.txt',
}

return files
Expand Down
13 changes: 8 additions & 5 deletions launch/test/launch/substitutions/test_path_join_substitution.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

"""Tests for the PathJoinSubstitution substitution class."""

import os
from pathlib import Path

from launch import LaunchContext
from launch.substitutions import PathJoinSubstitution, PathSubstitution
Expand All @@ -26,14 +26,17 @@ def test_this_launch_file_path():

path = ['asd', 'bsd', 'cds']
sub = PathJoinSubstitution(path)
assert sub.perform(context) == os.path.join(*path)
assert sub.perform(context) == str(Path(*path))

path = ['path', ['to'], ['my_', TextSubstitution(text='file'), '.yaml']]
sub = PathJoinSubstitution(path)
assert sub.perform(context) == os.path.join('path', 'to', 'my_file.yaml')
assert sub.perform(context) == str(Path('path', 'to', 'my_file.yaml'))

sub = PathSubstitution('some') / 'path'
sub = sub / PathJoinSubstitution(['to', 'some', 'dir'])
sub = sub / (TextSubstitution(text='my_model'), '.xacro')
assert sub.perform(context) == os.path.join(
'some', 'path', 'to', 'some', 'dir', 'my_model.xacro')
assert sub.perform(context) == str(Path('some', 'path', 'to', 'some', 'dir', 'my_model.xacro'))

path = ['path', [Path('to', 'my'), '_dir'], Path('file.yml')]
sub = PathJoinSubstitution(path)
assert sub.perform(context) == str(Path('path', 'to', 'my_dir', 'file.yml'))
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def generate_test_description():
return launch.LaunchDescription([
launch_ros.actions.Node(
executable=sys.executable,
arguments=[str(path_to_test / 'executables' / 'talker.py')],
arguments=[path_to_test / 'executables' / 'talker.py'],
additional_env={'PYTHONUNBUFFERED': '1'},
name='demo_node_1',
output='screen',
Expand Down
2 changes: 1 addition & 1 deletion launch_pytest/test/launch_pytest/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,6 @@ def test_examples(testdir):
if example.is_file() and example.name != 'check_node_msgs.py':
copied_example = Path(testdir.copy_example(example))
copied_example.rename(copied_example.parent / f'test_{copied_example.name}')
shutil.copytree(examples_dir / 'executables', Path(str(testdir.tmpdir)) / 'executables')
shutil.copytree(examples_dir / 'executables', Path(testdir.tmpdir) / 'executables')
result = testdir.runpytest()
result.assert_outcomes(passed=22)
2 changes: 1 addition & 1 deletion launch_xml/test/launch_xml/test_executable.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

def test_executable():
"""Parse node xml example."""
xml_file = str(Path(__file__).parent / 'executable.xml')
xml_file = Path(__file__).parent / 'executable.xml'
root_entity, parser = Parser.load(xml_file)
ld = parser.parse_description(root_entity)
executable = ld.entities[0]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
def launch_gtest(test_path):
"""Launch a gtest."""
ld = LaunchDescription([
GTest(path=str(test_path), timeout=5.0, on_exit=[EmitEvent(event=Shutdown())])
GTest(path=test_path, timeout=5.0, on_exit=[EmitEvent(event=Shutdown())])
])
ls = LaunchService()
ls.include_launch_description(ld)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
def launch_pytest(test_path):
"""Launch a pytest."""
ld = LaunchDescription([
PyTest(path=str(test_path), timeout=5.0, on_exit=[EmitEvent(event=Shutdown())])
PyTest(path=test_path, timeout=5.0, on_exit=[EmitEvent(event=Shutdown())])
])
ls = LaunchService()
ls.include_launch_description(ld)
Expand Down