cmdargparse 0.1.0__tar.gz → 0.3.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.
Files changed (22) hide show
  1. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/PKG-INFO +19 -7
  2. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/README.md +15 -2
  3. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/cmdargparse/__init__.py +1 -1
  4. cmdargparse-0.3.0/cmdargparse/actions/__init__.py +1 -0
  5. cmdargparse-0.3.0/cmdargparse/actions/store.py +58 -0
  6. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/cmdargparse/argument.py +1 -1
  7. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/cmdargparse/command.py +16 -12
  8. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/cmdargparse/field.py +31 -21
  9. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/cmdargparse/namespace.py +6 -3
  10. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/cmdargparse/parser.py +2 -2
  11. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/cmdargparse/unset.py +24 -9
  12. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/cmdargparse.egg-info/PKG-INFO +19 -7
  13. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/cmdargparse.egg-info/SOURCES.txt +3 -1
  14. cmdargparse-0.3.0/cmdargparse.egg-info/requires.txt +1 -0
  15. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/setup.py +42 -43
  16. cmdargparse-0.1.0/cmdargparse.egg-info/requires.txt +0 -1
  17. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/LICENSE +0 -0
  18. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/cmdargparse/custom.py +0 -0
  19. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/cmdargparse.egg-info/dependency_links.txt +0 -0
  20. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/cmdargparse.egg-info/top_level.txt +0 -0
  21. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/pyproject.toml +0 -0
  22. {cmdargparse-0.1.0 → cmdargparse-0.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmdargparse
3
- Version: 0.1.0
3
+ Version: 0.3.0
4
4
  Summary: A declarative way to define `cmd2` argument parsers.
5
5
  Home-page: https://github.com/krnd/cmdargparse
6
6
  Author: Kilian Kaiping (krnd)
@@ -11,15 +11,14 @@ Classifier: Environment :: Console
11
11
  Classifier: Environment :: Plugins
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: Intended Audience :: System Administrators
14
- Classifier: License :: OSI Approved :: MIT License
15
14
  Classifier: Operating System :: OS Independent
16
15
  Classifier: Programming Language :: Python :: 3 :: Only
17
- Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
18
17
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
- Requires-Python: >=3.13
18
+ Requires-Python: >=3.14
20
19
  Description-Content-Type: text/markdown
21
20
  License-File: LICENSE
22
- Requires-Dist: cmd2~=2.7
21
+ Requires-Dist: cmd2~=4.2
23
22
  Dynamic: author
24
23
  Dynamic: classifier
25
24
  Dynamic: description
@@ -46,7 +45,7 @@ The package provides a declarative way to define `cmd2` argument parsers.
46
45
  The core functionality is driven by three components:
47
46
  * `cmdargument` for defining an argument parser
48
47
  * `cmdfield` for declaring the arguments
49
- * `cmdcommand` for attatching an argument parser to a command
48
+ * `cmdcommand` for attaching an argument parser to a command
50
49
 
51
50
  ```py
52
51
 
@@ -56,7 +55,7 @@ class MyApplication(cmd2.Cmd):
56
55
  class _MyCommandArgs(cmdargument):
57
56
  my_argument: str = cmdfield.argument(...)
58
57
  my_option: str = cmdfield.option(...)
59
- my_flag: str = cmdfield.flag(...)
58
+ my_flag: bool = cmdfield.flag(...)
60
59
 
61
60
  @cmdcommand(_MyCommandArgs)
62
61
  def do_mycommand(self, args: _MyCommandArgs) -> None:
@@ -77,6 +76,9 @@ class MyApplication(cmd2.Cmd):
77
76
  * `default` <br/>
78
77
  The arguments default value if not specified.
79
78
  <br/> (Providing a default value makes the argument optional.)
79
+ * `nargs` <br/>
80
+ The number of command-line values to be consumed.
81
+ <br/> https://docs.python.org/3/library/argparse.html#nargs
80
82
  * `type` <br/>
81
83
  Explicitly specifies the `type` to be used by `argparse`.
82
84
  <br/> https://docs.python.org/3/library/argparse.html#type
@@ -95,6 +97,8 @@ arg: str | None = cmdfield.argument(
95
97
  },
96
98
  default=None,
97
99
  )
100
+ args: list[str] = cmdfield.argument()
101
+ more: list[str] = cmdfield.argument(nargs="+")
98
102
  ```
99
103
 
100
104
 
@@ -117,6 +121,9 @@ arg: str | None = cmdfield.argument(
117
121
  Explicitly specifies all option declarations.
118
122
  * `more_decls` <br/>
119
123
  Specifies additional option declarations.
124
+ * `nargs` <br/>
125
+ The number of command-line values to be consumed.
126
+ <br/> https://docs.python.org/3/library/argparse.html#nargs
120
127
  * `type` <br/>
121
128
  Explicitly specifies the `type` to be used by `argparse`.
122
129
  <br/> https://docs.python.org/3/library/argparse.html#type
@@ -132,6 +139,8 @@ arg: str | None = cmdfield.argument(
132
139
  xx: str | None = cmdfield.option()
133
140
  yy: int | None = cmdfield.option([1, 2, 3])
134
141
  zz: str = cmdfield.option(required=True)
142
+ hh: list[str] | None = cmdfield.option(default=None)
143
+ qq: list[int] | None = cmdfield.option(nargs=2, default=None)
135
144
  ```
136
145
 
137
146
  #### Declarations
@@ -146,6 +155,7 @@ mm: str | None = cmdfield.option(decls="--mm") # --mm
146
155
  nn: str | None = cmdfield.option(decls="-oo") # -oo
147
156
  pp: str | None = cmdfield.option(decls=("--rr", "-ss")) # --rr, -ss
148
157
  tt: str | None = cmdfield.option(more_decls="-uu") # -tt, -uu
158
+ vv_ww: str | None = cmdfield.option() # -vv-ww OR --vv-ww
149
159
  ```
150
160
 
151
161
 
@@ -167,6 +177,7 @@ tt: str | None = cmdfield.option(more_decls="-uu") # -tt, -uu
167
177
  Specifies additional flag declarations.
168
178
  * `type` <br/>
169
179
  Explicitly specifies the type to be used by argparse.
180
+ <br/> (Has no effect, as flag values are not type converted.)
170
181
  <br/> https://docs.python.org/3/library/argparse.html#type
171
182
  * `help` <br/>
172
183
  Brief description of the flag.
@@ -192,6 +203,7 @@ mm: bool = cmdfield.flag(decls="--mm") # --mm
192
203
  nn: bool = cmdfield.flag(decls="-oo") # -oo
193
204
  pp: bool = cmdfield.flag(decls=("--rr", "-ss")) # --rr, -ss
194
205
  tt: bool = cmdfield.flag(more_decls="-uu") # -tt, -uu
206
+ vv_ww: bool = cmdfield.flag() # -vv-ww OR --vv-ww
195
207
  ```
196
208
 
197
209
 
@@ -12,7 +12,7 @@ The package provides a declarative way to define `cmd2` argument parsers.
12
12
  The core functionality is driven by three components:
13
13
  * `cmdargument` for defining an argument parser
14
14
  * `cmdfield` for declaring the arguments
15
- * `cmdcommand` for attatching an argument parser to a command
15
+ * `cmdcommand` for attaching an argument parser to a command
16
16
 
17
17
  ```py
18
18
 
@@ -22,7 +22,7 @@ class MyApplication(cmd2.Cmd):
22
22
  class _MyCommandArgs(cmdargument):
23
23
  my_argument: str = cmdfield.argument(...)
24
24
  my_option: str = cmdfield.option(...)
25
- my_flag: str = cmdfield.flag(...)
25
+ my_flag: bool = cmdfield.flag(...)
26
26
 
27
27
  @cmdcommand(_MyCommandArgs)
28
28
  def do_mycommand(self, args: _MyCommandArgs) -> None:
@@ -43,6 +43,9 @@ class MyApplication(cmd2.Cmd):
43
43
  * `default` <br/>
44
44
  The arguments default value if not specified.
45
45
  <br/> (Providing a default value makes the argument optional.)
46
+ * `nargs` <br/>
47
+ The number of command-line values to be consumed.
48
+ <br/> https://docs.python.org/3/library/argparse.html#nargs
46
49
  * `type` <br/>
47
50
  Explicitly specifies the `type` to be used by `argparse`.
48
51
  <br/> https://docs.python.org/3/library/argparse.html#type
@@ -61,6 +64,8 @@ arg: str | None = cmdfield.argument(
61
64
  },
62
65
  default=None,
63
66
  )
67
+ args: list[str] = cmdfield.argument()
68
+ more: list[str] = cmdfield.argument(nargs="+")
64
69
  ```
65
70
 
66
71
 
@@ -83,6 +88,9 @@ arg: str | None = cmdfield.argument(
83
88
  Explicitly specifies all option declarations.
84
89
  * `more_decls` <br/>
85
90
  Specifies additional option declarations.
91
+ * `nargs` <br/>
92
+ The number of command-line values to be consumed.
93
+ <br/> https://docs.python.org/3/library/argparse.html#nargs
86
94
  * `type` <br/>
87
95
  Explicitly specifies the `type` to be used by `argparse`.
88
96
  <br/> https://docs.python.org/3/library/argparse.html#type
@@ -98,6 +106,8 @@ arg: str | None = cmdfield.argument(
98
106
  xx: str | None = cmdfield.option()
99
107
  yy: int | None = cmdfield.option([1, 2, 3])
100
108
  zz: str = cmdfield.option(required=True)
109
+ hh: list[str] | None = cmdfield.option(default=None)
110
+ qq: list[int] | None = cmdfield.option(nargs=2, default=None)
101
111
  ```
102
112
 
103
113
  #### Declarations
@@ -112,6 +122,7 @@ mm: str | None = cmdfield.option(decls="--mm") # --mm
112
122
  nn: str | None = cmdfield.option(decls="-oo") # -oo
113
123
  pp: str | None = cmdfield.option(decls=("--rr", "-ss")) # --rr, -ss
114
124
  tt: str | None = cmdfield.option(more_decls="-uu") # -tt, -uu
125
+ vv_ww: str | None = cmdfield.option() # -vv-ww OR --vv-ww
115
126
  ```
116
127
 
117
128
 
@@ -133,6 +144,7 @@ tt: str | None = cmdfield.option(more_decls="-uu") # -tt, -uu
133
144
  Specifies additional flag declarations.
134
145
  * `type` <br/>
135
146
  Explicitly specifies the type to be used by argparse.
147
+ <br/> (Has no effect, as flag values are not type converted.)
136
148
  <br/> https://docs.python.org/3/library/argparse.html#type
137
149
  * `help` <br/>
138
150
  Brief description of the flag.
@@ -158,6 +170,7 @@ mm: bool = cmdfield.flag(decls="--mm") # --mm
158
170
  nn: bool = cmdfield.flag(decls="-oo") # -oo
159
171
  pp: bool = cmdfield.flag(decls=("--rr", "-ss")) # --rr, -ss
160
172
  tt: bool = cmdfield.flag(more_decls="-uu") # -tt, -uu
173
+ vv_ww: bool = cmdfield.flag() # -vv-ww OR --vv-ww
161
174
  ```
162
175
 
163
176
 
@@ -7,4 +7,4 @@ from .namespace import Namespace
7
7
  from .parser import ArgumentParser
8
8
 
9
9
 
10
- _cmd2.set_default_argument_parser_type(ArgumentParser)
10
+ _cmd2.set_default_argument_parser(ArgumentParser)
@@ -0,0 +1 @@
1
+ from .store import StoreAction
@@ -0,0 +1,58 @@
1
+ import argparse
2
+ from typing import Annotated, Any, Mapping, Sequence
3
+
4
+ from cmdargparse.custom import (
5
+ TANY,
6
+ ArgumentParser,
7
+ Namespace,
8
+ decorator,
9
+ is_multiple_values,
10
+ )
11
+
12
+
13
+ # ################################ ACTION ######################################
14
+
15
+
16
+ class StoreAction(argparse._StoreAction):
17
+
18
+ def __init__(
19
+ self,
20
+ *args: Annotated[Any, "passthrough"],
21
+ choicesmap: Mapping[TANY, TANY] | None = None,
22
+ **kwargs: Annotated[Any, "passthrough"],
23
+ ) -> None:
24
+ assert not args, (
25
+ "There should be no positional arguments if not explicitly "
26
+ "specified. (The `argparse` module passes by keyword.)"
27
+ )
28
+
29
+ if "choices" in kwargs and choicesmap is not None:
30
+ if any(s not in kwargs["choices"] for s in choicesmap.values()):
31
+ raise ValueError(
32
+ "All mapped values in the choices mapping must be present "
33
+ "in the specified choices."
34
+ )
35
+ kwargs["choices"] = (
36
+ *kwargs["choices"],
37
+ *choicesmap.keys(),
38
+ )
39
+
40
+ super().__init__(*args, **kwargs)
41
+
42
+ self.choicesmap = choicesmap
43
+
44
+ @decorator.call
45
+ def __call__(
46
+ self,
47
+ parser: ArgumentParser,
48
+ namespace: Namespace,
49
+ values: Sequence[TANY] | TANY,
50
+ option_string: str | None = None,
51
+ ) -> None:
52
+ if self.choicesmap is not None:
53
+ values = (
54
+ [self.choicesmap.get(v, v) for v in values]
55
+ if is_multiple_values(values)
56
+ else self.choicesmap.get(values, values)
57
+ )
58
+ setattr(namespace, self.dest, values)
@@ -72,7 +72,7 @@ class _cmdargument(type):
72
72
  if _cls is None:
73
73
  return functools.partial(
74
74
  cls.__call__,
75
- default=form,
75
+ form=form,
76
76
  ) # type: ignore
77
77
 
78
78
  setattr(
@@ -36,14 +36,15 @@ class _cmdcommand(type):
36
36
  ]:
37
37
  """Decorate as command function."""
38
38
 
39
- if hasattr(argtype, "_cmdargparse_command_decorator"):
40
- return getattr(argtype, "_cmdargparse_command_decorator")
39
+ if "_cmdargparse_command_decorator" in argtype.__dict__:
40
+ return argtype.__dict__["_cmdargparse_command_decorator"]
41
41
 
42
42
  parser = ArgumentParser()
43
43
 
44
44
  _dcfields = dataclasses.fields(
45
45
  argtype # pyright: ignore[reportArgumentType]
46
46
  )
47
+ _fieldtypes = typing.get_type_hints(argtype, include_extras=True)
47
48
 
48
49
  default_form: _DeclFormSpecifier
49
50
  default_form = getattr(argtype, "_cmdargparse_default_form")
@@ -63,7 +64,7 @@ class _cmdcommand(type):
63
64
  )
64
65
 
65
66
  args: dict[str, Any]
66
- args = field.metadata["args"]
67
+ args = dict(field.metadata["args"])
67
68
 
68
69
  assert "dest" not in args, (
69
70
  "Specifying 'dest' directly is not supported."
@@ -86,8 +87,11 @@ class _cmdcommand(type):
86
87
  continue
87
88
 
88
89
  # Resolve the type from the fields type annotation.
90
+ (_type, _nargs) = argparse_type(_fieldtypes[field.name])
89
91
  if args.get("type", None) is None:
90
- args["type"] = argparse_type(field.type)
92
+ args["type"] = _type
93
+ if args.get("nargs", None) is None and _nargs is not None:
94
+ args["nargs"] = _nargs
91
95
 
92
96
  # Remove custom unspecified arguments.
93
97
  if args.get("choicesmap", None) is None:
@@ -168,7 +172,7 @@ def argparse_name_or_flags(
168
172
  return tuple(
169
173
  _decl
170
174
  for _decl in (
171
- decl or (form + field),
175
+ decl or (form + field.replace("_", "-")),
172
176
  altdecl,
173
177
  *more_decls,
174
178
  )
@@ -176,13 +180,10 @@ def argparse_name_or_flags(
176
180
  )
177
181
 
178
182
 
179
- def argparse_type(type: Any, /) -> Type[Any]:
180
- if isinstance(type, str):
181
- raise TypeError("forward reference type annotations are not supported")
182
-
183
+ def argparse_type(type: Any, /) -> Tuple[Type[Any], str | None]:
183
184
  origin = typing.get_origin(type)
184
185
  if origin is None:
185
- return type
186
+ return (type, None)
186
187
 
187
188
  if origin is typing.Annotated:
188
189
  (argtype, *_) = typing.get_args(type)
@@ -192,9 +193,12 @@ def argparse_type(type: Any, /) -> Type[Any]:
192
193
  # should be passed to the `argparse` module.
193
194
  if isinstance(type, types.UnionType):
194
195
  (argtype, *_) = typing.get_args(type)
195
- return argtype
196
+ return argparse_type(argtype)
196
197
  elif origin is typing.Union:
197
198
  (argtype, *_) = typing.get_args(type)
198
- return argtype
199
+ return argparse_type(argtype)
200
+ elif origin is list:
201
+ (argtype, *_) = typing.get_args(type)
202
+ return (argparse_type(argtype)[0], "*")
199
203
 
200
204
  raise TypeError("unsupported type annotation")
@@ -112,6 +112,8 @@ class _cmdfield(type):
112
112
 
113
113
  class _ArgumentArgs(TypedDict, total=False):
114
114
 
115
+ nargs: Annotated[int, "N"] | Literal["?", "*", "+"]
116
+
115
117
  type: Annotated[Any, Callable[[str], Annotated[Any, "FieldType"]]]
116
118
 
117
119
  help: str
@@ -180,6 +182,9 @@ class _cmdfield(type):
180
182
  The arguments default value if not specified.
181
183
  (Providing a default value makes the argument optional.)
182
184
 
185
+ :param nargs:
186
+ The number of command-line values to be consumed.
187
+ <br/> https://docs.python.org/3/library/argparse.html#nargs
183
188
  :param type:
184
189
  Explicitly specifies the `type` to be used by `argparse`.
185
190
  <br/> https://docs.python.org/3/library/argparse.html#type
@@ -192,10 +197,10 @@ class _cmdfield(type):
192
197
  """
193
198
  return _argparse(
194
199
  None,
195
- nargs=("?" if not isunset(default) else None),
196
200
  choices=choices,
197
201
  choicesmap=choicesmap,
198
202
  default=on_unset(default, None),
203
+ nargs=args.get("nargs", ("?" if not isunset(default) else None)),
199
204
  type=args.get("type", None),
200
205
  help=args.get("help", None),
201
206
  metavar=args.get("helpvar", None),
@@ -209,6 +214,8 @@ class _cmdfield(type):
209
214
  decls: Tuple[str, str] | str
210
215
  more_decls: Sequence[str] | str
211
216
 
217
+ nargs: Annotated[int, "N"] | Literal["?", "*", "+"]
218
+
212
219
  type: Annotated[Any, Callable[[str], Annotated[Any, "FieldType"]]]
213
220
 
214
221
  required: bool
@@ -388,6 +395,9 @@ class _cmdfield(type):
388
395
  :param more_decls:
389
396
  Specifies additional option declarations.
390
397
 
398
+ :param nargs:
399
+ The number of command-line values to be consumed.
400
+ <br/> https://docs.python.org/3/library/argparse.html#nargs
391
401
  :param type:
392
402
  Explicitly specifies the `type` to be used by `argparse`.
393
403
  <br/> https://docs.python.org/3/library/argparse.html#type
@@ -401,37 +411,37 @@ class _cmdfield(type):
401
411
  Reference name of the option value in the help message.
402
412
 
403
413
  """
404
- if decl is None:
405
- decl, altdecl, choices = (
406
- # 0 arguments
407
- (None, None, None)
414
+ if (
415
+ choices is None
416
+ and (decl is None or isinstance(decl, str))
417
+ and (altdecl is None or isinstance(altdecl, str))
418
+ ):
419
+ decl, altdecl, choices, choicesmap = (
420
+ # option
421
+ (decl, altdecl, None, None)
408
422
  ) # type: ignore
409
- elif altdecl is None:
410
- decl, altdecl, choices = (
411
- # 1 argument
412
- (decl, None, None)
413
- if isinstance(decl, str)
414
- else (None, None, decl)
423
+ elif decl is not None and not isinstance(decl, str):
424
+ decl, altdecl, choices, choicesmap = (
425
+ # choice option [derived]
426
+ (None, None, decl, altdecl)
415
427
  ) # type: ignore
416
- elif choices is None:
417
- decl, altdecl, choices = (
418
- # 2 arguments
419
- (decl, altdecl, None)
420
- if isinstance(decl, str)
421
- else (decl, None, altdecl)
428
+ elif altdecl is not None and not isinstance(altdecl, str):
429
+ decl, altdecl, choices, choicesmap = (
430
+ # choice option [augmented]
431
+ (decl, None, altdecl, choices)
422
432
  ) # type: ignore
423
433
  else:
424
- decl, altdecl, choices = (
425
- # 3 arguments
426
- (decl, altdecl, choices)
434
+ decl, altdecl, choices, choicesmap = (
435
+ # choice option [augmented]
436
+ (decl, altdecl, choices, choicesmap)
427
437
  ) # type: ignore
428
438
  return _argparse(
429
439
  _decls(decl, altdecl, args),
430
- nargs=("?" if not isunset(default) else None),
431
440
  choices=choices,
432
441
  choicesmap=choicesmap,
433
442
  default=on_unset(default, None),
434
443
  required=args.get("required", False),
444
+ nargs=args.get("nargs", None),
435
445
  type=args.get("type", None),
436
446
  help=args.get("help", None),
437
447
  metavar=args.get("helpvar", None),
@@ -22,16 +22,19 @@ class Namespace(argparse.Namespace):
22
22
  )
23
23
  )
24
24
 
25
+ cmd.pfeedback("[Namespace]")
26
+
27
+ if not fields:
28
+ cmd.pfeedback(" (no fields)")
29
+ return
30
+
25
31
  maxlen = max(
26
32
  len(attr)
27
33
  for attr in fields
28
34
  # <format-break>
29
35
  )
30
36
 
31
- cmd.pfeedback("[Namespace]")
32
37
  for name in fields:
33
38
  cmd.pfeedback(
34
39
  f" {str.ljust(name, maxlen)!s} : {self.__dict__[name]!r}"
35
40
  )
36
- if not fields:
37
- cmd.pfeedback(" (no fields)")
@@ -9,7 +9,7 @@ import cmd2
9
9
  class ArgumentParser(cmd2.Cmd2ArgumentParser):
10
10
 
11
11
  # Registers a custom argparse argument parameter.
12
- # https://cmd2.readthedocs.io/en/stable/api/argparse_custom/#cmd2.argparse_custom.register_argparse_argument_parameter
12
+ # https://cmd2.readthedocs.io/en/stable/api/argparse_utils/#cmd2.argparse_utils.register_argparse_argument_parameter
13
13
  # ```
14
14
  # def register_argparse_argument_parameter(
15
15
  # param_name: str,
@@ -22,7 +22,7 @@ class ArgumentParser(cmd2.Cmd2ArgumentParser):
22
22
  *args: Annotated[Any, "passthrough"],
23
23
  **kwargs: Annotated[Any, "passthrough"],
24
24
  ) -> None:
25
- super(cmd2.Cmd2ArgumentParser, self).__init__(*args, **kwargs)
25
+ super().__init__(*args, **kwargs)
26
26
 
27
27
  from .actions import StoreAction
28
28
 
@@ -1,11 +1,11 @@
1
- from typing import Any, Final, TypeAlias, TypeIs, TypeVar
1
+ from typing import Any, Final, TypeAlias, TypeIs, TypeVar, cast
2
2
 
3
3
 
4
- # ################################ PACKAGE #####################################
4
+ # ################################ COMPONENT ###################################
5
5
 
6
6
 
7
- __sname__ = "unset"
8
- __version__ = "1.3"
7
+ __component__ = "unset"
8
+ __version__ = "1.5"
9
9
  __description__ = ...
10
10
 
11
11
  __requires__ = ()
@@ -13,7 +13,7 @@ __requires__ = ()
13
13
 
14
14
  __all__ = (
15
15
  # fmt: off
16
- "UnsetType", "UNSET", "Unset",
16
+ "UnsetType", "UNSET", "Unset", "MayUnset",
17
17
  "isunset", "on_unset",
18
18
  # fmt: on
19
19
  )
@@ -24,7 +24,7 @@ __all__ = (
24
24
 
25
25
  T = TypeVar("T")
26
26
 
27
- TONCE: TypeAlias = Any
27
+ TONCE = TypeVar("TONCE")
28
28
 
29
29
 
30
30
  # ################################ UNSET #######################################
@@ -34,7 +34,6 @@ class _UnsetType(type):
34
34
 
35
35
  def __invert__(self) -> "UnsetType":
36
36
  """Returns the unset value."""
37
- global UNSET
38
37
  return UNSET
39
38
 
40
39
 
@@ -60,6 +59,22 @@ It can be used as follows:
60
59
  ```
61
60
  def function(arg: Type | Unset = ~Unset):
62
61
  arg = arg if not isunset(arg) else VALUE
62
+ # or
63
+ arg = on_unset(arg, VALUE)
64
+ ```
65
+ """
66
+
67
+
68
+ MayUnset: TypeAlias = T | UnsetType
69
+ """
70
+ The `MayUnset` attribute is a convenience alias for the union of a generic type
71
+ and the `UnsetType`.
72
+
73
+ It can be used as follows:
74
+ ```
75
+ def function(arg: MayUnset[Type] = ~Unset):
76
+ arg = arg if not isunset(arg) else VALUE
77
+ # or
63
78
  arg = on_unset(arg, VALUE)
64
79
  ```
65
80
  """
@@ -73,7 +88,7 @@ def isunset(obj: Any, /) -> TypeIs[UnsetType]:
73
88
  return obj is UNSET
74
89
 
75
90
 
76
- def on_unset(obj: T | Unset, value: TONCE, /) -> T | TONCE:
91
+ def on_unset(obj: T | UnsetType, value: TONCE, /) -> T | TONCE:
77
92
  """Returns either the object itself or the specified value if the object is
78
93
  unset."""
79
- return value if obj is UNSET else obj
94
+ return value if obj is UNSET else cast(T, obj)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmdargparse
3
- Version: 0.1.0
3
+ Version: 0.3.0
4
4
  Summary: A declarative way to define `cmd2` argument parsers.
5
5
  Home-page: https://github.com/krnd/cmdargparse
6
6
  Author: Kilian Kaiping (krnd)
@@ -11,15 +11,14 @@ Classifier: Environment :: Console
11
11
  Classifier: Environment :: Plugins
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: Intended Audience :: System Administrators
14
- Classifier: License :: OSI Approved :: MIT License
15
14
  Classifier: Operating System :: OS Independent
16
15
  Classifier: Programming Language :: Python :: 3 :: Only
17
- Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
18
17
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
- Requires-Python: >=3.13
18
+ Requires-Python: >=3.14
20
19
  Description-Content-Type: text/markdown
21
20
  License-File: LICENSE
22
- Requires-Dist: cmd2~=2.7
21
+ Requires-Dist: cmd2~=4.2
23
22
  Dynamic: author
24
23
  Dynamic: classifier
25
24
  Dynamic: description
@@ -46,7 +45,7 @@ The package provides a declarative way to define `cmd2` argument parsers.
46
45
  The core functionality is driven by three components:
47
46
  * `cmdargument` for defining an argument parser
48
47
  * `cmdfield` for declaring the arguments
49
- * `cmdcommand` for attatching an argument parser to a command
48
+ * `cmdcommand` for attaching an argument parser to a command
50
49
 
51
50
  ```py
52
51
 
@@ -56,7 +55,7 @@ class MyApplication(cmd2.Cmd):
56
55
  class _MyCommandArgs(cmdargument):
57
56
  my_argument: str = cmdfield.argument(...)
58
57
  my_option: str = cmdfield.option(...)
59
- my_flag: str = cmdfield.flag(...)
58
+ my_flag: bool = cmdfield.flag(...)
60
59
 
61
60
  @cmdcommand(_MyCommandArgs)
62
61
  def do_mycommand(self, args: _MyCommandArgs) -> None:
@@ -77,6 +76,9 @@ class MyApplication(cmd2.Cmd):
77
76
  * `default` <br/>
78
77
  The arguments default value if not specified.
79
78
  <br/> (Providing a default value makes the argument optional.)
79
+ * `nargs` <br/>
80
+ The number of command-line values to be consumed.
81
+ <br/> https://docs.python.org/3/library/argparse.html#nargs
80
82
  * `type` <br/>
81
83
  Explicitly specifies the `type` to be used by `argparse`.
82
84
  <br/> https://docs.python.org/3/library/argparse.html#type
@@ -95,6 +97,8 @@ arg: str | None = cmdfield.argument(
95
97
  },
96
98
  default=None,
97
99
  )
100
+ args: list[str] = cmdfield.argument()
101
+ more: list[str] = cmdfield.argument(nargs="+")
98
102
  ```
99
103
 
100
104
 
@@ -117,6 +121,9 @@ arg: str | None = cmdfield.argument(
117
121
  Explicitly specifies all option declarations.
118
122
  * `more_decls` <br/>
119
123
  Specifies additional option declarations.
124
+ * `nargs` <br/>
125
+ The number of command-line values to be consumed.
126
+ <br/> https://docs.python.org/3/library/argparse.html#nargs
120
127
  * `type` <br/>
121
128
  Explicitly specifies the `type` to be used by `argparse`.
122
129
  <br/> https://docs.python.org/3/library/argparse.html#type
@@ -132,6 +139,8 @@ arg: str | None = cmdfield.argument(
132
139
  xx: str | None = cmdfield.option()
133
140
  yy: int | None = cmdfield.option([1, 2, 3])
134
141
  zz: str = cmdfield.option(required=True)
142
+ hh: list[str] | None = cmdfield.option(default=None)
143
+ qq: list[int] | None = cmdfield.option(nargs=2, default=None)
135
144
  ```
136
145
 
137
146
  #### Declarations
@@ -146,6 +155,7 @@ mm: str | None = cmdfield.option(decls="--mm") # --mm
146
155
  nn: str | None = cmdfield.option(decls="-oo") # -oo
147
156
  pp: str | None = cmdfield.option(decls=("--rr", "-ss")) # --rr, -ss
148
157
  tt: str | None = cmdfield.option(more_decls="-uu") # -tt, -uu
158
+ vv_ww: str | None = cmdfield.option() # -vv-ww OR --vv-ww
149
159
  ```
150
160
 
151
161
 
@@ -167,6 +177,7 @@ tt: str | None = cmdfield.option(more_decls="-uu") # -tt, -uu
167
177
  Specifies additional flag declarations.
168
178
  * `type` <br/>
169
179
  Explicitly specifies the type to be used by argparse.
180
+ <br/> (Has no effect, as flag values are not type converted.)
170
181
  <br/> https://docs.python.org/3/library/argparse.html#type
171
182
  * `help` <br/>
172
183
  Brief description of the flag.
@@ -192,6 +203,7 @@ mm: bool = cmdfield.flag(decls="--mm") # --mm
192
203
  nn: bool = cmdfield.flag(decls="-oo") # -oo
193
204
  pp: bool = cmdfield.flag(decls=("--rr", "-ss")) # --rr, -ss
194
205
  tt: bool = cmdfield.flag(more_decls="-uu") # -tt, -uu
206
+ vv_ww: bool = cmdfield.flag() # -vv-ww OR --vv-ww
195
207
  ```
196
208
 
197
209
 
@@ -14,4 +14,6 @@ cmdargparse.egg-info/PKG-INFO
14
14
  cmdargparse.egg-info/SOURCES.txt
15
15
  cmdargparse.egg-info/dependency_links.txt
16
16
  cmdargparse.egg-info/requires.txt
17
- cmdargparse.egg-info/top_level.txt
17
+ cmdargparse.egg-info/top_level.txt
18
+ cmdargparse/actions/__init__.py
19
+ cmdargparse/actions/store.py
@@ -0,0 +1 @@
1
+ cmd2~=4.2
@@ -1,43 +1,42 @@
1
- from setuptools import find_packages, setup
2
-
3
-
4
- with open("README.md", "r", encoding="utf-8") as file:
5
- README = file.read()
6
-
7
-
8
- setup(
9
- name="cmdargparse",
10
- version="0.1.0",
11
- description="A declarative way to define `cmd2` argument parsers.",
12
- long_description=README,
13
- long_description_content_type="text/markdown",
14
- author="Kilian Kaiping (krnd)",
15
- url="https://github.com/krnd/cmdargparse",
16
- license="MIT",
17
- packages=find_packages(include=["cmdargparse"]),
18
- # Tested with Python 3.13 only.
19
- python_requires=">=3.13",
20
- install_requires=[
21
- ("cmd2" "~=2.7"),
22
- ],
23
- keywords=[
24
- "CLI",
25
- "cmd",
26
- "command",
27
- "interactive",
28
- "prompt",
29
- "Python",
30
- ],
31
- classifiers=[
32
- "Development Status :: 3 - Alpha",
33
- "Environment :: Console",
34
- "Environment :: Plugins",
35
- "Intended Audience :: Developers",
36
- "Intended Audience :: System Administrators",
37
- "License :: OSI Approved :: MIT License",
38
- "Operating System :: OS Independent",
39
- "Programming Language :: Python :: 3 :: Only",
40
- "Programming Language :: Python :: 3.13",
41
- "Topic :: Software Development :: Libraries :: Python Modules",
42
- ],
43
- )
1
+ from setuptools import find_packages, setup
2
+
3
+
4
+ with open("README.md", "r", encoding="utf-8") as file:
5
+ README = file.read()
6
+
7
+
8
+ setup(
9
+ name="cmdargparse",
10
+ version="0.3.0",
11
+ description="A declarative way to define `cmd2` argument parsers.",
12
+ long_description=README,
13
+ long_description_content_type="text/markdown",
14
+ author="Kilian Kaiping (krnd)",
15
+ url="https://github.com/krnd/cmdargparse",
16
+ license="MIT",
17
+ packages=find_packages(include=["cmdargparse", "cmdargparse.*"]),
18
+ # Tested with Python 3.14 only.
19
+ python_requires=">=3.14",
20
+ install_requires=[
21
+ ("cmd2" "~=4.2"),
22
+ ],
23
+ keywords=[
24
+ "CLI",
25
+ "cmd",
26
+ "command",
27
+ "interactive",
28
+ "prompt",
29
+ "Python",
30
+ ],
31
+ classifiers=[
32
+ "Development Status :: 3 - Alpha",
33
+ "Environment :: Console",
34
+ "Environment :: Plugins",
35
+ "Intended Audience :: Developers",
36
+ "Intended Audience :: System Administrators",
37
+ "Operating System :: OS Independent",
38
+ "Programming Language :: Python :: 3 :: Only",
39
+ "Programming Language :: Python :: 3.14",
40
+ "Topic :: Software Development :: Libraries :: Python Modules",
41
+ ],
42
+ )
@@ -1 +0,0 @@
1
- cmd2~=2.7
File without changes
File without changes
File without changes