wexample-cli 2.2.0__tar.gz → 2.2.2__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 (44) hide show
  1. wexample_cli-2.2.2/PKG-INFO +113 -0
  2. wexample_cli-2.2.2/README.md +93 -0
  3. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/pyproject.toml +4 -4
  4. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/command/__init__.py +0 -0
  5. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/common/__init__.py +0 -0
  6. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/const/__init__.py +0 -0
  7. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/const/tags.py +0 -0
  8. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/context/__init__.py +0 -0
  9. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/decorator/__init__.py +0 -0
  10. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/decorator/alias.py +0 -0
  11. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/decorator/api_command.py +0 -0
  12. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/decorator/screenable.py +0 -0
  13. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/exception/__init__.py +0 -0
  14. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/helper/__init__.py +0 -0
  15. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/helper/extra_args.py +0 -0
  16. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/middleware/__init__.py +0 -0
  17. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/py.typed +0 -0
  18. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/testing/__init__.py +0 -0
  19. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/testing/kernel.py +0 -0
  20. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/tests/.gitkeep +0 -0
  21. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/tests/helper/__init__.py +0 -0
  22. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/tests/helper/test_extra_args.py +0 -0
  23. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/tests/unit/__init__.py +0 -0
  24. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/tests/unit/helper/__init__.py +0 -0
  25. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/tests/unit/helper/test_extra_args.py +0 -0
  26. wexample_cli-2.2.0/PKG-INFO +0 -293
  27. wexample_cli-2.2.0/README.md +0 -273
  28. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/__init__.py +0 -0
  29. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/command/extended_command.py +0 -0
  30. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/common/command_method_wrapper.py +0 -0
  31. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/const/middleware.py +0 -0
  32. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/const/types.py +0 -0
  33. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/context/execution_context.py +0 -0
  34. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/decorator/as_sudo.py +0 -0
  35. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/decorator/command.py +0 -0
  36. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/decorator/middleware.py +0 -0
  37. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/decorator/option.py +0 -0
  38. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/decorator/option_stop_on_failure.py +0 -0
  39. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/decorator/webhook.py +0 -0
  40. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/exception/abstract_command_option_exception.py +0 -0
  41. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/exception/command_option_missing_exception.py +0 -0
  42. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/exception/command_option_validation_exception.py +0 -0
  43. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/src/wexample_cli/middleware/abstract_middleware.py +0 -0
  44. {wexample_cli-2.2.0 → wexample_cli-2.2.2}/tests/__init__.py +0 -0
