Skip to content

Commit

Permalink
Test fix for pydsdl #114 (#369)
Browse files Browse the repository at this point in the history
This new test will cause a deadlock unless pydsdl#114 is fixed.
  • Loading branch information
thirtytwobits authored Jan 11, 2025
1 parent 3e12b06 commit bb0ff76
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 7 deletions.
2 changes: 1 addition & 1 deletion src/nunavut/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
documentation or data interchange formats like JSON or XML.
The input to the nunavut library is a list of templates and a list of
``pydsdl.pydsdl.CompositeType`` objects. Typical use of this library is simply
``pydsdl.CompositeType`` objects. Typical use of this library is simply
invoking the ``nunavut.generate_all`` method.
"""
Expand Down
14 changes: 14 additions & 0 deletions src/nunavut/_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"""

import abc
import os
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Dict, Iterable, List, Mapping, Optional, Type, Union
Expand Down Expand Up @@ -391,6 +392,12 @@ def generate_all(
:param int jobs:
The number of parallel jobs to use when generating code. If 1 then no parallelism is used. If 0 then the
number of jobs is determined by the number of CPUs available.
.. note:: By default, any multiprocessing jobs used will not have a timeout set. To set a timeout for any jobs
set the environment variable ``NUNAVUT_JOB_TIMEOUT_SECONDS`` to the desired timeout in fractional seconds.
this is normally not useful as a correct timeout value is highly dependent on the system and the number of
types being generated.
:param bool no_overwrite:
If True then generated files will not be allowed to overwrite existing files under the `outdir` path causing
errors.
Expand Down Expand Up @@ -472,6 +479,12 @@ def generate_all_for_language(
:param int jobs:
The number of parallel jobs to use when generating code. If 1 then no parallelism is used. If 0 then the
number of jobs is determined by the number of CPUs available.
.. note:: By default, any multiprocessing jobs used will not have a timeout set. To set a timeout for any jobs
set the environment variable ``NUNAVUT_JOB_TIMEOUT_SECONDS`` to the desired timeout in fractional seconds.
this is normally not useful as a correct timeout value is highly dependent on the system and the number of
types being generated.
:param no_overwrite: If True then generated files will not be allowed to overwrite existing files under the `outdir`
path causing errors.
:param allow_unregulated_fixed_port_id: If True then errors will become warning when using fixed port identifiers
Expand All @@ -493,6 +506,7 @@ def generate_all_for_language(
target_files,
root_namespace_directories_or_names,
jobs,
float(os.environ.get("NUNAVUT_JOB_TIMEOUT_SECONDS", 0)),
allow_unregulated_fixed_port_id=allow_unregulated_fixed_port_id,
omit_dependencies=omit_dependencies,
)
Expand Down
10 changes: 8 additions & 2 deletions src/nunavut/_namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@

import collections
import itertools
import logging
import multiprocessing
import multiprocessing.pool
import sys
Expand Down Expand Up @@ -110,11 +111,16 @@ class NotAsyncResult:
def __init__(self, read_method: Callable[..., Any], args: Tuple[Any, ...]) -> None:
self.read_method = read_method
self.args = args
self._logger = logging.getLogger(NotAsyncResult.__name__)

def get(self, _: Optional[Any] = None) -> Any:
def get(self, timeout: Optional[Any] = None) -> Any:
"""
Perform the work synchronously.
"""
if timeout is not None and timeout > 0:
self._logger.debug(
"Timeout value for read_method '%s' ignored when not doing multiple jobs.", self.read_method.__name__
)
return self.read_method(*self.args)


Expand Down Expand Up @@ -325,7 +331,7 @@ class Namespace(pydsdl.Any): # pylint: disable=too-many-public-methods
K-ary tree (where K is the largest set of data types in a single dsdl namespace) where
the nodes represent dsdl namespaces and the children are the datatypes and other nested
namespaces (with datatypes always being leaf nodes). This structure extends :code:`pydsdl.Any`
and is a :code:`pydsdl.pydsdl.CompositeType` via duck typing.
and is a :code:`pydsdl.CompositeType` via duck typing.
:param str full_namespace: The full, dot-separated name of the namepace.
:param Path namespace_dir: If full_namespace is "" then this is interpreted as the directory under which all
Expand Down
2 changes: 1 addition & 1 deletion src/nunavut/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
__author__ = "OpenCyphal"
__copyright__ = "Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. Copyright (c) 2023 OpenCyphal."
__email__ = "[email protected]"
__pydsdl_version__ = ">= 1.22.1"
__pydsdl_version__ = ">= 1.22.2"
2 changes: 1 addition & 1 deletion submodules/pydsdl
26 changes: 24 additions & 2 deletions test/gentest_nnvg/test_nnvg.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def test_realgen_using_nnvg(gen_paths: Any, run_nnvg: Callable) -> None:
@pytest.mark.parametrize("jobs", [0, 1, 2])
def test_realgen_using_nnvg_jobs(gen_paths: Any, run_nnvg_main: Callable, jobs: int) -> None:
"""
Sanity test that nnvg can generate code from known types.
Verify stable behavior of nnvg with different job counts.
"""
public_regulated_data_types = gen_paths.root_dir / Path("submodules") / Path("public_regulated_data_types")

Expand All @@ -71,12 +71,34 @@ def test_realgen_using_nnvg_jobs(gen_paths: Any, run_nnvg_main: Callable, jobs:
(public_regulated_data_types / Path("uavcan", "node", "430.GetInfo.1.0.dsdl")).as_posix(),
]

run_nnvg_main(gen_paths, nnvg_args0)
run_nnvg_main(gen_paths, nnvg_args0, {"NUNAVUT_JOB_TIMEOUT_SECONDS": "20"})

get_info = gen_paths.out_dir / Path("uavcan") / Path("node") / Path("GetInfo_1_0").with_suffix(".h")
assert get_info.exists()


@pytest.mark.parametrize("jobs", [0, 1, 2])
def test_realgen_using_nnvg_failure(gen_paths: Any, run_nnvg_main: Callable, jobs: int) -> None:
"""
Ensure pydsdl errors are properly propagated.
"""

nnvg_args0 = [
"--outdir",
gen_paths.out_dir.as_posix(),
"-j",
str(jobs),
"-l",
"c",
"--lookup-dir",
Path("wrong"),
(Path("uavcan", "node", "430.GetInfo.1.0.dsdl")).as_posix(),
]

with pytest.raises(pydsdl.FrontendError):
run_nnvg_main(gen_paths, nnvg_args0)


def test_DSDL_INCLUDE_PATH(gen_paths: Any, run_nnvg_main: Callable) -> None:
"""
Verify that the DSDL_INCLUDE_PATH environment variable is used by nnvg.
Expand Down

0 comments on commit bb0ff76

Please sign in to comment.