cli-wizard 2.0.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.
Files changed (98) hide show
  1. {cli_wizard-2.0.0/src/cli_wizard.egg-info → cli_wizard-3.0.0}/PKG-INFO +86 -58
  2. cli_wizard-3.0.0/README.md +204 -0
  3. cli_wizard-3.0.0/VERSION +1 -0
  4. cli_wizard-3.0.0/pyproject.toml +117 -0
  5. cli_wizard-3.0.0/src/cli_wizard/cli.py +67 -0
  6. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/commands/bootstrap.py +121 -160
  7. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/commands/common.py +15 -7
  8. cli_wizard-3.0.0/src/cli_wizard/commands/config.py +107 -0
  9. cli_wizard-3.0.0/src/cli_wizard/commands/generate.py +243 -0
  10. cli_wizard-3.0.0/src/cli_wizard/config/configuration.py +77 -0
  11. cli_wizard-3.0.0/src/cli_wizard/config/project.py +100 -0
  12. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/config/schema.py +172 -14
  13. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/constants.py +1 -1
  14. cli_wizard-3.0.0/src/cli_wizard/errors.py +137 -0
  15. cli_wizard-3.0.0/src/cli_wizard/generator/generator.py +688 -0
  16. cli_wizard-3.0.0/src/cli_wizard/generator/models.py +220 -0
  17. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/generator/parser.py +75 -28
  18. cli_wizard-2.0.0/src/cli_wizard/templates/.github/workflows/changelog_enforcer.yaml → cli_wizard-3.0.0/src/cli_wizard/templates/.github/workflows/changelog-enforcer.yaml +1 -1
  19. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/workflows/codeql.yaml +4 -4
  20. cli_wizard-2.0.0/src/cli_wizard/templates/.github/workflows/docs.yaml → cli_wizard-3.0.0/src/cli_wizard/templates/.github/workflows/docs.yaml.j2 +7 -7
  21. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/workflows/labeler.yaml +1 -1
  22. cli_wizard-2.0.0/src/cli_wizard/templates/.github/workflows/pr-validation.yaml → cli_wizard-3.0.0/src/cli_wizard/templates/.github/workflows/pr-validation.yaml.j2 +10 -8
  23. cli_wizard-2.0.0/src/cli_wizard/templates/.github/workflows/release.yaml → cli_wizard-3.0.0/src/cli_wizard/templates/.github/workflows/release.yaml.j2 +5 -5
  24. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/workflows/sync-labels.yaml +2 -2
  25. cli_wizard-3.0.0/src/cli_wizard/templates/.github/workflows/test.yaml.j2 +46 -0
  26. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/CHANGELOG.md.j2 +0 -4
  27. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/DEVELOPMENT.md.j2 +34 -1
  28. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/Makefile.j2 +6 -4
  29. cli_wizard-3.0.0/src/cli_wizard/templates/README.md.j2 +168 -0
  30. cli_wizard-3.0.0/src/cli_wizard/templates/pre-commit-config.yaml.j2 +30 -0
  31. cli_wizard-3.0.0/src/cli_wizard/templates/pyproject.toml.j2 +100 -0
  32. cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/cli.py.j2 +94 -0
  33. cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/client.py.j2 +326 -0
  34. cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/commands/__init__.py.j2 +4 -0
  35. cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/commands/config.py.j2 +146 -0
  36. cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/commands/group.py.j2 +185 -0
  37. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/src/{{ PackageName }}/constants.py.j2 +40 -18
  38. cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/errors.py.j2 +149 -0
  39. cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/log.py.j2 +189 -0
  40. cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/options.py.j2 +123 -0
  41. cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/output.py.j2 +158 -0
  42. cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/profile.py.j2 +283 -0
  43. cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/redaction.py.j2 +88 -0
  44. cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/runner.py.j2 +77 -0
  45. cli_wizard-3.0.0/src/cli_wizard/templates/src/{{ PackageName }}/state.py.j2 +41 -0
  46. cli_wizard-3.0.0/src/cli_wizard/templates/tests/{{ PackageName }}/cli_test.py.j2 +2049 -0
  47. cli_wizard-3.0.0/src/cli_wizard/templates/tests/{{ PackageName }}/commands_test.py.j2 +73 -0
  48. cli_wizard-3.0.0/src/cli_wizard/templates/tox.ini.j2 +31 -0
  49. {cli_wizard-2.0.0 → cli_wizard-3.0.0/src/cli_wizard.egg-info}/PKG-INFO +86 -58
  50. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard.egg-info/SOURCES.txt +16 -7
  51. cli_wizard-3.0.0/src/cli_wizard.egg-info/requires.txt +6 -0
  52. cli_wizard-2.0.0/README.md +0 -158
  53. cli_wizard-2.0.0/VERSION +0 -1
  54. cli_wizard-2.0.0/pyproject.toml +0 -90
  55. cli_wizard-2.0.0/src/cli_wizard/cli.py +0 -39
  56. cli_wizard-2.0.0/src/cli_wizard/commands/config.py +0 -82
  57. cli_wizard-2.0.0/src/cli_wizard/commands/generate.py +0 -224
  58. cli_wizard-2.0.0/src/cli_wizard/config/configuration.py +0 -45
  59. cli_wizard-2.0.0/src/cli_wizard/generator/generator.py +0 -447
  60. cli_wizard-2.0.0/src/cli_wizard/generator/models.py +0 -123
  61. cli_wizard-2.0.0/src/cli_wizard/templates/.github/workflows/test.yaml +0 -46
  62. cli_wizard-2.0.0/src/cli_wizard/templates/README.md.j2 +0 -23
  63. cli_wizard-2.0.0/src/cli_wizard/templates/pre-commit-config.yaml.j2 +0 -27
  64. cli_wizard-2.0.0/src/cli_wizard/templates/pyproject.toml.j2 +0 -83
  65. cli_wizard-2.0.0/src/cli_wizard/templates/src/{{ PackageName }}/cli.py.j2 +0 -106
  66. cli_wizard-2.0.0/src/cli_wizard/templates/src/{{ PackageName }}/client.py.j2 +0 -150
  67. cli_wizard-2.0.0/src/cli_wizard/templates/src/{{ PackageName }}/commands/__init__.py.j2 +0 -14
  68. cli_wizard-2.0.0/src/cli_wizard/templates/src/{{ PackageName }}/commands/config.py.j2 +0 -384
  69. cli_wizard-2.0.0/src/cli_wizard/templates/src/{{ PackageName }}/commands/group.py.j2 +0 -272
  70. cli_wizard-2.0.0/src/cli_wizard/templates/src/{{ PackageName }}/logging.py.j2 +0 -183
  71. cli_wizard-2.0.0/src/cli_wizard/templates/src/{{ PackageName }}/profile.py.j2 +0 -93
  72. cli_wizard-2.0.0/src/cli_wizard/templates/tests/{{ PackageName }}/cli_test.py.j2 +0 -1165
  73. cli_wizard-2.0.0/src/cli_wizard/templates/tox.ini.j2 +0 -27
  74. cli_wizard-2.0.0/src/cli_wizard.egg-info/requires.txt +0 -26
  75. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/LICENSE +0 -0
  76. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/MANIFEST.in +0 -0
  77. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/setup.cfg +0 -0
  78. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/__init__.py +0 -0
  79. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/commands/__init__.py +0 -0
  80. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/config/__init__.py +0 -0
  81. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/generator/__init__.py +3 -3
  82. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/CODEOWNERS.j2 +0 -0
  83. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/ISSUE_TEMPLATE/bug-report.yml.j2 +0 -0
  84. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/ISSUE_TEMPLATE/config.yml.j2 +0 -0
  85. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/ISSUE_TEMPLATE/feature-request.yml.j2 +0 -0
  86. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  87. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/dependabot.yaml +0 -0
  88. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/labeler.yaml +0 -0
  89. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.github/labels.yaml.j2 +0 -0
  90. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/.gitignore.j2 +0 -0
  91. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/LICENSE.j2 +0 -0
  92. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/MANIFEST.in.j2 +0 -0
  93. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/VERSION.j2 +0 -0
  94. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/cli-wizard.yaml.j2 +0 -0
  95. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard/templates/src/{{ PackageName }}/__init__.py.j2 +0 -0
  96. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard.egg-info/dependency_links.txt +0 -0
  97. {cli_wizard-2.0.0 → cli_wizard-3.0.0}/src/cli_wizard.egg-info/entry_points.txt +0 -0
  98. {cli_wizard-2.0.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: 2.0.0
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.com/gmarciani/cli-wizard
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
@@ -17,30 +17,12 @@ Classifier: Programming Language :: Python :: 3.14
17
17
  Requires-Python: >=3.12
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
- Requires-Dist: click~=8.3.1
21
- Requires-Dist: Jinja2~=3.1.6
22
- Requires-Dist: pydantic~=2.12.5
23
- Requires-Dist: PyYAML~=6.0.3
24
- Requires-Dist: requests~=2.32.5
25
- Provides-Extra: dev
26
- Requires-Dist: autoflake~=2.3; extra == "dev"
27
- Requires-Dist: black~=26.1; extra == "dev"
28
- Requires-Dist: build~=1.4; extra == "dev"
29
- Requires-Dist: flake8~=7.3; extra == "dev"
30
- Requires-Dist: mypy~=1.19; extra == "dev"
31
- Requires-Dist: pre-commit~=4.5; extra == "dev"
32
- Requires-Dist: pytest~=9.0; extra == "dev"
33
- Requires-Dist: pytest-cov~=7.0; extra == "dev"
34
- Requires-Dist: tox~=4.34; extra == "dev"
35
- Requires-Dist: twine~=6.2; extra == "dev"
36
- Requires-Dist: types-PyYAML~=6.0; extra == "dev"
37
- Requires-Dist: types-requests~=2.32; extra == "dev"
38
- Provides-Extra: docs
39
- Requires-Dist: sphinx~=9.1; extra == "docs"
40
- Requires-Dist: sphinx-click~=6.2; extra == "docs"
41
- Requires-Dist: sphinx-rtd-theme~=3.1; extra == "docs"
42
- Requires-Dist: sphinx-new-tab-link~=0.8; extra == "docs"
43
- Requires-Dist: autodoc_pydantic~=2.2; extra == "docs"
20
+ Requires-Dist: click~=8.4
21
+ Requires-Dist: Jinja2~=3.1
22
+ Requires-Dist: pydantic~=2.13
23
+ Requires-Dist: PyYAML~=6.0
24
+ Requires-Dist: requests~=2.34
25
+ Requires-Dist: ruff~=0.16.2
44
26
  Dynamic: license-file
45
27
 
46
28
  # CLI WIZARD
@@ -49,12 +31,12 @@ Dynamic: license-file
49
31
  <img src="https://raw.githubusercontent.com/gmarciani/cli-wizard/main/resources/brand/banner.png" alt="cli-wizard-banner" width="500">
50
32
 
51
33
  [![PyPI version](https://img.shields.io/pypi/v/cli-wizard.svg)](https://pypi.org/project/cli-wizard)
52
- [![Python versions](https://img.shields.io/pypi/pyversions/cli-wizard.svg)](https://pypi.org/project/cli-wizard)
34
+ [![Python versions](https://img.shields.io/badge/python-3.12%20%7C%203.13%20%7C%203.14-blue.svg)](https://pypi.org/project/cli-wizard)
53
35
  [![License](https://img.shields.io/github/license/gmarciani/cli-wizard.svg)](https://github.com/gmarciani/cli-wizard/blob/main/LICENSE)
54
36
  [![Build status](https://img.shields.io/github/actions/workflow/status/gmarciani/cli-wizard/test.yaml?branch=main)](https://github.com/gmarciani/cli-wizard/actions)
55
37
  [![Tests](https://img.shields.io/github/actions/workflow/status/gmarciani/cli-wizard/test.yaml?branch=main&label=tests)](https://github.com/gmarciani/cli-wizard/actions)
56
38
  [![Coverage](https://img.shields.io/codecov/c/github/gmarciani/cli-wizard)](https://codecov.io/gh/gmarciani/cli-wizard)
57
- [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
39
+ [![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-261230.svg)](https://github.com/astral-sh/ruff)
58
40
  [![Downloads](https://img.shields.io/pypi/dm/cli-wizard.svg)](https://pypi.org/project/cli-wizard)
59
41
 
60
42
  </div>
@@ -78,7 +60,7 @@ Generate modern CLIs from OpenAPI specifications.
78
60
  - Automatic command grouping based on OpenAPI tags
79
61
  - Automatic help generation for all commands
80
62
  - Clean, colored terminal output
81
- - `--debug` flag for verbose logging
63
+ - `--debug` flag for verbose logging, with credentials redacted from the output
82
64
  - Built-in API client with configurable base URL and timeout
83
65
  - SSL/TLS support with custom CA certificate bundles
84
66
  - `--ca-file` option to specify custom CA certificates at runtime
@@ -94,7 +76,13 @@ Generate modern CLIs from OpenAPI specifications.
94
76
 
95
77
  ### Developer Experience
96
78
  - Generated projects are pip-installable out of the box
97
- - Auto-generated `pyproject.toml`, `README.md`, and `VERSION`
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`
98
86
  - Resources (CA certs, splash files) bundled in the package
99
87
  - Profile management for storing credentials and settings
100
88
 
@@ -127,51 +115,74 @@ paths:
127
115
  description: OK
128
116
  ```
129
117
 
130
- ### Step 2: Create a Configuration File
118
+ ### Step 2: Generate the CLI
131
119
 
132
- Create a `cli-wizard.yaml` file with your CLI settings. At minimum, you need `PackageName` and `DefaultBaseUrl`:
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:
133
151
 
134
152
  ```yaml
135
- # Required parameters
136
- PackageName: "my-cli"
153
+ ProjectName: "My CLI"
137
154
  DefaultBaseUrl: "https://api.example.com"
138
155
 
139
- # Optional: customize the splash screen
156
+ # Customize the splash screen
140
157
  SplashFile: "splash.txt"
141
158
  SplashColor: "#00FFFF"
142
159
 
143
- # Optional: filter which tags to include
160
+ # Filter which tags to include
144
161
  IncludeTags:
145
162
  - Users
146
163
  - Products
147
164
  ```
148
165
 
149
- ### Step 3: Generate the CLI
150
-
151
- Run the `generate` command:
166
+ Then generate from it. The project lands in the current directory, in a
167
+ directory named after `CommandName`:
152
168
 
153
169
  ```shell
154
- cli-wizard generate --openapi openapi.yaml --config cli-wizard.yaml --output my-cli
170
+ cli-wizard generate --configuration cli-wizard.yaml --api openapi.yaml
155
171
  ```
156
172
 
157
- This creates a complete Python CLI project in the `my-cli` directory.
173
+ ### Starting Without a Specification
158
174
 
159
- ### Step 4: Install the Generated CLI
160
-
161
- Navigate to the generated project and install it:
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:
162
179
 
163
180
  ```shell
164
- pip install -e my-cli
181
+ cli-wizard bootstrap --configuration cli-wizard.yaml
165
182
  ```
166
183
 
167
- ### Step 5: Use Your CLI
168
-
169
- Your CLI is now ready to use:
170
-
171
- ```shell
172
- my-cli --help
173
- my-cli users list-users
174
- ```
184
+ Then edit the configuration, point `Api` at your specification, and rebuild
185
+ with `cli-wizard generate --configuration cli-wizard.yaml`.
175
186
 
176
187
  ## Configuration
177
188
 
@@ -182,17 +193,34 @@ See the [examples](examples/) directory for complete configuration examples.
182
193
 
183
194
  ### cli-wizard generate
184
195
 
185
- Generate a CLI from an OpenAPI specification and configuration file.
196
+ Generate a CLI from an OpenAPI specification, with an optional configuration file.
186
197
 
187
198
  ```shell
188
199
  cli-wizard generate [OPTIONS]
189
200
  ```
190
201
 
191
202
  Options:
192
- - `--openapi, -o` - Path to OpenAPI spec file (default: `openapi.yaml`)
193
- - `--config, -c` - Path to config YAML file (default: `cli-wizard.yaml`)
194
- - `--output, -d` - Output directory for generated CLI (default: `cli`)
195
- - `--working-dir, -w` - Working directory for resolving relative paths
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
196
224
 
197
225
  ## Issues
198
226
 
@@ -0,0 +1,204 @@
1
+ # CLI WIZARD
2
+
3
+ <div align="center">
4
+ <img src="https://raw.githubusercontent.com/gmarciani/cli-wizard/main/resources/brand/banner.png" alt="cli-wizard-banner" width="500">
5
+
6
+ [![PyPI version](https://img.shields.io/pypi/v/cli-wizard.svg)](https://pypi.org/project/cli-wizard)
7
+ [![Python versions](https://img.shields.io/badge/python-3.12%20%7C%203.13%20%7C%203.14-blue.svg)](https://pypi.org/project/cli-wizard)
8
+ [![License](https://img.shields.io/github/license/gmarciani/cli-wizard.svg)](https://github.com/gmarciani/cli-wizard/blob/main/LICENSE)
9
+ [![Build status](https://img.shields.io/github/actions/workflow/status/gmarciani/cli-wizard/test.yaml?branch=main)](https://github.com/gmarciani/cli-wizard/actions)
10
+ [![Tests](https://img.shields.io/github/actions/workflow/status/gmarciani/cli-wizard/test.yaml?branch=main&label=tests)](https://github.com/gmarciani/cli-wizard/actions)
11
+ [![Coverage](https://img.shields.io/codecov/c/github/gmarciani/cli-wizard)](https://codecov.io/gh/gmarciani/cli-wizard)
12
+ [![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-261230.svg)](https://github.com/astral-sh/ruff)
13
+ [![Downloads](https://img.shields.io/pypi/dm/cli-wizard.svg)](https://pypi.org/project/cli-wizard)
14
+
15
+ </div>
16
+
17
+ Generate modern CLIs from OpenAPI specifications.
18
+
19
+ ## Table of Contents
20
+
21
+ - [Features](#features)
22
+ - [Installation](#installation)
23
+ - [Usage](#usage)
24
+ - [Configuration](#configuration)
25
+ - [Commands](#commands)
26
+ - [Issues](#issues)
27
+ - [License](#license)
28
+
29
+ ## Features
30
+
31
+ ### Code Generation
32
+ - Generate complete Python CLI projects from OpenAPI v3 specifications
33
+ - Automatic command grouping based on OpenAPI tags
34
+ - Automatic help generation for all commands
35
+ - Clean, colored terminal output
36
+ - `--debug` flag for verbose logging, with credentials redacted from the output
37
+ - Built-in API client with configurable base URL and timeout
38
+ - SSL/TLS support with custom CA certificate bundles
39
+ - `--ca-file` option to specify custom CA certificates at runtime
40
+ - `--no-verify-ssl` flag to disable certificate verification
41
+
42
+ ### Customization
43
+ - YAML-based configuration for full customization
44
+ - Configurable output directory and package name
45
+ - Tag inclusion/exclusion filters
46
+ - Custom command naming via `TagMapping` and `CommandMapping`
47
+ - Customizable splash screen with color support
48
+ - Configurable logging with colors, file output, and rotation
49
+
50
+ ### Developer Experience
51
+ - Generated projects are pip-installable out of the box
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`
59
+ - Resources (CA certs, splash files) bundled in the package
60
+ - Profile management for storing credentials and settings
61
+
62
+ ## Installation
63
+
64
+ ```shell
65
+ pip install cli-wizard
66
+ ```
67
+
68
+ ## Usage
69
+
70
+ ### Step 1: Prepare Your OpenAPI Specification
71
+
72
+ Ensure you have an OpenAPI v3 specification file (JSON or YAML format). For example, `openapi.yaml`:
73
+
74
+ ```yaml
75
+ openapi: 3.0.0
76
+ info:
77
+ title: My API
78
+ version: 1.0.0
79
+ paths:
80
+ /users:
81
+ get:
82
+ operationId: listUsers
83
+ summary: List all users
84
+ tags:
85
+ - Users
86
+ responses:
87
+ '200':
88
+ description: OK
89
+ ```
90
+
91
+ ### Step 2: Generate the CLI
92
+
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:
124
+
125
+ ```yaml
126
+ ProjectName: "My CLI"
127
+ DefaultBaseUrl: "https://api.example.com"
128
+
129
+ # Customize the splash screen
130
+ SplashFile: "splash.txt"
131
+ SplashColor: "#00FFFF"
132
+
133
+ # Filter which tags to include
134
+ IncludeTags:
135
+ - Users
136
+ - Products
137
+ ```
138
+
139
+ Then generate from it. The project lands in the current directory, in a
140
+ directory named after `CommandName`:
141
+
142
+ ```shell
143
+ cli-wizard generate --configuration cli-wizard.yaml --api openapi.yaml
144
+ ```
145
+
146
+ ### Starting Without a Specification
147
+
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:
152
+
153
+ ```shell
154
+ cli-wizard bootstrap --configuration cli-wizard.yaml
155
+ ```
156
+
157
+ Then edit the configuration, point `Api` at your specification, and rebuild
158
+ with `cli-wizard generate --configuration cli-wizard.yaml`.
159
+
160
+ ## Configuration
161
+
162
+ See [configuration reference](https://gmarciani.github.io/cli-wizard/configuration.html) for full documentation.
163
+ See the [examples](examples/) directory for complete configuration examples.
164
+
165
+ ## Commands
166
+
167
+ ### cli-wizard generate
168
+
169
+ Generate a CLI from an OpenAPI specification, with an optional configuration file.
170
+
171
+ ```shell
172
+ cli-wizard generate [OPTIONS]
173
+ ```
174
+
175
+ Options:
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
197
+
198
+ ## Issues
199
+
200
+ Please report any issues or feature requests on the [GitHub Issues](https://github.com/gmarciani/cli-wizard/issues) page.
201
+
202
+ ## License
203
+
204
+ This project is licensed under the MIT License. See the [LICENSE](https://github.com/gmarciani/cli-wizard/blob/main/LICENSE) file for details.
@@ -0,0 +1 @@
1
+ 3.0.0
@@ -0,0 +1,117 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "cli-wizard"
7
+ dynamic = ["version"]
8
+ description = "Generate modern CLIs from OpenAPI specifications"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ authors = [
12
+ {name = "Giacomo Marciani", email = "giacomo.marciani@gmail.com"}
13
+ ]
14
+ classifiers = [
15
+ "Development Status :: 5 - Production/Stable",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Programming Language :: Python :: 3.14",
22
+ ]
23
+ requires-python = ">=3.12"
24
+ dependencies = [
25
+ "click~=8.4",
26
+ "Jinja2~=3.1",
27
+ "pydantic~=2.13",
28
+ "PyYAML~=6.0",
29
+ "requests~=2.34",
30
+ "ruff~=0.16.2",
31
+ ]
32
+
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]
46
+ dev = [
47
+ {include-group = "test"},
48
+ {include-group = "docs"},
49
+ "build~=1.5",
50
+ "pre-commit~=4.6",
51
+ "tox~=4.58",
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",
59
+ "types-PyYAML~=6.0",
60
+ "types-requests~=2.33",
61
+ ]
62
+ docs = [
63
+ "sphinx~=9.1",
64
+ "sphinx-click~=6.2",
65
+ "sphinx-rtd-theme~=3.1",
66
+ "sphinx-new-tab-link~=0.8",
67
+ "autodoc_pydantic~=2.2",
68
+ ]
69
+
70
+ [tool.setuptools.packages.find]
71
+ where = ["src"]
72
+ include = ["cli_wizard*"]
73
+
74
+ [tool.setuptools.package-data]
75
+ cli_wizard = [
76
+ "templates/**/*.j2",
77
+ "templates/**/*.yaml",
78
+ "templates/**/*.yml",
79
+ "templates/**/*.md",
80
+ "config/*.yaml",
81
+ ]
82
+
83
+ [tool.setuptools.dynamic]
84
+ version = {file = "VERSION"}
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.
88
+ [tool.ruff]
89
+ line-length = 88
90
+ target-version = "py312"
91
+
92
+ [tool.ruff.lint]
93
+ # E/W pycodestyle, F pyflakes, I isort, B bugbear, S bandit, UP pyupgrade
94
+ select = ["E", "F", "W", "I", "B", "S", "UP"]
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.
101
+ [tool.mypy]
102
+ python_version = "3.14"
103
+ warn_return_any = true
104
+ warn_unused_configs = true
105
+ disallow_untyped_defs = true
106
+
107
+ [tool.coverage.run]
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()