paramspecli 0.2.1__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paramspecli
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Summary: Type-safe facade for the venerable argparse
5
5
  Author: jkmnt
6
6
  Requires-Python: >=3.12
@@ -78,7 +78,7 @@ pip install paramspecli
78
78
  - Commands match handler functions parameters with arguments and options.
79
79
  - Arguments are bound to the handler's positional parameters.
80
80
  - Options are bound to the handler's keyword parameters.
81
- - Groups organize the commands. Groups may be nested. They could act like like an intermediate commands, i.e. have own handlers, options and arguments.
81
+ - Groups organize the commands. Groups may be nested. They could act like an intermediate commands, i.e. have own handlers, options and arguments.
82
82
  - CLI 'compiles' to the `argparse`, runs it, then outputs the parse result.
83
83
  - Parse result is a callable. Calling it invokes handlers along the route.
84
84
 
@@ -64,7 +64,7 @@ pip install paramspecli
64
64
  - Commands match handler functions parameters with arguments and options.
65
65
  - Arguments are bound to the handler's positional parameters.
66
66
  - Options are bound to the handler's keyword parameters.
67
- - Groups organize the commands. Groups may be nested. They could act like like an intermediate commands, i.e. have own handlers, options and arguments.
67
+ - Groups organize the commands. Groups may be nested. They could act like an intermediate commands, i.e. have own handlers, options and arguments.
68
68
  - CLI 'compiles' to the `argparse`, runs it, then outputs the parse result.
69
69
  - Parse result is a callable. Calling it invokes handlers along the route.
70
70
 
@@ -64,6 +64,7 @@ ignore = [
64
64
  ]
65
65
 
66
66
  [tool.pyright]
67
+ include = ["src", "tests"]
67
68
  # typeCheckingMode = "strict"
68
69
  typeCheckingMode = "standard"
69
70
  useLibraryCodeForTypes = true
@@ -1,20 +1,23 @@
1
1
  """Type-safe facade for the venerable argparse"""
2
2
 
3
- __version__ = "0.2.1"
3
+ __version__ = "0.3.0"
4
4
 
5
5
 
6
+ from .acts import custom_action as custom_action
7
+ from .acts import version_action as version_action
6
8
  from .args import argument as argument
7
- from .cli import Action as Action
9
+ from .cli import MISSING as MISSING
8
10
  from .cli import CallableGroup as CallableGroup
9
11
  from .cli import Command as Command
10
12
  from .cli import Config as Config
11
13
  from .cli import Group as Group
12
14
  from .cli import Handler as Handler
15
+ from .cli import Missing as Missing
13
16
  from .cli import Route as Route
14
17
  from .cli import help_action as help_action
15
- from .cli import version_action as version_action
18
+ from .const import const as const
16
19
  from .conv import PathConv as PathConv
17
- from .fake import Const as Const
20
+ from .exc import ParseAgain as ParseAgain
18
21
  from .fake import Context as Context
19
22
  from .fake import deprecated as deprecated
20
23
  from .fake import required as required
@@ -25,3 +28,6 @@ from .flags import repeated_flag as repeated_flag
25
28
  from .flags import switch as switch
26
29
  from .opts import option as option
27
30
  from .opts import repeated_option as repeated_option
