argdec 0.2.1__py3-none-any.whl
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.
- argdec-0.2.1.dist-info/METADATA +352 -0
- argdec-0.2.1.dist-info/RECORD +6 -0
- argdec-0.2.1.dist-info/WHEEL +5 -0
- argdec-0.2.1.dist-info/licenses/LICENSE +674 -0
- argdec-0.2.1.dist-info/top_level.txt +1 -0
- argdec.py +423 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: argdec
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: A decorator-based, declarative interface to Python's argparse for building hierarchical CLI applications.
|
|
5
|
+
Author: argdec contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: argparse,cli,command-line,declarative,decorator
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
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: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.7
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# argdec
|
|
25
|
+
|
|
26
|
+
A decorator-based, declarative interface to Python's argparse for building hierarchical CLI applications.
|
|
27
|
+
|
|
28
|
+
[](https://www.python.org/downloads/)
|
|
29
|
+
[](LICENSE)
|
|
30
|
+
|
|
31
|
+
## Overview
|
|
32
|
+
|
|
33
|
+
**argdec** (formerly [argdeclare](http://code.activestate.com/recipes/576935-argdeclare-declarative-interface-to-argparse)) provides two complementary approaches to configuring argparse:
|
|
34
|
+
|
|
35
|
+
1. **Decorator-based configuration** - Use `@option` and `@option_group` decorators to attach argparse arguments directly to command methods, keeping argument definitions co-located with the code that uses them.
|
|
36
|
+
|
|
37
|
+
2. **Declarative class structure** - Define CLI applications as classes where methods become commands, docstrings become help text, and class attributes configure parser behavior.
|
|
38
|
+
|
|
39
|
+
This combination eliminates boilerplate while preserving full access to argparse's capabilities.
|
|
40
|
+
|
|
41
|
+
## Features
|
|
42
|
+
|
|
43
|
+
- **Decorator-driven options** - Configure argparse arguments with `@option` and `@option_group` decorators directly on methods
|
|
44
|
+
- **Declarative command structure** - Methods prefixed with `do_` automatically become subcommands
|
|
45
|
+
- **Hierarchical commands** - Build nested command structures (e.g., `git remote add`) using underscore-separated method names
|
|
46
|
+
- **Reusable option groups** - Define common options once, apply to multiple commands with `@option_group`
|
|
47
|
+
- **Full argparse compatibility** - All argparse features available through decorator parameters
|
|
48
|
+
- **Customizable** - Configure command prefix, hierarchy levels, and more
|
|
49
|
+
- **Production ready** - Comprehensive test suite, type hints, error handling
|
|
50
|
+
|
|
51
|
+
## Installation
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Coming soon to PyPI
|
|
55
|
+
pip install argdec
|
|
56
|
+
|
|
57
|
+
# For now, use directly from source
|
|
58
|
+
git clone https://github.com/yourusername/argdec.git
|
|
59
|
+
cd argdec
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Quick Start
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from argdec import Commander, option
|
|
66
|
+
|
|
67
|
+
class MyApp(Commander):
|
|
68
|
+
"""My awesome CLI application."""
|
|
69
|
+
name = 'myapp'
|
|
70
|
+
version = '1.0'
|
|
71
|
+
|
|
72
|
+
@option("-v", "--verbose", action="store_true", help="verbose output")
|
|
73
|
+
def do_build(self, args):
|
|
74
|
+
"""Build the project."""
|
|
75
|
+
print(f"Building... (verbose={args.verbose})")
|
|
76
|
+
|
|
77
|
+
if __name__ == '__main__':
|
|
78
|
+
app = MyApp()
|
|
79
|
+
app.cmdline()
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
$ python myapp.py build --verbose
|
|
84
|
+
Building... (verbose=True)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Declarative Format Example
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
#!/usr/bin/env python3
|
|
91
|
+
|
|
92
|
+
from argdec import Commander, option, option_group
|
|
93
|
+
|
|
94
|
+
# ----------------------------------------------------------------------------
|
|
95
|
+
# Commandline interface
|
|
96
|
+
|
|
97
|
+
common_options = option_group(
|
|
98
|
+
option("--dump", action="store_true", help="dump project and product vars"),
|
|
99
|
+
option("-d","--download",
|
|
100
|
+
action="store_true",
|
|
101
|
+
help="download python build/downloads"),
|
|
102
|
+
option("-r", "--reset", action="store_true", help="reset python build"),
|
|
103
|
+
option("-i","--install",
|
|
104
|
+
action="store_true",
|
|
105
|
+
help="install python to build/lib"),
|
|
106
|
+
option("-b","--build",
|
|
107
|
+
action="store_true",
|
|
108
|
+
help="build python in build/src"),
|
|
109
|
+
option("-c","--clean",
|
|
110
|
+
action="store_true",
|
|
111
|
+
help="clean python in build/src"),
|
|
112
|
+
option("-z", "--ziplib", action="store_true", help="zip python library"),
|
|
113
|
+
option("-p", "--py-version", type=str,
|
|
114
|
+
help="set required python version to download and build"),
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
class Application(Commander):
|
|
118
|
+
"""builder: builds the py-js max external and python from source."""
|
|
119
|
+
name = 'builder'
|
|
120
|
+
epilog = ''
|
|
121
|
+
version = '0.1'
|
|
122
|
+
default_args = ['--help']
|
|
123
|
+
_argparse_levels = 1
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# ----------------------------------------------------------------------------
|
|
127
|
+
# python builder methods
|
|
128
|
+
|
|
129
|
+
# def do_python(self, args):
|
|
130
|
+
# "download and build python from src"
|
|
131
|
+
|
|
132
|
+
@common_options
|
|
133
|
+
def do_python_static(self, args):
|
|
134
|
+
"""build static python"""
|
|
135
|
+
print(args)
|
|
136
|
+
|
|
137
|
+
@common_options
|
|
138
|
+
def do_python_shared(self, args):
|
|
139
|
+
"""build shared python"""
|
|
140
|
+
print(args)
|
|
141
|
+
|
|
142
|
+
@common_options
|
|
143
|
+
def do_python_shared_pkg(self, args):
|
|
144
|
+
"""build shared python to embed in package"""
|
|
145
|
+
print(args)
|
|
146
|
+
|
|
147
|
+
@common_options
|
|
148
|
+
def do_python_framework(self, args):
|
|
149
|
+
"""build framework python"""
|
|
150
|
+
print(args)
|
|
151
|
+
|
|
152
|
+
@common_options
|
|
153
|
+
def do_python_framework_pkg(self, args):
|
|
154
|
+
"""build framework python to embed in a package"""
|
|
155
|
+
print(args)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
# ----------------------------------------------------------------------------
|
|
159
|
+
# utility methods
|
|
160
|
+
|
|
161
|
+
# def do_check(self, args):
|
|
162
|
+
# """check reference utilities"""
|
|
163
|
+
# print(args)
|
|
164
|
+
|
|
165
|
+
@common_options
|
|
166
|
+
def do_check_log_day(self, args):
|
|
167
|
+
"""analyze log day"""
|
|
168
|
+
print(args)
|
|
169
|
+
|
|
170
|
+
@common_options
|
|
171
|
+
def do_check_log_week(self, args):
|
|
172
|
+
"""analyze log week"""
|
|
173
|
+
print(args)
|
|
174
|
+
|
|
175
|
+
@common_options
|
|
176
|
+
def do_check_sys_month(self, args):
|
|
177
|
+
"""analyze sys month"""
|
|
178
|
+
print(args)
|
|
179
|
+
|
|
180
|
+
@common_options
|
|
181
|
+
def do_check_sys_def(self, args):
|
|
182
|
+
"""analyze sys def"""
|
|
183
|
+
print(args)
|
|
184
|
+
|
|
185
|
+
@common_options
|
|
186
|
+
def do_check_sys_xyz(self, args):
|
|
187
|
+
"""analyze sys xyz"""
|
|
188
|
+
print(args)
|
|
189
|
+
|
|
190
|
+
@common_options
|
|
191
|
+
def do_test(self, args):
|
|
192
|
+
"""test suite"""
|
|
193
|
+
print(args)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@common_options
|
|
197
|
+
def do_test_app(self, args):
|
|
198
|
+
"""test app"""
|
|
199
|
+
print(args)
|
|
200
|
+
|
|
201
|
+
@common_options
|
|
202
|
+
def do_test_functions(self, args):
|
|
203
|
+
"""test functions"""
|
|
204
|
+
print(args)
|
|
205
|
+
|
|
206
|
+
if __name__ == '__main__':
|
|
207
|
+
app = Application()
|
|
208
|
+
app.cmdline()
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
`with levels=0` gives:
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
```text
|
|
215
|
+
$ python3 demo.py
|
|
216
|
+
usage: demo.py [-h] [-v] ...
|
|
217
|
+
|
|
218
|
+
builder: builds the py-js max external and python from source.
|
|
219
|
+
|
|
220
|
+
optional arguments:
|
|
221
|
+
-h, --help show this help message and exit
|
|
222
|
+
-v, --version show program's version number and exit
|
|
223
|
+
|
|
224
|
+
subcommands:
|
|
225
|
+
valid subcommands
|
|
226
|
+
|
|
227
|
+
additional help
|
|
228
|
+
check_log_day analyze log day
|
|
229
|
+
check_log_week analyze log week
|
|
230
|
+
check_sys_def analyze sys def
|
|
231
|
+
check_sys_month analyze sys month
|
|
232
|
+
check_sys_xyz analyze sys xyz
|
|
233
|
+
python_framework build framework python
|
|
234
|
+
python_framework_pkg
|
|
235
|
+
build framework python to embed in a package
|
|
236
|
+
python_shared build shared python
|
|
237
|
+
python_shared_pkg build shared python to embed in package
|
|
238
|
+
python_static build static python
|
|
239
|
+
test test suite
|
|
240
|
+
test_app test app
|
|
241
|
+
test_functions test functions
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
`with levels=1` gives:
|
|
245
|
+
|
|
246
|
+
```text
|
|
247
|
+
|
|
248
|
+
$ python3 demo.py
|
|
249
|
+
usage: demo.py [-h] [-v] ...
|
|
250
|
+
|
|
251
|
+
builder: builds the py-js max external and python from source.
|
|
252
|
+
|
|
253
|
+
optional arguments:
|
|
254
|
+
-h, --help show this help message and exit
|
|
255
|
+
-v, --version show program's version number and exit
|
|
256
|
+
|
|
257
|
+
subcommands:
|
|
258
|
+
valid subcommands
|
|
259
|
+
|
|
260
|
+
additional help
|
|
261
|
+
check check commands
|
|
262
|
+
python python commands
|
|
263
|
+
test test suite
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Advanced Features
|
|
267
|
+
|
|
268
|
+
### Custom Command Prefix
|
|
269
|
+
|
|
270
|
+
By default, methods starting with `do_` become commands. You can customize this:
|
|
271
|
+
|
|
272
|
+
```python
|
|
273
|
+
class MyApp(Commander):
|
|
274
|
+
_command_prefix = "cmd_" # Use 'cmd_' instead of 'do_'
|
|
275
|
+
|
|
276
|
+
def cmd_build(self, args):
|
|
277
|
+
"""Build the project."""
|
|
278
|
+
pass
|
|
279
|
+
|
|
280
|
+
def cmd_deploy(self, args):
|
|
281
|
+
"""Deploy the project."""
|
|
282
|
+
pass
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
See `example_custom_prefix.py` for more examples.
|
|
286
|
+
|
|
287
|
+
### Error Handling
|
|
288
|
+
|
|
289
|
+
Version 0.2.0+ includes comprehensive error handling:
|
|
290
|
+
|
|
291
|
+
```python
|
|
292
|
+
from argdec import ArgDecError, CommandExecutionError
|
|
293
|
+
|
|
294
|
+
try:
|
|
295
|
+
app.cmdline()
|
|
296
|
+
except CommandExecutionError as e:
|
|
297
|
+
print(f"Command failed: {e}")
|
|
298
|
+
except ArgDecError as e:
|
|
299
|
+
print(f"Configuration error: {e}")
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Examples
|
|
303
|
+
|
|
304
|
+
Can be found in the `examples` directory:
|
|
305
|
+
|
|
306
|
+
- `basic.py` - Basic example application
|
|
307
|
+
- `hierarchical.py` - Full-featured example application
|
|
308
|
+
- `custom_prefix.py` - Custom prefix demonstrations
|
|
309
|
+
|
|
310
|
+
## Development
|
|
311
|
+
|
|
312
|
+
### Running Tests
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
make test # Run test suite (38 tests)
|
|
316
|
+
make coverage # Run with coverage report
|
|
317
|
+
make lint # Run ruff linter
|
|
318
|
+
make typecheck # Run mypy type checker
|
|
319
|
+
make all # Run all checks
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Requirements
|
|
323
|
+
|
|
324
|
+
- Python 3.7+
|
|
325
|
+
- No external dependencies (uses stdlib only)
|
|
326
|
+
- Development: pytest, ruff, mypy (optional)
|
|
327
|
+
|
|
328
|
+
## Version History
|
|
329
|
+
|
|
330
|
+
- **v0.2.1** (2025-12-16) - Renamed to `argdec`
|
|
331
|
+
- **v0.2.0** (2025-11-07) - Release with tests, type hints, error handling, and configurable prefix
|
|
332
|
+
- **v0.1.0** - Initial release with basic functionality
|
|
333
|
+
|
|
334
|
+
See [CHANGELOG.md](CHANGELOG.md) for detailed version history.
|
|
335
|
+
|
|
336
|
+
## License
|
|
337
|
+
|
|
338
|
+
MIT License - See [LICENSE](LICENSE) file for details.
|
|
339
|
+
|
|
340
|
+
## Credits
|
|
341
|
+
|
|
342
|
+
Based on the original [argdec recipe](http://code.activestate.com/recipes/576935-argdec-declarative-interface-to-argparse) from ActiveState.
|
|
343
|
+
|
|
344
|
+
## Contributing
|
|
345
|
+
|
|
346
|
+
Contributions welcome! Please:
|
|
347
|
+
1. Run tests: `make test`
|
|
348
|
+
2. Check types: `make typecheck`
|
|
349
|
+
3. Lint code: `make lint`
|
|
350
|
+
4. Add tests for new features
|
|
351
|
+
|
|
352
|
+
```
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
argdec.py,sha256=k4b9XL9PW0VjrvohYAJCWpKsECqXYvjjm3CHfqqEa0o,15163
|
|
2
|
+
argdec-0.2.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
3
|
+
argdec-0.2.1.dist-info/METADATA,sha256=QbewHSij_UIVFlmT9a7QAuSpCmPMQhFHRZJIoZ21dzU,9950
|
|
4
|
+
argdec-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
5
|
+
argdec-0.2.1.dist-info/top_level.txt,sha256=2iTdZESanPihxLYULCTHh75DrwvD-ZE_UnWM880w2n0,7
|
|
6
|
+
argdec-0.2.1.dist-info/RECORD,,
|