Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ Added
- Support for Python 3.14 (`#753
<https://github.com/omni-us/jsonargparse/pull/753>`__).

Fixed
^^^^^
- Improved parameter kind handling for argument requirement determination.
``KEYWORD_ONLY`` parameters now correctly use ``--flag`` style (`#756
<https://github.com/omni-us/jsonargparse/pull/756>`__).

Changed
^^^^^^^
- Removed support for python 3.8 (`#752
Expand Down
23 changes: 19 additions & 4 deletions jsonargparse/_signatures.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,22 @@ def _add_signature_parameter(
default = None
elif get_typehint_origin(annotation) in not_required_types:
default = SUPPRESS
is_required = default == inspect_empty
# Determine argument characteristics based on parameter kind and default value
if kind == kinds.POSITIONAL_ONLY:
is_required = True # Always required
is_non_positional = False # Can be positional
elif kind == kinds.POSITIONAL_OR_KEYWORD:
is_required = default == inspect_empty # Required if no default
is_non_positional = False # Can be positional
elif kind == kinds.KEYWORD_ONLY:
is_required = default == inspect_empty # Required if no default
is_non_positional = True # Must use --flag style
elif kind is None:
# programmatically created parameters without kind
is_required = default == inspect_empty # Required if no default
is_non_positional = False # Can be positional (preserve old behavior)
else:
raise RuntimeError(f"The code should never reach here: kind={kind}") # pragma: no cover
src = get_parameter_origins(param.component, param.parent)
skip_message = f'Skipping parameter "{name}" from "{src}" because of: '
if not fail_untyped and annotation == inspect_empty:
Expand All @@ -356,7 +371,7 @@ def _add_signature_parameter(
default = None
is_required = False
is_required_link_target = True
if kind in {kinds.VAR_POSITIONAL, kinds.VAR_KEYWORD} or (not is_required and name[0] == "_"):
if not is_required and name[0] == "_":
return
elif skip and name in skip:
self.logger.debug(skip_message + "Parameter requested to be skipped.")
Expand All @@ -371,12 +386,12 @@ def _add_signature_parameter(
kwargs["default"] = default
if default is None and not is_optional(annotation, object) and not is_required_link_target:
annotation = Optional[annotation]
elif not as_positional:
elif not as_positional or is_non_positional:
kwargs["required"] = True
is_subclass_typehint = False
is_dataclass_like_typehint = is_dataclass_like(annotation)
dest = (nested_key + "." if nested_key else "") + name
args = [dest if is_required and as_positional else "--" + dest]
args = [dest if is_required and as_positional and not is_non_positional else "--" + dest]
if param.origin:
parser = container
if not isinstance(container, ArgumentParser):
Expand Down
16 changes: 16 additions & 0 deletions jsonargparse_tests/test_signatures.py
Original file line number Diff line number Diff line change
Expand Up @@ -697,3 +697,19 @@ def test_add_function_param_conflict(parser):
with pytest.raises(ValueError) as ctx:
parser.add_function_arguments(func_param_conflict)
ctx.match("Unable to add parameter 'cfg' from")


def func_positional_and_keyword_only(a: int, /, b: int, *, c: int, d: int = 1):
pass


def test_add_function_positional_and_keyword_only_parameters(parser):
parser.add_function_arguments(func_positional_and_keyword_only, as_positional=True)

# Test that we can parse with both parameters
cfg = parser.parse_args(["1", "2", "--c=3", "--d=4"])
assert cfg == Namespace(a=1, b=2, c=3, d=4)
with pytest.raises(ArgumentError, match="Unrecognized arguments: --b=2"):
parser.parse_args(["1", "--b=2", "--c=3", "--d=4"])
with pytest.raises(ArgumentError, match='Key "c" is required'):
parser.parse_args(["1", "2", "--d=4"])
Loading