31
+
32
+ # compat
33
+ Const = const
@@ -0,0 +1,159 @@
1
+ import argparse
2
+ from typing import Any, Iterable, Literal, NoReturn, overload
3
+
4
+ from . import util
5
+ from .apstub import TypeConverter
6
+ from .cli import MISSING, Action, ActionHandler, Markup, Missing
7
+
8
+
9
+ @overload
10
+ def custom_action(
11
+ *names: str,
12
+ handler: ActionHandler[str],
13
+ default: Any = None,
14
+ #
15
+ help: str | bool | Markup | None = None,
16
+ choices: Iterable[Any] | None = None,
17
+ metavar: str | tuple[str, ...] | None = None,
18
+ show_default: bool | str | None = False,
19
+ ) -> Action[str]: ...
20
+
21
+
22
+ # nargs=0
23
+ @overload
24
+ def custom_action(
25
+ *names: str,
26
+ handler: ActionHandler[None],
27
+ nargs: Literal[0],
28
+ default: Any = None,
29
+ #
30
+ help: str | bool | Markup | None = None,
31
+ show_default: bool | str | None = False,
32
+ ) -> Action[None]: ...
33
+
34
+
35
+ # nargs
36
+ @overload
37
+ def custom_action(
38
+ *names: str,
39
+ handler: ActionHandler[list[str]],
40
+ nargs: int | Literal["+", "*"],
41
+ default: Any = None,
42
+ #
43
+ help: str | bool | Markup | None = None,
44
+ choices: Iterable[Any] | None = None,
45
+ metavar: str | tuple[str, ...] | None = None,
46
+ show_default: bool | str | None = False,
47
+ ) -> Action[list[str]]: ...
48
+
49
+
50
+ # optional
51
+ @overload
52
+ def custom_action(
53
+ *names: str,
54
+ handler: ActionHandler[str],
55
+ nargs: Literal["?"],
56
+ default: Any = None,
57
+ #
58
+ help: str | bool | Markup | None = None,
59
+ choices: Iterable[Any] | None = None,
60
+ metavar: str | tuple[str, ...] | None = None,
61
+ show_default: bool | str | None = False,
62
+ ) -> Action[str | Missing]: ...
63
+
64
+
65
+ # T
66
+ @overload
67
+ def custom_action[T](
68
+ *names: str,
69
+ handler: ActionHandler[T],
70
+ type: TypeConverter[T],
71
+ default: Any = None,
72
+ #
73
+ help: str | bool | Markup | None = None,
74
+ choices: Iterable[Any] | None = None,
75
+ metavar: str | tuple[str, ...] | None = None,
76
+ show_default: bool | str | None = False,
77
+ ) -> Action[T]: ...
78
+
79
+
80
+ # T, nargs
81
+ @overload
82
+ def custom_action[T](
83
+ *names: str,
84
+ handler: ActionHandler[list[T]],
85
+ type: TypeConverter[T],
86
+ nargs: int | Literal["+", "*"],
87
+ default: Any = None,
88
+ #
89
+ help: str | bool | Markup | None = None,
90
+ choices: Iterable[Any] | None = None,
91
+ metavar: str | tuple[str, ...] | None = None,
92
+ show_default: bool | str | None = False,
93
+ ) -> Action[list[T]]: ...
94
+
95
+
96
+ # T, optional
97
+ @overload
98
+ def custom_action[T](
99
+ *names: str,
100
+ handler: ActionHandler[T | Missing],
101
+ type: TypeConverter[T],
102
+ nargs: Literal["?"],
103
+ default: Any = None,
104
+ #
105
+ help: str | bool | Markup | None = None,
106
+ choices: Iterable[Any] | None = None,
107
+ metavar: str | tuple[str, ...] | None = None,
108
+ show_default: bool | str | None = False,
109
+ ) -> Action[T | Missing]: ...
110
+
111
+
112
+ def custom_action(
113
+ *names: str,
114
+ handler: ActionHandler[Any],
115
+ type: TypeConverter[Any] | None = None,
116
+ nargs: int | Literal["+", "*", "?"] | None = None,
117
+ default: Any = None,
118
+ #
119
+ help: str | bool | Markup | None = None,
120
+ choices: Iterable[Any] | None = None,
121
+ metavar: str | tuple[str, ...] | None = None,
122
+ show_default: bool | str | None = False,
123
+ ) -> Action[Any]:
124
+ """Custom action calling the `handler` upon the option match"""
125
+ if metavar is None and choices is None and nargs != 0:
126
+ metavar = names[0].lstrip("-").upper()
127
+
128
+ return Action(
129
+ names,
130
+ handler=handler,
131
+ help=help,
132
+ conv=type,
133
+ nargs=nargs,
134
+ default=default,
135
+ const=MISSING if nargs == "?" else None,
136
+ choices=choices,
137
+ metavar=metavar,
138
+ #
139
+ hard_show_default=show_default,
140
+ soft_show_default=default is not None and default != [],
141
+ )
142
+
143
+
144
+ class _VersionPrinter:
145
+ def __init__(self, version: str):
146
+ self.version = version
147
+
148
+ def __call__(self, *, parser: argparse.ArgumentParser, **kwargs: Any) -> NoReturn:
149
+ util.echo(self.version)
150
+ parser.exit(0)
151
+
152
+
153
+ def version_action(
154
+ version: str,
155
+ *,
156
+ help: str | Markup | bool = "Show program's version number and exit",
157
+ names: tuple[str, ...] = ("--version",),
158
+ ) -> Action[None]:
159
+ return Action(names, help=help, nargs=0, handler=_VersionPrinter(version))
@@ -81,4 +81,4 @@ class ArgumentParserLike(
81
81
  def exit(self, status: int = ..., message: str | None = ...) -> NoReturn: ...
82
82
 
83
83
 
84
- class ArgumentGroupLike(SupportsAddArgument, SupportsAddOneofGroup, Protocol): ...
84
+ class ArgumentGroupLike(SupportsAddArgument, SupportsAddOneofGroup, SupportsSetDefaults, Protocol): ...
@@ -0,0 +1,164 @@
1
+ from typing import Any, Iterable, Literal, overload
2
+
3
+ from .apstub import TypeConverter
4
+ from .cli import Markup
5
+ from .fake import Argument
6
+
7
+
8
+ # 1.
9
+ # {'type': 'None', 'nargs': 'None'}
10
+ @overload
11
+ def argument(
12
+ metavar: str,
13
+ *,
14
+ #
15
+ type: None = None,
16
+ nargs: None = None,
17
+ #
18
+ help: str | bool | Markup | None = None,
19
+ choices: Iterable[str] | None = None,
20
+ ) -> Argument[str, str]: ...
21
+
22
+
23
+ # 2.
24
+ # {'type': 'None', 'nargs': 'int | Literal["*", "+"]'}
25
+ @overload
26
+ def argument(
27
+ metavar: str,
28
+ *,
29
+ #
30
+ type: None = None,
31
+ nargs: int | Literal["*", "+"],
32
+ #
33
+ help: str | bool | Markup | None = None,
34
+ choices: Iterable[str] | None = None,
35
+ ) -> Argument[list[str], list[str]]: ...
36
+
37
+
38
+ # 3.
39
+ # {'type': 'None', 'nargs': 'Literal["?"]', 'default': 'None'}
40
+ @overload
41
+ def argument(
42
+ metavar: str,
43
+ *,
44
+ #
45
+ type: None = None,
46
+ nargs: Literal["?"],
47
+ default: None = None,
48
+ #
49
+ help: str | bool | Markup | None = None,
50
+ choices: Iterable[str] | None = None,
51
+ ) -> Argument[str, None]: ...
52
+
53
+
54
+ # 4.
55
+ # {'type': 'None', 'nargs': 'Literal["?"]', 'default': 'D'}
56
+ @overload
57
+ def argument[D](
58
+ metavar: str,
59
+ *,
60
+ #
61
+ type: None = None,
62
+ nargs: Literal["?"],
63
+ default: D,
64
+ #
65
+ help: str | bool | Markup | None = None,
66
+ choices: Iterable[str] | None = None,
67
+ ) -> Argument[str, D]: ...
68
+
69
+
70
+ # 5.
71
+ # {'type': 'TypeConverter[T]', 'nargs': 'None'}
72
+ @overload
73
+ def argument[T](
74
+ metavar: str,
75
+ *,
76
+ #
77
+ type: TypeConverter[T],
78
+ nargs: None = None,
79
+ #
80
+ help: str | bool | Markup | None = None,
81
+ choices: Iterable[T] | None = None,
82
+ ) -> Argument[T, T]: ...
83
+
84
+
85
+ # 6.
86
+ # {'type': 'TypeConverter[T]', 'nargs': 'int | Literal["*", "+"]'}
87
+ @overload
88
+ def argument[T](
89
+ metavar: str,
90
+ *,
91
+ #
92
+ type: TypeConverter[T],
93
+ nargs: int | Literal["*", "+"],
94
+ #
95
+ help: str | bool | Markup | None = None,
96
+ choices: Iterable[T] | None = None,
97
+ ) -> Argument[list[T], list[T]]: ...
98
+
99
+
100
+ # 7.
101
+ # {'type': 'TypeConverter[T]', 'nargs': 'Literal["?"', 'default': 'None'}
102
+ @overload
103
+ def argument[T](
104
+ metavar: str,
105
+ *,
106
+ #
107
+ type: TypeConverter[T],
108
+ nargs: Literal["?"],
109
+ default: None = None,
110
+ #
111
+ help: str | bool | Markup | None = None,
112
+ choices: Iterable[T] | None = None,
113
+ ) -> Argument[T, None]: ...
114
+
115
+
116
+ # 8.
117
+ # {'type': 'TypeConverter[T]', 'nargs': 'Literal["?"', 'default': 'str'}
118
+ @overload
119
+ def argument[T, D](
120
+ metavar: str,
121
+ *,
122
+ #
123
+ type: TypeConverter[T],
124
+ nargs: Literal["?"],
125
+ default: str,
126
+ #
127
+ help: str | bool | Markup | None = None,
128
+ choices: Iterable[T] | None = None,
129
+ ) -> Argument[T, T]: ...
130
+
131
+
132
+ # 8.
133
+ # {'type': 'TypeConverter[T]', 'nargs': 'Literal["?"', 'default': 'D'}
134
+ @overload
135
+ def argument[T, D](
136
+ metavar: str,
137
+ *,
138
+ #
139
+ type: TypeConverter[T],
140
+ nargs: Literal["?"],
141
+ default: D,
142
+ #
143
+ help: str | bool | Markup | None = None,
144
+ choices: Iterable[T] | None = None,
145
+ ) -> Argument[T, D]: ...
146
+
147
+
148
+ def argument(
149
+ metavar: str,
150
+ *,
151
+ #
152
+ type: TypeConverter[Any] | None = None,
153
+ nargs: int | Literal["*", "+", "?"] | None = None,
154
+ default: Any | None = None,
155
+ #
156
+ help: str | bool | Markup | None = None,
157
+ choices: Iterable[Any] | None = None,
158
+ ) -> Argument[Any, Any]:
159
+ """Positional argument. Always required, unless made optional via `nargs="?"`."""
160
+
161
+ if isinstance(nargs, int) and nargs <= 0:
162
+ raise ValueError("Arguments could not have nargs == 0")
163
+
164
+ return Argument(metavar, help=help, conv=type, choices=choices, nargs=nargs, default=default)