Skip to content

Commit da62b3b

Browse files
authored
Merge branch 'master' into feat/autocompletion
2 parents 8668bb7 + ccbd35d commit da62b3b

34 files changed

+656
-85
lines changed

.github/workflows/build-docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ jobs:
5757
with:
5858
python-version: "3.11"
5959
- name: Setup uv
60-
uses: astral-sh/setup-uv@v3
60+
uses: astral-sh/setup-uv@v4
6161
with:
6262
version: "0.4.15"
6363
enable-cache: true

.github/workflows/deploy-docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
with:
3030
python-version: "3.11"
3131
- name: Setup uv
32-
uses: astral-sh/setup-uv@v3
32+
uses: astral-sh/setup-uv@v4
3333
with:
3434
version: "0.4.15"
3535
enable-cache: true

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,4 @@ jobs:
3636
TIANGOLO_BUILD_PACKAGE: ${{ matrix.package }}
3737
run: python -m build
3838
- name: Publish
39-
uses: pypa/gh-action-pypi-publish@v1.10.3
39+
uses: pypa/gh-action-pypi-publish@v1.12.2

.github/workflows/smokeshow.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
with:
2828
python-version: '3.9'
2929
- name: Setup uv
30-
uses: astral-sh/setup-uv@v3
30+
uses: astral-sh/setup-uv@v4
3131
with:
3232
version: "0.4.15"
3333
enable-cache: true

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ jobs:
4545
with:
4646
python-version: ${{ matrix.python-version }}
4747
- name: Setup uv
48-
uses: astral-sh/setup-uv@v3
48+
uses: astral-sh/setup-uv@v4
4949
with:
5050
version: "0.4.15"
5151
enable-cache: true
@@ -83,7 +83,7 @@ jobs:
8383
with:
8484
python-version: '3.8'
8585
- name: Setup uv
86-
uses: astral-sh/setup-uv@v3
86+
uses: astral-sh/setup-uv@v4
8787
with:
8888
version: "0.4.15"
8989
enable-cache: true

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ repos:
1414
- id: end-of-file-fixer
1515
- id: trailing-whitespace
1616
- repo: https://github.com/astral-sh/ruff-pre-commit
17-
rev: v0.7.4
17+
rev: v0.8.0
1818
hooks:
1919
- id: ruff
2020
args:

docs/release-notes.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,82 @@
22

33
## Latest Changes
44

