diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bdded866..fd6d23f3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,18 @@ The semantic versioning only considers the public API as described in paths are considered internals and can change in minor and patch releases. +v4.27.7 (2024-03-??) +-------------------- + +Fixed +^^^^^ +- Regression from `14456c2 + `__ + that prevented ``**kwargs`` parameter resolving when an ``Optional[Callable]`` + type is used (`#473 + `__). + + v4.27.6 (2024-03-15) -------------------- diff --git a/jsonargparse/_typehints.py b/jsonargparse/_typehints.py index 67ec5eb6..6dab1803 100644 --- a/jsonargparse/_typehints.py +++ b/jsonargparse/_typehints.py @@ -955,7 +955,11 @@ def get_callable_return_type(typehint): def get_subclass_types(typehint, callable_return=True): subclass_types = None - if callable_return and ActionTypeHint.is_callable_typehint(typehint, all_subtypes=False) and typehint.__args__: + if ( + callable_return + and ActionTypeHint.is_callable_typehint(typehint, all_subtypes=False) + and getattr(typehint, "__args__", None) + ): typehint = get_optional_arg(typehint) typehint = typehint.__args__[-1] if ActionTypeHint.is_subclass_typehint(typehint, all_subtypes=False): diff --git a/jsonargparse_tests/test_parameter_resolvers.py b/jsonargparse_tests/test_parameter_resolvers.py index 22b89e99..9cc6f800 100644 --- a/jsonargparse_tests/test_parameter_resolvers.py +++ b/jsonargparse_tests/test_parameter_resolvers.py @@ -5,7 +5,7 @@ import xml.dom from calendar import Calendar from random import shuffle -from typing import Any, Callable, Dict, List, Union +from typing import Any, Callable, Dict, List, Optional, Union from unittest.mock import patch import pytest @@ -541,6 +541,14 @@ def conditional_calls(**kwargs): cond_3(**kwargs) +def function_optional_callable(p1: Optional[Callable] = None, **kw): + """ + Args: + p1: help for p1 + """ + function_no_args_no_kwargs(**kw) + + def assert_params(params, expected, origins={}): assert expected == [p.name for p in params] docs = [f"help for {p.name}" for p in params] if docstring_parser_support else [None] * len(params) @@ -864,6 +872,10 @@ def test_conditional_calls_kwargs(): assert get_params(conditional_calls) == [] +def test_get_params_optional_callable(): + assert_params(get_params(function_optional_callable), ["p1", "pk1", "k2"]) + + # unsupported cases