cli-wizard 2.1.0__tar.gz → 3.0.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.
- {cli_wizard-2.1.0/src/cli_wizard.egg-info → cli_wizard-3.0.0}/PKG-INFO +79 -49
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/README.md +77 -31
- cli_wizard-3.0.0/VERSION +1 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/pyproject.toml +40 -14
- cli_wizard-3.0.0/src/cli_wizard/cli.py +67 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/commands/bootstrap.py +105 -175
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/commands/common.py +13 -6
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/commands/config.py +10 -9
- cli_wizard-3.0.0/src/cli_wizard/commands/generate.py +243 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/config/configuration.py +6 -6
- cli_wizard-3.0.0/src/cli_wizard/config/project.py +100 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/config/schema.py +43 -7
- cli_wizard-3.0.0/src/cli_wizard/errors.py +137 -0
- cli_wizard-3.0.0/src/cli_wizard/generator/generator.py +688 -0
- cli_wizard-3.0.0/src/cli_wizard/generator/models.py +220 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/generator/parser.py +75 -28
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/workflows/docs.yaml.j2 +1 -1
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/workflows/pr-validation.yaml.j2 +5 -3
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/workflows/test.yaml.j2 +1 -1
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/CHANGELOG.md.j2 +0 -4
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/DEVELOPMENT.md.j2 +34 -1
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/Makefile.j2 +2 -1
- cli_wizard-3.0.0/src/cli_wizard/templates/README.md.j2 +168 -0
- cli_wizard-3.0.0/src/cli_wizard/templates/pre-commit-config.yaml.j2 +30 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/pyproject.toml.j2 +34 -18
- cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/cli.py.j2 +94 -0
- cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/client.py.j2 +326 -0
- cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/commands/__init__.py.j2 +4 -0
- cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/commands/config.py.j2 +146 -0
- cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/commands/group.py.j2 +185 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/src/{{ PackageName }}/constants.py.j2 +40 -18
- cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/errors.py.j2 +149 -0
- cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/log.py.j2 +189 -0
- cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/options.py.j2 +123 -0
- cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/output.py.j2 +158 -0
- cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/profile.py.j2 +283 -0
- cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/redaction.py.j2 +88 -0
- cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/runner.py.j2 +77 -0
- cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/state.py.j2 +41 -0
- cli_wizard-3.0.0/src/cli_wizard/templates/tests/{{ PackageName }}/cli_test.py.j2 +2049 -0
- cli_wizard-3.0.0/src/cli_wizard/templates/tests/{{ PackageName }}/commands_test.py.j2 +73 -0
- cli_wizard-3.0.0/src/cli_wizard/templates/tox.ini.j2 +31 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0/src/cli_wizard.egg-info}/PKG-INFO +79 -49
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard.egg-info/SOURCES.txt +11 -2
- cli_wizard-3.0.0/src/cli_wizard.egg-info/requires.txt +6 -0
- cli_wizard-2.1.0/VERSION +0 -1
- cli_wizard-2.1.0/src/cli_wizard/cli.py +0 -41
- cli_wizard-2.1.0/src/cli_wizard/commands/generate.py +0 -263
- cli_wizard-2.1.0/src/cli_wizard/generator/generator.py +0 -532
- cli_wizard-2.1.0/src/cli_wizard/generator/models.py +0 -126
- cli_wizard-2.1.0/src/cli_wizard/templates/README.md.j2 +0 -23
- cli_wizard-2.1.0/src/cli_wizard/templates/pre-commit-config.yaml.j2 +0 -23
- cli_wizard-2.1.0/src/cli_wizard/templates/src/{{ PackageName }}/cli.py.j2 +0 -106
- cli_wizard-2.1.0/src/cli_wizard/templates/src/{{ PackageName }}/client.py.j2 +0 -150
- cli_wizard-2.1.0/src/cli_wizard/templates/src/{{ PackageName }}/commands/__init__.py.j2 +0 -14
- cli_wizard-2.1.0/src/cli_wizard/templates/src/{{ PackageName }}/commands/config.py.j2 +0 -384
- cli_wizard-2.1.0/src/cli_wizard/templates/src/{{ PackageName }}/commands/group.py.j2 +0 -272
- cli_wizard-2.1.0/src/cli_wizard/templates/src/{{ PackageName }}/logging.py.j2 +0 -183
- cli_wizard-2.1.0/src/cli_wizard/templates/src/{{ PackageName }}/profile.py.j2 +0 -93
- cli_wizard-2.1.0/src/cli_wizard/templates/tests/{{ PackageName }}/cli_test.py.j2 +0 -1163
- cli_wizard-2.1.0/src/cli_wizard/templates/tox.ini.j2 +0 -27
- cli_wizard-2.1.0/src/cli_wizard.egg-info/requires.txt +0 -24
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/LICENSE +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/MANIFEST.in +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/setup.cfg +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/__init__.py +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/commands/__init__.py +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/config/__init__.py +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/constants.py +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/generator/__init__.py +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/CODEOWNERS.j2 +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/ISSUE_TEMPLATE/bug-report.yml.j2 +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/ISSUE_TEMPLATE/config.yml.j2 +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/ISSUE_TEMPLATE/feature-request.yml.j2 +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/dependabot.yaml +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/labeler.yaml +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/labels.yaml.j2 +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/workflows/changelog-enforcer.yaml +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/workflows/codeql.yaml +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/workflows/labeler.yaml +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/workflows/release.yaml.j2 +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/workflows/sync-labels.yaml +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.gitignore.j2 +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/LICENSE.j2 +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/MANIFEST.in.j2 +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/VERSION.j2 +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/cli-wizard.yaml.j2 +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/src/{{ PackageName }}/__init__.py.j2 +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard.egg-info/dependency_links.txt +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard.egg-info/entry_points.txt +0 -0
- {cli_wizard-2.1.0 → cli_wizard-3.0.0}/src/cli_wizard.egg-info/top_level.txt +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cli-wizard
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: Generate modern CLIs from OpenAPI specifications
|
|
5
5
|
Author-email: Giacomo Marciani <giacomo.marciani@gmail.com>
|
|
6
6
|
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.
|
|
7
|
+
Project-URL: Homepage, https://gmarciani.github.io/cli-wizard/
|
|
8
8
|
Project-URL: Repository, https://github.com/gmarciani/cli-wizard
|
|
9
9
|
Project-URL: Issues, https://github.com/gmarciani/cli-wizard/issues
|
|
10
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
@@ -23,22 +23,6 @@ Requires-Dist: pydantic~=2.13
|
|
|
23
23
|
Requires-Dist: PyYAML~=6.0
|
|
24
24
|
Requires-Dist: requests~=2.34
|
|
25
25
|
Requires-Dist: ruff~=0.16.2
|
|
26
|
-
Provides-Extra: dev
|
|
27
|
-
Requires-Dist: build~=1.5; extra == "dev"
|
|
28
|
-
Requires-Dist: mypy~=2.3; extra == "dev"
|
|
29
|
-
Requires-Dist: pre-commit~=4.6; extra == "dev"
|
|
30
|
-
Requires-Dist: pytest~=9.1; extra == "dev"
|
|
31
|
-
Requires-Dist: pytest-cov~=7.1; extra == "dev"
|
|
32
|
-
Requires-Dist: tox~=4.58; extra == "dev"
|
|
33
|
-
Requires-Dist: twine<8.0,>=6.2; extra == "dev"
|
|
34
|
-
Requires-Dist: types-PyYAML~=6.0; extra == "dev"
|
|
35
|
-
Requires-Dist: types-requests~=2.33; extra == "dev"
|
|
36
|
-
Provides-Extra: docs
|
|
37
|
-
Requires-Dist: sphinx~=9.1; extra == "docs"
|
|
38
|
-
Requires-Dist: sphinx-click~=6.2; extra == "docs"
|
|
39
|
-
Requires-Dist: sphinx-rtd-theme~=3.1; extra == "docs"
|
|
40
|
-
Requires-Dist: sphinx-new-tab-link~=0.8; extra == "docs"
|
|
41
|
-
Requires-Dist: autodoc_pydantic~=2.2; extra == "docs"
|
|
42
26
|
Dynamic: license-file
|
|
43
27
|
|
|
44
28
|
# CLI WIZARD
|
|
@@ -47,7 +31,7 @@ Dynamic: license-file
|
|
|
47
31
|
<img src="https://raw.githubusercontent.com/gmarciani/cli-wizard/main/resources/brand/banner.png" alt="cli-wizard-banner" width="500">
|
|
48
32
|
|
|
49
33
|
[](https://pypi.org/project/cli-wizard)
|
|
50
|
-
[](https://pypi.org/project/cli-wizard)
|
|
51
35
|
[](https://github.com/gmarciani/cli-wizard/blob/main/LICENSE)
|
|
52
36
|
[](https://github.com/gmarciani/cli-wizard/actions)
|
|
53
37
|
[](https://github.com/gmarciani/cli-wizard/actions)
|
|
@@ -76,7 +60,7 @@ Generate modern CLIs from OpenAPI specifications.
|
|
|
76
60
|
- Automatic command grouping based on OpenAPI tags
|
|
77
61
|
- Automatic help generation for all commands
|
|
78
62
|
- Clean, colored terminal output
|
|
79
|
-
- `--debug` flag for verbose logging
|
|
63
|
+
- `--debug` flag for verbose logging, with credentials redacted from the output
|
|
80
64
|
- Built-in API client with configurable base URL and timeout
|
|
81
65
|
- SSL/TLS support with custom CA certificate bundles
|
|
82
66
|
- `--ca-file` option to specify custom CA certificates at runtime
|
|
@@ -92,7 +76,13 @@ Generate modern CLIs from OpenAPI specifications.
|
|
|
92
76
|
|
|
93
77
|
### Developer Experience
|
|
94
78
|
- Generated projects are pip-installable out of the box
|
|
95
|
-
- Auto-generated `pyproject.toml
|
|
79
|
+
- Auto-generated `pyproject.toml` and `VERSION`
|
|
80
|
+
- Auto-generated `README.md` with commands and configuration reference
|
|
81
|
+
- Auto-generated `DEVELOPMENT.md`, `CHANGELOG.md` and `LICENSE`
|
|
82
|
+
- Test suite for the generated CLI, ready to run
|
|
83
|
+
- `tox.ini` with test, lint, type, format and coverage environments, plus a `Makefile` wrapping them
|
|
84
|
+
- Pre-commit configuration running ruff and mypy
|
|
85
|
+
- Optional GitHub setup (`IncludeGithubWorkflows`): test, release, docs, PR validation, CodeQL, changelog and labeler workflows, plus Dependabot, issue and PR templates, and `CODEOWNERS`
|
|
96
86
|
- Resources (CA certs, splash files) bundled in the package
|
|
97
87
|
- Profile management for storing credentials and settings
|
|
98
88
|
|
|
@@ -125,51 +115,74 @@ paths:
|
|
|
125
115
|
description: OK
|
|
126
116
|
```
|
|
127
117
|
|
|
128
|
-
### Step 2:
|
|
118
|
+
### Step 2: Generate the CLI
|
|
129
119
|
|
|
130
|
-
|
|
120
|
+
Run the `generate` command, passing the OpenAPI spec and a project name:
|
|
121
|
+
|
|
122
|
+
```shell
|
|
123
|
+
cli-wizard generate --api openapi.yaml --project-name "My CLI"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
This creates a complete Python CLI project in the `my-cli` directory: the
|
|
127
|
+
command name derives from the project name, and every other setting takes its
|
|
128
|
+
default. Pass `--output` to write it elsewhere.
|
|
129
|
+
|
|
130
|
+
### Step 3: Install the Generated CLI
|
|
131
|
+
|
|
132
|
+
Navigate to the generated project and install it:
|
|
133
|
+
|
|
134
|
+
```shell
|
|
135
|
+
pip install -e my-cli
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Step 4: Use Your CLI
|
|
139
|
+
|
|
140
|
+
Your CLI is now ready to use:
|
|
141
|
+
|
|
142
|
+
```shell
|
|
143
|
+
my-cli --help
|
|
144
|
+
my-cli users list-users
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Step 5: Customize with a Configuration File
|
|
148
|
+
|
|
149
|
+
To go beyond the defaults, create a `cli-wizard.yaml` file with the settings you
|
|
150
|
+
want to change. Every parameter is optional:
|
|
131
151
|
|
|
132
152
|
```yaml
|
|
133
|
-
|
|
134
|
-
PackageName: "my-cli"
|
|
153
|
+
ProjectName: "My CLI"
|
|
135
154
|
DefaultBaseUrl: "https://api.example.com"
|
|
136
155
|
|
|
137
|
-
#
|
|
156
|
+
# Customize the splash screen
|
|
138
157
|
SplashFile: "splash.txt"
|
|
139
158
|
SplashColor: "#00FFFF"
|
|
140
159
|
|
|
141
|
-
#
|
|
160
|
+
# Filter which tags to include
|
|
142
161
|
IncludeTags:
|
|
143
162
|
- Users
|
|
144
163
|
- Products
|
|
145
164
|
```
|
|
146
165
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
Run the `generate` command:
|
|
166
|
+
Then generate from it. The project lands in the current directory, in a
|
|
167
|
+
directory named after `CommandName`:
|
|
150
168
|
|
|
151
169
|
```shell
|
|
152
|
-
cli-wizard generate --
|
|
170
|
+
cli-wizard generate --configuration cli-wizard.yaml --api openapi.yaml
|
|
153
171
|
```
|
|
154
172
|
|
|
155
|
-
|
|
173
|
+
### Starting Without a Specification
|
|
156
174
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
175
|
+
To start from scratch instead, run `bootstrap`. It prompts for the main
|
|
176
|
+
settings, writes a commented `cli-wizard.yaml`, and generates a basic CLI from
|
|
177
|
+
it, without API commands. The CLI lands in the current directory, in a
|
|
178
|
+
directory named after `CommandName`; pass `--output` to write it elsewhere:
|
|
160
179
|
|
|
161
180
|
```shell
|
|
162
|
-
|
|
181
|
+
cli-wizard bootstrap --configuration cli-wizard.yaml
|
|
163
182
|
```
|
|
164
183
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
Your CLI is now ready to use:
|
|
168
|
-
|
|
169
|
-
```shell
|
|
170
|
-
my-cli --help
|
|
171
|
-
my-cli users list-users
|
|
172
|
-
```
|
|
184
|
+
Then edit the configuration, point `Api` at your specification, and rebuild
|
|
185
|
+
with `cli-wizard generate --configuration cli-wizard.yaml`.
|
|
173
186
|
|
|
174
187
|
## Configuration
|
|
175
188
|
|
|
@@ -180,17 +193,34 @@ See the [examples](examples/) directory for complete configuration examples.
|
|
|
180
193
|
|
|
181
194
|
### cli-wizard generate
|
|
182
195
|
|
|
183
|
-
Generate a CLI from an OpenAPI specification
|
|
196
|
+
Generate a CLI from an OpenAPI specification, with an optional configuration file.
|
|
184
197
|
|
|
185
198
|
```shell
|
|
186
199
|
cli-wizard generate [OPTIONS]
|
|
187
200
|
```
|
|
188
201
|
|
|
189
202
|
Options:
|
|
190
|
-
- `--
|
|
191
|
-
- `--
|
|
192
|
-
- `--
|
|
193
|
-
- `--
|
|
203
|
+
- `--api, -a` - Path to the OpenAPI spec file, YAML or JSON. Without it and without `Api` in the configuration, the CLI is generated without API commands
|
|
204
|
+
- `--configuration, -c` - Path to the `cli-wizard.yaml` configuration file. Without it, every parameter takes its default
|
|
205
|
+
- `--project-name, -p` - Human-readable project name; the generated command name derives from it, unless the configuration sets it
|
|
206
|
+
- `--output, -o` - Output directory (default: a directory named after `CommandName` in the current directory)
|
|
207
|
+
- `--force, -f` - Skip the confirmation prompt when the output directory is not empty
|
|
208
|
+
|
|
209
|
+
### cli-wizard bootstrap
|
|
210
|
+
|
|
211
|
+
Bootstrap a new CLI project interactively, without an OpenAPI specification.
|
|
212
|
+
It does two things: it writes a configuration file to evolve the project from,
|
|
213
|
+
then generates a basic CLI from that file, without API commands, in the output
|
|
214
|
+
directory.
|
|
215
|
+
|
|
216
|
+
```shell
|
|
217
|
+
cli-wizard bootstrap [OPTIONS]
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Options:
|
|
221
|
+
- `--configuration, -c` - Path for the `cli-wizard.yaml` configuration file (default: `./cli-wizard.yaml`). An existing file is overwritten, after confirmation, without keeping any of its values
|
|
222
|
+
- `--output, -o` - Output directory of the basic CLI (default: a directory named after `CommandName` in the current directory)
|
|
223
|
+
- `--force, -f` - Skip the confirmation prompts to overwrite an existing configuration file or to write into a non-empty directory
|
|
194
224
|
|
|
195
225
|
## Issues
|
|
196
226
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<img src="https://raw.githubusercontent.com/gmarciani/cli-wizard/main/resources/brand/banner.png" alt="cli-wizard-banner" width="500">
|
|
5
5
|
|
|
6
6
|
[](https://pypi.org/project/cli-wizard)
|
|
7
|
-
[](https://pypi.org/project/cli-wizard)
|
|
8
8
|
[](https://github.com/gmarciani/cli-wizard/blob/main/LICENSE)
|
|
9
9
|
[](https://github.com/gmarciani/cli-wizard/actions)
|
|
10
10
|
[](https://github.com/gmarciani/cli-wizard/actions)
|
|
@@ -33,7 +33,7 @@ Generate modern CLIs from OpenAPI specifications.
|
|
|
33
33
|
- Automatic command grouping based on OpenAPI tags
|
|
34
34
|
- Automatic help generation for all commands
|
|
35
35
|
- Clean, colored terminal output
|
|
36
|
-
- `--debug` flag for verbose logging
|
|
36
|
+
- `--debug` flag for verbose logging, with credentials redacted from the output
|
|
37
37
|
- Built-in API client with configurable base URL and timeout
|
|
38
38
|
- SSL/TLS support with custom CA certificate bundles
|
|
39
39
|
- `--ca-file` option to specify custom CA certificates at runtime
|
|
@@ -49,7 +49,13 @@ Generate modern CLIs from OpenAPI specifications.
|
|
|
49
49
|
|
|
50
50
|
### Developer Experience
|
|
51
51
|
- Generated projects are pip-installable out of the box
|
|
52
|
-
- Auto-generated `pyproject.toml
|
|
52
|
+
- Auto-generated `pyproject.toml` and `VERSION`
|
|
53
|
+
- Auto-generated `README.md` with commands and configuration reference
|
|
54
|
+
- Auto-generated `DEVELOPMENT.md`, `CHANGELOG.md` and `LICENSE`
|
|
55
|
+
- Test suite for the generated CLI, ready to run
|
|
56
|
+
- `tox.ini` with test, lint, type, format and coverage environments, plus a `Makefile` wrapping them
|
|
57
|
+
- Pre-commit configuration running ruff and mypy
|
|
58
|
+
- Optional GitHub setup (`IncludeGithubWorkflows`): test, release, docs, PR validation, CodeQL, changelog and labeler workflows, plus Dependabot, issue and PR templates, and `CODEOWNERS`
|
|
53
59
|
- Resources (CA certs, splash files) bundled in the package
|
|
54
60
|
- Profile management for storing credentials and settings
|
|
55
61
|
|
|
@@ -82,51 +88,74 @@ paths:
|
|
|
82
88
|
description: OK
|
|
83
89
|
```
|
|
84
90
|
|
|
85
|
-
### Step 2:
|
|
91
|
+
### Step 2: Generate the CLI
|
|
86
92
|
|
|
87
|
-
|
|
93
|
+
Run the `generate` command, passing the OpenAPI spec and a project name:
|
|
94
|
+
|
|
95
|
+
```shell
|
|
96
|
+
cli-wizard generate --api openapi.yaml --project-name "My CLI"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
This creates a complete Python CLI project in the `my-cli` directory: the
|
|
100
|
+
command name derives from the project name, and every other setting takes its
|
|
101
|
+
default. Pass `--output` to write it elsewhere.
|
|
102
|
+
|
|
103
|
+
### Step 3: Install the Generated CLI
|
|
104
|
+
|
|
105
|
+
Navigate to the generated project and install it:
|
|
106
|
+
|
|
107
|
+
```shell
|
|
108
|
+
pip install -e my-cli
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Step 4: Use Your CLI
|
|
112
|
+
|
|
113
|
+
Your CLI is now ready to use:
|
|
114
|
+
|
|
115
|
+
```shell
|
|
116
|
+
my-cli --help
|
|
117
|
+
my-cli users list-users
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Step 5: Customize with a Configuration File
|
|
121
|
+
|
|
122
|
+
To go beyond the defaults, create a `cli-wizard.yaml` file with the settings you
|
|
123
|
+
want to change. Every parameter is optional:
|
|
88
124
|
|
|
89
125
|
```yaml
|
|
90
|
-
|
|
91
|
-
PackageName: "my-cli"
|
|
126
|
+
ProjectName: "My CLI"
|
|
92
127
|
DefaultBaseUrl: "https://api.example.com"
|
|
93
128
|
|
|
94
|
-
#
|
|
129
|
+
# Customize the splash screen
|
|
95
130
|
SplashFile: "splash.txt"
|
|
96
131
|
SplashColor: "#00FFFF"
|
|
97
132
|
|
|
98
|
-
#
|
|
133
|
+
# Filter which tags to include
|
|
99
134
|
IncludeTags:
|
|
100
135
|
- Users
|
|
101
136
|
- Products
|
|
102
137
|
```
|
|
103
138
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
Run the `generate` command:
|
|
139
|
+
Then generate from it. The project lands in the current directory, in a
|
|
140
|
+
directory named after `CommandName`:
|
|
107
141
|
|
|
108
142
|
```shell
|
|
109
|
-
cli-wizard generate --
|
|
143
|
+
cli-wizard generate --configuration cli-wizard.yaml --api openapi.yaml
|
|
110
144
|
```
|
|
111
145
|
|
|
112
|
-
|
|
146
|
+
### Starting Without a Specification
|
|
113
147
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
148
|
+
To start from scratch instead, run `bootstrap`. It prompts for the main
|
|
149
|
+
settings, writes a commented `cli-wizard.yaml`, and generates a basic CLI from
|
|
150
|
+
it, without API commands. The CLI lands in the current directory, in a
|
|
151
|
+
directory named after `CommandName`; pass `--output` to write it elsewhere:
|
|
117
152
|
|
|
118
153
|
```shell
|
|
119
|
-
|
|
154
|
+
cli-wizard bootstrap --configuration cli-wizard.yaml
|
|
120
155
|
```
|
|
121
156
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
Your CLI is now ready to use:
|
|
125
|
-
|
|
126
|
-
```shell
|
|
127
|
-
my-cli --help
|
|
128
|
-
my-cli users list-users
|
|
129
|
-
```
|
|
157
|
+
Then edit the configuration, point `Api` at your specification, and rebuild
|
|
158
|
+
with `cli-wizard generate --configuration cli-wizard.yaml`.
|
|
130
159
|
|
|
131
160
|
## Configuration
|
|
132
161
|
|
|
@@ -137,17 +166,34 @@ See the [examples](examples/) directory for complete configuration examples.
|
|
|
137
166
|
|
|
138
167
|
### cli-wizard generate
|
|
139
168
|
|
|
140
|
-
Generate a CLI from an OpenAPI specification
|
|
169
|
+
Generate a CLI from an OpenAPI specification, with an optional configuration file.
|
|
141
170
|
|
|
142
171
|
```shell
|
|
143
172
|
cli-wizard generate [OPTIONS]
|
|
144
173
|
```
|
|
145
174
|
|
|
146
175
|
Options:
|
|
147
|
-
- `--
|
|
148
|
-
- `--
|
|
149
|
-
- `--
|
|
150
|
-
- `--
|
|
176
|
+
- `--api, -a` - Path to the OpenAPI spec file, YAML or JSON. Without it and without `Api` in the configuration, the CLI is generated without API commands
|
|
177
|
+
- `--configuration, -c` - Path to the `cli-wizard.yaml` configuration file. Without it, every parameter takes its default
|
|
178
|
+
- `--project-name, -p` - Human-readable project name; the generated command name derives from it, unless the configuration sets it
|
|
179
|
+
- `--output, -o` - Output directory (default: a directory named after `CommandName` in the current directory)
|
|
180
|
+
- `--force, -f` - Skip the confirmation prompt when the output directory is not empty
|
|
181
|
+
|
|
182
|
+
### cli-wizard bootstrap
|
|
183
|
+
|
|
184
|
+
Bootstrap a new CLI project interactively, without an OpenAPI specification.
|
|
185
|
+
It does two things: it writes a configuration file to evolve the project from,
|
|
186
|
+
then generates a basic CLI from that file, without API commands, in the output
|
|
187
|
+
directory.
|
|
188
|
+
|
|
189
|
+
```shell
|
|
190
|
+
cli-wizard bootstrap [OPTIONS]
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Options:
|
|
194
|
+
- `--configuration, -c` - Path for the `cli-wizard.yaml` configuration file (default: `./cli-wizard.yaml`). An existing file is overwritten, after confirmation, without keeping any of its values
|
|
195
|
+
- `--output, -o` - Output directory of the basic CLI (default: a directory named after `CommandName` in the current directory)
|
|
196
|
+
- `--force, -f` - Skip the confirmation prompts to overwrite an existing configuration file or to write into a non-empty directory
|
|
151
197
|
|
|
152
198
|
## Issues
|
|
153
199
|
|
cli_wizard-3.0.0/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.0.0
|
|
@@ -30,15 +30,32 @@ dependencies = [
|
|
|
30
30
|
"ruff~=0.16.2",
|
|
31
31
|
]
|
|
32
32
|
|
|
33
|
-
[project.
|
|
33
|
+
[project.scripts]
|
|
34
|
+
cli-wizard = "cli_wizard.cli:main"
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://gmarciani.github.io/cli-wizard/"
|
|
38
|
+
Repository = "https://github.com/gmarciani/cli-wizard"
|
|
39
|
+
Issues = "https://github.com/gmarciani/cli-wizard/issues"
|
|
40
|
+
|
|
41
|
+
# Local-only tooling (PEP 735). Groups are never published, so none of this
|
|
42
|
+
# reaches anyone installing cli-wizard from an index. There are no extras: the
|
|
43
|
+
# built distributions carry no tests, so a published test extra would only
|
|
44
|
+
# install pytest for a consumer with nothing to run it against.
|
|
45
|
+
[dependency-groups]
|
|
34
46
|
dev = [
|
|
47
|
+
{include-group = "test"},
|
|
48
|
+
{include-group = "docs"},
|
|
35
49
|
"build~=1.5",
|
|
36
|
-
"mypy~=2.3",
|
|
37
50
|
"pre-commit~=4.6",
|
|
38
|
-
"pytest~=9.1",
|
|
39
|
-
"pytest-cov~=7.1",
|
|
40
51
|
"tox~=4.58",
|
|
41
52
|
"twine>=6.2,<8.0",
|
|
53
|
+
]
|
|
54
|
+
# mypy and the stubs too: the suite type checks the code it generates.
|
|
55
|
+
test = [
|
|
56
|
+
"mypy~=2.3",
|
|
57
|
+
"pytest~=9.1",
|
|
58
|
+
"pytest-cov~=7.1",
|
|
42
59
|
"types-PyYAML~=6.0",
|
|
43
60
|
"types-requests~=2.33",
|
|
44
61
|
]
|
|
@@ -50,14 +67,6 @@ docs = [
|
|
|
50
67
|
"autodoc_pydantic~=2.2",
|
|
51
68
|
]
|
|
52
69
|
|
|
53
|
-
[project.scripts]
|
|
54
|
-
cli-wizard = "cli_wizard.cli:main"
|
|
55
|
-
|
|
56
|
-
[project.urls]
|
|
57
|
-
Homepage = "https://github.com/gmarciani/cli-wizard"
|
|
58
|
-
Repository = "https://github.com/gmarciani/cli-wizard"
|
|
59
|
-
Issues = "https://github.com/gmarciani/cli-wizard/issues"
|
|
60
|
-
|
|
61
70
|
[tool.setuptools.packages.find]
|
|
62
71
|
where = ["src"]
|
|
63
72
|
include = ["cli_wizard*"]
|
|
@@ -74,18 +83,35 @@ cli_wizard = [
|
|
|
74
83
|
[tool.setuptools.dynamic]
|
|
75
84
|
version = {file = "VERSION"}
|
|
76
85
|
|
|
86
|
+
# Ruff targets the oldest supported version: it emits syntax valid for the
|
|
87
|
+
# target, and newer syntax would be a SyntaxError on 3.12.
|
|
77
88
|
[tool.ruff]
|
|
78
89
|
line-length = 88
|
|
79
90
|
target-version = "py312"
|
|
80
91
|
|
|
81
92
|
[tool.ruff.lint]
|
|
82
|
-
|
|
93
|
+
# E/W pycodestyle, F pyflakes, I isort, B bugbear, S bandit, UP pyupgrade
|
|
94
|
+
select = ["E", "F", "W", "I", "B", "S", "UP"]
|
|
83
95
|
|
|
96
|
+
[tool.ruff.lint.per-file-ignores]
|
|
97
|
+
# Tests assert by design.
|
|
98
|
+
"tests/**" = ["S101"]
|
|
99
|
+
|
|
100
|
+
# mypy checks against the default interpreter, the newest supported version.
|
|
84
101
|
[tool.mypy]
|
|
85
|
-
python_version = "3.
|
|
102
|
+
python_version = "3.14"
|
|
86
103
|
warn_return_any = true
|
|
87
104
|
warn_unused_configs = true
|
|
88
105
|
disallow_untyped_defs = true
|
|
89
106
|
|
|
90
107
|
[tool.coverage.run]
|
|
91
108
|
omit = ["*/__init__.py"]
|
|
109
|
+
|
|
110
|
+
[tool.coverage.report]
|
|
111
|
+
fail_under = 90
|
|
112
|
+
|
|
113
|
+
[tool.pytest.ini_options]
|
|
114
|
+
# Import cli_wizard from the checkout being tested. The editable install names
|
|
115
|
+
# one checkout in its .pth file, so a run started from a git worktree would
|
|
116
|
+
# otherwise import that other checkout.
|
|
117
|
+
pythonpath = ["src"]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Copyright (c) 2026, Giacomo Marciani
|
|
2
|
+
# Licensed under the MIT License
|
|
3
|
+
|
|
4
|
+
"""Main CLI module for CLI Wizard."""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
import traceback
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
|
|
12
|
+
from cli_wizard.commands.bootstrap import bootstrap
|
|
13
|
+
from cli_wizard.commands.common import configure_logging, debug_option
|
|
14
|
+
from cli_wizard.commands.config import config
|
|
15
|
+
from cli_wizard.commands.generate import generate
|
|
16
|
+
from cli_wizard.constants import __version__
|
|
17
|
+
from cli_wizard.errors import UnexpectedError, reported
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class RootGroup(click.Group):
|
|
23
|
+
"""The root group, reporting what Click raises on its own as JSON too.
|
|
24
|
+
|
|
25
|
+
Click's main() shows a ClickException and exits with its code; wrapping the
|
|
26
|
+
parsing and the dispatch turns everything else into one of cli-wizard's
|
|
27
|
+
errors first, so every failure is the one JSON document on stdout.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def make_context(
|
|
31
|
+
self,
|
|
32
|
+
info_name: str | None,
|
|
33
|
+
args: list[str],
|
|
34
|
+
parent: click.Context | None = None,
|
|
35
|
+
**extra: Any,
|
|
36
|
+
) -> click.Context:
|
|
37
|
+
with reported():
|
|
38
|
+
return super().make_context(info_name, args, parent, **extra)
|
|
39
|
+
|
|
40
|
+
def invoke(self, ctx: click.Context) -> Any:
|
|
41
|
+
try:
|
|
42
|
+
with reported():
|
|
43
|
+
return super().invoke(ctx)
|
|
44
|
+
except UnexpectedError as e:
|
|
45
|
+
# The traceback the bug came with, kept for --debug
|
|
46
|
+
logger.debug("".join(traceback.format_exception(e.__cause__)))
|
|
47
|
+
raise
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@click.group(cls=RootGroup, help="CLI Wizard - Generate modern CLI from OpenAPI.")
|
|
51
|
+
@click.version_option(version=__version__, prog_name="cli-wizard")
|
|
52
|
+
@debug_option
|
|
53
|
+
@click.pass_context
|
|
54
|
+
def main(ctx: click.Context, debug: bool) -> None:
|
|
55
|
+
"""Main CLI entry point."""
|
|
56
|
+
ctx.ensure_object(dict)
|
|
57
|
+
ctx.obj["debug"] = debug
|
|
58
|
+
configure_logging(debug)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
main.add_command(bootstrap)
|
|
62
|
+
main.add_command(config)
|
|
63
|
+
main.add_command(generate)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
if __name__ == "__main__":
|
|
67
|
+
main()
|