Skip to content

Commit 8809929

Browse files
437 add a how flag for tools (#593)
* Add --how option * Document --how option * Add more testing for --how * Add further tests for --how
1 parent 4ff9709 commit 8809929

File tree

4 files changed

+238
-24
lines changed

4 files changed

+238
-24
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ Add a new tool to a Python project, including:
152152
Supported options:
153153

154154
- `--remove` to remove the tool instead of adding it
155+
- `--how` to only print how to use the tool, with no other side effects
155156
- `--offline` to disable network access and rely on caches
156157
- `--frozen` to leave the virtual environment and lockfile unchanged
157158
- `--quiet` to suppress output

src/usethis/_core/tool.py

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,13 @@
3636
from usethis._tool.base import Tool
3737

3838

39-
def use_codespell(*, remove: bool = False) -> None:
39+
def use_codespell(*, remove: bool = False, how: bool = False) -> None:
4040
tool = CodespellTool()
4141

42+
if how:
43+
tool.print_how_to_use()
44+
return
45+
4246
ensure_pyproject_toml()
4347

4448
if not remove:
@@ -58,9 +62,13 @@ def use_codespell(*, remove: bool = False) -> None:
5862
tool.remove_managed_files()
5963

6064

61-
def use_coverage(*, remove: bool = False) -> None:
65+
def use_coverage(*, remove: bool = False, how: bool = False) -> None:
6266
tool = CoverageTool()
6367

68+
if how:
69+
tool.print_how_to_use()
70+
return
71+
6472
ensure_pyproject_toml()
6573

6674
if not remove:
@@ -73,9 +81,13 @@ def use_coverage(*, remove: bool = False) -> None:
7381
tool.remove_managed_files()
7482

7583

76-
def use_deptry(*, remove: bool = False) -> None:
84+
def use_deptry(*, remove: bool = False, how: bool = False) -> None:
7785
tool = DeptryTool()
7886

87+
if how:
88+
tool.print_how_to_use()
89+
return
90+
7991
ensure_pyproject_toml()
8092

8193
if not remove:
@@ -94,9 +106,13 @@ def use_deptry(*, remove: bool = False) -> None:
94106
tool.remove_managed_files()
95107

96108

97-
def use_import_linter(*, remove: bool = False) -> None:
109+
def use_import_linter(*, remove: bool = False, how: bool = False) -> None:
98110
tool = ImportLinterTool()
99111

112+
if how:
113+
tool.print_how_to_use()
114+
return
115+
100116
ensure_pyproject_toml()
101117

102118
if not remove:
@@ -116,8 +132,13 @@ def use_import_linter(*, remove: bool = False) -> None:
116132
tool.remove_managed_files()
117133

118134

119-
def use_pre_commit(*, remove: bool = False) -> None:
135+
def use_pre_commit(*, remove: bool = False, how: bool = False) -> None:
120136
tool = PreCommitTool()
137+
138+
if how:
139+
tool.print_how_to_use()
140+
return
141+
121142
pyproject_fmt_tool = PyprojectFmtTool()
122143
codespell_tool = CodespellTool()
123144
requirements_txt_tool = RequirementsTxtTool()
@@ -201,9 +222,13 @@ def _remove_bitbucket_linter_steps_from_default() -> None:
201222
RuffTool().remove_bitbucket_steps()
202223

203224

204-
def use_pyproject_fmt(*, remove: bool = False) -> None:
225+
def use_pyproject_fmt(*, remove: bool = False, how: bool = False) -> None:
205226
tool = PyprojectFmtTool()
206227

228+
if how:
229+
tool.print_how_to_use()
230+
return
231+
207232
ensure_pyproject_toml()
208233

209234
if not remove:
@@ -223,9 +248,13 @@ def use_pyproject_fmt(*, remove: bool = False) -> None:
223248
tool.remove_managed_files()
224249

225250

226-
def use_pyproject_toml(*, remove: bool = False) -> None:
251+
def use_pyproject_toml(*, remove: bool = False, how: bool = False) -> None:
227252
tool = PyprojectTOMLTool()
228253

254+
if how:
255+
tool.print_how_to_use()
256+
return
257+
229258
ensure_pyproject_toml()
230259

231260
if not remove:
@@ -236,9 +265,13 @@ def use_pyproject_toml(*, remove: bool = False) -> None:
236265
tool.remove_managed_files()
237266

238267

239-
def use_pytest(*, remove: bool = False) -> None:
268+
def use_pytest(*, remove: bool = False, how: bool = False) -> None:
240269
tool = PytestTool()
241270

271+
if how:
272+
tool.print_how_to_use()
273+
return
274+
242275
ensure_pyproject_toml()
243276

244277
rule_config = tool.get_rule_config()
@@ -273,9 +306,13 @@ def use_pytest(*, remove: bool = False) -> None:
273306
tool.remove_managed_files()
274307

275308

276-
def use_requirements_txt(*, remove: bool = False) -> None:
309+
def use_requirements_txt(*, remove: bool = False, how: bool = False) -> None:
277310
tool = RequirementsTxtTool()
278311

312+
if how:
313+
tool.print_how_to_use()
314+
return
315+
279316
ensure_pyproject_toml()
280317

281318
path = Path.cwd() / "requirements.txt"
@@ -311,7 +348,7 @@ def use_requirements_txt(*, remove: bool = False) -> None:
311348
tool.remove_managed_files()
312349

313350

314-
def use_ruff(*, remove: bool = False, minimal: bool = False) -> None:
351+
def use_ruff(*, remove: bool = False, how: bool = False, minimal: bool = False) -> None:
315352
"""Add Ruff to the project.
316353
317354
By default, sensible default rules are selected. If rules are already selected, the
@@ -322,6 +359,10 @@ def use_ruff(*, remove: bool = False, minimal: bool = False) -> None:
322359

323360
tool = RuffTool()
324361

362+
if how:
363+
tool.print_how_to_use()
364+
return
365+
325366
ensure_pyproject_toml()
326367

327368
# Only add ruff rules if the user doesn't already have a select/ignore list.

src/usethis/_interface/tool.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@
2323
help="Add and configure development tools, e.g. linters.", add_completion=False
2424
)
2525

26+
how_opt = typer.Option(
27+
False, "--how", help="Only print how to use the tool, do not add or remove it."
28+
)
2629
remove_opt = typer.Option(
2730
False, "--remove", help="Remove the tool instead of adding it."
2831
)
29-
3032
frozen_opt = typer.Option(False, "--frozen", help="Use the frozen dependencies.")
3133

3234

@@ -37,6 +39,7 @@
3739
)
3840
def codespell(
3941
remove: bool = remove_opt,
42+
how: bool = how_opt,
4043
offline: bool = offline_opt,
4144
quiet: bool = quiet_opt,
4245
frozen: bool = frozen_opt,
@@ -45,7 +48,7 @@ def codespell(
4548
usethis_config.set(offline=offline, quiet=quiet, frozen=frozen),
4649
files_manager(),
4750
):
48-
_run_tool(use_codespell, remove=remove)
51+
_run_tool(use_codespell, remove=remove, how=how)
4952

5053

5154
@app.command(
@@ -55,6 +58,7 @@ def codespell(
5558
)
5659
def coverage(
5760
remove: bool = remove_opt,
61+
how: bool = how_opt,
5862
offline: bool = offline_opt,
5963
quiet: bool = quiet_opt,
6064
frozen: bool = frozen_opt,
@@ -63,7 +67,7 @@ def coverage(
6367
usethis_config.set(offline=offline, quiet=quiet, frozen=frozen),
6468
files_manager(),
6569
):
66-
_run_tool(use_coverage, remove=remove)
70+
_run_tool(use_coverage, remove=remove, how=how)
6771

6872

6973
@app.command(
@@ -73,6 +77,7 @@ def coverage(
7377
)
7478
def deptry(
7579
remove: bool = remove_opt,
80+
how: bool = how_opt,
7681
offline: bool = offline_opt,
7782
quiet: bool = quiet_opt,
7883
frozen: bool = frozen_opt,
@@ -81,7 +86,7 @@ def deptry(
8186
usethis_config.set(offline=offline, quiet=quiet, frozen=frozen),
8287
files_manager(),
8388
):
84-
_run_tool(use_deptry, remove=remove)
89+
_run_tool(use_deptry, remove=remove, how=how)
8590

8691

8792
@app.command(
@@ -91,6 +96,7 @@ def deptry(
9196
)
9297
def import_linter(
9398
remove: bool = remove_opt,
99+
how: bool = how_opt,
94100
offline: bool = offline_opt,
95101
quiet: bool = quiet_opt,
96102
frozen: bool = frozen_opt,
@@ -99,7 +105,7 @@ def import_linter(
99105
usethis_config.set(offline=offline, quiet=quiet, frozen=frozen),
100106
files_manager(),
101107
):
102-
_run_tool(use_import_linter, remove=remove)
108+
_run_tool(use_import_linter, remove=remove, how=how)
103109

104110

105111
@app.command(
@@ -109,6 +115,7 @@ def import_linter(
109115
)
110116
def pre_commit(
111117
remove: bool = remove_opt,
118+
how: bool = how_opt,
112119
offline: bool = offline_opt,
113120
quiet: bool = quiet_opt,
114121
frozen: bool = frozen_opt,
@@ -117,7 +124,7 @@ def pre_commit(
117124
usethis_config.set(offline=offline, quiet=quiet, frozen=frozen),
118125
files_manager(),
119126
):
120-
_run_tool(use_pre_commit, remove=remove)
127+
_run_tool(use_pre_commit, remove=remove, how=how)
121128

122129

123130
@app.command(
@@ -127,6 +134,7 @@ def pre_commit(
127134
)
128135
def pyproject_fmt(
129136
remove: bool = remove_opt,
137+
how: bool = how_opt,
130138
offline: bool = offline_opt,
131139
quiet: bool = quiet_opt,
132140
frozen: bool = frozen_opt,
@@ -135,7 +143,7 @@ def pyproject_fmt(
135143
usethis_config.set(offline=offline, quiet=quiet, frozen=frozen),
136144
files_manager(),
137145
):
138-
_run_tool(use_pyproject_fmt, remove=remove)
146+
_run_tool(use_pyproject_fmt, remove=remove, how=how)
139147

140148

141149
@app.command(
@@ -145,6 +153,7 @@ def pyproject_fmt(
145153
)
146154
def pyproject_toml(
147155
remove: bool = remove_opt,
156+
how: bool = how_opt,
148157
offline: bool = offline_opt,
149158
quiet: bool = quiet_opt,
150159
frozen: bool = frozen_opt,
@@ -153,14 +162,15 @@ def pyproject_toml(
153162
usethis_config.set(offline=offline, quiet=quiet, frozen=frozen),
154163
files_manager(),
155164
):
156-
_run_tool(use_pyproject_toml, remove=remove)
165+
_run_tool(use_pyproject_toml, remove=remove, how=how)
157166

158167

159168
@app.command(
160169
name="pytest", help="Use the pytest testing framework.", rich_help_panel="Testing"
161170
)
162171
def pytest(
163172
remove: bool = remove_opt,
173+
how: bool = how_opt,
164174
offline: bool = offline_opt,
165175
quiet: bool = quiet_opt,
166176
frozen: bool = frozen_opt,
@@ -169,7 +179,7 @@ def pytest(
169179
usethis_config.set(offline=offline, quiet=quiet, frozen=frozen),
170180
files_manager(),
171181
):
172-
_run_tool(use_pytest, remove=remove)
182+
_run_tool(use_pytest, remove=remove, how=how)
173183

174184

175185
@app.command(
@@ -179,6 +189,7 @@ def pytest(
179189
)
180190
def requirements_txt(
181191
remove: bool = remove_opt,
192+
how: bool = how_opt,
182193
offline: bool = offline_opt,
183194
quiet: bool = quiet_opt,
184195
frozen: bool = frozen_opt,
@@ -187,7 +198,7 @@ def requirements_txt(
187198
usethis_config.set(offline=offline, quiet=quiet, frozen=frozen),
188199
files_manager(),
189200
):
190-
_run_tool(use_requirements_txt, remove=remove)
201+
_run_tool(use_requirements_txt, remove=remove, how=how)
191202

192203

193204
@app.command(
@@ -197,6 +208,7 @@ def requirements_txt(
197208
)
198209
def ruff(
199210
remove: bool = remove_opt,
211+
how: bool = how_opt,
200212
offline: bool = offline_opt,
201213
quiet: bool = quiet_opt,
202214
frozen: bool = frozen_opt,
@@ -205,16 +217,16 @@ def ruff(
205217
usethis_config.set(offline=offline, quiet=quiet, frozen=frozen),
206218
files_manager(),
207219
):
208-
_run_tool(use_ruff, remove=remove)
220+
_run_tool(use_ruff, remove=remove, how=how)
209221

210222

211223
class UseToolFunc(Protocol):
212-
def __call__(self, *, remove: bool) -> None: ...
224+
def __call__(self, *, remove: bool, how: bool) -> None: ...
213225

214226

215-
def _run_tool(caller: UseToolFunc, *, remove: bool):
227+
def _run_tool(caller: UseToolFunc, *, remove: bool, how: bool):
216228
try:
217-
caller(remove=remove)
229+
caller(remove=remove, how=how)
218230
except UsethisError as err:
219231
err_print(err)
220232
raise typer.Exit(code=1) from None

0 commit comments

Comments
 (0)