Skip to content

Commit

Permalink
Rosidl cli types with specs_set fix (#831)
Browse files Browse the repository at this point in the history
* init

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* add type to fixture

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* remove import

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* add #type: ignore on yaml import

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* move #

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* Add ament_mypy dep

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* Add missing py.typed file

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* fix entry_points

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* Fix Unpack erros by removing kwargs

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* fix groups error

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* remove unused import

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* Use Union Tuple

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* Add missing specs_set default

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

---------

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
InvincibleRMC and mergify[bot] authored Oct 30, 2024
1 parent a2706a5 commit 4f5f80c
Show file tree
Hide file tree
Showing 22 changed files with 184 additions and 112 deletions.
1 change: 1 addition & 0 deletions rosidl_cli/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_mypy</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>ament_xmllint</test_depend>
<test_depend>python3-pytest</test_depend>
Expand Down
Empty file added rosidl_cli/py.typed
Empty file.
12 changes: 9 additions & 3 deletions rosidl_cli/rosidl_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@

import argparse
import signal
from typing import Any, List, Union

from rosidl_cli.command.generate import GenerateCommand
from rosidl_cli.command.translate import TranslateCommand
from rosidl_cli.common import get_first_line_doc


def add_subparsers(parser, cli_name, commands):
def add_subparsers(
parser: argparse.ArgumentParser,
cli_name: str,
commands: List[Union[GenerateCommand, TranslateCommand]]
) -> argparse._SubParsersAction[argparse.ArgumentParser]:
"""
Create argparse subparser for each command.
Expand Down Expand Up @@ -63,7 +68,7 @@ def add_subparsers(parser, cli_name, commands):
return subparser


def main():
def main() -> Union[str, signal.Signals, Any]:
script_name = 'rosidl'
description = f'{script_name} is an extensible command-line tool ' \
'for ROS interface generation.'
Expand All @@ -74,7 +79,8 @@ def main():
formatter_class=argparse.RawDescriptionHelpFormatter
)

commands = [GenerateCommand(), TranslateCommand()]
commands: List[Union[GenerateCommand, TranslateCommand]] = \
[GenerateCommand(), TranslateCommand()]

# add arguments for command extension(s)
add_subparsers(
Expand Down
6 changes: 4 additions & 2 deletions rosidl_cli/rosidl_cli/command/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import argparse


class Command:
"""
Expand All @@ -22,8 +24,8 @@ class Command:
* `add_arguments`
"""

def add_arguments(self, parser):
def add_arguments(self, parser: argparse.ArgumentParser) -> None:
pass

def main(self, *, parser, args):
def main(self, *, args: argparse.Namespace) -> None:
raise NotImplementedError()
5 changes: 3 additions & 2 deletions rosidl_cli/rosidl_cli/command/generate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import argparse
import pathlib

from rosidl_cli.command import Command
Expand All @@ -24,7 +25,7 @@ class GenerateCommand(Command):

name = 'generate'

def add_arguments(self, parser):
def add_arguments(self, parser: argparse.ArgumentParser) -> None:
parser.add_argument(
'-o', '--output-path', metavar='PATH',
type=pathlib.Path, default=None,
Expand All @@ -50,7 +51,7 @@ def add_arguments(self, parser):
"If prefixed by another path followed by a colon ':', "
'path resolution is performed against such path.'))

def main(self, *, args):
def main(self, *, args: argparse.Namespace) -> None:
generate(
package_name=args.package_name,
interface_files=args.interface_files,
Expand Down
18 changes: 10 additions & 8 deletions rosidl_cli/rosidl_cli/command/generate/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,22 @@

import os
import pathlib
from typing import List, Optional

from .extensions import GenerateCommandExtension
from .extensions import load_type_extensions
from .extensions import load_typesupport_extensions


def generate(
*,
package_name,
interface_files,
include_paths=None,
output_path=None,
types=None,
typesupports=None
):
package_name: str,
interface_files: List[str],
include_paths: Optional[List[str]] = None,
output_path: Optional[pathlib.Path] = None,
types: Optional[List[str]] = None,
typesupports: Optional[List[str]] = None
) -> List[List[str]]:
"""
Generate source code from interface definition files.
Expand Down Expand Up @@ -60,7 +62,7 @@ def generate(
:returns: list of lists of paths to generated source code files,
one group per type or type support extension invoked
"""
extensions = []
extensions: List[GenerateCommandExtension] = []

unspecific_generation = not types and not typesupports

Expand Down
27 changes: 18 additions & 9 deletions rosidl_cli/rosidl_cli/command/generate/extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from pathlib import Path
from typing import cast, List, Optional

from rosidl_cli.extensions import Extension
from rosidl_cli.extensions import load_extensions

Expand All @@ -26,11 +29,11 @@ class GenerateCommandExtension(Extension):

def generate(
self,
package_name,
interface_files,
include_paths,
output_path
):
package_name: str,
interface_files: List[str],
include_paths: List[str],
output_path: Path
) -> List[str]:
"""
Generate source code.
Expand All @@ -48,11 +51,17 @@ def generate(
raise NotImplementedError()


def load_type_extensions(**kwargs):
def load_type_extensions(*, specs: Optional[List[str]],
strict: bool) -> List[GenerateCommandExtension]:
"""Load extensions for type representation source code generation."""
return load_extensions('rosidl_cli.command.generate.type_extensions', **kwargs)
extensions = load_extensions('rosidl_cli.command.generate.type_extensions', specs=specs,
strict=strict)
return cast(List[GenerateCommandExtension], extensions)


def load_typesupport_extensions(**kwargs):
def load_typesupport_extensions(*, specs: Optional[List[str]], strict: bool
) -> List[GenerateCommandExtension]:
"""Load extensions for type support source code generation."""
return load_extensions('rosidl_cli.command.generate.typesupport_extensions', **kwargs)
extensions = load_extensions('rosidl_cli.command.generate.typesupport_extensions',
specs=specs, strict=strict)
return cast(List[GenerateCommandExtension], extensions)
49 changes: 26 additions & 23 deletions rosidl_cli/rosidl_cli/command/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
import os
import pathlib
import tempfile
from typing import Generator, List, Tuple


def package_name_from_interface_file_path(path):
def package_name_from_interface_file_path(path: pathlib.Path) -> str:
"""
Derive ROS package name from a ROS interface definition file path.
Expand All @@ -29,7 +30,7 @@ def package_name_from_interface_file_path(path):
return pathlib.Path(os.path.abspath(path)).parents[1].name


def dependencies_from_include_paths(include_paths):
def dependencies_from_include_paths(include_paths: List[str]) -> List[str]:
"""
Collect dependencies' ROS interface definition files from include paths.
Expand All @@ -45,7 +46,7 @@ def dependencies_from_include_paths(include_paths):
})


def interface_path_as_tuple(path):
def interface_path_as_tuple(path: str) -> Tuple[pathlib.Path, pathlib.Path]:
"""
Express interface definition file path as an (absolute prefix, relative path) tuple.
Expand All @@ -61,41 +62,43 @@ def interface_path_as_tuple(path):
"""
path_as_string = str(path)
if ':' not in path_as_string:
prefix = pathlib.Path.cwd()
prefix_path = pathlib.Path.cwd()
else:
prefix, _, path = path_as_string.rpartition(':')
prefix = pathlib.Path(os.path.abspath(prefix))
path = pathlib.Path(path)
if path.is_absolute():
prefix_path = pathlib.Path(os.path.abspath(prefix))
path_as_path = pathlib.Path(path)
if path_as_path.is_absolute():
raise ValueError('Interface definition file path '
f"'{path}' cannot be absolute")
return prefix, path
f"'{path_as_path}' cannot be absolute")
return prefix_path, path_as_path


