omni-us / jsonargparse

Implement minimal boilerplate CLIs derived from type hints and parse from command line, config files and environment variables
https://jsonargparse.readthedocs.io
MIT License
314 stars 42 forks source link

Question. How to pass None via environment? #496

Closed ilejn closed 4 months ago

ilejn commented 4 months ago

Hello, I have a configuration variable that is defined like this

parser.add_argument(
    "--total",
    dest="total",
    type = int

It does not have a default value. When I set correspondent environment variable to 'null' I am getting

Traceback (most recent call last):
  File "/usr/local/lib/python3.12/site-packages/jsonargparse/_core.py", line 386, in parse_args
    cfg = self._parse_defaults_and_environ(defaults, env)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/jsonargparse/_core.py", line 341, in _parse_defaults_and_environ
    cfg_env = self._load_env_vars(env=environ, defaults=defaults)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/jsonargparse/_core.py", line 483, in _load_env_vars
    cfg[action.dest] = self._check_value_key(action, env_val, action.dest, cfg)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/jsonargparse/_core.py", line 1354, in _check_value_key
    value = action._check_type_(value, cfg=cfg)  # type: ignore[attr-defined]
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/jsonargparse/_common.py", line 268, in _check_type_
    return self._check_type(value, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/jsonargparse/_typehints.py", line 542, in _check_type
    raise TypeError(f'Parser key "{self.dest}"{elem}:\n{error}') from ex
TypeError: Parser key "total":
  Expected a <class 'int'>. Got value: None

So the question is if it is possible to pass None for int via environment?

The rationale is I need to have all Docker variables listed, so just omitting some variables is not an option for me.

mauvilsa commented 4 months ago

If you want to be able to set None, the type would have to be Optional[int]. Setting the environment variable as null is correct. The error just says that none is not an int, which was expected.

ilejn commented 4 months ago

Thanks a lot for rapid and helpful answer.

Everything works fine, although I am not 100% sure that I fully understand the idea. (1) If I don't pass the parameter 'total' with type 'int' at all, it has value None. (2) Although if I want to pass it via environment, I have to use Optional[int]. If None is not allowed for int, why (1) works? If None is allowed for int, why (2) is required?

mauvilsa commented 4 months ago

When an argument is added and no default is set, and no value given when parsing, then in the key for that argument there will be a None value. This just means "unset" and it is the default behavior from standard argparse. It could be more convenient when a value is not set, then some "unset" object is used instead of None to avoid this kind of confusion. But such a feature has not been implemented. And even if that feature existed, the default would still be to use None for unset, since that is how it is in argparse.

Note that without Opional only int values are accepted when given by the user (i.e. not the default), however it was given, command line, config file, etc. It is not specific to environment variables.

ilejn commented 4 months ago

Many thanks for the help and clarifications.