@@ -0,0 +1,113 @@
1
+ Metadata-Version: 2.1
2
+ Name: wexample-cli
3
+ Version: 2.2.2
4
+ Summary: Supplies command decorators, typed options, and a composable middleware pipeline for kernels built on wexample-app
5
+ Author-Email: weeger <contact@wexample.com>
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Project-URL: homepage, https://github.com/wexample/python-cli
11
+ Requires-Python: >=3.10
12
+ Requires-Dist: attrs>=23.1.0
13
+ Requires-Dist: wexample-app>=19.4.2
14
+ Requires-Dist: wexample-helpers>=20.6.0
15
+ Requires-Dist: wexample-prompt>=16.0.7
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest; extra == "dev"
18
+ Requires-Dist: pytest-cov; extra == "dev"
19
+ Description-Content-Type: text/markdown
20
+
21
+ # cli
22
+
23
+ Version: 2.2.2
24
+
25
+ Supplies command decorators, typed options, and a composable middleware pipeline for kernels built on wexample-app
26
+
27
+ ## Table of Contents
28
+
29
+ - [Install](#install)
30
+ - [Tests](#tests)
31
+ - [Roadmap](#roadmap)
32
+ - [Status Compatibility](#status-compatibility)
33
+ - [Useful Links](#useful-links)
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pip install wexample-cli
39
+ ```
40
+
41
+ Requires Python >=3.10.
42
+
43
+ ## Tests
44
+
45
+ This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.
46
+
47
+ ### Installation
48
+
49
+ First, install the required testing dependencies:
50
+ ```bash
51
+ .venv/bin/python -m pip install pytest pytest-cov
52
+ ```
53
+
54
+ ### Basic Usage
55
+
56
+ Run all tests with coverage:
57
+ ```bash
58
+ .venv/bin/python -m pytest --cov --cov-report=html
59
+ ```
60
+
61
+ ### Common Commands
62
+ ```bash
63
+ # Run tests with coverage for a specific module
64
+ .venv/bin/python -m pytest --cov=your_module
65
+
66
+ # Show which lines are not covered
67
+ .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing
68
+
69
+ # Generate an HTML coverage report
70
+ .venv/bin/python -m pytest --cov=your_module --cov-report=html
71
+
72
+ # Combine terminal and HTML reports
73
+ .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html
74
+
75
+ # Run specific test file with coverage
76
+ .venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
77
+ ```
78
+
79
+ ### Viewing HTML Reports
80
+
81
+ After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.
82
+
83
+ ### Coverage Threshold
84
+
85
+ To enforce a minimum coverage percentage:
86
+ ```bash
87
+ .venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
88
+ ```
89
+
90
+ This will cause the test suite to fail if coverage drops below 80%.
91
+
92
+ ## Known Limitations & Roadmap
93
+
94
+ Current limitations and planned features are tracked in the GitHub issues.
95
+
96
+ See the [project roadmap](https://github.com/wexample/python-cli/issues) for upcoming features and improvements.
97
+
98
+ ## Status & Compatibility
99
+
100
+ **Maturity**: Production-ready
101
+
102
+ **Python Support**: >=3.10
103
+
104
+ **OS Support**: Linux, macOS, Windows
105
+
106
+ **Status**: Actively maintained
107
+
108
+ ## Useful Links
109
+
110
+ - **Homepage**: https://github.com/wexample/python-cli
111
+ - **Issue Tracker**: https://github.com/wexample/python-cli/issues
112
+ - **Discussions**: https://github.com/wexample/python-cli/discussions
113
+ - **PyPI**: [pypi.org/project/wexample-cli](https://pypi.org/project/wexample-cli/)
@@ -0,0 +1,93 @@
1
+ # cli
2
+
3
+ Version: 2.2.2
4
+
5
+ Supplies command decorators, typed options, and a composable middleware pipeline for kernels built on wexample-app
6
+
7
+ ## Table of Contents
8
+
9
+ - [Install](#install)
10
+ - [Tests](#tests)
11
+ - [Roadmap](#roadmap)
12
+ - [Status Compatibility](#status-compatibility)
13
+ - [Useful Links](#useful-links)
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ pip install wexample-cli
19
+ ```
20
+
21
+ Requires Python >=3.10.
22
+
23
+ ## Tests
24
+
25
+ This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.
26
+
27
+ ### Installation
28
+
29
+ First, install the required testing dependencies:
30
+ ```bash
31
+ .venv/bin/python -m pip install pytest pytest-cov
32
+ ```
33
+
34
+ ### Basic Usage
35
+
36
+ Run all tests with coverage:
37
+ ```bash
38
+ .venv/bin/python -m pytest --cov --cov-report=html
39
+ ```
40
+
41
+ ### Common Commands
42
+ ```bash
43
+ # Run tests with coverage for a specific module
44
+ .venv/bin/python -m pytest --cov=your_module
45
+
46
+ # Show which lines are not covered
47
+ .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing
48
+
49
+ # Generate an HTML coverage report
50
+ .venv/bin/python -m pytest --cov=your_module --cov-report=html
51
+
52
+ # Combine terminal and HTML reports
53
+ .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html
54
+
55
+ # Run specific test file with coverage
56
+ .venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
57
+ ```
58
+
59
+ ### Viewing HTML Reports
60
+
61
+ After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.
62
+
63
+ ### Coverage Threshold
64
+
65
+ To enforce a minimum coverage percentage:
66
+ ```bash
67
+ .venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
68
+ ```
69
+
70
+ This will cause the test suite to fail if coverage drops below 80%.
71
+
72
+ ## Known Limitations & Roadmap
73
+
74
+ Current limitations and planned features are tracked in the GitHub issues.
75
+
76
+ See the [project roadmap](https://github.com/wexample/python-cli/issues) for upcoming features and improvements.
77
+
78
+ ## Status & Compatibility
79
+
80
+ **Maturity**: Production-ready
81
+
82
+ **Python Support**: >=3.10
83
+
84
+ **OS Support**: Linux, macOS, Windows
85
+
86
+ **Status**: Actively maintained
87
+
88
+ ## Useful Links
89
+
90
+ - **Homepage**: https://github.com/wexample/python-cli
91
+ - **Issue Tracker**: https://github.com/wexample/python-cli/issues
92
+ - **Discussions**: https://github.com/wexample/python-cli/discussions
93
+ - **PyPI**: [pypi.org/project/wexample-cli](https://pypi.org/project/wexample-cli/)
@@ -6,7 +6,7 @@ build-backend = "pdm.backend"
6
6
 
7
7
  [project]
8
8
  name = "wexample-cli"
9
- version = "2.2.0"
9
+ version = "2.2.2"
10
10
  description = "Supplies command decorators, typed options, and a composable middleware pipeline for kernels built on wexample-app"
11
11
  authors = [
12
12
  { name = "weeger", email = "contact@wexample.com" },
@@ -19,9 +19,9 @@ classifiers = [
19
19
  ]
20
20
  dependencies = [
21
21
  "attrs>=23.1.0",
22
- "wexample-app>=19.4.0",
23
- "wexample-helpers>=20.5.0",
24
- "wexample-prompt>=16.0.0",
22
+ "wexample-app>=19.4.2",
23
+ "wexample-helpers>=20.6.0",
24
+ "wexample-prompt>=16.0.7",
25
25
  ]
26
26
 
27
27
  [project.readme]
@@ -1,293 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: wexample-cli
3
- Version: 2.2.0
4
- Summary: Supplies command decorators, typed options, and a composable middleware pipeline for kernels built on wexample-app
5
- Author-Email: weeger <contact@wexample.com>
6
- License: MIT
7
- Classifier: Programming Language :: Python :: 3
8
- Classifier: License :: OSI Approved :: MIT License
9
- Classifier: Operating System :: OS Independent
10
- Project-URL: homepage, https://github.com/wexample/python-cli
11
- Requires-Python: >=3.10
12
- Requires-Dist: attrs>=23.1.0
13
- Requires-Dist: wexample-app>=19.4.0
14
- Requires-Dist: wexample-helpers>=20.5.0
15
- Requires-Dist: wexample-prompt>=16.0.0
16
- Provides-Extra: dev
17
- Requires-Dist: pytest; extra == "dev"
18
- Requires-Dist: pytest-cov; extra == "dev"
19
- Description-Content-Type: text/markdown
20
-
21
- # cli
22
-
23
- Version: 2.2.0
24
-
25
- `wexample-cli` supplies the decorator layer — `@command`, `@option`, and `@middleware` — that turns plain Python methods into typed, discoverable commands for kernels built on `wexample-app`. Options are declared with Python types, short names, defaults, required flags, and per-value validators; a composable middleware pipeline can fan a single invocation across multiple execution contexts, run them in parallel, and abort on the first failure. It is aimed at Python developers building or extending a `wexample-app` kernel with new CLI commands.
26
-
27
- ## Table of Contents
28
-
29
- - [Installation](#installation)
30
- - [Quickstart](#quickstart)
31
- - [Tests](#tests)
32
- - [Architecture](#architecture)
33
- - [Integration in the Suite](#integration-in-the-suite)
34
- - [Dependencies](#dependencies)
35
- - [Versioning & Compatibility Policy](#versioning--compatibility-policy)
36
- - [License](#license)
37
- - [About us](#about-us)
38
- - [Known Limitations & Roadmap](#known-limitations--roadmap)
39
- - [Status & Compatibility](#status--compatibility)
40
- - [Useful Links](#useful-links)
41
- - [Migration Notes](#migration-notes)
42
-
43
- ## Installation
44
-
45
- ```bash
46
- pip install wexample-cli
47
- ```
48
-
49
- Requires Python >=3.10.
50
-
51
- ## Quickstart
52
-
53
- Install the package:
54
-
55
- ```bash
56
- pip install wexample-cli
57
- ```
58
-
59
- Declare a command inside your kernel class. `@command` wraps the method into a `CommandMethodWrapper`; each `@option` stacks on top in outer-to-inner order to append a typed option to it.
60
-
61
- ```python
62
- from wexample_cli.decorator.command import command
63
- from wexample_cli.decorator.option import option
64
-
65
- @option(name="name", type=str, description="Who to greet", required=True)
66
- @command(type="demo", description="Print a greeting")
67
- def demo__greet(context, name: str) -> None:
68
- context.io.log(f"Hello, {name}!")
69
- ```
70
-
71
- The decorated object is a `CommandMethodWrapper`. You can inspect it immediately:
72
-
73
- ```python
74
- demo__greet.description # "Print a greeting"
75
- demo__greet.options[0].name # "name"
76
- ```
77
-
78
- The kernel maps the function name `demo__greet` to the command path `demo/greet`. To exercise the full decorator and middleware pipeline in a test, use the helpers in src/wexample_cli/testing/kernel.py:
79
-
80
- ```python
81
- from wexample_cli.testing.kernel import boot_kernel, dispatch_command
82
-
83
- kernel = boot_kernel(MyKernel, entrypoint_path="/path/to/__main__.py")
84
- response = dispatch_command(kernel, "demo/greet", {"name": "world"})
85
- ```
86
-
87
- `dispatch_command` accepts pre-parsed kwargs (`{"name": "world"}`) or CLI-style strings (`["--name", "world"]`).
88
-
89
- ## Tests
90
-
91
- This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.
92
-
93
- ### Installation
94
-
95
- First, install the required testing dependencies:
96
- ```bash
97
- .venv/bin/python -m pip install pytest pytest-cov
98
- ```
99
-
100
- ### Basic Usage
101
-
102
- Run all tests with coverage:
103
- ```bash
104
- .venv/bin/python -m pytest --cov --cov-report=html
105
- ```
106
-
107
- ### Common Commands
108
- ```bash
109
- # Run tests with coverage for a specific module
110
- .venv/bin/python -m pytest --cov=your_module
111
-
112
- # Show which lines are not covered
113
- .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing
114
-
115
- # Generate an HTML coverage report
116
- .venv/bin/python -m pytest --cov=your_module --cov-report=html
117
-
118
- # Combine terminal and HTML reports
119
- .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html
120
-
121
- # Run specific test file with coverage
122
- .venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
123
- ```
124
-
125
- ### Viewing HTML Reports
126
-
127
- After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.
128
-
129
- ### Coverage Threshold
130
-
131
- To enforce a minimum coverage percentage:
132
- ```bash
133
- .venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
134
- ```
135
-
136
- This will cause the test suite to fail if coverage drops below 80%.
137
-
138
- ## Architecture
139
-
140
- `wexample-cli` is a decorator and dispatch layer that sits between a `wexample-app` kernel and the Python functions that implement its commands. It has no entry-point of its own; downstream kernels import its decorators, wrap their methods, and pass the resulting objects to the kernel's registration machinery.
141
-
142
- ### Parts
143
-
144
- **Decorators** — `src/wexample_cli/decorator/`
145
-
146
- The decorators are the only thing a command author touches directly. Applied bottom-to-top on a plain function, they produce a `CommandMethodWrapper`:
147
-
148
- - `@command(type, description, tags)` — creates the wrapper; must be the innermost decorator.
149
- - `@option(name, type, ...)` — calls `wrapper.set_option(Option(...))` to append a typed option.
150
- - `@middleware(name, **kwargs)` — calls `wrapper.register_middleware(name, kwargs)` to schedule a middleware class at runtime.
151
- - `@alias(*names)` — extends `wrapper.aliases`.
152
- - `@screenable(interval, height)` — adds `--screen` and `--screen-interval` options and pushes a pipeline wrapper that drives a refresh loop.
153
- - `@as_sudo()` — sets `wrapper.sudo = True`.
154
- - `@webhook()` — sets `wrapper.webhook = True`.
155
- - `@option_stop_on_failure()` — adds a `--stop-on-failure` flag option.
156
-
157
- **`CommandMethodWrapper`** — `src/wexample_cli/common/command_method_wrapper.py`
158
-
159
- The data structure produced by decoration. It carries everything the runtime needs: `function`, `options`, `middlewares_attributes` (names → init-kwargs, resolved at call time), `pipeline_wrappers` (registered in outer-to-inner order), `aliases`, `tags`, and the boolean flags `sudo` and `webhook`. It owns no execution logic.
160
-
161
- **`ExtendedCommand`** — `src/wexample_cli/command/extended_command.py`
162
-
163
- The runtime command object registered with the kernel; extends `wexample_app.common.command.Command`. It owns the full execution path for one `CommandRequest`.
164
-
165
- **`AbstractMiddleware`** — `src/wexample_cli/middleware/abstract_middleware.py`
166
-
167
- Base class for middleware. A middleware can add options dynamically (`append_options`), produce multiple `ExecutionContext` objects from a single request (`build_execution_contexts`), and declare whether execution should be parallel, show a progress bar, or abort on the first failure. The values `"allways"` and `"optional"` (defined in `src/wexample_cli/const/middleware.py`) allow a middleware to make a behaviour mandatory or user-selectable.
168
-
169
- **`ExecutionContext`** — `src/wexample_cli/context/execution_context.py`
170
-
171
- A single unit of work inside one dispatch. Holds `function_kwargs`, `request`, `kernel`, `middleware`, and an optional `function` override. Its `__attrs_post_init__` injects `context=self` into `function_kwargs` so every command function receives it. Also provides progress-tracking helpers (`create_progress_range`, `finish_progress`, `get_or_create_progress`).
172
-
173
- **Exceptions** — `src/wexample_cli/exception/`
174
-
175
- `CommandOptionMissingException` and `CommandOptionValidationException` both extend `AbstractCommandOptionException`. The first is raised when a required option is absent; the second when an `AbstractValidator` rejects a value.
176
-
177
- **Constants** — `src/wexample_cli/const/`
178
-
179
- - `types.py` — `ParsedArgs = dict[str, Any]`.
180
- - `middleware.py` — the `"allways"` / `"optional"` sentinel strings.
181
- - `tags.py` — `EffectTag`, `AudienceTag`, and `ScopeTag` class-level string constants for `@command(tags=[...])`.
182
-
183
- **Testing helpers** — `src/wexample_cli/testing/kernel.py`
184
-
185
- `boot_kernel(KernelClass, entrypoint_path)` and `dispatch_command(kernel, name, arguments)` exercise the full decorator and dispatch pipeline from a test, identical to a real invocation.
186
-
187
- **Helper** — `src/wexample_cli/helper/extra_args.py`
188
-
189
- `resolve_shell_command(context, command, extra_args)` — resolves a shell command string from either a `--command "..."` option or positional `-- args`, preferring the positional form.
190
-
191
- ### Call path
192
-
193
- **At import time** (decorators run):
194
-
195
- ```
196
- @alias / @as_sudo / @webhook
197
- @screenable → set_option(screen, screen_interval) + register_pipeline_wrapper(screen_wrapper)
198
- @middleware(name) → register_middleware(name, kwargs)
199
- @option(...) → set_option(Option(...))
200
- @command(type, ...) → CommandMethodWrapper(function=fn, ...)
201
- ```
202
-
203
- The resulting `CommandMethodWrapper` is what the kernel stores; `ExtendedCommand` wraps it.
204
-
205
- **At invocation** (`ExtendedCommand.execute_request`):
206
-
207
- 1. Instantiate each middleware from the kernel's `"middlewares"` registry using `middlewares_attributes`; attach it with `set_middleware` (which also extends `wrapper.options` with the middleware's own options).
208
- 2. If `--help` or `-h` is in the raw arguments, render help via `_render_help` and return.
209
- 3. `_build_function_kwargs`:
210
- - Each middleware calls `append_options` to inject any dynamic options (e.g. `--parallel`, `--progress`).
211
- - Raw arguments (list or dict) are parsed by `_parse_arguments` into `ParsedArgs`.
212
- - Each declared option is resolved from parsed args, then its default, then `CommandOptionMissingException` if required.
213
- - Each non-`None` value is run through its validators; failure raises `CommandOptionValidationException`.
214
- - If `--` passthrough tokens are present, they land in `parsed_args["__extra_args__"]` and are forwarded as `extra_args` if the function declares that parameter, otherwise `CommandUnexpectedArgumentException`.
215
- 4. Build the pipeline: `_make_dispatch` produces the innermost callable; each entry in `pipeline_wrappers` is composed around it with `_wrap_dispatch`.
216
- 5. Call `dispatch(function_kwargs)`.
217
-
218
- **Inside `_execute_dispatch`:**
219
-
220
- - With middlewares: each middleware calls `build_execution_contexts` (base returns one context; subclasses may fan out). Contexts are executed sequentially or in parallel (`asyncio` + `ThreadPoolExecutor`). Parallel runs each context with a `PromptBufferOutputHandler` so output is buffered per-context. Results accumulate in a `MultipleResponse`; a single result is unwrapped. `stop_on_failure` halts the loop early on `FailureResponse`.
221
- - Without middlewares: a single `ExecutionContext` is built by `request.resolver.build_execution_context`, and the function is called directly.
222
-
223
- In both paths, `ExecutionContext.__attrs_post_init__` injects `context=self` so the function can access `context.io`, `context.kernel`, progress handles, and the resolved `function_kwargs`.
224
-
225
- ## Integration in the Suite
226
-
227
- This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.
228
-
229
- ### Related Packages
230
-
231
- The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.
232
-
233
- ## Dependencies
234
-
235
- - attrs: >=23.1.0
236
- - wexample-app: >=19.4.0
237
- - wexample-helpers: >=20.5.0
238
- - wexample-prompt: >=16.0.0
239
-
240
- ## Versioning & Compatibility Policy
241
-
242
- Wexample packages follow **Semantic Versioning** (SemVer):
243
-
244
- - **MAJOR**: Breaking changes
245
- - **MINOR**: New features, backward compatible
246
- - **PATCH**: Bug fixes, backward compatible
247
-
248
- We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.
249
-
250
- ## License
251
-
252
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
253
-
254
- Free to use in both personal and commercial projects.
255
-
256
- ## About us
257
-
258
- [Wexample](https://wexample.com) stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.
259
-
260
- This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.
261
-
262
- Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.
263
-
264
- Built and maintained by [Romain Weeger](https://weeger.io).
265
-
266
- ## Known Limitations & Roadmap
267
-
268
- Current limitations and planned features are tracked in the GitHub issues.
269
-
270
- See the [project roadmap](https://github.com/wexample/python-cli/issues) for upcoming features and improvements.
271
-
272
- ## Status & Compatibility
273
-
274
- **Maturity**: Production-ready
275
-
276
- **Python Support**: >=3.10
277
-
278
- **OS Support**: Linux, macOS, Windows
279
-
280
- **Status**: Actively maintained
281
-
282
- ## Useful Links
283
-
284
- - **Homepage**: https://github.com/wexample/python-cli
285
- - **Issue Tracker**: https://github.com/wexample/python-cli/issues
286
- - **Discussions**: https://github.com/wexample/python-cli/discussions
287
- - **PyPI**: [pypi.org/project/wexample-cli](https://pypi.org/project/wexample-cli/)
288
-
289
- ## Migration Notes
290
-
291
- When upgrading between major versions, refer to the migration guides in the documentation.
292
-
293
- Breaking changes are clearly documented with upgrade paths and examples.
@@ -1,273 +0,0 @@
1
- # cli
2
-
3
- Version: 2.2.0
4
-
5
- `wexample-cli` supplies the decorator layer — `@command`, `@option`, and `@middleware` — that turns plain Python methods into typed, discoverable commands for kernels built on `wexample-app`. Options are declared with Python types, short names, defaults, required flags, and per-value validators; a composable middleware pipeline can fan a single invocation across multiple execution contexts, run them in parallel, and abort on the first failure. It is aimed at Python developers building or extending a `wexample-app` kernel with new CLI commands.
6
-
7
- ## Table of Contents
8
-
9
- - [Installation](#installation)
10
- - [Quickstart](#quickstart)
11
- - [Tests](#tests)
12
- - [Architecture](#architecture)
13
- - [Integration in the Suite](#integration-in-the-suite)
14
- - [Dependencies](#dependencies)
15
- - [Versioning & Compatibility Policy](#versioning--compatibility-policy)
16
- - [License](#license)
17
- - [About us](#about-us)
18
- - [Known Limitations & Roadmap](#known-limitations--roadmap)
19
- - [Status & Compatibility](#status--compatibility)
20
- - [Useful Links](#useful-links)
21
- - [Migration Notes](#migration-notes)
22
-
23
- ## Installation
24
-
25
- ```bash
26
- pip install wexample-cli
27
- ```
28
-
29
- Requires Python >=3.10.
30
-
31
- ## Quickstart
32
-
33
- Install the package:
34
-
35
- ```bash
36
- pip install wexample-cli
37
- ```
38
-
39
- Declare a command inside your kernel class. `@command` wraps the method into a `CommandMethodWrapper`; each `@option` stacks on top in outer-to-inner order to append a typed option to it.
40
-
41
- ```python
42
- from wexample_cli.decorator.command import command
43
- from wexample_cli.decorator.option import option
44
-
45
- @option(name="name", type=str, description="Who to greet", required=True)
46
- @command(type="demo", description="Print a greeting")
47
- def demo__greet(context, name: str) -> None:
48
- context.io.log(f"Hello, {name}!")
49
- ```
50
-
51
- The decorated object is a `CommandMethodWrapper`. You can inspect it immediately:
52
-
53
- ```python
54
- demo__greet.description # "Print a greeting"
55
- demo__greet.options[0].name # "name"
56
- ```
57
-
58
- The kernel maps the function name `demo__greet` to the command path `demo/greet`. To exercise the full decorator and middleware pipeline in a test, use the helpers in src/wexample_cli/testing/kernel.py:
59
-
60
- ```python
61
- from wexample_cli.testing.kernel import boot_kernel, dispatch_command
62
-
63
- kernel = boot_kernel(MyKernel, entrypoint_path="/path/to/__main__.py")
64
- response = dispatch_command(kernel, "demo/greet", {"name": "world"})
65
- ```
66
-
67
- `dispatch_command` accepts pre-parsed kwargs (`{"name": "world"}`) or CLI-style strings (`["--name", "world"]`).
68
-
69
- ## Tests
70
-
71
- This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.
72
-
73
- ### Installation
74
-
75
- First, install the required testing dependencies:
76
- ```bash
77
- .venv/bin/python -m pip install pytest pytest-cov
78
- ```
79
-
80
- ### Basic Usage
81
-
82
- Run all tests with coverage:
83
- ```bash
84
- .venv/bin/python -m pytest --cov --cov-report=html
85
- ```
86
-
87
- ### Common Commands
88
- ```bash
89
- # Run tests with coverage for a specific module
90
- .venv/bin/python -m pytest --cov=your_module
91
-
92
- # Show which lines are not covered
93
- .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing
94
-
95
- # Generate an HTML coverage report
96
- .venv/bin/python -m pytest --cov=your_module --cov-report=html
97
-
98
- # Combine terminal and HTML reports
99
- .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html
100
-
101
- # Run specific test file with coverage
102
- .venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
103
- ```
104
-
105
- ### Viewing HTML Reports
106
-
107
- After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.
108
-
109
- ### Coverage Threshold
110
-
111
- To enforce a minimum coverage percentage:
112
- ```bash
113
- .venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
114
- ```
115
-
116
- This will cause the test suite to fail if coverage drops below 80%.
117
-
118
- ## Architecture
119
-
120
- `wexample-cli` is a decorator and dispatch layer that sits between a `wexample-app` kernel and the Python functions that implement its commands. It has no entry-point of its own; downstream kernels import its decorators, wrap their methods, and pass the resulting objects to the kernel's registration machinery.
121
-
122
- ### Parts
123
-
124
- **Decorators** — `src/wexample_cli/decorator/`
125
-
126
- The decorators are the only thing a command author touches directly. Applied bottom-to-top on a plain function, they produce a `CommandMethodWrapper`:
127
-
128
- - `@command(type, description, tags)` — creates the wrapper; must be the innermost decorator.
129
- - `@option(name, type, ...)` — calls `wrapper.set_option(Option(...))` to append a typed option.
130
- - `@middleware(name, **kwargs)` — calls `wrapper.register_middleware(name, kwargs)` to schedule a middleware class at runtime.
131
- - `@alias(*names)` — extends `wrapper.aliases`.
132
- - `@screenable(interval, height)` — adds `--screen` and `--screen-interval` options and pushes a pipeline wrapper that drives a refresh loop.
133
- - `@as_sudo()` — sets `wrapper.sudo = True`.
134
- - `@webhook()` — sets `wrapper.webhook = True`.
135
- - `@option_stop_on_failure()` — adds a `--stop-on-failure` flag option.
136
-
137
- **`CommandMethodWrapper`** — `src/wexample_cli/common/command_method_wrapper.py`
138
-
139
- The data structure produced by decoration. It carries everything the runtime needs: `function`, `options`, `middlewares_attributes` (names → init-kwargs, resolved at call time), `pipeline_wrappers` (registered in outer-to-inner order), `aliases`, `tags`, and the boolean flags `sudo` and `webhook`. It owns no execution logic.
140
-
141
- **`ExtendedCommand`** — `src/wexample_cli/command/extended_command.py`
142
-
143
- The runtime command object registered with the kernel; extends `wexample_app.common.command.Command`. It owns the full execution path for one `CommandRequest`.
144
-
145
- **`AbstractMiddleware`** — `src/wexample_cli/middleware/abstract_middleware.py`
146
-
147
- Base class for middleware. A middleware can add options dynamically (`append_options`), produce multiple `ExecutionContext` objects from a single request (`build_execution_contexts`), and declare whether execution should be parallel, show a progress bar, or abort on the first failure. The values `"allways"` and `"optional"` (defined in `src/wexample_cli/const/middleware.py`) allow a middleware to make a behaviour mandatory or user-selectable.
148
-
149
- **`ExecutionContext`** — `src/wexample_cli/context/execution_context.py`
150
-
151
- A single unit of work inside one dispatch. Holds `function_kwargs`, `request`, `kernel`, `middleware`, and an optional `function` override. Its `__attrs_post_init__` injects `context=self` into `function_kwargs` so every command function receives it. Also provides progress-tracking helpers (`create_progress_range`, `finish_progress`, `get_or_create_progress`).
152
-
153
- **Exceptions** — `src/wexample_cli/exception/`
154
-
155
- `CommandOptionMissingException` and `CommandOptionValidationException` both extend `AbstractCommandOptionException`. The first is raised when a required option is absent; the second when an `AbstractValidator` rejects a value.
156
-
157
- **Constants** — `src/wexample_cli/const/`
158
-
159
- - `types.py` — `ParsedArgs = dict[str, Any]`.
160
- - `middleware.py` — the `"allways"` / `"optional"` sentinel strings.
161
- - `tags.py` — `EffectTag`, `AudienceTag`, and `ScopeTag` class-level string constants for `@command(tags=[...])`.
162
-
163
- **Testing helpers** — `src/wexample_cli/testing/kernel.py`
164
-
165
- `boot_kernel(KernelClass, entrypoint_path)` and `dispatch_command(kernel, name, arguments)` exercise the full decorator and dispatch pipeline from a test, identical to a real invocation.
166
-
167
- **Helper** — `src/wexample_cli/helper/extra_args.py`
168
-
169
- `resolve_shell_command(context, command, extra_args)` — resolves a shell command string from either a `--command "..."` option or positional `-- args`, preferring the positional form.
170
-
171
- ### Call path
172
-
173
- **At import time** (decorators run):
174
-
175
- ```
176
- @alias / @as_sudo / @webhook
177
- @screenable → set_option(screen, screen_interval) + register_pipeline_wrapper(screen_wrapper)
178
- @middleware(name) → register_middleware(name, kwargs)
179
- @option(...) → set_option(Option(...))
180
- @command(type, ...) → CommandMethodWrapper(function=fn, ...)
181
- ```
182
-
183
- The resulting `CommandMethodWrapper` is what the kernel stores; `ExtendedCommand` wraps it.
184
-
185
- **At invocation** (`ExtendedCommand.execute_request`):
186
-
187
- 1. Instantiate each middleware from the kernel's `"middlewares"` registry using `middlewares_attributes`; attach it with `set_middleware` (which also extends `wrapper.options` with the middleware's own options).
188
- 2. If `--help` or `-h` is in the raw arguments, render help via `_render_help` and return.
189
- 3. `_build_function_kwargs`:
190
- - Each middleware calls `append_options` to inject any dynamic options (e.g. `--parallel`, `--progress`).
191
- - Raw arguments (list or dict) are parsed by `_parse_arguments` into `ParsedArgs`.
192
- - Each declared option is resolved from parsed args, then its default, then `CommandOptionMissingException` if required.
193
- - Each non-`None` value is run through its validators; failure raises `CommandOptionValidationException`.
194
- - If `--` passthrough tokens are present, they land in `parsed_args["__extra_args__"]` and are forwarded as `extra_args` if the function declares that parameter, otherwise `CommandUnexpectedArgumentException`.
195
- 4. Build the pipeline: `_make_dispatch` produces the innermost callable; each entry in `pipeline_wrappers` is composed around it with `_wrap_dispatch`.
196
- 5. Call `dispatch(function_kwargs)`.
197
-
198
- **Inside `_execute_dispatch`:**
199
-
200
- - With middlewares: each middleware calls `build_execution_contexts` (base returns one context; subclasses may fan out). Contexts are executed sequentially or in parallel (`asyncio` + `ThreadPoolExecutor`). Parallel runs each context with a `PromptBufferOutputHandler` so output is buffered per-context. Results accumulate in a `MultipleResponse`; a single result is unwrapped. `stop_on_failure` halts the loop early on `FailureResponse`.
201
- - Without middlewares: a single `ExecutionContext` is built by `request.resolver.build_execution_context`, and the function is called directly.
202
-
203
- In both paths, `ExecutionContext.__attrs_post_init__` injects `context=self` so the function can access `context.io`, `context.kernel`, progress handles, and the resolved `function_kwargs`.
204
-
205
- ## Integration in the Suite
206
-
207
- This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.
208
-
209
- ### Related Packages
210
-
211
- The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.
212
-
213
- ## Dependencies
214
-
215
- - attrs: >=23.1.0
216
- - wexample-app: >=19.4.0
217
- - wexample-helpers: >=20.5.0
218
- - wexample-prompt: >=16.0.0
219
-
220
- ## Versioning & Compatibility Policy
221
-
222
- Wexample packages follow **Semantic Versioning** (SemVer):
223
-
224
- - **MAJOR**: Breaking changes
225
- - **MINOR**: New features, backward compatible
226
- - **PATCH**: Bug fixes, backward compatible
227
-
228
- We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.
229
-
230
- ## License
231
-
232
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
233
-
234
- Free to use in both personal and commercial projects.
235
-
236
- ## About us
237
-
238
- [Wexample](https://wexample.com) stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.
239
-
240
- This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.
241
-
242
- Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.
243
-
244
- Built and maintained by [Romain Weeger](https://weeger.io).
245
-
246
- ## Known Limitations & Roadmap
247
-
248
- Current limitations and planned features are tracked in the GitHub issues.
249
-
250
- See the [project roadmap](https://github.com/wexample/python-cli/issues) for upcoming features and improvements.
251
-
252
- ## Status & Compatibility
253
-
254
- **Maturity**: Production-ready
255
-
256
- **Python Support**: >=3.10
257
-
258
- **OS Support**: Linux, macOS, Windows
259
-
260
- **Status**: Actively maintained
261
-
262
- ## Useful Links
263
-
264
- - **Homepage**: https://github.com/wexample/python-cli
265
- - **Issue Tracker**: https://github.com/wexample/python-cli/issues
266
- - **Discussions**: https://github.com/wexample/python-cli/discussions
267
- - **PyPI**: [pypi.org/project/wexample-cli](https://pypi.org/project/wexample-cli/)
268
-
269
- ## Migration Notes
270
-
271
- When upgrading between major versions, refer to the migration guides in the documentation.
272
-
273
- Breaking changes are clearly documented with upgrade paths and examples.