Skip to content

Commit 2d1a598

Browse files
patrick91svlandegtiangolo
authored
🔥 Remove auto naming of groups added via add_typer based on the group's callback function name (#1052)
Co-authored-by: svlandeg <svlandeg@github.com> Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
1 parent 45cbfcd commit 2d1a598

File tree

10 files changed

+109
-75
lines changed

10 files changed

+109
-75
lines changed

‎docs/tutorial/subcommands/name-and-help.md‎

Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ app.add_typer(users.app, name="users")
1010

1111
## Add a help text
1212

13-
We can also set the `help` while adding a Typer:
13+
We can also set the `help` text while adding a Typer:
1414

1515
{* docs_src/subcommands/name_help/tutorial001.py hl[6] *}
1616

@@ -48,7 +48,7 @@ Commands:
4848

4949
</div>
5050

51-
We can set the `name` and `help` in several places, each one taking precedence over the other, overriding the previous value.
51+
We can set the `help` in several places, each one taking precedence over the other, overriding the previous value.
5252

5353
Let's see those locations.
5454

@@ -60,9 +60,9 @@ But those are documented later in another section.
6060

6161
///
6262

63-
## Inferring name and help from callback
63+
## Inferring help text from callback
6464

65-
### Inferring a command's name and help
65+
### Inferring a command's help text
6666

6767
When you create a command with `@app.command()`, by default, it generates the name from the function name.
6868

@@ -81,23 +81,15 @@ def create(item: str):
8181

8282
...will create a command `create` with a help text of `Create an item`.
8383

84-
### Inferring name and help from `@app.callback()`
84+
### Inferring the help text from `@app.callback()`
8585

8686
The same way, if you define a callback in a `typer.Typer()`, the help text is extracted from the callback function's docstring.
8787

88-
And if that Typer app is added to another Typer app, the default name of the command is generated from the name of the callback function.
89-
9088
Here's an example:
9189

92-
{* docs_src/subcommands/name_help/tutorial002.py hl[6,9,10,11,12,13] *}
93-
94-
Notice that now we added the sub-Typer without specifying a `name` nor a `help`.
95-
96-
They are now inferred from the callback function.
90+
{* docs_src/subcommands/name_help/tutorial002.py hl[9,10,11,12,13] *}
9791

98-
The command name will be the same callback function's name: `users`.
99-
100-
And the help text for that `users` command will be the callback function's docstring: `Manage users in the app.`.
92+
The help text for that command will be the callback function's docstring: `Manage users in the app.`.
10193

10294
Check it:
10395

@@ -107,7 +99,7 @@ Check it:
10799
// Check the main help
108100
$ python main.py --help
109101

110-
// Notice the command name "users" and the help text "Manage users in the app."
102+
// Notice the help text "Manage users in the app."
111103
Usage: main.py [OPTIONS] COMMAND [ARGS]...
112104

113105
Options:
@@ -135,9 +127,15 @@ Commands:
135127

136128
</div>
137129

138-
### Name and help from callback parameter in `typer.Typer()`
130+
/// note
131+
132+
Before Typer 0.14.0, in addition to the help text, the command name was also inferred from the callback function name, this is no longer the case.
133+
134+
///
135+
136+
### Help from callback parameter in `typer.Typer()`
139137

140-
If you pass a `callback` parameter while creating a `typer.Typer(callback=some_function)` it will be used to infer the name and help text.
138+
If you pass a `callback` parameter while creating a `typer.Typer(callback=some_function)` it will be used to infer the help text.
141139

142140
This has the lowest priority, we'll see later what has a higher priority and can override it.
143141

@@ -155,7 +153,7 @@ Check it:
155153
// Check the main help
156154
$ python main.py --help
157155

158-
// Notice the command name "users" and the help text "Manage users in the app."
156+
// Notice the help text "Manage users in the app."
159157
Usage: main.py [OPTIONS] COMMAND [ARGS]...
160158

161159
Options:
@@ -185,11 +183,11 @@ Commands:
185183

186184
### Override a callback set in `typer.Typer()` with `@app.callback()`
187185

188-
The same as with normal **Typer** apps, if you pass a `callback` to `typer.Typer(callback=some_function)` and then override it with `@app.callback()`, the name and help text will be inferred from the new callback:
186+
The same as with normal **Typer** apps, if you pass a `callback` to `typer.Typer(callback=some_function)` and then override it with `@app.callback()`, the help text will be inferred from the new callback:
189187

190188
{* docs_src/subcommands/name_help/tutorial004.py hl[16,17,18,19,20] *}
191189

192-
Now the name of the command will be `users` instead of `old-callback`, and the help text will be `Manage users in the app.` instead of `Old callback help.`.
190+
Now the help text will be `Manage users in the app.` instead of `Old callback help.`.
193191

194192
Check it:
195193

@@ -199,7 +197,7 @@ Check it:
199197
// Check the main help
200198
$ python main.py --help
201199

202-
// Notice the command name "users" and the help text "Manage users in the app."
200+
// Notice the help text "Manage users in the app."
203201
Usage: main.py [OPTIONS] COMMAND [ARGS]...
204202

