The read-only selected-launch resolver expands a bounded Python launch description without importing or executing project code. It narrows candidate declarations to one supplied launch file and argument context, including the hashes and lines of included files and referenced parameter files. It does not establish which launch started an observed process or which override supplied its effective value.
Usage
flightops-tui launch-resolve \
--project /absolute/project --launch launch/robot.launch.py \
--launch-arg namespace:=robot_1
flightops-tui config-diff \
--project /absolute/project --launch launch/robot.launch.py \
--launch-arg namespace:=robot_1 --node /robot_1/camera \
--observed /absolute/observed.jsonConfiguration comparison also supports live ROS observation (--ros-container, --ros-domain-id). The workspace accepts the same --launch and --launch-arg options alongside --project; project refresh and the selected node's d configuration comparison retain that selected context. Without --launch, configuration comparison retains the original whole-project inventory behavior. Repeated --launch-arg NAME:=VALUE inputs must have unique names. Argument values are strings; missing required arguments remain unresolved.
Python APIs:
from flightops_tools.launch_resolution import resolve_launch
from flightops_tools.configuration import compare_configuration
inventory = resolve_launch(root, "launch/robot.launch.py", {"namespace": "robot_1"})
report = compare_configuration(root, "/robot_1/camera", observed_path,
launch="launch/robot.launch.py",
launch_arguments={"namespace": "robot_1"})The resolver returns flightops.project/0, compatible with match_entity, with additional selection, includes, and per-node launch_context fields. Selection arguments participate in the identity hash. Configuration comparison rechecks the same selected context after observation. Parameter rows retain effective_origin: unresolved and duplicate declarations remain competing candidates; this feature never invents override precedence.
Supported static subset
- Whitelisted direct imports, including aliases, for the supported launch classes.
- One undecorated, argument-free
generate_launch_description, returning an explicitLaunchDescription([...])or tuple of actions. - Single-assignment local expression bindings and literal strings/numbers, dictionaries and lists/tuples; no project Python evaluation.
DeclareLaunchArgumentwith string defaults, supplied argument overrides, andLaunchConfigurationwith an optional default.PathJoinSubstitutionwith supported string components.Nodenames, namespaces, package/executable, remappings, inline literal parameters and parameter-file references. Output and terminal-emulation options do not alter the declaration identity.- Scoped
GroupActionandPushRosNamespace; group namespace changes do not leak to following parent actions. IncludeLaunchDescription(PythonLaunchDescriptionSource(absolute_path)), with string argument pairs or a dictionary's.items(). Includes must be the final action in their local scope. Wrap independent includes in separate scoped groups when appropriate. This avoids guessing how an included file changes the launch context used by later actions.
Explicit limits and failure behavior
Selected expansion currently supports Python, not XML/YAML. Package-share lookup, os.path calls, environment substitutions, __file__, opaque callbacks, event handlers, conditional/computed flow, runtime remap arguments, and unscoped groups remain unsupported. Unexpected imports or executable statements also prevent certification. The existing broad inventory remains available for XML declarations.
Relative include paths remain unresolved because the runtime working directory is unknown. Relative parameter references likewise remain unresolved; a launch argument containing an absolute path inside the project is supported. All files must stay inside the selected project. Paths outside it fail collection.
Parameter substitutions are not treated as typed literal values: launch-time type conversion remains unresolved. Supported static node/remap names are declaration candidates only. Any unresolved launch flow disables name matching for the entire selected expansion. Cycles produce explicit warnings. Other budgets include 16 include levels, 128 file visits, 20,000 AST elements per file and 1,024 nodes, plus the shared intake byte/file limits and input-change checks.
CLI exit status is 0 for a complete supported declaration expansion and 2 for a partial expansion or invalid input. A complete result is not runtime verification.
Validation
Focused tests cover argument selection and identity, nested includes and source hashes, scoped namespaces and remaps, selected configuration comparison, literal aliases and path joins, unresolved substitution types, missing arguments, relative paths, include cycles, outside-project paths, import shadowing and no execution of unsupported code. The tests need a source checkout: they are in integrations/tests/, which is not in the install. From the repository root, put this checkout's packages first on PYTHONPATH so that you do not test an unrelated editable installation:
PYTHONPATH="$PWD/integrations:$PWD/launchcommit:$PWD/onscope:$PWD/axikit:$PWD/highbay:$PWD/splashdown" \
python -m pytest -q integrations/tests/test_launch_resolution.py \
integrations/tests/test_project.py integrations/tests/test_configuration.py