From 2f1d495439fed00954068c9135eff39188dd79f8 Mon Sep 17 00:00:00 2001 From: Mauricio Villegas <5780272+mauvilsa@users.noreply.github.com> Date: Mon, 27 May 2024 07:53:16 +0200 Subject: [PATCH] Allow adding config argument with action="config" avoiding need to import action class. --- CHANGELOG.rst | 9 +++++++ DOCUMENTATION.rst | 28 ++++++++++----------- jsonargparse/_actions.py | 6 +++-- jsonargparse/_core.py | 1 + jsonargparse_tests/test_actions.py | 13 +++++----- jsonargparse_tests/test_argcomplete.py | 4 +-- jsonargparse_tests/test_core.py | 29 ++++++++++++++-------- jsonargparse_tests/test_dataclass_like.py | 3 +-- jsonargparse_tests/test_deprecated.py | 3 +-- jsonargparse_tests/test_formatters.py | 4 +-- jsonargparse_tests/test_jsonnet.py | 7 +++--- jsonargparse_tests/test_jsonschema.py | 6 ++--- jsonargparse_tests/test_link_arguments.py | 15 ++++++----- jsonargparse_tests/test_loaders_dumpers.py | 6 ++--- jsonargparse_tests/test_paths.py | 4 +-- jsonargparse_tests/test_signatures.py | 9 +++---- jsonargparse_tests/test_subclasses.py | 27 ++++++++++---------- jsonargparse_tests/test_subcommands.py | 7 +++--- jsonargparse_tests/test_typehints.py | 8 +++--- 19 files changed, 100 insertions(+), 89 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index aec33cb7..02662c7b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,15 @@ The semantic versioning only considers the public API as described in paths are considered internals and can change in minor and patch releases. +v4.30.0 (2024-06-??) +-------------------- + +Added +^^^^^ +- Allow adding config argument with ``action="config"`` avoiding need to import + action class. + + v4.29.0 (2024-05-24) -------------------- diff --git a/DOCUMENTATION.rst b/DOCUMENTATION.rst index d11af8d7..9fb6a2bd 100644 --- a/DOCUMENTATION.rst +++ b/DOCUMENTATION.rst @@ -285,7 +285,7 @@ Depending on the parse method used (see :class:`.ArgumentParser`) and how the parser was built, some of the options above might not apply. Parsing of environment variables must be explicitly enabled, except if using :py:meth:`.ArgumentParser.parse_env`. If the parser does not have an -:class:`.ActionConfigFile` argument, then there is no parsing of a full config +`action="config"` argument, then there is no parsing of a full config environment variable or a way to provide a config file from command line. @@ -651,11 +651,11 @@ If you import ``from jsonargparse import set_config_read_mode`` and then run ``set_config_read_mode(fsspec_enabled=True)``, the following functions and classes will also support loading from URLs: :py:meth:`.ArgumentParser.parse_path`, :py:meth:`.ArgumentParser.get_defaults` -(``default_config_files`` argument), :class:`.ActionConfigFile`, +(``default_config_files`` argument), `action="config"`, :class:`.ActionJsonSchema`, :class:`.ActionJsonnet` and :class:`.ActionParser`. This means that a tool that can receive a configuration file via -:class:`.ActionConfigFile` is able to get the content from a URL, thus something -like the following would work: +`action="config"` is able to get the content from a URL, thus something like the +following would work: .. code-block:: bash @@ -1285,11 +1285,11 @@ the following would be observed: .. doctest:: config - >>> from jsonargparse import ArgumentParser, ActionConfigFile + >>> from jsonargparse import ArgumentParser >>> parser = ArgumentParser() >>> parser.add_argument("--lev1.opt1", default="from default 1") # doctest: +IGNORE_RESULT >>> parser.add_argument("--lev1.opt2", default="from default 2") # doctest: +IGNORE_RESULT - >>> parser.add_argument("--config", action=ActionConfigFile) # doctest: +IGNORE_RESULT + >>> parser.add_argument("--config", action="config") # doctest: +IGNORE_RESULT >>> cfg = parser.parse_args(["--lev1.opt1", "from arg 1", "--config", "example.yaml", "--lev1.opt2", "from arg 2"]) >>> cfg.lev1.opt1 'from yaml 1' @@ -1318,7 +1318,7 @@ string respectively. Serialization ------------- -Parsers that have an :class:`.ActionConfigFile` argument also include a +Parsers that have an `action="config"` argument also include a ``--print_config`` option. This is useful particularly for command line tools with a large set of options to create an initial config file including all default values. If the `ruyaml `__ package is @@ -2243,7 +2243,7 @@ This yaml could be parsed as follows: >>> parser = ArgumentParser(parser_mode="omegaconf") >>> parser.add_argument("--server", type=ServerOptions) # doctest: +IGNORE_RESULT >>> parser.add_argument("--client", type=ClientOptions) # doctest: +IGNORE_RESULT - >>> parser.add_argument("--config", action=ActionConfigFile) # doctest: +IGNORE_RESULT + >>> parser.add_argument("--config", action="config") # doctest: +IGNORE_RESULT >>> cfg = parser.parse_args(["--config=example.yaml"]) >>> cfg.client.url @@ -2303,9 +2303,9 @@ There is also the :py:meth:`.ArgumentParser.parse_env` function to only parse environment variables, which might be useful for some use cases in which there is no command line call involved. -If a parser includes an :class:`.ActionConfigFile` argument, then the -environment variable for this config file will be parsed before all the other -environment variables. +If a parser includes an `action="config"` argument, then the environment +variable for this config file will be parsed before all the other environment +variables. .. _sub-commands: @@ -2450,10 +2450,10 @@ config files to be in jsonnet format instead. Example: .. testcode:: jsonnet - from jsonargparse import ArgumentParser, ActionConfigFile + from jsonargparse import ArgumentParser parser = ArgumentParser(parser_mode="jsonnet") - parser.add_argument("--config", action=ActionConfigFile) + parser.add_argument("--config", action="config") cfg = parser.parse_args(["--config", "example.jsonnet"]) Jsonnet files are commonly parametrized, thus requiring external variables for @@ -2511,7 +2511,7 @@ following: When using the :class:`.ActionParser` class, the value of the node in a config file can be either the complex node itself, or the path to a file which will be loaded and parsed with the corresponding inner parser. Naturally using -:class:`.ActionConfigFile` to parse a complete config file will parse the inner +`action="config"` to parse a complete config file will parse the inner nodes correctly. Note that when adding ``inner_parser`` a title was given. In the help, the added diff --git a/jsonargparse/_actions.py b/jsonargparse/_actions.py index 7da06167..43c31998 100644 --- a/jsonargparse/_actions.py +++ b/jsonargparse/_actions.py @@ -174,8 +174,10 @@ def set_default_error(): @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.") + if (action == "config" or 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 'config' argument.") @staticmethod def _add_print_config_argument(container, action): diff --git a/jsonargparse/_core.py b/jsonargparse/_core.py index 4a002342..5e499608 100644 --- a/jsonargparse/_core.py +++ b/jsonargparse/_core.py @@ -102,6 +102,7 @@ def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.register("type", None, identity) self.register("action", "parsers", _ActionSubCommands) + self.register("action", "config", ActionConfigFile) def add_argument(self, *args, enable_path: bool = False, **kwargs): """Adds an argument to the parser or argument group. diff --git a/jsonargparse_tests/test_actions.py b/jsonargparse_tests/test_actions.py index f75d084f..3ee8120d 100644 --- a/jsonargparse_tests/test_actions.py +++ b/jsonargparse_tests/test_actions.py @@ -5,7 +5,6 @@ import pytest from jsonargparse import ( - ActionConfigFile, ActionParser, ActionYesNo, ArgumentError, @@ -24,7 +23,7 @@ def test_action_config_file(parser, tmp_cwd): abs_yaml_file.parent.mkdir() abs_yaml_file.write_text("val: yaml\n") - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--val") cfg = parser.parse_args([f"--cfg={abs_yaml_file}", f"--cfg={rel_yaml_file}", "--cfg", "val: arg"]) @@ -36,7 +35,7 @@ def test_action_config_file(parser, tmp_cwd): def test_action_config_file_set_defaults_error(parser): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") with pytest.raises(ValueError) as ctx: parser.set_defaults(cfg="config.yaml") ctx.match("does not accept a default, use default_config_files") @@ -44,18 +43,18 @@ def test_action_config_file_set_defaults_error(parser): def test_action_config_file_add_argument_default_error(parser): with pytest.raises(ValueError) as ctx: - parser.add_argument("--cfg", default="config.yaml", action=ActionConfigFile) + parser.add_argument("--cfg", default="config.yaml", action="config") ctx.match("does not accept a default, use default_config_files") def test_action_config_file_nested_error(parser): with pytest.raises(ValueError) as ctx: - parser.add_argument("--nested.cfg", action=ActionConfigFile) + parser.add_argument("--nested.cfg", action="config") ctx.match("ActionConfigFile must be a top level option") def test_action_config_file_argument_errors(parser, tmp_cwd): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") pytest.raises(ArgumentError, lambda: parser.parse_args(["--cfg", '"""'])) pytest.raises(ArgumentError, lambda: parser.parse_args(["--cfg=not-exist"])) pytest.raises(ArgumentError, lambda: parser.parse_args(["--cfg", '{"k":"v"}'])) @@ -251,7 +250,7 @@ def test_action_parser_parse_args_subconfig_string(composed_parsers): def test_action_parser_parse_args_global_config(composed_parsers): parser, yaml_main = composed_parsers[:2] - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") expected = {"opt1": "opt1_yaml", "inner2": {"opt2": "opt2_yaml", "inner3": {"opt3": "opt3_yaml"}}} cfg = parser.parse_args([f"--cfg={yaml_main}"], with_meta=False) diff --git a/jsonargparse_tests/test_argcomplete.py b/jsonargparse_tests/test_argcomplete.py index ce08c507..de88c3e8 100644 --- a/jsonargparse_tests/test_argcomplete.py +++ b/jsonargparse_tests/test_argcomplete.py @@ -12,7 +12,7 @@ import pytest -from jsonargparse import ActionConfigFile, ActionJsonSchema, ActionYesNo +from jsonargparse import ActionJsonSchema, ActionYesNo from jsonargparse._common import parser_context from jsonargparse.typing import Email, Path_fr, PositiveFloat, PositiveInt from jsonargparse_tests.conftest import ( @@ -102,7 +102,7 @@ def test_stderr_instruction_simple_types(parser, value, expected): @skip_if_not_posix def test_action_config_file(parser, tmp_cwd): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") Path("file1").touch() Path("config.yaml").touch() diff --git a/jsonargparse_tests/test_core.py b/jsonargparse_tests/test_core.py index 09e340d7..eb1b6766 100644 --- a/jsonargparse_tests/test_core.py +++ b/jsonargparse_tests/test_core.py @@ -132,7 +132,7 @@ def test_parse_args_positional_nargs_plus(parser): def test_parse_args_positional_config(parser): parser.add_argument("pos1") parser.add_argument("pos2", nargs="+") - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") cfg = parser.parse_args(["--cfg", '{"pos2": ["v2", "v3"]}', "v1"]) assert cfg == Namespace(cfg=[None], pos1="v1", pos2=["v2", "v3"]) @@ -147,7 +147,7 @@ def test_parse_args_choices(parser): def test_parse_args_choices_config(parser): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--ch1", choices="ABC") parser.add_argument("--ch2", type=str, choices=["v1", "v2"]) assert parser.parse_args(["--cfg=ch1: B"]).ch1 == "B" @@ -158,7 +158,7 @@ def test_parse_args_choices_config(parser): def test_parse_args_non_hashable_choice(parser): choices = {"A": 1, "B": 2} - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--ch1", choices=choices.keys()) with pytest.raises(ArgumentError) as ctx: parser.parse_args(["--cfg=ch1: [1,2]"]) @@ -209,7 +209,7 @@ def test_parse_env_nested(): def test_parse_env_config(parser): parser.env_prefix = "app" - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--l1.num", type=int) cfg = parser.parse_env({"APP_CFG": '{"l1": {"num": 1}}'}) assert cfg.cfg == [None] @@ -344,7 +344,7 @@ def test_precedence_of_sources(tmp_cwd, subtests): parser = ArgumentParser(prog="app", default_env=True, default_config_files=[default_config_file]) parser.add_argument("--op1", default="from parser default") parser.add_argument("--op2") - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") input1_config_file.write_text("op1: from input config file") input2_config_file.write_text("op2: unused") @@ -435,7 +435,7 @@ def test_non_positional_required(parser, subtests): pytest.raises(ArgumentError, lambda: parser.parse_args(["--req1", "val1"])) with subtests.test("parse_args config"): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") cfg = parser.parse_args(["--cfg", '{"req1":"val1","lev1":{"req2":"val2"}}']) assert cfg == Namespace(cfg=[None], lev1=Namespace(req2="val2"), req1="val1") @@ -507,7 +507,7 @@ def test_dump_order(parser, subtests): @pytest.fixture def parser_schema_jsonnet(parser, example_parser): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--subparser", action=ActionParser(parser=example_parser)) if jsonschema_support: schema = { @@ -696,7 +696,7 @@ def test_save_fsspec(example_parser): @pytest.fixture def print_parser(parser, subparser): parser.description = "cli tool" - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--v0", help=SUPPRESS, default="0") parser.add_argument("--v1", help="Option v1.", default=1) parser.add_argument("--g1.v2", help="Option v2.", default="2") @@ -885,10 +885,17 @@ def test_set_get_defaults_multiple(parser, subparser, subtests): pytest.raises(KeyError, lambda: parser.get_default("v4")) -def test_add_multiple_config_arguments_error(parser): - parser.add_argument("--cfg1", action=ActionConfigFile) +def test_add_config_action_class(parser): + parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--op", type=int) + assert parser.parse_args(['--cfg={"op": 2}']).op == 2 + + +@pytest.mark.parametrize("action", [ActionConfigFile, "config"]) +def test_add_multiple_config_arguments_error(parser, action): + parser.add_argument("--cfg1", action=action) with pytest.raises(ValueError) as ctx: - parser.add_argument("--cfg2", action=ActionConfigFile) + parser.add_argument("--cfg2", action=action) ctx.match("only allowed to have a single") diff --git a/jsonargparse_tests/test_dataclass_like.py b/jsonargparse_tests/test_dataclass_like.py index 3e302165..cbaa97d2 100644 --- a/jsonargparse_tests/test_dataclass_like.py +++ b/jsonargparse_tests/test_dataclass_like.py @@ -8,7 +8,6 @@ import yaml from jsonargparse import ( - ActionConfigFile, ArgumentError, ArgumentParser, Namespace, @@ -404,7 +403,7 @@ class SingleParamChange: def test_optional_dataclass_single_param_change(parser): - parser.add_argument("--config", action=ActionConfigFile) + parser.add_argument("--config", action="config") parser.add_argument("--data", type=Optional[SingleParamChange]) config = {"data": {"p1": 1}} cfg = parser.parse_args([f"--config={config}", "--data.p2=2"]) diff --git a/jsonargparse_tests/test_deprecated.py b/jsonargparse_tests/test_deprecated.py index 6665c33c..e7271142 100644 --- a/jsonargparse_tests/test_deprecated.py +++ b/jsonargparse_tests/test_deprecated.py @@ -13,7 +13,6 @@ from jsonargparse import ( CLI, - ActionConfigFile, ActionJsonnet, ArgumentError, ArgumentParser, @@ -340,7 +339,7 @@ def test_ActionPath(tmp_cwd): output_file.write("file: " + rel_yaml_file + "\ndir: " + str(tmp_cwd) + "\n") parser = ArgumentParser(exit_on_error=False) - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") with catch_warnings(record=True) as w: parser.add_argument("--file", action=ActionPath(mode="fr")) assert_deprecation_warn( diff --git a/jsonargparse_tests/test_formatters.py b/jsonargparse_tests/test_formatters.py index c6f175e6..5720062c 100644 --- a/jsonargparse_tests/test_formatters.py +++ b/jsonargparse_tests/test_formatters.py @@ -7,7 +7,7 @@ import pytest -from jsonargparse import ActionConfigFile, ActionParser, ActionYesNo, ArgumentParser +from jsonargparse import ActionParser, ActionYesNo, ArgumentParser from jsonargparse_tests.conftest import get_parser_help @@ -23,7 +23,7 @@ def test_help_basics(parser): def test_help_action_config_file(parser): - parser.add_argument("-c", "--cfg", help="Config in yaml/json.", action=ActionConfigFile) + parser.add_argument("-c", "--cfg", help="Config in yaml/json.", action="config") help_str = get_parser_help(parser) assert "ARG: --print_config" in help_str assert "ARG: -c CFG, --cfg CFG" in help_str diff --git a/jsonargparse_tests/test_jsonnet.py b/jsonargparse_tests/test_jsonnet.py index 5b7d603a..add7a4a3 100644 --- a/jsonargparse_tests/test_jsonnet.py +++ b/jsonargparse_tests/test_jsonnet.py @@ -8,7 +8,6 @@ import yaml from jsonargparse import ( - ActionConfigFile, ActionJsonnet, ActionJsonSchema, ArgumentError, @@ -77,7 +76,7 @@ def skip_if_jsonnet_unavailable(): @skip_if_jsonschema_unavailable def test_parser_mode_jsonnet(tmp_path): parser = ArgumentParser(parser_mode="jsonnet", exit_on_error=False) - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--param", type=int) parser.add_argument("--records", action=ActionJsonSchema(schema=records_schema)) @@ -95,7 +94,7 @@ def test_parser_mode_jsonnet(tmp_path): def test_parser_mode_jsonnet_import_libsonnet(parser, tmp_cwd): parser.parser_mode = "jsonnet" - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--name", type=str, default="Lucky") parser.add_argument("--prize", type=int, default=100) @@ -158,7 +157,7 @@ def test_action_jsonnet(parser): def test_action_jsonnet_save_config_metadata(parser, tmp_path): parser.add_argument("--ext_vars", type=dict) parser.add_argument("--jsonnet", action=ActionJsonnet(ext_vars="ext_vars")) - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") jsonnet_file = tmp_path / "example.jsonnet" jsonnet_file.write_text(example_2_jsonnet) diff --git a/jsonargparse_tests/test_jsonschema.py b/jsonargparse_tests/test_jsonschema.py index daac2b50..a923d325 100644 --- a/jsonargparse_tests/test_jsonschema.py +++ b/jsonargparse_tests/test_jsonschema.py @@ -6,7 +6,7 @@ import pytest -from jsonargparse import ActionConfigFile, ActionJsonSchema, ArgumentError +from jsonargparse import ActionJsonSchema, ArgumentError from jsonargparse_tests.conftest import get_parser_help @@ -84,7 +84,7 @@ def parser_schema_object(parser): "additionalProperties": False, } parser.add_argument("--op2", action=ActionJsonSchema(schema=schema_object, with_meta=False)) - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") return parser @@ -136,7 +136,7 @@ def test_schema_oneof_add_defaults(parser): ] } parser.add_argument("--data", action=ActionJsonSchema(schema=schema)) - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") cfg = parser.parse_args(['--data={"kind": "x"}']) assert cfg.data == {"kind": "x", "pc": 1, "px": "dx"} diff --git a/jsonargparse_tests/test_link_arguments.py b/jsonargparse_tests/test_link_arguments.py index 54f27445..0115923d 100644 --- a/jsonargparse_tests/test_link_arguments.py +++ b/jsonargparse_tests/test_link_arguments.py @@ -9,7 +9,6 @@ import yaml from jsonargparse import ( - ActionConfigFile, ArgumentError, ArgumentParser, Namespace, @@ -30,7 +29,7 @@ def test_on_parse_help_target_lacking_type_and_help(parser): def test_on_parse_shallow_print_config(parser): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--a", type=int, default=0) parser.add_argument("--b", type=str) parser.link_arguments("a", "b") @@ -47,7 +46,7 @@ def to_str(value): subparser.add_argument("--a", type=int, default=0) subparser.add_argument("--b", type=str) subparser.link_arguments("a", "b", to_str) - subparser.add_argument("--config", action=ActionConfigFile) + subparser.add_argument("--config", action="config") subcommands = parser.add_subcommands() subcommands.add_subcommand("sub", subparser) @@ -89,7 +88,7 @@ def a_prod(a): def test_on_parse_compute_fn_subclass_spec(parser, subtests): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--cal1", type=Calendar, default=lazy_instance(TextCalendar)) parser.add_argument("--cal2", type=Calendar, default=lazy_instance(Calendar)) parser.link_arguments( @@ -765,7 +764,7 @@ def test_on_instantiate_within_deep_subclass(parser, caplog): parser.logger = {"level": "DEBUG"} parser.logger.handlers = [caplog.handler] - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--model", type=WithinDeepModel) parser.link_arguments( "model.encoder.output_channels", @@ -799,7 +798,7 @@ def test_on_instantiate_within_deeper_subclass(parser, caplog): parser.logger = {"level": "DEBUG"} parser.logger.handlers = [caplog.handler] - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_subclass_arguments(WithinDeeperSystem, "system") parser.link_arguments( "system.model.encoder.output_channels", @@ -1006,7 +1005,7 @@ def test_on_instantiate_linking_deep_targets(parser, tmp_path): config_path = tmp_path / "config.yaml" config_path.write_text(yaml.safe_dump(config)) - parser.add_argument("--config", action=ActionConfigFile) + parser.add_argument("--config", action="config") parser.add_subclass_arguments(DeepBSuper, nested_key="b", required=True) parser.add_class_arguments(DeepC, nested_key="c") parser.link_arguments("c", "b.init_args.a.init_args.d", compute_fn=DeepC.fn, apply_on="instantiate") @@ -1038,7 +1037,7 @@ def test_on_instantiate_linking_deep_targets_mapping(parser, tmp_path): config_path = tmp_path / "config.yaml" config_path.write_text(yaml.safe_dump(config)) - parser.add_argument("--config", action=ActionConfigFile) + parser.add_argument("--config", action="config") parser.add_subclass_arguments(DeepBSuper, nested_key="b", required=True) parser.add_class_arguments(DeepC, nested_key="c") parser.link_arguments( diff --git a/jsonargparse_tests/test_loaders_dumpers.py b/jsonargparse_tests/test_loaders_dumpers.py index b403b22b..919e78e0 100644 --- a/jsonargparse_tests/test_loaders_dumpers.py +++ b/jsonargparse_tests/test_loaders_dumpers.py @@ -7,7 +7,7 @@ import pytest import yaml -from jsonargparse import ActionConfigFile, ArgumentParser, set_dumper, set_loader +from jsonargparse import ArgumentParser, set_dumper, set_loader from jsonargparse._common import parser_context from jsonargparse._loaders_dumpers import load_value, loaders, yaml_dump from jsonargparse._optionals import omegaconf_support @@ -49,7 +49,7 @@ def test_parser_mode_omegaconf_interpolation(): parser.add_argument("--server.host", type=str) parser.add_argument("--server.port", type=int) parser.add_argument("--client.url", type=str) - parser.add_argument("--config", action=ActionConfigFile) + parser.add_argument("--config", action="config") config = { "server": { @@ -67,7 +67,7 @@ def test_parser_mode_omegaconf_interpolation(): @pytest.mark.skipif(not omegaconf_support, reason="omegaconf package is required") def test_parser_mode_omegaconf_interpolation_in_subcommands(parser, subparser): - subparser.add_argument("--config", action=ActionConfigFile) + subparser.add_argument("--config", action="config") subparser.add_argument("--source", type=str) subparser.add_argument("--target", type=str) diff --git a/jsonargparse_tests/test_paths.py b/jsonargparse_tests/test_paths.py index 5020669f..81adecdd 100644 --- a/jsonargparse_tests/test_paths.py +++ b/jsonargparse_tests/test_paths.py @@ -8,7 +8,7 @@ import pytest -from jsonargparse import ActionConfigFile, ArgumentError, Namespace +from jsonargparse import ArgumentError, Namespace from jsonargparse.typing import Path_drw, Path_fc, Path_fr, path_type from jsonargparse_tests.conftest import get_parser_help @@ -48,7 +48,7 @@ def test_path_fr_already_registered(): def test_paths_config_relative_absolute(parser, tmp_cwd): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--file", type=Path_fr) parser.add_argument("--dir", type=Path_drw) diff --git a/jsonargparse_tests/test_signatures.py b/jsonargparse_tests/test_signatures.py index 54b13462..6bcc6f2c 100644 --- a/jsonargparse_tests/test_signatures.py +++ b/jsonargparse_tests/test_signatures.py @@ -8,7 +8,6 @@ import yaml from jsonargparse import ( - ActionConfigFile, ArgumentError, Namespace, lazy_instance, @@ -179,7 +178,7 @@ class NoParams: def test_add_class_without_parameters(parser): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_class_arguments(NoParams, "no_params") help_str = get_parser_help(parser) @@ -247,7 +246,7 @@ def __init__(self, n: int, m: float): def test_add_class_with_required_parameters(parser): parser.add_class_arguments(RequiredParams, "model") - parser.add_argument("--config", action=ActionConfigFile) + parser.add_argument("--config", action="config") for args in [ [], @@ -616,7 +615,7 @@ def test_add_function_group_config(parser, tmp_cwd): def test_add_function_group_config_within_config(parser, tmp_cwd): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_function_arguments(func, "func") cfg_path = Path("subdir", "config.yaml") @@ -635,7 +634,7 @@ def func_param_conflict(p1: int, cfg: dict): def test_add_function_param_conflict(parser): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") with pytest.raises(ValueError) as ctx: parser.add_function_arguments(func_param_conflict) ctx.match("Unable to add parameter 'cfg' from") diff --git a/jsonargparse_tests/test_subclasses.py b/jsonargparse_tests/test_subclasses.py index b580712d..80db7b5f 100644 --- a/jsonargparse_tests/test_subclasses.py +++ b/jsonargparse_tests/test_subclasses.py @@ -17,7 +17,6 @@ import yaml from jsonargparse import ( - ActionConfigFile, ArgumentError, ArgumentParser, Namespace, @@ -214,7 +213,7 @@ def __init__(self, param_a: int = 1, param_b: str = "x", **kwargs): def test_subclass_merge_init_args_global_config(parser): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--cal", type=Calendar) config1 = { @@ -247,7 +246,7 @@ def test_subclass_init_args_without_class_path(parser): def test_subclass_init_args_without_class_path_dict(parser): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--cal", type=Calendar) config = {"cal": {"class_path": "TextCalendar", "init_args": {"firstweekday": 2}}} @@ -307,7 +306,7 @@ def test_subclass_in_subcommand_with_global_default_config_file(parser, subparse default_path.write_text("fit:\n model:\n foo: 123") parser.default_config_files = [default_path] - parser.add_argument("--config", action=ActionConfigFile) + parser.add_argument("--config", action="config") subcommands = parser.add_subcommands() subparser.add_class_arguments(DefaultConfigSubcommands, nested_key="model") @@ -633,7 +632,7 @@ def __init__(self, encoder: Module): def test_subclass_dict_parameter_deep(parser): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_class_arguments(Model, "model") config = f"""model: @@ -942,7 +941,7 @@ def __init__(self, s2: str = "-"): def test_subclass_discard_init_args_config_with_default(parser, logger): parser.logger = logger - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--s", type=OverrideBase, default=lazy_instance(OverrideSub1, s1="v1")) config = {"s": {"class_path": "OverrideSub2", "init_args": {"s2": "v2"}}} @@ -1036,7 +1035,7 @@ def __init__(self, sub: ConfigDiscardBase = lazy_instance(ConfigDiscardSub1)): @pytest.mark.parametrize("method", ["class", "subclass"]) def test_discard_init_args_config_nested(parser, logger, tmp_cwd, method): parser.logger = logger - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") subconfig = { "sub": { @@ -1090,7 +1089,7 @@ def __init__(self, sub: Optional[dict] = None): def test_subclass_discard_init_args_dict_looks_like_subclass(parser, logger, tmp_cwd): parser.logger = logger - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_subclass_arguments(DictDiscardMain, "main") parser.set_defaults(main=lazy_instance(DictDiscardMain)) @@ -1146,7 +1145,7 @@ def test_subclass_unresolved_parameters(parser, subtests): dict_kwargs={"p3": 7.0, "p4": "x"}, ) - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--cls", type=UnresolvedParams) with subtests.test("args"): @@ -1211,7 +1210,7 @@ def test_add_subclass_lazy_default(parser): assert cfg.cal.class_path == "calendar.Calendar" assert cfg.cal.init_args.firstweekday == 4 - parser.add_argument("--config", action=ActionConfigFile) + parser.add_argument("--config", action="config") parser.set_defaults({"cal": lazy_instance(Calendar, firstweekday=5)}) out = get_parse_args_stdout(parser, ["--print_config"]) assert "class_path: calendar.Calendar" in out @@ -1352,7 +1351,7 @@ class PrintConfig: def test_subclass_print_config(parser): - parser.add_argument("--config", action=ActionConfigFile) + parser.add_argument("--config", action="config") parser.add_class_arguments(PrintConfig, "g") out = get_parse_args_stdout(parser, ["--g.a1=calendar.Calendar", "--print_config"]) @@ -1379,7 +1378,7 @@ def __init__(self, arg1: int, arg2: int = 1): def test_subclass_print_config_required_parameters_as_null(parser): - parser.add_argument("--config", action=ActionConfigFile) + parser.add_argument("--config", action="config") parser.add_class_arguments(PrintConfigRequired, "class") parser.add_subclass_arguments(PrintConfigRequiredBase, "subclass") @@ -1453,7 +1452,7 @@ def test_subclass_invalid_init_args_in_yaml(parser): class_path: calendar.Calendar init_args: """ - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--cal", type=Calendar) pytest.raises(ArgumentError, lambda: parser.parse_args([f"--cfg={value}"])) @@ -1545,7 +1544,7 @@ def __init__(self, val: int): def test_subclass_error_indentation_in_union_invalid_value(parser): parser.add_argument("--union", type=Union[str, ErrorIndentation2]) - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") config = {"union": [{"class_path": "ErrorIndentation2", "init_args": {"val": "x"}}]} err = get_parse_args_stderr(parser, [f"--cfg={config}"]) expected = textwrap.dedent( diff --git a/jsonargparse_tests/test_subcommands.py b/jsonargparse_tests/test_subcommands.py index 306996f3..117b49f7 100644 --- a/jsonargparse_tests/test_subcommands.py +++ b/jsonargparse_tests/test_subcommands.py @@ -9,7 +9,6 @@ import yaml from jsonargparse import ( - ActionConfigFile, ArgumentError, ArgumentParser, Namespace, @@ -105,7 +104,7 @@ def test_subcommands_parse_args_alias(subcommands_parser): def test_subcommands_parse_args_config(subcommands_parser): - subcommands_parser.add_argument("--cfg", action=ActionConfigFile) + subcommands_parser.add_argument("--cfg", action="config") cfg = subcommands_parser.parse_args(['--cfg={"o1": "o1_arg"}', "a", "ap1_arg"]).as_dict() assert cfg == { "a": {"ao1": "ao1_def", "ap1": "ap1_arg"}, @@ -141,7 +140,7 @@ def test_subcommands_parse_string_explicit_subcommand(subcommands_parser): def test_subcommands_parse_args_config_explicit_subcommand_arg(subcommands_parser): - subcommands_parser.add_argument("--cfg", action=ActionConfigFile) + subcommands_parser.add_argument("--cfg", action="config") cfg = subcommands_parser.parse_args(['--cfg={"a": {"ap1": "ap1_cfg"}, "b": {"nums": {"val1": 2}}}', "a"]) assert cfg.as_dict() == { "o1": "o1_def", @@ -201,7 +200,7 @@ def test_subcommand_without_options(parser, subparser): def test_subcommand_print_config_default_env(subparser): - subparser.add_argument("--config", action=ActionConfigFile) + subparser.add_argument("--config", action="config") subparser.add_argument("--o", type=int, default=1) parser = ArgumentParser(exit_on_error=False, default_env=True) diff --git a/jsonargparse_tests/test_typehints.py b/jsonargparse_tests/test_typehints.py index e4de2ec7..b4d237d6 100644 --- a/jsonargparse_tests/test_typehints.py +++ b/jsonargparse_tests/test_typehints.py @@ -31,7 +31,7 @@ import pytest import yaml -from jsonargparse import ActionConfigFile, ArgumentError, Namespace, lazy_instance +from jsonargparse import ArgumentError, Namespace, lazy_instance from jsonargparse._typehints import ( ActionTypeHint, Literal, @@ -64,7 +64,7 @@ def test_add_argument_failure_given_type_and_action(parser): def test_str_no_strip(parser): parser.add_argument("--op", type=Optional[str]) - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") assert " " == parser.parse_args(["--op", " "]).op assert "" == parser.parse_args(["--op", ""]).op assert " abc " == parser.parse_args(["--op= abc "]).op @@ -373,7 +373,7 @@ def test_list_append_default_empty(parser): def test_list_append_config(parser): - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") parser.add_argument("--val", type=List[int], default=[1, 2]) assert [3, 4] == parser.parse_args(["--cfg", "val: [3, 4]"]).val assert [1, 2, 3] == parser.parse_args(["--cfg", "val+: 3"]).val @@ -455,7 +455,7 @@ def test_dict_without_arg(parser): def test_dict_int_keys(parser): parser.add_argument("--d", type=Dict[int, str]) - parser.add_argument("--cfg", action=ActionConfigFile) + parser.add_argument("--cfg", action="config") cfg = {"d": {1: "val1", 2: "val2"}} assert cfg["d"] == parser.parse_args(["--cfg", str(cfg)]).d pytest.raises(ArgumentError, lambda: parser.parse_args(['--cfg={"d": {"a": "b"}}']))