205203
Options:
@@ -227,17 +225,17 @@ Commands:
227225

228226
</div>
229227

230-
### Infer name and help from callback in `app.add_typer()`
228+
### Help from callback in `app.add_typer()`
231229

232-
If you override the callback in `app.add_typer()` when including a sub-app, the name and help will be inferred from this callback function.
230+
If you override the callback in `app.add_typer()` when including a sub-app, the help will be inferred from this callback function.
233231

234-
This takes precedence over inferring the name and help from a callback set in `@sub_app.callback()` and `typer.Typer(callback=sub_app_callback)`.
232+
This takes precedence over inferring the help from a callback set in `@sub_app.callback()` and `typer.Typer(callback=sub_app_callback)`.
235233

236234
Check the code:
237235

238236
{* docs_src/subcommands/name_help/tutorial005.py hl[15,16,17,18,21] *}
239237

240-
Now the command will be `new-users` instead of `users`. And the help text will be `I have the highland! Create some users.` instead of the previous ones.
238+
The help text will be `I have the highland! Create some users.` instead of the previous ones.
241239

242240
Check it:
243241

@@ -277,29 +275,29 @@ Commands:
277275

278276
### Enough inferring
279277

280-
So, when inferring a name and help text, the precedence order from lowest priority to highest is:
278+
So, when inferring help text, the precedence order from lowest priority to highest is:
281279

282280
* `sub_app = typer.Typer(callback=some_function)`
283281
* `@sub_app.callback()`
284282
* `app.add_typer(sub_app, callback=new_function)`
285283

286-
That's for inferring the name and help text from functions.
284+
That's for inferring the help text from functions.
287285

288-
But if you set the name and help text explicitly, that has a higher priority than these.
286+
But if you set the help text explicitly, that has a higher priority than these.
289287

290288
## Set the name and help
291289

292290
Let's now see the places where you can set the command name and help text, from lowest priority to highest.
293291

294292
/// tip
295293

296-
Setting the name and help text explicitly always has a higher precedence than inferring from a callback function.
294+
Setting the help text explicitly always has a higher precedence than inferring from a callback function.
297295

298296
///
299297

300298
### Name and help in `typer.Typer()`
301299

302-
You could have all the callbacks and overrides we defined before, but the name and help text was inferred from the function name and docstring.
300+
You could have all the callbacks and overrides we defined before, but the help text was inferred from the function docstring.
303301

304302
If you set it explicitly, that takes precedence over inferring.
305303

@@ -313,7 +311,7 @@ The rest of the callbacks and overrides are there only to show you that they don
313311

314312
///
315313

316-
We set an explicit name `exp-users`, and an explicit help `Explicit help.`.
314+
We set an explicit help `Explicit help.`.
317315

318316
So that will take precedence now.
319317

@@ -353,15 +351,15 @@ Commands:
353351

354352
</div>
355353

356-
### Name and help in `@app.callback()`
354+
### Help text in `@app.callback()`
357355

358-
Any parameter that you use when creating a `typer.Typer()` app can be overridden in the parameters of `@app.callback()`.
356+
Many parameters that you use when creating a `typer.Typer()` app can be overridden in the parameters of `@app.callback()`.
359357

360-
Continuing with the previous example, we now override the values in `@user_app.callback()`:
358+
Continuing with the previous example, we now override the `help` in `@user_app.callback()`:
361359

362360
{* docs_src/subcommands/name_help/tutorial007.py hl[24] *}
363361

364-
And now the command name will be `call-users` and the help text will be `Help from callback for users.`.
362+
And now the help text will be `Help from callback for users.`.
365363

366364
Check it:
367365

@@ -371,7 +369,7 @@ Check it:
371369
// Check the help
372370
$ python main.py --help
373371

374-
// The command name now is call-users and the help text is "Help from callback for users.".
372+
// The help text is now "Help from callback for users.".
375373
Usage: main.py [OPTIONS] COMMAND [ARGS]...
376374

377375
Options:
@@ -380,13 +378,13 @@ Options:
380378
--help Show this message and exit.
381379

382380
Commands:
383-
call-users Help from callback for users.
381+
users Help from callback for users.
384382

385-
// Check the call-users command help
386-
$ python main.py call-users --help
383+
// Check the users command help
384+
$ python main.py users --help
387385

388386
// Notice the main help text
389-
Usage: main.py call-users [OPTIONS] COMMAND [ARGS]...
387+
Usage: main.py users [OPTIONS] COMMAND [ARGS]...
390388

391389
Help from callback for users.
392390

@@ -445,13 +443,17 @@ Commands:
445443

446444
## Recap
447445

448-
The precedence to generate a command's name and help, from lowest priority to highest, is:
446+
The precedence to generate a command's **help**, from lowest priority to highest, is:
449447

