You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/index.md
+66
Original file line number
Diff line number
Diff line change
@@ -1113,6 +1113,72 @@ For `BaseModel` and `pydantic.dataclasses.dataclass` types, `CliApp.run` will in
1113
1113
*`cli_implicit_flags=True`
1114
1114
*`cli_kebab_case=True`
1115
1115
1116
+
### Asynchronous CLI Commands
1117
+
1118
+
Pydantic settings supports running asynchronous CLI commands via `CliApp.run` and `CliApp.run_subcommand`. With this feature, you can define async def methods within your Pydantic models (including subcommands) and have them executed just like their synchronous counterparts. Specifically:
1119
+
1120
+
1. Asynchronous methods are supported: You can now mark your cli_cmd or similar CLI entrypoint methods as async def and have CliApp execute them.
1121
+
2. Subcommands may also be asynchronous: If you have nested CLI subcommands, the final (lowest-level) subcommand methods can likewise be asynchronous.
1122
+
3. Limit asynchronous methods to final subcommands: Defining parent commands as asynchronous is not recommended, because it can result in additional threads and event loops being created. For best performance and to avoid unnecessary resource usage, only implement your deepest (child) subcommands as async def.
1123
+
1124
+
Below is a simple example demonstrating an asynchronous top-level command:
1125
+
1126
+
```py
1127
+
from pydantic_settings import BaseSettings, CliApp
1128
+
1129
+
1130
+
classAsyncSettings(BaseSettings):
1131
+
asyncdefcli_cmd(self) -> None:
1132
+
print('Hello from an async CLI method!')
1133
+
#> Hello from an async CLI method!
1134
+
1135
+
1136
+
# If an event loop is already running, a new thread will be used;
1137
+
# otherwise, asyncio.run() is used to execute this async method.
As mentioned above, you can also define subcommands as async. However, only do so for the leaf (lowest-level) subcommand to avoid spawning new threads and event loops unnecessarily in parent commands:
1144
+
1145
+
```py
1146
+
from pydantic import BaseModel
1147
+
1148
+
from pydantic_settings import (
1149
+
BaseSettings,
1150
+
CliApp,
1151
+
CliPositionalArg,
1152
+
CliSubCommand,
1153
+
)
1154
+
1155
+
1156
+
classClone(BaseModel):
1157
+
repository: CliPositionalArg[str]
1158
+
directory: CliPositionalArg[str]
1159
+
1160
+
asyncdefcli_cmd(self) -> None:
1161
+
# Perform async tasks here, e.g. network or I/O operations
1162
+
print(f'Cloning async from "{self.repository}" into "{self.directory}"')
1163
+
#> Cloning async from "repo" into "dir"
1164
+
1165
+
1166
+
classGit(BaseSettings):
1167
+
clone: CliSubCommand[Clone]
1168
+
1169
+
defcli_cmd(self) -> None:
1170
+
# Run the final subcommand (clone/init). It is recommended to define async methods only at the deepest level.
When executing a subcommand with an asynchronous cli_cmd, Pydantic settings automatically detects whether the current thread already has an active event loop. If so, the async command is run in a fresh thread to avoid conflicts. Otherwise, it uses asyncio.run() in the current thread. This handling ensures your asynchronous subcommands “just work” without additional manual setup.
1181
+
1116
1182
### Mutually Exclusive Groups
1117
1183
1118
1184
CLI mutually exclusive groups can be created by inheriting from the `CliMutuallyExclusiveGroup` class.
0 commit comments