Repository: omni-us/jsonargparse
Pull request #358 (2023-08-22 05:08:06)

Deprecate ActionJsonnetExtVars in favor of type=dict
## Before submitting

- [x] Did you read the [contributing guideline](https://github.com/omni-us/jsonargparse/blob/main/CONTRIBUTING.rst)?
- [x] Did you update **the documentation**? (readme and public docstrings)
- [x] Did you write **unit tests** such that there is 100% coverage on related code? (required for bug fixes and new features)
- [x] Did you verify that new and existing **tests pass locally**?
- [x] Did you make sure that all changes preserve **backward compatibility**?
- [x] Did you update **the CHANGELOG**? (not for typos, docs, test updates, or minor internal changes/refactors)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=omni-us_jsonargparse&pullRequest=358)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=358&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=358&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=358&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=358&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=358&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=358&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=omni-us_jsonargparse&pullRequest=358&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=omni-us_jsonargparse&pullRequest=358&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=omni-us_jsonargparse&pullRequest=358&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=358&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=358&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=358&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=358) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=358&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=358&metric=new_duplicated_lines_density&view=list)


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) Report
Patch coverage: **`100.00%`** and no project coverage change.
> Comparison is base [(`16aa1f7`)](https://app.codecov.io/gh/omni-us/jsonargparse/commit/16aa1f77d809b31423a8a5f3d808a0f7d9774991?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) 100.00% compared to head [(`e1a4997`)](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) 100.00%.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff            @@
##              main      #358   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           21        21           
  Lines         5646      5669   +23     
=========================================
+ Hits          5646      5669   +23     
```

| [Flag](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | Coverage Δ | |
|---|---|---|
| [py3.10](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `87.59% <67.34%> (-0.11%)` | :arrow_down: |
| [py3.10_all](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `98.87% <100.00%> (+<0.01%)` | :arrow_up: |
| [py3.10_types](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `98.87% <100.00%> (+<0.01%)` | :arrow_up: |
| [py3.11](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `87.58% <67.34%> (-0.11%)` | :arrow_down: |
| [py3.11_all](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `98.85% <100.00%> (+<0.01%)` | :arrow_up: |
| [py3.11_types](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `98.85% <100.00%> (+<0.01%)` | :arrow_up: |
| [py3.6](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `84.96% <64.44%> (-0.11%)` | :arrow_down: |
| [py3.6_all](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `96.68% <100.00%> (+0.01%)` | :arrow_up: |
| [py3.7](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `88.14% <64.44%> (-0.13%)` | :arrow_down: |
| [py3.7_all](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `99.57% <100.00%> (+<0.01%)` | :arrow_up: |
| [py3.7_types](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `99.55% <100.00%> (+<0.01%)` | :arrow_up: |
| [py3.8](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `88.30% <67.34%> (-0.12%)` | :arrow_down: |
| [py3.8_all](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `99.62% <100.00%> (+<0.01%)` | :arrow_up: |
| [py3.8_types](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `99.61% <100.00%> (+<0.01%)` | :arrow_up: |
| [py3.9](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `88.16% <67.34%> (-0.12%)` | :arrow_down: |
| [py3.9_all](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `99.52% <100.00%> (+<0.01%)` | :arrow_up: |
| [py3.9_types](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | `99.52% <100.00%> (+<0.01%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Files Changed](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | Coverage Δ | |
|---|---|---|
| [jsonargparse/\_actions.py](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us#diff-anNvbmFyZ3BhcnNlL19hY3Rpb25zLnB5) | `100.00% <100.00%> (ø)` | |
| [jsonargparse/\_core.py](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us#diff-anNvbmFyZ3BhcnNlL19jb3JlLnB5) | `100.00% <100.00%> (ø)` | |
| [jsonargparse/\_deprecated.py](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us#diff-anNvbmFyZ3BhcnNlL19kZXByZWNhdGVkLnB5) | `100.00% <100.00%> (ø)` | |
| [jsonargparse/\_jsonnet.py](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us#diff-anNvbmFyZ3BhcnNlL19qc29ubmV0LnB5) | `100.00% <100.00%> (ø)` | |


</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/omni-us/jsonargparse/pull/358?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us).


Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index b95f2b4..0dac530 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -25,6 +25,12 @@ Added
 - Resolve types that use ``TYPE_CHECKING`` blocks (`#337 comment
   <https://github.com/omni-us/jsonargparse/issues/337#issuecomment-1665055459>`__).
 - Improved resolving of nested forward references in types.
+- The ``ext_vars`` for an ``ActionJsonnet`` argument can now have a default.
+
+Deprecated
+^^^^^^^^^^
+- ``ActionJsonnetExtVars`` is deprecated and will be removed in v5.0.0. Instead
+  use ``type=dict``.
 
 
 v4.23.1 (2023-08-04)
diff --git a/DOCUMENTATION.rst b/DOCUMENTATION.rst
index 914efad..73ecf4b 100644
--- a/DOCUMENTATION.rst
+++ b/DOCUMENTATION.rst
@@ -2288,10 +2288,10 @@ dictionary of variables. Its use would be as follows:
 
 .. testcode:: jsonnet
 
-    from jsonargparse import ArgumentParser, ActionJsonnet, ActionJsonnetExtVars
+    from jsonargparse import ArgumentParser, ActionJsonnet
 
     parser = ArgumentParser()
-    parser.add_argument("--in_ext_vars", action=ActionJsonnetExtVars())
+    parser.add_argument("--in_ext_vars", type=dict)
     parser.add_argument("--in_jsonnet", action=ActionJsonnet(ext_vars="in_ext_vars"))
 
 For example, if a jsonnet file required some external variable ``param``, then
diff --git a/jsonargparse/_actions.py b/jsonargparse/_actions.py
index 57a6269..3210335 100644
--- a/jsonargparse/_actions.py
+++ b/jsonargparse/_actions.py
@@ -177,6 +177,16 @@ class ActionConfigFile(Action, FilesCompleterMethod):
     def set_default_error():
         raise ValueError("ActionConfigFile does not accept a default, use default_config_files.")
 
+    @staticmethod
+    def _ensure_single_config_argument(container, action):
+        if is_subclass(action, ActionConfigFile) and any(isinstance(a, ActionConfigFile) for a in container._actions):
+            raise ValueError("A parser is only allowed to have a single ActionConfigFile argument.")
+
+    @staticmethod
+    def _add_print_config_argument(container, action):
+        if isinstance(action, ActionConfigFile) and getattr(container, "_print_config", None) is not None:
+            container.add_argument(container._print_config, action=_ActionPrintConfig)
+
     @staticmethod
     def apply_config(parser, cfg, dest, value) -> None:
         from ._link_arguments import skip_apply_links
@@ -491,6 +501,14 @@ class ActionParser:
         if not isinstance(self._parser, import_object("jsonargparse.ArgumentParser")):
             raise ValueError("Expected parser keyword argument to be an ArgumentParser.")
 
+    @staticmethod
+    def _is_valid_action_parser(parser, action) -> bool:
+        if not isinstance(action, ActionParser):
+            return False
+        if action._parser == parser:
+            raise ValueError("Parser cannot be added as a subparser of itself.")
+        return True
+
     @staticmethod
     def _move_parser_actions(parser, args, kwargs):
         subparser = kwargs.pop("action")._parser
diff --git a/jsonargparse/_core.py b/jsonargparse/_core.py
index 8a1562f..055a83f 100644
--- a/jsonargparse/_core.py
+++ b/jsonargparse/_core.py
@@ -5,7 +5,6 @@ import glob
 import inspect
 import logging
 import os
-import re
 import sys
 from contextlib import suppress
 from typing import (
@@ -38,10 +37,10 @@ from ._actions import (
     parent_parsers,
     previous_config,
 )
-from ._common import is_dataclass_like, is_subclass, lenient_check, parser_context
+from ._common import is_dataclass_like, lenient_check, parser_context
 from ._deprecated import ParserDeprecations
 from ._formatters import DefaultHelpFormatter, empty_help, get_env_var
-from ._jsonnet import ActionJsonnet, ActionJsonnetExtVars
+from ._jsonnet import ActionJsonnet
 from ._jsonschema import ActionJsonSchema
 from ._link_arguments import ActionLink, ArgumentLinking
 from ._loaders_dumpers import (
@@ -107,19 +106,13 @@ class ActionsContainer(SignatureArguments, argparse._ActionsContainer):
         """
         parser = self.parser if hasattr(self, "parser") else self
         if "action" in kwargs:
-            if isinstance(kwargs["action"], ActionParser):
-                if kwargs["action"]._parser == parser:
-                    raise ValueError("Parser cannot be added as a subparser of itself.")
+            if ActionParser._is_valid_action_parser(parser, kwargs["action"]):
                 return ActionParser._move_parser_actions(parser, args, kwargs)
-            if is_subclass(kwargs["action"], ActionConfigFile) and any(
-                isinstance(a, ActionConfigFile) for a in self._actions
-            ):
-                raise ValueError("A parser is only allowed to have a single ActionConfigFile argument.")
+            ActionConfigFile._ensure_single_config_argument(self, kwargs["action"])
         if "type" in kwargs:
             if is_dataclass_like(kwargs["type"]):
-                theclass = kwargs.pop("type")
-                nested_key = re.sub("^--", "", args[0])
-                self.add_dataclass_arguments(theclass, nested_key, **kwargs)
+                nested_key = args[0].lstrip("-")
+                self.add_dataclass_arguments(kwargs.pop("type"), nested_key, **kwargs)
                 return _find_action(parser, nested_key)
             if ActionTypeHint.is_supported_typehint(kwargs["type"]):
                 args = ActionTypeHint.prepare_add_argument(
@@ -131,8 +124,8 @@ class ActionsContainer(SignatureArguments, argparse._ActionsContainer):
                 )
         action = super().add_argument(*args, **kwargs)
         action.logger = self._logger  # type: ignore
-        if isinstance(action, ActionConfigFile) and getattr(self, "_print_config", None) is not None:
-            self.add_argument(self._print_config, action=_ActionPrintConfig)  # type: ignore
+        ActionConfigFile._add_print_config_argument(self, action)
+        ActionJsonnet._check_ext_vars_action(parser, action)
         if is_meta_key(action.dest):
             raise ValueError(f'Argument with destination name "{action.dest}" not allowed.')
         if action.help is None:
@@ -1252,7 +1245,7 @@ class ArgumentParser(ParserDeprecations, ActionsContainer, ArgumentLinking, argp
             if isinstance(action, _ActionConfigLoad):
                 config_keys.add(action_dest)
                 keys.append(action_dest)
-            elif isinstance(action, ActionJsonnetExtVars):
+            elif getattr(action, "jsonnet_ext_vars", False):
                 prev_cfg[action_dest] = value
             cfg[action_dest] = value
         return cfg[parent_key] if parent_key else cfg
diff --git a/jsonargparse/_deprecated.py b/jsonargparse/_deprecated.py
index 6112c58..048fef0 100644
--- a/jsonargparse/_deprecated.py
+++ b/jsonargparse/_deprecated.py
@@ -17,6 +17,7 @@ from ._type_checking import ArgumentParser
 
 __all__ = [
     "ActionEnum",
+    "ActionJsonnetExtVars",
     "ActionOperators",
     "ActionPath",
     "ActionPathList",
@@ -581,3 +582,20 @@ deprecated_module(
         "import_docstring_parse": ("_optionals", "import_docstring_parser"),
     },
 )
+
+
+@deprecated(
+    """
+    ActionJsonnetExtVars was deprecated in v4.24.0 and will be removed in
+    v5.0.0. Instead use ``type=dict``.
+"""
+)
+class ActionJsonnetExtVars:
+    """Action to add argument to provide ext_vars for jsonnet parsing."""
+
+    def __call__(self, *args, **kwargs):
+        from ._typehints import ActionTypeHint
+
+        action = ActionTypeHint(typehint=dict)(**kwargs)
+        action.jsonnet_ext_vars = True
+        return action
diff --git a/jsonargparse/_jsonnet.py b/jsonargparse/_jsonnet.py
index 80239a9..c6f8b4d 100644
--- a/jsonargparse/_jsonnet.py
+++ b/jsonargparse/_jsonnet.py
@@ -2,7 +2,7 @@
 
 from typing import Any, Dict, Optional, Tuple, Union
 
-from ._actions import Action, _is_action_value_list
+from ._actions import Action, _find_action, _is_action_value_list
 from ._common import parser_context
 from ._jsonschema import ActionJsonSchema
 from ._loaders_dumpers import get_loader_exceptions, load_value
@@ -12,28 +12,10 @@ from ._optionals import (
     import_jsonnet,
     import_jsonschema,
 )
+from ._typehints import ActionTypeHint
 from ._util import Path, argument_error
 
-__all__ = [
-    "ActionJsonnetExtVars",
-    "ActionJsonnet",
-]
-
-
-class ActionJsonnetExtVars(ActionJsonSchema):
-    """Action to add argument to provide ext_vars for jsonnet parsing."""
-
-    def __init__(self, **kwargs):
-        """Initializer for ActionJsonnetExtVars instance."""
-        if kwargs:
-            super().__init__(**kwargs)
-        else:
-            super().__init__(schema={"type": "object"}, with_meta=False)
-
-    def __call__(self, *args, **kwargs):
-        if len(args) == 0 and "default" not in kwargs:
-            kwargs["default"] = {}
-        return super().__call__(*args, _class_type=ActionJsonnetExtVars, **kwargs)
+__all__ = ["ActionJsonnet"]
 
 
 class ActionJsonnet(Action):
@@ -67,7 +49,7 @@ class ActionJsonnet(Action):
                         try:
                             schema = load_value(schema)
                         except get_loader_exceptions() as ex:
-                            raise ValueError(f"Problems parsing schema :: {ex}") from ex
+                            raise ValueError(f"Problems parsing schema: {ex}") from ex
                 jsonvalidator.check_schema(schema)
                 self._validator = ActionJsonSchema._extend_jsonvalidator_with_default(jsonvalidator)(schema)
             else:
@@ -113,6 +95,26 @@ class ActionJsonnet(Action):
                 raise TypeError(f'Parser key "{self.dest}"{elem}: {ex}') from ex
         return value if islist else value[0]
 
+    @staticmethod
+    def _check_ext_vars_action(parser, action):
+        if isinstance(action, ActionJsonnet) and action._ext_vars:
+            ext_vars_action = _find_action(parser, action._ext_vars)
+            if not ext_vars_action:
+                raise ValueError(f"No argument found for ext_vars='{action._ext_vars}'")
+            ext_vars_type = isinstance(ext_vars_action, ActionTypeHint) and ext_vars_action._typehint
+            if ext_vars_type not in {dict, Dict}:
+                raise ValueError(
+                    f"Type for ext_vars='{action._ext_vars}' argument must be dict, given: {ext_vars_type}"
+                )
+            if ext_vars_action.default is None:
+                ext_vars_action.default = {}
+            if not isinstance(ext_vars_action.default, dict):
+                raise ValueError(
+                    f"Default value for the ext_vars='{action._ext_vars}' argument "
+                    f"must be dict or None, given: {ext_vars_action.default}"
+                )
+            ext_vars_action.jsonnet_ext_vars = True
+
     @staticmethod
     def split_ext_vars(ext_vars: Optional[Dict[str, Any]]) -> Tuple[Dict[str, Any], Dict[str, Any]]:
         """Splits an ext_vars dict into the ext_codes and ext_vars required by jsonnet.


Test patch:
diff --git a/jsonargparse_tests/test_deprecated.py b/jsonargparse_tests/test_deprecated.py
index ae74e20..f1dfba3 100644
--- a/jsonargparse_tests/test_deprecated.py
+++ b/jsonargparse_tests/test_deprecated.py
@@ -15,6 +15,7 @@ import pytest
 from jsonargparse import (
     CLI,
     ActionConfigFile,
+    ActionJsonnet,
     ArgumentError,
     ArgumentParser,
     Path,
@@ -23,6 +24,7 @@ from jsonargparse import (
 )
 from jsonargparse._deprecated import (
     ActionEnum,
+    ActionJsonnetExtVars,
     ActionOperators,
     ActionPath,
     ActionPathList,
@@ -31,13 +33,14 @@ from jsonargparse._deprecated import (
     shown_deprecation_warnings,
     usage_and_exit_error_handler,
 )
-from jsonargparse._optionals import url_support
+from jsonargparse._optionals import jsonnet_support, url_support
 from jsonargparse._util import LoggerProperty, argument_error
 from jsonargparse_tests.conftest import (
     get_parser_help,
     skip_if_docstring_parser_unavailable,
     skip_if_requests_unavailable,
 )
+from jsonargparse_tests.test_jsonnet import example_2_jsonnet
 
 
 @pytest.fixture(autouse=True)
@@ -475,3 +478,17 @@ def test_import_from_module(module, attr):
         getattr(module, attr)
     if sys.version_info[:2] != (3, 6):
         assert "Only use the public API" in str(w[-1].message)
+
+
+@pytest.mark.skipif(not jsonnet_support, reason="jsonnet package is required")
+def test_action_jsonnet_ext_vars(parser):
+    with catch_warnings(record=True) as w:
+        parser.add_argument("--ext_vars", action=ActionJsonnetExtVars())
+    assert "ActionJsonnetExtVars was deprecated" in str(w[-1].message)
+    parser.add_argument("--jsonnet", action=ActionJsonnet(ext_vars="ext_vars"))
+
+    cfg = parser.parse_args(["--ext_vars", '{"param": 123}', "--jsonnet", example_2_jsonnet])
+    assert 123 == cfg.jsonnet["param"]
+    assert 9 == len(cfg.jsonnet["records"])
+    assert "#8" == cfg.jsonnet["records"][-2]["ref"]
+    assert 15.5 == cfg.jsonnet["records"][-2]["val"]
diff --git a/jsonargparse_tests/test_jsonnet.py b/jsonargparse_tests/test_jsonnet.py
index 910d515..5b7d603 100644
--- a/jsonargparse_tests/test_jsonnet.py
+++ b/jsonargparse_tests/test_jsonnet.py
@@ -10,7 +10,6 @@ import yaml
 from jsonargparse import (
     ActionConfigFile,
     ActionJsonnet,
-    ActionJsonnetExtVars,
     ActionJsonSchema,
     ArgumentError,
     ArgumentParser,
@@ -135,7 +134,7 @@ def test_parser_mode_jsonnet_subconfigs(parser, tmp_cwd):
 
 @skip_if_jsonschema_unavailable
 def test_action_jsonnet(parser):
-    parser.add_argument("--input.ext_vars", action=ActionJsonnetExtVars())
+    parser.add_argument("--input.ext_vars", type=dict)
     parser.add_argument(
         "--input.jsonnet",
         action=ActionJsonnet(ext_vars="input.ext_vars", schema=json.dumps(example_schema)),
@@ -157,7 +156,7 @@ def test_action_jsonnet(parser):
 
 
 def test_action_jsonnet_save_config_metadata(parser, tmp_path):
-    parser.add_argument("--ext_vars", action=ActionJsonnetExtVars())
+    parser.add_argument("--ext_vars", type=dict)
     parser.add_argument("--jsonnet", action=ActionJsonnet(ext_vars="ext_vars"))
     parser.add_argument("--cfg", action=ActionConfigFile)
 
@@ -221,6 +220,33 @@ def test_action_jsonnet_parse_method():
     assert 15.5 == parsed["records"][-2]["val"]
 
 
+def test_action_jsonnet_ext_vars_default(parser):
+    parser.add_argument("--ext_vars", type=dict, default={"param": 432})
+    parser.add_argument("--jsonnet", action=ActionJsonnet(ext_vars="ext_vars"))
+    cfg = parser.parse_args(["--jsonnet", example_2_jsonnet])
+    assert 432 == cfg.jsonnet["param"]
+
+
+def test_action_jsonnet_ext_vars_not_defined(parser):
+    with pytest.raises(ValueError) as ctx:
+        parser.add_argument("--jsonnet", action=ActionJsonnet(ext_vars="ext_vars"))
+    ctx.match("No argument found for ext_vars")
+
+
+def test_action_jsonnet_ext_vars_invalid_type(parser):
+    parser.add_argument("--ext_vars", type=list)
+    with pytest.raises(ValueError) as ctx:
+        parser.add_argument("--jsonnet", action=ActionJsonnet(ext_vars="ext_vars"))
+    ctx.match("Type for ext_vars='ext_vars' argument must be dict")
+
+
+def test_action_jsonnet_ext_vars_invalid_default(parser):
+    parser.add_argument("--ext_vars", type=dict, default="none")
+    with pytest.raises(ValueError) as ctx:
+        parser.add_argument("--jsonnet", action=ActionJsonnet(ext_vars="ext_vars"))
+    ctx.match("Default value for the ext_vars='ext_vars' argument must be dict or None")
+
+
 # other tests
 
 
diff --git a/jsonargparse_tests/test_jsonschema.py b/jsonargparse_tests/test_jsonschema.py
index fc756de..4413dc7 100644
--- a/jsonargparse_tests/test_jsonschema.py
+++ b/jsonargparse_tests/test_jsonschema.py
@@ -83,7 +83,7 @@ def parser_schema_object(parser):
         },
         "additionalProperties": False,
     }
-    parser.add_argument("--op2", action=ActionJsonSchema(schema=schema_object))
+    parser.add_argument("--op2", action=ActionJsonSchema(schema=schema_object, with_meta=False))
     parser.add_argument("--cfg", action=ActionConfigFile)
     return parser