nested-argparse 0.1.2__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Stephen Zhao
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,137 @@
1
+ Metadata-Version: 2.4
2
+ Name: nested-argparse
3
+ Version: 0.2.0
4
+ Summary: A python module that extends argparser to create nested namespace trees for subparsers.
5
+ Author-email: Stephen Zhao <mail@zhaostephen.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/stephen-zhao/nested_argparse
8
+ Project-URL: Source, https://github.com/stephen-zhao/nested_argparse
9
+ Keywords: argparse,nested,namespace,subparser,conflict,parser,cli,command,subcommand
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: System Administrators
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Natural Language :: English
20
+ Classifier: Operating System :: OS Independent
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Utilities
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Dynamic: license-file
28
+
29
+ # nested-argparse 💬 → 🅰.🅱.🆒
30
+
31
+ [![PyPI](https://img.shields.io/pypi/v/nested-argparse?color=brightgreen&label=pypi%20package)](https://pypi.org/project/nested-argparse/)
32
+ ![PyPI - Status](https://img.shields.io/pypi/status/nested-argparse)
33
+ ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/nested-argparse)
34
+ [![PyPI - License](https://img.shields.io/pypi/l/nested-argparse)](https://github.com/stephen-zhao/nested_argparse/blob/main/LICENSE)
35
+
36
+ nested-argparse is a python module that non-invasively builds on top of the built-in `argparse` library to allow subparsers to parse into their own nested namespaces.
37
+
38
+ The library exposes a class `NestedArgumentParser` which allows arbitrary nesting without worry of namespace conflicts. This is achieved with the following principles of this library:
39
+
40
+ - **Inversion of Control:** A parser, when adding a subparser, is in control of what name to use for the sub-namespace which the subparser sends its parsed args to.
41
+ - **Drop-In Replacement:** The constructor for `nested_argparse.NestedArgumentParser` can be substituted in directly to where the constructor for `argparse.ArgumentParser` is being used. All subsequent method calls and subparser API calls should work without any additional code change!
42
+ - **Customizeability:** There are additional `kwargs` exposed to further customize the nesting options to your liking, if the defaults do not suit your scenario.
43
+
44
+ The main difference between this library and its built-in counterpart is the return value of the `parse_args` method. Instead of a flat namespace containing all parsed arguments across all subparsers, `NestedArgumentParser` will produce a namespace tree.
45
+
46
+ ## Simple Conceptual Example
47
+
48
+ Given the following parser:
49
+
50
+ ```
51
+ Root Parser
52
+ ├─ positional_1
53
+ ├─ --optional_1
54
+ ├─ --optional_2
55
+ └─ sub parsers with dest='subcommand'
56
+ ├─ Sub Parser 1 with name='sub1'
57
+ │ ├─ --optional_1
58
+ │ └─ --optional_2 with dest='optional2AltName'
59
+ └─ Sub Parser 2 with name='sub2'
60
+ ├─ --optional_1
61
+ └─ --optional_2
62
+ ```
63
+
64
+ And the following args to parse:
65
+
66
+ ```sh
67
+ Alice --optional_1=Bob sub1 --optional_1=Carol --optional_2=David
68
+ ```
69
+
70
+ The built-in `ArgumentParser` would not be able to handle the duplication in `dest`s, but `NestedArgumentParser` will produce the following result when run through `parse_args`:
71
+
72
+ ```py
73
+ Namespace(
74
+ subcommand='sub1',
75
+ positional_1='Alice',
76
+ optional_1='Bob',
77
+ sub1=Namespace(
78
+ optional_1='Carol',
79
+ optional2AltName='David'
80
+ )
81
+ )
82
+ ```
83
+
84
+ ## API Documentation
85
+
86
+ The library exposes the following modules.
87
+
88
+ ### Module `nested_argparse`
89
+
90
+ The module exports the following classes.
91
+
92
+ #### Class `NestedArgumentParser`
93
+
94
+ - extends `argparser.ArgumentParser`
95
+ - for documentation for the superclass, see the official [Python API reference docs for `argparse`](https://docs.python.org/3/library/argparse.html).
96
+
97
+ ##### Constructor
98
+
99
+ In addition to the parameters available to `ArgumentParser` constructor, the following parameters are also accepted:
100
+
101
+ - Param `nest_dir`, optional, type: `Optional[str]`
102
+ - When a string is passed in, it is used as the attribute name in the parent namespace to which the nested namespace, where the parsed values will be stored, is assigned to.
103
+ - When `None` is passed in, no nested namespace is created, and parsed values are directly assigned to the parent namespace. This is the behavior of the base `ArgumentParser`.
104
+ - Default value: `None`.
105
+
106
+ - Param `nest_separator`, optional, type: `str`
107
+ - It is used as the separator to delimit components in the nest path when representing the path as a string (for example, this is used to generate `dest`s)
108
+ - Default value: `'__'`.
109
+
110
+ - Param `nest_path`, optional, type: `Optional[List[str]]`
111
+ - When a list of strings is passed in, it is used as a sequence of nested attribute names from the parent namespace which locates the nested namespace where the parsed values will be stored.
112
+ - When `None` is passed in, no nested namespace is created, and parsed values are directly assigned to the parent namespace. This is the behavior of the base `ArgumentParser`.
113
+
114
+ ##### Override `NestedArgumentParser.add_argument`
115
+
116
+ Instead of adding an argument definition which stores the parsed value to `dest` in the flat top-level namespace, the parsed value will be stored at attribute with the name given by `dest` in the namesapce at the nesting path associated with this parser.
117
+
118
+ ##### Override `NestedArgumentParser.add_subparsers`
119
+
120
+ The return value of this method is an instance of internal subparser handler `_NestedSubParsersAction`, which exposes extra options for adding subparsers.
121
+
122
+ ##### Override `NestedArgumentParser.parse_args`
123
+
124
+ The return value of this method is a namespace tree rather than a flat namespace. The tree is built according to the nesting paths associated with each of the parsed values.
125
+
126
+ ##### Override `NestedArgumentParser.parse_known_args`
127
+
128
+ The return value of this method is a namespace tree rather than a flat namespace. The tree is built according to the nesting paths associated with each of the parsed values.
129
+
130
+ #### Class `_NestedSubParsersAction`
131
+
132
+ ##### Override `_NestedSubParsersAction.add_parser`
133
+
134
+ - Param `nest_dir`, optional, type: `Optional[str]`
135
+ - When a string is passed in, it is used as the attribute name in the parent namespace to which the subparser will store its parsed values to.
136
+ - When `None` is passed in, the `dest` field is used as the nesting directory instead.
137
+ - Default value: `None`.
@@ -0,0 +1,109 @@
1
+ # nested-argparse 💬 → 🅰.🅱.🆒
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/nested-argparse?color=brightgreen&label=pypi%20package)](https://pypi.org/project/nested-argparse/)
4
+ ![PyPI - Status](https://img.shields.io/pypi/status/nested-argparse)
5
+ ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/nested-argparse)
6
+ [![PyPI - License](https://img.shields.io/pypi/l/nested-argparse)](https://github.com/stephen-zhao/nested_argparse/blob/main/LICENSE)
7
+
8
+ nested-argparse is a python module that non-invasively builds on top of the built-in `argparse` library to allow subparsers to parse into their own nested namespaces.
9
+
10
+ The library exposes a class `NestedArgumentParser` which allows arbitrary nesting without worry of namespace conflicts. This is achieved with the following principles of this library:
11
+
12
+ - **Inversion of Control:** A parser, when adding a subparser, is in control of what name to use for the sub-namespace which the subparser sends its parsed args to.
13
+ - **Drop-In Replacement:** The constructor for `nested_argparse.NestedArgumentParser` can be substituted in directly to where the constructor for `argparse.ArgumentParser` is being used. All subsequent method calls and subparser API calls should work without any additional code change!
14
+ - **Customizeability:** There are additional `kwargs` exposed to further customize the nesting options to your liking, if the defaults do not suit your scenario.
15
+
16
+ The main difference between this library and its built-in counterpart is the return value of the `parse_args` method. Instead of a flat namespace containing all parsed arguments across all subparsers, `NestedArgumentParser` will produce a namespace tree.
17
+
18
+ ## Simple Conceptual Example
19
+
20
+ Given the following parser:
21
+
22
+ ```
23
+ Root Parser
24
+ ├─ positional_1
25
+ ├─ --optional_1
26
+ ├─ --optional_2
27
+ └─ sub parsers with dest='subcommand'
28
+ ├─ Sub Parser 1 with name='sub1'
29
+ │ ├─ --optional_1
30
+ │ └─ --optional_2 with dest='optional2AltName'
31
+ └─ Sub Parser 2 with name='sub2'
32
+ ├─ --optional_1
33
+ └─ --optional_2
34
+ ```
35
+
36
+ And the following args to parse:
37
+
38
+ ```sh
39
+ Alice --optional_1=Bob sub1 --optional_1=Carol --optional_2=David
40
+ ```
41
+
42
+ The built-in `ArgumentParser` would not be able to handle the duplication in `dest`s, but `NestedArgumentParser` will produce the following result when run through `parse_args`:
43
+
44
+ ```py
45
+ Namespace(
46
+ subcommand='sub1',
47
+ positional_1='Alice',
48
+ optional_1='Bob',
49
+ sub1=Namespace(
50
+ optional_1='Carol',
51
+ optional2AltName='David'
52
+ )
53
+ )
54
+ ```
55
+
56
+ ## API Documentation
57
+
58
+ The library exposes the following modules.
59
+
60
+ ### Module `nested_argparse`
61
+
62
+ The module exports the following classes.
63
+
64
+ #### Class `NestedArgumentParser`
65
+
66
+ - extends `argparser.ArgumentParser`
67
+ - for documentation for the superclass, see the official [Python API reference docs for `argparse`](https://docs.python.org/3/library/argparse.html).
68
+
69
+ ##### Constructor
70
+
71
+ In addition to the parameters available to `ArgumentParser` constructor, the following parameters are also accepted:
72
+
73
+ - Param `nest_dir`, optional, type: `Optional[str]`
74
+ - When a string is passed in, it is used as the attribute name in the parent namespace to which the nested namespace, where the parsed values will be stored, is assigned to.
75
+ - When `None` is passed in, no nested namespace is created, and parsed values are directly assigned to the parent namespace. This is the behavior of the base `ArgumentParser`.
76
+ - Default value: `None`.
77
+
78
+ - Param `nest_separator`, optional, type: `str`
79
+ - It is used as the separator to delimit components in the nest path when representing the path as a string (for example, this is used to generate `dest`s)
80
+ - Default value: `'__'`.
81
+
82
+ - Param `nest_path`, optional, type: `Optional[List[str]]`
83
+ - When a list of strings is passed in, it is used as a sequence of nested attribute names from the parent namespace which locates the nested namespace where the parsed values will be stored.
84
+ - When `None` is passed in, no nested namespace is created, and parsed values are directly assigned to the parent namespace. This is the behavior of the base `ArgumentParser`.
85
+
86
+ ##### Override `NestedArgumentParser.add_argument`
87
+
88
+ Instead of adding an argument definition which stores the parsed value to `dest` in the flat top-level namespace, the parsed value will be stored at attribute with the name given by `dest` in the namesapce at the nesting path associated with this parser.
89
+
90
+ ##### Override `NestedArgumentParser.add_subparsers`
91
+
92
+ The return value of this method is an instance of internal subparser handler `_NestedSubParsersAction`, which exposes extra options for adding subparsers.
93
+
94
+ ##### Override `NestedArgumentParser.parse_args`
95
+
96
+ The return value of this method is a namespace tree rather than a flat namespace. The tree is built according to the nesting paths associated with each of the parsed values.
97
+
98
+ ##### Override `NestedArgumentParser.parse_known_args`
99
+
100
+ The return value of this method is a namespace tree rather than a flat namespace. The tree is built according to the nesting paths associated with each of the parsed values.
101
+
102
+ #### Class `_NestedSubParsersAction`
103
+
104
+ ##### Override `_NestedSubParsersAction.add_parser`
105
+
106
+ - Param `nest_dir`, optional, type: `Optional[str]`
107
+ - When a string is passed in, it is used as the attribute name in the parent namespace to which the subparser will store its parsed values to.
108
+ - When `None` is passed in, the `dest` field is used as the nesting directory instead.
109
+ - Default value: `None`.
@@ -0,0 +1,87 @@
1
+ [project]
2
+ name = "nested-argparse"
3
+ version = "0.2.0"
4
+ description = "A python module that extends argparser to create nested namespace trees for subparsers."
5
+ readme = { file = "README.md", content-type = "text/markdown" }
6
+ requires-python = ">=3.10"
7
+ dependencies = [
8
+ ]
9
+ classifiers = [
10
+ "Development Status :: 3 - Alpha",
11
+ "Intended Audience :: Developers",
12
+ "Intended Audience :: System Administrators",
13
+ "Programming Language :: Python :: 3",
14
+ "Programming Language :: Python :: 3.10",
15
+ "Programming Language :: Python :: 3.11",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Programming Language :: Python :: 3.13",
18
+ "Programming Language :: Python :: 3.14",
19
+ "Natural Language :: English",
20
+ "Operating System :: OS Independent",
21
+ "Topic :: Software Development :: Libraries :: Python Modules",
22
+ "Topic :: Utilities",
23
+ "Typing :: Typed",
24
+ ]
25
+ license = "MIT"
26
+ license-files = ["LICENSE"]
27
+ authors = [
28
+ { name = "Stephen Zhao", email = "mail@zhaostephen.com" },
29
+ ]
30
+ keywords = [
31
+ "argparse",
32
+ "nested",
33
+ "namespace",
34
+ "subparser",
35
+ "conflict",
36
+ "parser",
37
+ "cli",
38
+ "command",
39
+ "subcommand",
40
+ ]
41
+
42
+ [project.urls]
43
+ Homepage = "https://github.com/stephen-zhao/nested_argparse"
44
+ Source = "https://github.com/stephen-zhao/nested_argparse"
45
+
46
+ [build-system]
47
+ requires = ["setuptools >= 77.0.3"]
48
+ build-backend = "setuptools.build_meta"
49
+
50
+ [tool.setuptools.package-dir]
51
+ "" = "src"
52
+
53
+ [tool.setuptools.packages.find]
54
+ where = ["src"]
55
+ include = ["nested_argparse"]
56
+
57
+ [tool.setuptools.package-data]
58
+ nested_argparse = ["py.typed"]
59
+
60
+ [tool.uv]
61
+ dev-dependencies = [
62
+ "bump-my-version>=1.2.1",
63
+ "pytest>=8.4.1",
64
+ "uv>=0.8.11",
65
+ ]
66
+
67
+ [tool.bumpversion]
68
+ current_version = "0.2.0"
69
+ parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
70
+ serialize = ["{major}.{minor}.{patch}"]
71
+ search = "{current_version}"
72
+ replace = "{new_version}"
73
+ regex = false
74
+ ignore_missing_version = false
75
+ ignore_missing_files = false
76
+ tag = true
77
+ sign_tags = false
78
+ tag_name = "v{new_version}"
79
+ tag_message = "Bump version: {current_version} → {new_version}"
80
+ allow_dirty = false
81
+ commit = true
82
+ message = "Bump version: {current_version} → {new_version}"
83
+ moveable_tags = []
84
+ commit_args = ""
85
+ setup_hooks = []
86
+ pre_commit_hooks = []
87
+ post_commit_hooks = []
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -1,7 +1,7 @@
1
1
  import argparse
2
- from typing import Any, Dict, List, Optional, Tuple
2
+ from typing import Any
3
3
 
4
- DEBUG=False
4
+ DEBUG = False
5
5
 
6
6
  def _debug_log(*args):
7
7
  if DEBUG:
@@ -35,26 +35,25 @@ class NestedArgumentParser(argparse.ArgumentParser):
35
35
  nest_components = nest_path
36
36
 
37
37
  # Save the nest path and related config
38
- self.nest_dir: Optional[str] = nest_components[-1] if len(nest_components) > 0 else None
39
- self.nest_path_components: List[str] = nest_components
38
+ self.nest_dir: str | None = nest_components[-1] if len(nest_components) > 0 else None
39
+ self.nest_path_components: list[str] = nest_components
40
40
  self.nest_separator: str = nest_separator
41
41
 
42
42
  # Mapping from nested dest back to the original dest for contained Actions
43
- self._original_dest_by_nested_dest = {}
44
-
45
- superinit = super(NestedArgumentParser, self).__init__
46
- superinit(prog=prog,
47
- usage=usage,
48
- description=description,
49
- epilog=epilog,
50
- parents=parents,
51
- formatter_class=formatter_class,
52
- prefix_chars=prefix_chars,
53
- fromfile_prefix_chars=fromfile_prefix_chars,
54
- argument_default=argument_default,
55
- conflict_handler=conflict_handler,
56
- add_help=add_help,
57
- allow_abbrev=allow_abbrev)
43
+ self._original_dest_by_nested_dest: dict[str, str] = {}
44
+
45
+ super().__init__(prog=prog,
46
+ usage=usage,
47
+ description=description,
48
+ epilog=epilog,
49
+ parents=parents,
50
+ formatter_class=formatter_class,
51
+ prefix_chars=prefix_chars,
52
+ fromfile_prefix_chars=fromfile_prefix_chars,
53
+ argument_default=argument_default,
54
+ conflict_handler=conflict_handler,
55
+ add_help=add_help,
56
+ allow_abbrev=allow_abbrev)
58
57
 
59
58
  # Override the subparsers action to use the Nested edition
60
59
  self.register('action', 'parsers', _NestedSubParsersAction)
@@ -84,7 +83,7 @@ class NestedArgumentParser(argparse.ArgumentParser):
84
83
  # Command line argument parsing methods
85
84
  # =====================================
86
85
 
87
- def parse_known_args(self, args=None, namespace=None) -> Tuple[argparse.Namespace, List[str]]:
86
+ def parse_known_args(self, args=None, namespace=None) -> tuple[argparse.Namespace, list[str]]:
88
87
  _debug_log('IN override parse_known_args given args=', args, '; namespace=', namespace)
89
88
  parsed_args, unknown_args = super().parse_known_args(args=args, namespace=namespace)
90
89
  deflattened_args = self._deflatten_namespace(parsed_args)
@@ -186,7 +185,7 @@ class NestedArgumentParser(argparse.ArgumentParser):
186
185
  if isinstance(subparser, NestedArgumentParser):
187
186
  self._remap_container_dests(subparser)
188
187
 
189
- def _get_positional_kwargs(self, dest: str, **kwargs: Any) -> Dict[str, Any]:
188
+ def _get_positional_kwargs(self, dest: str, **kwargs: Any) -> dict[str, Any]:
190
189
  # Get the nested dest
191
190
  nested_dest = self._get_nested_dest_and_save_original(dest.replace('-', '_'))
192
191
 
@@ -195,7 +194,7 @@ class NestedArgumentParser(argparse.ArgumentParser):
195
194
 
196
195
  return super()._get_positional_kwargs(nested_dest, **kwargs)
197
196
 
198
- def _get_optional_kwargs(self, *args: Any, **kwargs: Any) -> Dict[str, Any]:
197
+ def _get_optional_kwargs(self, *args: Any, **kwargs: Any) -> dict[str, Any]:
199
198
  # Extract dest from args and kwargs
200
199
  dest = self._extract_dest(*args, **kwargs)
201
200
 
@@ -266,14 +265,13 @@ class _NestedSubParsersAction(argparse._SubParsersAction):
266
265
  required=False,
267
266
  help=None,
268
267
  metavar=None) -> None:
269
- superinit = super(_NestedSubParsersAction, self).__init__
270
- superinit(option_strings,
271
- prog,
272
- parser_class,
273
- dest=dest,
274
- required=required,
275
- help=help,
276
- metavar=metavar)
268
+ super().__init__(option_strings,
269
+ prog,
270
+ parser_class,
271
+ dest=dest,
272
+ required=required,
273
+ help=help,
274
+ metavar=metavar)
277
275
 
278
276
  self.base_nest_path_components = base_nest_path
279
277
  self.nest_separator = nest_separator
File without changes
@@ -0,0 +1,137 @@
1
+ Metadata-Version: 2.4
2
+ Name: nested-argparse
3
+ Version: 0.2.0
4
+ Summary: A python module that extends argparser to create nested namespace trees for subparsers.
5
+ Author-email: Stephen Zhao <mail@zhaostephen.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/stephen-zhao/nested_argparse
8
+ Project-URL: Source, https://github.com/stephen-zhao/nested_argparse
9
+ Keywords: argparse,nested,namespace,subparser,conflict,parser,cli,command,subcommand
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: System Administrators
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Natural Language :: English
20
+ Classifier: Operating System :: OS Independent
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Utilities
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Dynamic: license-file
28
+
29
+ # nested-argparse 💬 → 🅰.🅱.🆒
30
+
31
+ [![PyPI](https://img.shields.io/pypi/v/nested-argparse?color=brightgreen&label=pypi%20package)](https://pypi.org/project/nested-argparse/)
32
+ ![PyPI - Status](https://img.shields.io/pypi/status/nested-argparse)
33
+ ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/nested-argparse)
34
+ [![PyPI - License](https://img.shields.io/pypi/l/nested-argparse)](https://github.com/stephen-zhao/nested_argparse/blob/main/LICENSE)
35
+
36
+ nested-argparse is a python module that non-invasively builds on top of the built-in `argparse` library to allow subparsers to parse into their own nested namespaces.
37
+
38
+ The library exposes a class `NestedArgumentParser` which allows arbitrary nesting without worry of namespace conflicts. This is achieved with the following principles of this library:
39
+
40
+ - **Inversion of Control:** A parser, when adding a subparser, is in control of what name to use for the sub-namespace which the subparser sends its parsed args to.
41
+ - **Drop-In Replacement:** The constructor for `nested_argparse.NestedArgumentParser` can be substituted in directly to where the constructor for `argparse.ArgumentParser` is being used. All subsequent method calls and subparser API calls should work without any additional code change!
42
+ - **Customizeability:** There are additional `kwargs` exposed to further customize the nesting options to your liking, if the defaults do not suit your scenario.
43
+
44
+ The main difference between this library and its built-in counterpart is the return value of the `parse_args` method. Instead of a flat namespace containing all parsed arguments across all subparsers, `NestedArgumentParser` will produce a namespace tree.
45
+
46
+ ## Simple Conceptual Example
47
+
48
+ Given the following parser:
49
+
50
+ ```
51
+ Root Parser
52
+ ├─ positional_1
53
+ ├─ --optional_1
54
+ ├─ --optional_2
55
+ └─ sub parsers with dest='subcommand'
56
+ ├─ Sub Parser 1 with name='sub1'
57
+ │ ├─ --optional_1
58
+ │ └─ --optional_2 with dest='optional2AltName'
59
+ └─ Sub Parser 2 with name='sub2'
60
+ ├─ --optional_1
61
+ └─ --optional_2
62
+ ```
63
+
64
+ And the following args to parse:
65
+
66
+ ```sh
67
+ Alice --optional_1=Bob sub1 --optional_1=Carol --optional_2=David
68
+ ```
69
+
70
+ The built-in `ArgumentParser` would not be able to handle the duplication in `dest`s, but `NestedArgumentParser` will produce the following result when run through `parse_args`:
71
+
72
+ ```py
73
+ Namespace(
74
+ subcommand='sub1',
75
+ positional_1='Alice',
76
+ optional_1='Bob',
77
+ sub1=Namespace(
78
+ optional_1='Carol',
79
+ optional2AltName='David'
80
+ )
81
+ )
82
+ ```
83
+
84
+ ## API Documentation
85
+
86
+ The library exposes the following modules.
87
+
88
+ ### Module `nested_argparse`
89
+
90
+ The module exports the following classes.
91
+
92
+ #### Class `NestedArgumentParser`
93
+
94
+ - extends `argparser.ArgumentParser`
95
+ - for documentation for the superclass, see the official [Python API reference docs for `argparse`](https://docs.python.org/3/library/argparse.html).
96
+
97
+ ##### Constructor
98
+
99
+ In addition to the parameters available to `ArgumentParser` constructor, the following parameters are also accepted:
100
+
101
+ - Param `nest_dir`, optional, type: `Optional[str]`
102
+ - When a string is passed in, it is used as the attribute name in the parent namespace to which the nested namespace, where the parsed values will be stored, is assigned to.
103
+ - When `None` is passed in, no nested namespace is created, and parsed values are directly assigned to the parent namespace. This is the behavior of the base `ArgumentParser`.
104
+ - Default value: `None`.
105
+
106
+ - Param `nest_separator`, optional, type: `str`
107
+ - It is used as the separator to delimit components in the nest path when representing the path as a string (for example, this is used to generate `dest`s)
108
+ - Default value: `'__'`.
109
+
110
+ - Param `nest_path`, optional, type: `Optional[List[str]]`
111
+ - When a list of strings is passed in, it is used as a sequence of nested attribute names from the parent namespace which locates the nested namespace where the parsed values will be stored.
112
+ - When `None` is passed in, no nested namespace is created, and parsed values are directly assigned to the parent namespace. This is the behavior of the base `ArgumentParser`.
113
+
114
+ ##### Override `NestedArgumentParser.add_argument`
115
+
116
+ Instead of adding an argument definition which stores the parsed value to `dest` in the flat top-level namespace, the parsed value will be stored at attribute with the name given by `dest` in the namesapce at the nesting path associated with this parser.
117
+
118
+ ##### Override `NestedArgumentParser.add_subparsers`
119
+
120
+ The return value of this method is an instance of internal subparser handler `_NestedSubParsersAction`, which exposes extra options for adding subparsers.
121
+
122
+ ##### Override `NestedArgumentParser.parse_args`
123
+
124
+ The return value of this method is a namespace tree rather than a flat namespace. The tree is built according to the nesting paths associated with each of the parsed values.
125
+
126
+ ##### Override `NestedArgumentParser.parse_known_args`
127
+
128
+ The return value of this method is a namespace tree rather than a flat namespace. The tree is built according to the nesting paths associated with each of the parsed values.
129
+
130
+ #### Class `_NestedSubParsersAction`
131
+
132
+ ##### Override `_NestedSubParsersAction.add_parser`
133
+
134
+ - Param `nest_dir`, optional, type: `Optional[str]`
135
+ - When a string is passed in, it is used as the attribute name in the parent namespace to which the subparser will store its parsed values to.
136
+ - When `None` is passed in, the `dest` field is used as the nesting directory instead.
137
+ - Default value: `None`.
@@ -1,8 +1,9 @@
1
+ LICENSE
1
2
  README.md
2
- setup.cfg
3
- setup.py
3
+ pyproject.toml
4
4
  src/nested_argparse/__init__.py
5
5
  src/nested_argparse/nested_argparse.py
6
+ src/nested_argparse/py.typed
6
7
  src/nested_argparse.egg-info/PKG-INFO
7
8
  src/nested_argparse.egg-info/SOURCES.txt
8
9
  src/nested_argparse.egg-info/dependency_links.txt
@@ -1,4 +1,4 @@
1
- from src.nested_argparse import NestedArgumentParser
1
+ from nested_argparse import NestedArgumentParser
2
2
 
3
3
  def test_multinesting():
4
4
  subparser_3 = NestedArgumentParser()
@@ -1,4 +1,4 @@
1
- from src.nested_argparse import NestedArgumentParser
1
+ from nested_argparse import NestedArgumentParser
2
2
 
3
3
  def test_sanity_check():
4
4
  # Create a subparser as a standalone parser first
@@ -1,73 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: nested_argparse
3
- Version: 0.1.2
4
- Summary: A python module that extends argparser to create nested namespace trees for subparsers.
5
- Home-page: UNKNOWN
6
- Author: Stephen Zhao
7
- Author-email: mail@zhaostephen.com
8
- License: MIT License
9
- Description: # nested-argparse 💬 → 🅰.🅱.🆒
10
-
11
- [![PyPI](https://img.shields.io/pypi/v/nested-argparse?color=brightgreen&label=pypi%20package)](https://pypi.org/project/nested-argparse/)
12
- ![PyPI - Status](https://img.shields.io/pypi/status/nested-argparse)
13
- ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/nested-argparse)
14
- [![PyPI - License](https://img.shields.io/pypi/l/nested-argparse)](https://github.com/stephen-zhao/nested_argparse/blob/main/LICENSE)
15
-
16
- nested-argparse is a python module that non-invasively builds on top of the built-in `argparse` library to allow subparsers to parse into their own nested namespaces.
17
-
18
- The library exposes a class `NestedArgumentParser` which allows arbitrary nesting without worry of namespace conflicts. This is achieved with the following principles of this library:
19
-
20
- - **Inversion of Control:** A parser, when adding a subparser, is in control of what name to use for the sub-namespace which the subparser sends its parsed args to.
21
- - **Drop-In Replacement:** The constructor for `nested_argparse.NestedArgumentParser` can be substituted in directly to where the constructor for `argparse.ArgumentParser` is being used. All subsequent method calls and subparser API calls should work without any additional code change!
22
- - **Customizeability:** There are additional `kwargs` exposed to further customize the nesting options to your liking, if the defaults do not suit your scenario.
23
-
24
- The main difference between this library and its built-in counterpart is the return value of the `parse_args` method. Instead of a flat namespace containing all parsed arguments across all subparsers, `NestedArgumentParser` will produce a namespace tree.
25
-
26
- ## Simple Conceptual Example
27
-
28
- Given the following parser:
29
-
30
- ```
31
- Root Parser
32
- ├─ positional_1
33
- ├─ --optional_1
34
- ├─ --optional_2
35
- └─ sub parsers with dest='subcommand'
36
- ├─ Sub Parser 1 with name='sub1'
37
- │ ├─ --optional_1
38
- │ └─ --optional_2 with dest='optional2AltName'
39
- └─ Sub Parser 2 with name='sub2'
40
- ├─ --optional_1
41
- └─ --optional_2
42
- ```
43
-
44
- And the following args to parse:
45
-
46
- ```sh
47
- Alice --optional_1=Bob sub1 --optional_1=Carol --optional_2=David
48
- ```
49
-
50
- The built-in `ArgumentParser` would not be able to handle the duplication in `dest`s, but `NestedArgumentParser` will produce the following result when run through `parse_args`:
51
-
52
- ```py
53
- Namespace(
54
- subcommand='sub1',
55
- positional_1='Alice',
56
- optional_1='Bob',
57
- sub1=Namespace(
58
- optional_1='Carol',
59
- optional2AltName='David'
60
- )
61
- )
62
- ```
63
- Keywords: argparse,nested,namespace,subparser,conflict,parser,cli,command,subcommand
64
- Platform: UNKNOWN
65
- Classifier: Development Status :: 2 - Pre-Alpha
66
- Classifier: Intended Audience :: Developers
67
- Classifier: Programming Language :: Python :: 3
68
- Classifier: License :: OSI Approved :: MIT License
69
- Classifier: Operating System :: OS Independent
70
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
71
- Classifier: Topic :: Utilities
72
- Requires-Python: >=3.6
73
- Description-Content-Type: text/markdown
@@ -1,54 +0,0 @@
1
- # nested-argparse 💬 → 🅰.🅱.🆒
2
-
3
- [![PyPI](https://img.shields.io/pypi/v/nested-argparse?color=brightgreen&label=pypi%20package)](https://pypi.org/project/nested-argparse/)
4
- ![PyPI - Status](https://img.shields.io/pypi/status/nested-argparse)
5
- ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/nested-argparse)
6
- [![PyPI - License](https://img.shields.io/pypi/l/nested-argparse)](https://github.com/stephen-zhao/nested_argparse/blob/main/LICENSE)
7
-
8
- nested-argparse is a python module that non-invasively builds on top of the built-in `argparse` library to allow subparsers to parse into their own nested namespaces.
9
-
10
- The library exposes a class `NestedArgumentParser` which allows arbitrary nesting without worry of namespace conflicts. This is achieved with the following principles of this library:
11
-
12
- - **Inversion of Control:** A parser, when adding a subparser, is in control of what name to use for the sub-namespace which the subparser sends its parsed args to.
13
- - **Drop-In Replacement:** The constructor for `nested_argparse.NestedArgumentParser` can be substituted in directly to where the constructor for `argparse.ArgumentParser` is being used. All subsequent method calls and subparser API calls should work without any additional code change!
14
- - **Customizeability:** There are additional `kwargs` exposed to further customize the nesting options to your liking, if the defaults do not suit your scenario.
15
-
16
- The main difference between this library and its built-in counterpart is the return value of the `parse_args` method. Instead of a flat namespace containing all parsed arguments across all subparsers, `NestedArgumentParser` will produce a namespace tree.
17
-
18
- ## Simple Conceptual Example
19
-
20
- Given the following parser:
21
-
22
- ```
23
- Root Parser
24
- ├─ positional_1
25
- ├─ --optional_1
26
- ├─ --optional_2
27
- └─ sub parsers with dest='subcommand'
28
- ├─ Sub Parser 1 with name='sub1'
29
- │ ├─ --optional_1
30
- │ └─ --optional_2 with dest='optional2AltName'
31
- └─ Sub Parser 2 with name='sub2'
32
- ├─ --optional_1
33
- └─ --optional_2
34
- ```
35
-
36
- And the following args to parse:
37
-
38
- ```sh
39
- Alice --optional_1=Bob sub1 --optional_1=Carol --optional_2=David
40
- ```
41
-
42
- The built-in `ArgumentParser` would not be able to handle the duplication in `dest`s, but `NestedArgumentParser` will produce the following result when run through `parse_args`:
43
-
44
- ```py
45
- Namespace(
46
- subcommand='sub1',
47
- positional_1='Alice',
48
- optional_1='Bob',
49
- sub1=Namespace(
50
- optional_1='Carol',
51
- optional2AltName='David'
52
- )
53
- )
54
- ```
@@ -1,41 +0,0 @@
1
- [metadata]
2
- name = nested_argparse
3
- version = 0.1.2
4
- author = Stephen Zhao
5
- author_email = mail@zhaostephen.com
6
- description = A python module that extends argparser to create nested namespace trees for subparsers.
7
- long_description = file: README.md
8
- long_description_content_type = text/markdown
9
- license = MIT License
10
- keywords =
11
- argparse
12
- nested
13
- namespace
14
- subparser
15
- conflict
16
- parser
17
- cli
18
- command
19
- subcommand
20
- classifiers =
21
- Development Status :: 2 - Pre-Alpha
22
- Intended Audience :: Developers
23
- Programming Language :: Python :: 3
24
- License :: OSI Approved :: MIT License
25
- Operating System :: OS Independent
26
- Topic :: Software Development :: Libraries :: Python Modules
27
- Topic :: Utilities
28
-
29
- [options]
30
- packages = find:
31
- package_dir =
32
- =src
33
- python_requires = >=3.6
34
-
35
- [options.packages.find]
36
- where = src
37
-
38
- [egg_info]
39
- tag_build =
40
- tag_date = 0
41
-
@@ -1,4 +0,0 @@
1
- from setuptools import setup
2
-
3
- if __name__ == '__main__':
4
- setup()
@@ -1,73 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: nested-argparse
3
- Version: 0.1.2
4
- Summary: A python module that extends argparser to create nested namespace trees for subparsers.
5
- Home-page: UNKNOWN
6
- Author: Stephen Zhao
7
- Author-email: mail@zhaostephen.com
8
- License: MIT License
9
- Description: # nested-argparse 💬 → 🅰.🅱.🆒
10
-
11
- [![PyPI](https://img.shields.io/pypi/v/nested-argparse?color=brightgreen&label=pypi%20package)](https://pypi.org/project/nested-argparse/)
12
- ![PyPI - Status](https://img.shields.io/pypi/status/nested-argparse)
13
- ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/nested-argparse)
14
- [![PyPI - License](https://img.shields.io/pypi/l/nested-argparse)](https://github.com/stephen-zhao/nested_argparse/blob/main/LICENSE)
15
-
16
- nested-argparse is a python module that non-invasively builds on top of the built-in `argparse` library to allow subparsers to parse into their own nested namespaces.
17
-
18
- The library exposes a class `NestedArgumentParser` which allows arbitrary nesting without worry of namespace conflicts. This is achieved with the following principles of this library:
19
-
20
- - **Inversion of Control:** A parser, when adding a subparser, is in control of what name to use for the sub-namespace which the subparser sends its parsed args to.
21
- - **Drop-In Replacement:** The constructor for `nested_argparse.NestedArgumentParser` can be substituted in directly to where the constructor for `argparse.ArgumentParser` is being used. All subsequent method calls and subparser API calls should work without any additional code change!
22
- - **Customizeability:** There are additional `kwargs` exposed to further customize the nesting options to your liking, if the defaults do not suit your scenario.
23
-
24
- The main difference between this library and its built-in counterpart is the return value of the `parse_args` method. Instead of a flat namespace containing all parsed arguments across all subparsers, `NestedArgumentParser` will produce a namespace tree.
25
-
26
- ## Simple Conceptual Example
27
-
28
- Given the following parser:
29
-
30
- ```
31
- Root Parser
32
- ├─ positional_1
33
- ├─ --optional_1
34
- ├─ --optional_2
35
- └─ sub parsers with dest='subcommand'
36
- ├─ Sub Parser 1 with name='sub1'
37
- │ ├─ --optional_1
38
- │ └─ --optional_2 with dest='optional2AltName'
39
- └─ Sub Parser 2 with name='sub2'
40
- ├─ --optional_1
41
- └─ --optional_2
42
- ```
43
-
44
- And the following args to parse:
45
-
46
- ```sh
47
- Alice --optional_1=Bob sub1 --optional_1=Carol --optional_2=David
48
- ```
49
-
50
- The built-in `ArgumentParser` would not be able to handle the duplication in `dest`s, but `NestedArgumentParser` will produce the following result when run through `parse_args`:
51
-
52
- ```py
53
- Namespace(
54
- subcommand='sub1',
55
- positional_1='Alice',
56
- optional_1='Bob',
57
- sub1=Namespace(
58
- optional_1='Carol',
59
- optional2AltName='David'
60
- )
61
- )
62
- ```
63
- Keywords: argparse,nested,namespace,subparser,conflict,parser,cli,command,subcommand
64
- Platform: UNKNOWN
65
- Classifier: Development Status :: 2 - Pre-Alpha
66
- Classifier: Intended Audience :: Developers
67
- Classifier: Programming Language :: Python :: 3
68
- Classifier: License :: OSI Approved :: MIT License
69
- Classifier: Operating System :: OS Independent
70
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
71
- Classifier: Topic :: Utilities
72
- Requires-Python: >=3.6
73
- Description-Content-Type: text/markdown