def idl_tuples_from_interface_files(interface_files):
def idl_tuples_from_interface_files(
interface_files: List[str]
) -> List[str]:
"""
Express ROS interface definition file paths as IDL tuples.
An IDL tuple is a relative path prefixed by an absolute path against
which to resolve it followed by a colon ':'. This function then applies
the same logic as `interface_path_as_tuple`.
"""
idl_tuples = []
for path in interface_files:
prefix, path = interface_path_as_tuple(path)
idl_tuples: List[str] = []
for interface_path in interface_files:
prefix, path = interface_path_as_tuple(interface_path)
idl_tuples.append(f'{prefix}:{path.as_posix()}')
return idl_tuples


@contextlib.contextmanager
def legacy_generator_arguments_file(
*,
package_name,
interface_files,
include_paths,
templates_path,
output_path
):
package_name: str,
interface_files: List[str],
include_paths: List[str],
templates_path: str,
output_path: str
) -> Generator[str, None, None]:
"""
Generate a temporary rosidl generator arguments file.
Expand Down Expand Up @@ -138,10 +141,10 @@ def legacy_generator_arguments_file(

def generate_visibility_control_file(
*,
package_name,
template_path,
output_path
):
package_name: str,
template_path: str,
output_path: str
) -> None:
"""
Generate a visibility control file from a template.
Expand Down
6 changes: 4 additions & 2 deletions rosidl_cli/rosidl_cli/command/translate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import argparse
import pathlib


