Repository: omni-us/jsonargparse
Pull request #721 (2025-05-09 06:06:57)

New auto_parser function for convenience and more visibility of the capture_parser feature
## 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)


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/omni-us/jsonargparse/pull/721?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 100.00%. Comparing base [(`dbc6398`)](https://app.codecov.io/gh/omni-us/jsonargparse/commit/dbc6398897eda085917e0ce02892c83645e0cadd?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) to head [(`67ff9f0`)](https://app.codecov.io/gh/omni-us/jsonargparse/commit/67ff9f0c0b9d3a1b85b25d35be890e9782b61dd6?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us).

:white_check_mark: All tests successful. No failed tests found.

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


```diff
@@            Coverage Diff            @@
##              main      #721   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           22        22           
  Lines         6843      6845    +2     
=========================================
+ Hits          6843      6845    +2     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/omni-us/jsonargparse/pull/721?dropdown=coverage&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).

sonarqubecloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=omni-us_jsonargparse&pullRequest=721) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=721&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=721&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=omni-us_jsonargparse&pullRequest=721&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [100.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=721&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=721&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=omni-us_jsonargparse&pullRequest=721)



Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 03422f2..8e1fd60 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -15,6 +15,12 @@ paths are considered internals and can change in minor and patch releases.
 v4.40.0 (2025-05-??)
 --------------------
 
+Added
+^^^^^
+- New ``auto_parser`` function for convenience and more visibility of the
+  ``capture_parser`` feature (`#721
+  <https://github.com/omni-us/jsonargparse/pull/721>`__).
+
 Fixed
 ^^^^^
 - ``set_parsing_settings(validate_defaults=True)`` fails when the parser has a
diff --git a/DOCUMENTATION.rst b/DOCUMENTATION.rst
index a92091b..688919c 100644
--- a/DOCUMENTATION.rst
+++ b/DOCUMENTATION.rst
@@ -329,7 +329,8 @@ This can be easily implemented with :func:`.capture_parser` as follows:
 .. note::
 
     The official way to obtain the parser for command line tools based on
-    :func:`.auto_cli` is by using :func:`.capture_parser`.
+    :func:`.auto_cli` is by using :func:`.auto_parser`, which is just a
+    convenience function that calls :func:`.capture_parser`.
 
 
 Optionals as positionals
diff --git a/README.rst b/README.rst
index e3f1d69..a3278b8 100644
--- a/README.rst
+++ b/README.rst
@@ -27,6 +27,49 @@ a `substantial user base
 it serves as the framework behind pytorch-lightning's `LightningCLI
 <https://lightning.ai/docs/pytorch/stable/cli/lightning_cli.html>`__.
 
+Teaser examples
+---------------
+
+CLI with minimal boilerplate:
+
+.. code-block:: python
+
+    from jsonargparse import auto_cli
+
+    def main_function(...):  # your main parameters and logic here
+        ...
+
+    if __name__ == "__main__":
+        auto_cli(main_function)  # parses arguments and runs main_function
+
+Minimal boilerplate but manually parsing:
+
+.. code-block:: python
+
+    from jsonargparse import auto_parser
+
+    ...
+
+    if __name__ == "__main__":
+        parser = auto_parser(main_function)
+        cfg = parser.parse_args()
+        ...
+
+Powerful argparse-like low level parsers:
+
+.. code-block:: python
+
+    from typing import Union, Literal
+    from jsonargparse import ArgumentParser
+
+    parser = ArgumentParser()
+    parser.add_argument("--config", action="config")  # support config files
+    parser.add_argument("--opt", type=Union[int, Literal["off"])  # complex arguments via type hints
+    parser.add_function_arguments(main_function, "function")  # add entire function signatures
+    ...
+    cfg = parser.parse_args()
+    ...
+
 
 Features
 --------
diff --git a/jsonargparse/_cli.py b/jsonargparse/_cli.py
index 32953bb..622da1a 100644
--- a/jsonargparse/_cli.py
+++ b/jsonargparse/_cli.py
@@ -8,9 +8,13 @@ from ._core import ArgumentParser
 from ._deprecated import deprecation_warning_cli_return_parser
 from ._namespace import Namespace, dict_to_namespace
 from ._optionals import get_doc_short_description
-from ._util import default_config_option_help
+from ._util import capture_parser, default_config_option_help
 
-__all__ = ["CLI", "auto_cli"]
+__all__ = [
+    "CLI",
+    "auto_cli",
+    "auto_parser",
+]
 
 
 ComponentType = Union[Callable, Type]
@@ -125,6 +129,14 @@ def auto_cli(
     return _run_component(component, init.get(subcommand))
 
 
+def auto_parser(*args, **kwargs) -> ArgumentParser:
+    """Same as auto_cli, but returns the parser, so doesn't parse arguments or run.
+
+    This is a shorthand for ``capture_parser(lambda: auto_cli(*args, **kwargs))``.
+    """
+    return capture_parser(lambda: auto_cli(*args, **kwargs))
+
+
 def get_help_str(component, logger):
     if isinstance(component, dict):
         return component.get("_help")


Test patch:
diff --git a/jsonargparse_tests/test_cli.py b/jsonargparse_tests/test_cli.py
index ea860fa..fb60012 100644
--- a/jsonargparse_tests/test_cli.py
+++ b/jsonargparse_tests/test_cli.py
@@ -15,7 +15,8 @@ from unittest.mock import patch
 
 import pytest
 
-from jsonargparse import CLI, auto_cli, capture_parser, lazy_instance
+from jsonargparse import CLI, auto_cli, auto_parser, capture_parser, lazy_instance
+from jsonargparse._namespace import Namespace
 from jsonargparse._optionals import docstring_parser_support, ruyaml_support
 from jsonargparse.typing import final
 from jsonargparse_tests.conftest import json_or_yaml_dump, json_or_yaml_load, skip_if_docstring_parser_unavailable
@@ -28,6 +29,15 @@ def get_cli_stdout(*args, **kwargs) -> str:
     return out.getvalue()
 
 
+def simple_main(a1: int = 0, a2: bool = False):
+    pass
+
+
+def test_auto_parser():
+    parser = auto_parser(simple_main)
+    assert parser.parse_args([]) == Namespace(config=None, a1=0, a2=False)
+
+
 # failure cases