Skip to content

Commit 0fa2d9c

Browse files
committed
Initial scriptconfig support
1 parent 6c89858 commit 0fa2d9c

File tree

2 files changed

+98
-2
lines changed

2 files changed

+98
-2
lines changed

jsonargparse/_parameter_resolvers.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,32 @@ class ParamData:
4444
component: Optional[Union[Callable, Type, Tuple]] = None
4545
parent: Optional[Union[Type, Tuple]] = None
4646
origin: Optional[Union[str, Tuple]] = None
47+
short_aliases: Optional[List[str]] = None
48+
long_aliases: Optional[List[str]] = None
49+
50+
def _resolve_args_and_dest(
51+
self,
52+
is_required=False,
53+
as_positional=False,
54+
nested_key: Optional[str] = None
55+
):
56+
name = self.name
57+
dest = (nested_key + "." if nested_key else "") + name
58+
args = [dest if is_required and as_positional else "--" + dest]
59+
long_names = [name] + list((self.long_aliases or []))
60+
short_names = list(self.short_aliases or [])
61+
# if fuzzy_hyphens:
62+
# # Do we want to allow for people to use hyphens on the CLI?
63+
# # Maybe, we can make it optional.
64+
# unique_long_names = set(long_names)
65+
# modified_long_names = {n.replace('_', '-') for n in unique_long_names}
66+
# extra_long_names = modified_long_names - unique_long_names
67+
# long_names += sorted(extra_long_names)
68+
nest_prefix = (nested_key + '.' if nested_key else '')
69+
short_option_strings = ['-' + nest_prefix + n for n in short_names]
70+
long_option_strings = ['--' + nest_prefix + n for n in long_names]
71+
args = short_option_strings + long_option_strings
72+
return args, dest
4773

4874

4975
ParamList = List[ParamData]

jsonargparse/_signatures.py

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ def _add_signature_arguments(
285285

286286
## Add parameter arguments ##
287287
added_args: List[str] = []
288+
288289
for param in params:
289290
self._add_signature_parameter(
290291
container,
@@ -298,8 +299,76 @@ def _add_signature_arguments(
298299
as_positional=as_positional,
299300
)
300301

302+
if hasattr(function_or_class, '__scriptconfig__'):
303+
# Integrate with scriptconfig style classes.
304+
# When a function/class has a __scriptconfig__ object that means it
305+
# should accept any of the options defined in the config as keyword
306+
# arguments. We can utilize additional metadata stored in the
307+
# scriptconfig object to enrich our CLI.
308+
config_cls = function_or_class.__scriptconfig__
309+
self._add_scriptconfig_arguments(
310+
config_cls=config_cls,
311+
added_args=added_args,
312+
function_or_class=function_or_class,
313+
component=component,
314+
container=container,
315+
nested_key=nested_key,
316+
fail_untyped=fail_untyped,
317+
as_positional=as_positional,
318+
sub_configs=sub_configs,
319+
skip=skip,
320+
linked_targets=linked_targets)
321+
301322
return added_args
302323

324+
def _add_scriptconfig_arguments(
325+
self,
326+
config_cls,
327+
added_args,
328+
function_or_class,
329+
component,
330+
container,
331+
nested_key,
332+
fail_untyped: bool = True,
333+
as_positional: bool = False,
334+
sub_configs: bool = False,
335+
skip: Optional[Set[Union[str, int]]] = None,
336+
linked_targets: Optional[Set[str]] = None,
337+
):
338+
339+
for key, value in config_cls.__default__.items():
340+
from scriptconfig import value as value_mod
341+
if not isinstance(value, value_mod.Value):
342+
# hack
343+
value = value_mod.Value(value)
344+
type_ = value.parsekw['type']
345+
if type_ is None or not isinstance(type_, type):
346+
annotation = inspect._empty
347+
else:
348+
annotation = type_
349+
param = ParamData(
350+
name=key,
351+
annotation=annotation,
352+
kind=inspect.Parameter.KEYWORD_ONLY,
353+
default=value.value,
354+
doc=value.parsekw['help'],
355+
component=component,
356+
parent=function_or_class,
357+
short_aliases=value.short_alias,
358+
long_aliases=value.alias,
359+
)
360+
self._add_signature_parameter(
361+
container,
362+
nested_key,
363+
param,
364+
added_args,
365+
skip={s for s in (skip or []) if isinstance(s, str)},
366+
fail_untyped=fail_untyped,
367+
sub_configs=sub_configs,
368+
linked_targets=linked_targets,
369+
as_positional=as_positional,
370+
)
371+
303372
def _add_signature_parameter(
304373
self,
305374
container,
@@ -355,8 +424,9 @@ def _add_signature_parameter(
355424
kwargs["required"] = True
356425
is_subclass_typehint = False
357426
is_dataclass_like_typehint = is_dataclass_like(annotation)
358-
dest = (nested_key + "." if nested_key else "") + name
359-
args = [dest if is_required and as_positional else "--" + dest]
427+
# dest = (nested_key + "." if nested_key else "") + name
428+
# args = [dest if is_required and as_positional else "--" + dest]
429+
args, dest = param._resolve_args_and_dest(is_required, as_positional, nested_key)
360430
if param.origin:
361431
parser = container
362432
if not isinstance(container, ArgumentParser):

0 commit comments

Comments
 (0)