5+
## 0.15.0
6+
7+
### Features
8+
9+
* ✨ Add support for extending typer apps without passing a name, add commands to the top level. PR [#1037](https://github.com/fastapi/typer/pull/1037) by [@patrick91](https://github.com/patrick91).
10+
* New docs: [One File Per Command](https://typer.tiangolo.com/tutorial/one-file-per-command/).
11+
12+
### Internal
13+
14+
* ⬆ Bump mkdocs-material from 9.5.46 to 9.5.47. PR [#1070](https://github.com/fastapi/typer/pull/1070) by [@dependabot[bot]](https://github.com/apps/dependabot).
15+
* ⬆ Bump ruff from 0.8.0 to 0.8.1. PR [#1066](https://github.com/fastapi/typer/pull/1066) by [@dependabot[bot]](https://github.com/apps/dependabot).
16+
17+
## 0.14.0
18+
19+
### Breaking Changes
20+
21+
* 🔥 Remove auto naming of groups added via `add_typer` based on the group's callback function name. PR [#1052](https://github.com/fastapi/typer/pull/1052) by [@patrick91](https://github.com/patrick91).
22+
23+
Before, it was supported to infer the name of a command group from the callback function name in the sub-app, so, in this code:
24+
25+
```python
26+
import typer
27+
28+
app = typer.Typer()
29+
users_app = typer.Typer()
30+
31+
app.add_typer(users_app)
32+
33+
34+
@users_app.callback()
35+
def users(): # <-- This was the inferred command group name
36+
"""
37+
Manage users in the app.
38+
"""
39+
40+
41+
@users_app.command()
42+
def create(name: str):
43+
print(f"Creating user: {name}")
44+
```
45+
46+
...the command group would be named `users`, based on the name of the function `def users()`.
47+
48+
Now you need to set it explicitly:
49+
50+
```python
51+
import typer
52+
53+
app = typer.Typer()
54+
users_app = typer.Typer()
55+
56+
app.add_typer(users_app, name="users") # <-- Explicitly set the command group name
57+
58+
59+
@users_app.callback()
60+
def users():
61+
"""
62+
Manage users in the app.
63+
"""
64+
65+
66+
@users_app.command()
67+
def create(name: str):
68+
print(f"Creating user: {name}")
69+
```
70+
71+
Updated docs [SubCommand Name and Help](https://typer.tiangolo.com/tutorial/subcommands/name-and-help/).
72+
73+
**Note**: this change will enable important features in the next release. 🤩
74+
575
### Internal
676

77+
* ⬆ Bump pypa/gh-action-pypi-publish from 1.10.3 to 1.12.2. PR [#1043](https://github.com/fastapi/typer/pull/1043) by [@dependabot[bot]](https://github.com/apps/dependabot).
78+
* ⬆ Bump mkdocs-material from 9.5.44 to 9.5.46. PR [#1062](https://github.com/fastapi/typer/pull/1062) by [@dependabot[bot]](https://github.com/apps/dependabot).
79+
* ⬆ Bump ruff from 0.7.4 to 0.8.0. PR [#1059](https://github.com/fastapi/typer/pull/1059) by [@dependabot[bot]](https://github.com/apps/dependabot).
80+
* ⬆ Bump astral-sh/setup-uv from 3 to 4. PR [#1061](https://github.com/fastapi/typer/pull/1061) by [@dependabot[bot]](https://github.com/apps/dependabot).
781
*[pre-commit.ci] pre-commit autoupdate. PR [#1053](https://github.com/fastapi/typer/pull/1053) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
882

983
## 0.13.1

docs/tutorial/one-file-per-command.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# One File Per Command
2+
3+
When your CLI application grows, you can split it into multiple files and modules. This pattern helps maintain a clean and organized code structure. ✨
4+
5+
This tutorial will show you how to use `add_typer` to create sub commands and organize your commands in multiple files.
6+
7+
We will create a simple CLI with the following commands:
8+
9+
- `version`
10+
- `users add NAME`
11+
- `users delete NAME`
12+
13+
## CLI structure
14+
15+
Here is the structure we'll be working with:
16+
17+
```text
18+
mycli/
19+
├── __init__.py
20+
├── main.py
21+
├── users/
22+
│ ├── __init__.py
23+
│ ├── add.py
24+
│ └── delete.py
25+
└── version.py
26+
```
27+
28+
`mycli` will be our <abbr title="a directory with an __init__.py file, it can be imported">package</abbr>, and it will contain the following modules:
29+
30+
- `main.py`: The main <abbr title="a Python file that can be imported">module</abbr> that will import the `version` and `users` modules.
31+
- `version.py`: A <abbr title="a Python file that can be imported">module</abbr> that will contain the `version` command.
32+
- `users/`: A <abbr title="another directory with an __init__.py file, it can also be imported">package</abbr> (inside of our `mycli` package) that will contain the `add` and `delete` commands.
33+
34+
## Implementation
35+
36+
Let's start implementing our CLI! 🚀
37+
38+
We'll create the `version` module, the `main` module, and the `users` package.
39+
40+
### Version Module (`version.py`)
41+
42+
Let's start by creating the `version` module. This module will contain the `version` command.
43+
44+
{* docs_src/one_file_per_command/version.py *}
45+
46+
In this file we are creating a new Typer app instance for the `version` command.
47+
48+
This is not required in single-file applications, but in the case of multi-file applications it will allow us to include this command in the main application using `app.add_typer()`.
49+
50+
Let's see that next!
51+
52+
### Main Module (`main.py`)
53+
54+
The main module will be the entry point of the application. It will import the version module and the users module.
55+
56+
/// tip
57+
58+
We'll see how to implement the users module in the next section.
59+
60+
///
61+
62+
{* docs_src/one_file_per_command/main.py hl[8,9] *}
63+
64+
In this module, we import the `version` and `users` modules and add them to the main app using `app.add_typer()`.
65+
66+
For the `users` module, we specify the name as `"users"` to group the commands under the `users` sub-command.
67+
68+
Notice that we didn't add a name for the `version_app` Typer app. Because of this, Typer will add the commands (just one in this case) declared in the `version_app` directly at the top level. So, there will be a top-level `version` sub-command.
69+
70+
But for `users`, we add a name `"users"`, this way those commands will be under the sub-command `users` instead of at the top level. So, there will be a `users add` and `users delete` sub-sub-commands. 😅
71+
72+
/// tip
73+
74+
If you want a command to group the included commands in a sub-app, add a name.
75+
76+
If you want to include the commands from a sub-app directly at the top level, don't add a name, or set it to `None`. 🤓
77+
78+
///
79+
80+
Let's now create the `users` module with the `add` and `delete` commands.
81+
82+
### Users Add Command (`users/add.py`)
83+
84+
{* docs_src/one_file_per_command/users/add.py *}
85+
86+
Like the `version` module, we create a new Typer app instance for the `users/add` command. This allows us to include the `add` command in the users app.
87+
88+
### Users Delete Command (`users/delete.py`)
89+
90+
{* docs_src/one_file_per_command/users/delete.py *}
91+
92+
And once again, we create a new Typer app instance for the `users/delete` command. This allows us to include the `delete` command in the users app.
93+
94+
### Users' app (`users/__init__.py`)
95+
96+
Finally, we need to create an `__init__.py` file in the `users` directory to define the `users` app.
97+
98+
{* docs_src/one_file_per_command/users/__init__.py *}
99+
100+
Similarly to the `version` module, we create a new `Typer` app instance for the `users` module. This allows us to include the `add` and `delete` commands in the users app.
101+
102+
## Running the Application
103+
104+
Now we are ready to run the application! 😎
105+
106+
To run the application, you can execute it as a Python module:
107+
108+
<div class="termy">
109+
110+
```console
111+
$ python -m mycli.main version
112+
113+
My CLI Version 1.0
114+
115+
$ python -m mycli.main users add Camila
116+
117+
Adding user: Camila
118+
```
119+
120+
</div>
121+
122+
And if you built a package and installed your app, you can then use the `mycli` command:
123+
124+
<div class="termy">
125+
126+
```console
127+
$ mycli version
128+
129+
My CLI Version 1.0
130+
131+
$ mycli users add Camila
132+
133+
Adding user: Camila
134+
```
135+
136+
</div>
137+
138+
## Callbacks
139+
140+
Have in mind that if you include a sub-app with `app.add_typer()` **without a name**, the commands will be added to the top level, so **only the top level callback** (if there's any) will be used, the one declared in the main app.
141+
142+
If you **want to use a callback** for a sub-app, you need to include the sub-app **with a name**, which creates a sub-command grouping the commands in that sub-app. 🤓
143+
144+
In the example above, if the `users` sub-app had a callback, it would be used. But if the `version` sub-app had a callback, it would not be used, because the `version` sub-app was included without a name.

0 commit comments

Comments
 (0)