450448
* Implicitly inferred from `sub_app = typer.Typer(callback=some_function)`
451449
* Implicitly inferred from the callback function under `@sub_app.callback()`
452450
* Implicitly inferred from `app.add_typer(sub_app, callback=some_function)`
453-
* Explicitly set on `sub_app = typer.Typer(name="some-name", help="Some help.")`
454-
* Explicitly set on `@sub_app.callback("some-name", help="Some help.")`
455-
* Explicitly set on `app.add_typer(sub_app, name="some-name", help="Some help.")`
451+
* Explicitly set on `sub_app = typer.Typer(help="Some help.")`
452+
* Explicitly set on `app.add_typer(sub_app, help="Some help.")`
453+
454+
And the priority to set the command's **name**, from lowest priority to highest, is:
455+
456+
* Explicitly set on `sub_app = typer.Typer(name="some-name")`
457+
* Explicitly set on `app.add_typer(sub_app, name="some-name")`
456458

457459
So, `app.add_typer(sub_app, name="some-name", help="Some help.")` always wins.

‎docs_src/subcommands/name_help/tutorial002.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
app = typer.Typer()
44

55
users_app = typer.Typer()
6-
app.add_typer(users_app)
6+
app.add_typer(users_app, name="users")
77

88

99
@users_app.callback()

‎docs_src/subcommands/name_help/tutorial003.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def users():
99
"""
1010

1111

12-
users_app = typer.Typer(callback=users)
12+
users_app = typer.Typer(callback=users, name="users")
1313
app.add_typer(users_app)
1414

1515

‎docs_src/subcommands/name_help/tutorial004.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def old_callback():
1010

1111

1212
users_app = typer.Typer(callback=old_callback)
13-
app.add_typer(users_app)
13+
app.add_typer(users_app, name="users")
1414

1515

1616
@users_app.callback()

‎docs_src/subcommands/name_help/tutorial005.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def old_callback():
99
"""
1010

1111

12-
users_app = typer.Typer(callback=old_callback)
12+
users_app = typer.Typer(callback=old_callback, name="users")
1313

1414

1515
def new_users():
@@ -18,7 +18,7 @@ def new_users():
1818
"""
1919

2020

21-
app.add_typer(users_app, callback=new_users)
21+
app.add_typer(users_app, callback=new_users, name="new-users")
2222

2323

2424
@users_app.callback()

‎docs_src/subcommands/name_help/tutorial007.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def old_callback():
99
"""
1010

1111

12-
users_app = typer.Typer(callback=old_callback, name="exp-users", help="Explicit help.")
12+
users_app = typer.Typer(callback=old_callback, name="users", help="Explicit help.")
1313

1414

1515
def new_users():
@@ -21,7 +21,7 @@ def new_users():
2121
app.add_typer(users_app, callback=new_users)
2222

2323

24-
@users_app.callback("call-users", help="Help from callback for users.")
24+
@users_app.callback(help="Help from callback for users.")
2525
def users():
2626
"""
2727
Manage users in the app.

‎docs_src/subcommands/name_help/tutorial008.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def new_users():
2626
)
2727

2828

29-
@users_app.callback("call-users", help="Help from callback for users.")
29+
@users_app.callback(help="Help from callback for users.")
3030
def users():
3131
"""
3232
Manage users in the app.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import pytest
2+
import typer
3+
from typer.testing import CliRunner
4+
5+
runner = CliRunner()
6+
7+
8+
def test_warns_when_callback_is_not_supported():
9+
app = typer.Typer()
10+
11+
sub_app = typer.Typer()
12+
13+
@sub_app.callback()
14+
def callback():
15+
"""This help text is not used."""
16+
17+
app.add_typer(sub_app)
18+
19+
with pytest.warns(
20+
match="The 'callback' parameter is not supported by Typer when using `add_typer` without a name"
21+
):
22+
try:
23+
app()
24+
except SystemExit:
25+
pass
26+
27+
28+
def test_warns_when_callback_is_not_supported_added_after_add_typer():
29+
app = typer.Typer()
30+
31+
sub_app = typer.Typer()
32+
app.add_typer(sub_app)
33+
34+
@sub_app.callback()
35+
def callback():
36+
"""This help text is not used."""
37+
38+
with pytest.warns(
39+
match="The 'callback' parameter is not supported by Typer when using `add_typer` without a name"
40+
):
41+
try:
42+
app()
43+
except SystemExit:
44+
pass

‎tests/test_tutorial/test_subcommands/test_name_help/test_tutorial007.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,18 @@ def test_help():
1414
result = runner.invoke(app, ["--help"])
1515
assert result.exit_code == 0
1616
assert "Commands" in result.output
17-
assert "call-users" in result.output
17+
assert "users" in result.output
1818
assert "Help from callback for users." in result.output
1919

2020

2121
def test_command_help():
22-
result = runner.invoke(app, ["call-users", "--help"])
22+
result = runner.invoke(app, ["users", "--help"])
2323
assert result.exit_code == 0
2424
assert "Help from callback for users." in result.output
2525

2626

2727
def test_command():
28-
result = runner.invoke(app, ["call-users", "create", "Camila"])
28+
result = runner.invoke(app, ["users", "create", "Camila"])
2929
assert result.exit_code == 0
3030
assert "Creating user: Camila" in result.output
3131

0 commit comments

Comments
 (0)