from rosidl_cli.command import Command

from .api import translate
Expand All @@ -24,7 +26,7 @@ class TranslateCommand(Command):

name = 'translate'

def add_arguments(self, parser):
def add_arguments(self, parser: argparse.ArgumentParser) -> None:
parser.add_argument(
'-o', '--output-path', metavar='PATH',
type=pathlib.Path, default=None,
Expand Down Expand Up @@ -64,7 +66,7 @@ def add_arguments(self, parser):
'path resolution is performed against such path.')
)

def main(self, *, args):
def main(self, *, args: argparse.Namespace) -> None:
translate(
package_name=args.package_name,
interface_files=args.interface_files,
Expand Down
20 changes: 11 additions & 9 deletions rosidl_cli/rosidl_cli/command/translate/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,21 @@
import collections
import os
import pathlib
from typing import DefaultDict, Dict, List, Optional, Union

from .extensions import load_translate_extensions


def translate(
*,
package_name,
interface_files,
output_format,
input_format=None,
include_paths=None,
output_path=None,
translators=None
):
package_name: str,
interface_files: List[str],
output_format: str,
input_format: Optional[str] = None,
include_paths: Optional[List[str]] = None,
output_path: Optional[pathlib.Path] = None,
translators: Optional[List[str]] = None
) -> List[str]:
"""
Translate interface definition files from one format to another.
Expand Down Expand Up @@ -64,7 +65,8 @@ def translate(
raise RuntimeError('No translate extensions found')

if not input_format:
interface_files_per_format = collections.defaultdict(list)
interface_files_per_format: Union[DefaultDict[str, List[str]],
Dict[str, List[str]]] = collections.defaultdict(list)
for interface_file in interface_files:
input_format = os.path.splitext(interface_file)[-1][1:]
interface_files_per_format[input_format].append(interface_file)
Expand Down
23 changes: 15 additions & 8 deletions rosidl_cli/rosidl_cli/command/translate/extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from pathlib import Path
from typing import cast, ClassVar, List, Optional

from rosidl_cli.extensions import Extension
from rosidl_cli.extensions import load_extensions
Expand All @@ -28,13 +30,16 @@ class TranslateCommandExtension(Extension):
* `translate`
"""

input_format: ClassVar[str]
output_format: ClassVar[str]

def translate(
self,
package_name,
interface_files,
include_paths,
output_path
):
package_name: str,
interface_files: List[str],
include_paths: List[str],
output_path: Path
) -> List[str]:
"""
Translate interface definition files.
Expand All @@ -57,8 +62,10 @@ def translate(
raise NotImplementedError()


def load_translate_extensions(**kwargs):
def load_translate_extensions(*, specs: Optional[List[str]], strict: bool
) -> List[TranslateCommandExtension]:
"""Load extensions for interface definition translation."""
return load_extensions(
'rosidl_cli.command.translate.extensions', **kwargs
extensions = load_extensions(
'rosidl_cli.command.translate.extensions', specs=specs, strict=strict
)
return cast(List[TranslateCommandExtension], extensions)
Loading

0 comments on commit 4f5f80c

Please sign in to comment.