Skip to content

Commit 159cd5e

Browse files
Merge pull request #129 from duckietown/DTSW-7670-Make-Duckietown-Shell-commands-that-run-other-commands-more-robust
DTSW-7670-Make-Duckietown-Shell-commands-that-run-other-commands-more-robust
2 parents f45ceda + b78745a commit 159cd5e

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

lib/dt_shell/commands/commands.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,51 @@ def complete(shell: DTShell, word: str, line: str):
6969
"""
7070
return []
7171

72+
@classmethod
73+
def _resolve_parsed(
74+
cls,
75+
args: List[str],
76+
pre_parsed: Optional[argparse.Namespace] = None,
77+
*,
78+
parser: Optional[argparse.ArgumentParser] = None,
79+
) -> argparse.Namespace:
80+
"""Resolve CLI arguments consistently for both direct and nested invocations.
81+
82+
When a command is invoked directly from the CLI, ``pre_parsed`` is
83+
``None`` and the raw ``args`` list is parsed normally. When it is
84+
called programmatically by a parent command (e.g. via
85+
``shell.include.*``), the parent passes its own
86+
:class:`~argparse.Namespace` through ``kwargs["parsed"]``; in that
87+
case the parent's values are overlaid on top of this command's
88+
defaults so that every argument always has its declared default value.
89+
90+
:func:`~argparse.ArgumentParser.parse_known_args` is used throughout
91+
so that unknown arguments are silently forwarded in both code paths,
92+
matching the behaviour expected by commands that call nested commands
93+
with an extended argument set.
94+
95+
Args:
96+
args: Raw argument list forwarded from ``command(shell, args, **kwargs)``.
97+
pre_parsed: :class:`~argparse.Namespace` forwarded by a parent
98+
command via ``kwargs["parsed"]``, or ``None`` when
99+
this command is the top-level caller.
100+
parser: :class:`~argparse.ArgumentParser` to use. Defaults
101+
to ``cls.parser`` (the class-level parser provided by
102+
the shell framework).
103+
104+
Returns:
105+
A fully resolved :class:`~argparse.Namespace` that always carries
106+
the correct default value for every declared argument.
107+
"""
108+
_parser: argparse.ArgumentParser = parser if parser is not None else cls.parser
109+
if pre_parsed is None:
110+
resolved, _ = _parser.parse_known_args(args=args)
111+
else:
112+
defaults, _ = _parser.parse_known_args(args=[])
113+
defaults.__dict__.update(pre_parsed.__dict__)
114+
resolved = defaults
115+
return resolved
116+
72117
@staticmethod
73118
def fail(msg: str):
74119
raise Exception(msg)

0 commit comments

Comments
 (0)