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
+63Lines changed: 63 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1061,6 +1061,69 @@ For `BaseModel` and `pydantic.dataclasses.dataclass` types, `CliApp.run` will in
1061
1061
*`cli_implicit_flags=True`
1062
1062
*`cli_kebab_case=True`
1063
1063
1064
+
### Asynchronous CLI Commands
1065
+
1066
+
Pydantic settings now 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:
1067
+
1068
+
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.
1069
+
2. Subcommands may also be asynchronous: If you have nested CLI subcommands, the final (lowest-level) subcommand methods can likewise be asynchronous.
1070
+
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.
1071
+
1072
+
Below is a simple example demonstrating an asynchronous top-level command:
1073
+
1074
+
```py
1075
+
from pydantic_settings import BaseSettings, CliApp
1076
+
1077
+
1078
+
classAsyncSettings(BaseSettings):
1079
+
asyncdefcli_cmd(self) -> None:
1080
+
print('Hello from an async CLI method!')
1081
+
1082
+
1083
+
if__name__=='__main__':
1084
+
# If an event loop is already running, a new thread will be used;
1085
+
# otherwise, asyncio.run() is used to execute this async method.
1086
+
CliApp.run(AsyncSettings)
1087
+
```
1088
+
1089
+
#### Asynchronous Subcommands
1090
+
1091
+
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:
1092
+
1093
+
```py
1094
+
from pydantic import BaseModel
1095
+
1096
+
from pydantic_settings import (
1097
+
BaseSettings,
1098
+
CliApp,
1099
+
CliPositionalArg,
1100
+
CliSubCommand,
1101
+
)
1102
+
1103
+
1104
+
classClone(BaseModel):
1105
+
repository: CliPositionalArg[str]
1106
+
directory: CliPositionalArg[str]
1107
+
1108
+
asyncdefcli_cmd(self) -> None:
1109
+
print(f'Cloning async from "{self.repository}" into "{self.directory}"')
1110
+
# Perform async tasks here, e.g. network or I/O operations
1111
+
1112
+
1113
+
classGit(BaseSettings):
1114
+
clone: CliSubCommand[Clone]
1115
+
1116
+
defcli_cmd(self) -> None:
1117
+
# 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.
1126
+
1064
1127
### Mutually Exclusive Groups
1065
1128
1066
1129
CLI mutually exclusive groups can be created by inheriting from the `CliMutuallyExclusiveGroup` class.
0 commit comments