You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python-Click将命令行选项映射为Dataclass/Pydantic对象?

实现Click与Pydantic模型的自动绑定

针对你的需求,我们可以通过自定义装饰器和Click参数类型两种方式,实现命令行选项与Pydantic/dataclass对象的自动转换,无需手动组装实例。

一、自动生成多选项,直接接收Pydantic实例

通过自定义装饰器遍历Pydantic模型的字段,自动生成对应的Click选项,并在命令函数中直接传入组装好的模型实例。

步骤1:定义Pydantic模型和装饰器

import click
from pydantic import BaseModel, Optional, Field
from getpass import getlogin

class Host(BaseModel):
    username: str = Field(getlogin(), description="Remote host login username")
    password: Optional[str] = Field(None, description="Remote host login password")
    address: str = Field('localhost', description="Remote host IP/domain")
    port: int = Field(22, description="Remote host SSH port")

def click_pydantic_options(model: type[BaseModel]):
    def decorator(func):
        # 反向遍历字段,保证选项顺序与模型定义一致(装饰器从下往上应用)
        for field_name in reversed(model.model_fields):
            field = model.model_fields[field_name]
            short_opt = f"-{field_name[0]}"
            long_opt = f"--{field_name}"
            
            # 动态添加Click选项
            func = click.option(
                short_opt, long_opt,
                type=field.annotation,
                default=field.default if not field.is_required() else None,
                help=field.description
            )(func)
        
        # 包装函数,将参数组装为模型实例
        def wrapper(**kwargs):
            model_args = {k: v for k, v in kwargs.items() if k in model.model_fields}
            return func(host=model(**model_args))
        
        return wrapper
    return decorator

步骤2:使用装饰器定义命令

@click.group()
def remote_tools():
    pass

@remote_tools.command(
    name='remote', 
    help='Execute command on remote host', 
    context_settings=dict(max_content_width=120)
)
@click_pydantic_options(Host)
def command(host: Host):
    print(host)

运行命令示例:

remote_tools remote -a 192.168.1.100 -o 2222 -u admin

输出会是自动组装好的Host实例:

username='admin' password=None address='192.168.1.100' port=2222

二、单个选项解析为Pydantic实例,保留字段帮助信息

通过自定义Click参数类型,解析单个选项的键值对输入为Pydantic实例,并在帮助信息中展示每个字段的说明。

步骤1:定义自定义参数类型

class HostParamType(click.ParamType):
    name = "host"
    
    def convert(self, value, param, ctx):
        # 解析"key=value,key2=value2"格式的输入
        try:
            field_map = Host.model_fields
            kwargs = {}
            for part in value.split(','):
                key, val = part.split('=', 1)
                # 根据模型字段类型转换输入值
                kwargs[key] = field_map[key].annotation(val)
            return Host(**kwargs)
        except Exception as e:
            self.fail(
                f"Invalid format: {e}. Use 'address=ADDR[,port=PORT][,username=USER][,password=PASS]'",
                param, ctx
            )
    
    def get_metavar(self, param):
        return "address=ADDR[,port=PORT][,username=USER][,password=PASS]"
    
    def get_help_record(self, param):
        # 生成包含字段详情的帮助信息
        help_lines = [
            f"  {self.get_metavar(param)}:",
            "    Available fields:",
        ]
        for field_name, field in Host.model_fields.items():
            default_note = f" (default: {repr(field.default)})" if not field.is_required() else ""
            help_lines.append(f"      {field_name}: {field.description}{default_note}")
        return ('', '\n'.join(help_lines))

步骤2:使用自定义类型定义命令

@remote_tools.command(
    name='remote-single', 
    help='Execute command on remote host with single host option', 
    context_settings=dict(max_content_width=120)
)
@click.option('-h', '--host', type=HostParamType(), help='Remote host details')
def command_single(host: Host):
    print(host)

运行帮助命令remote_tools remote-single --help,会看到详细的字段说明:

Usage: remote_tools remote-single [OPTIONS]

  Execute command on remote host with single host option

Options:
  -h, --host address=ADDR[,port=PORT][,username=USER][,password=PASS]
        Available fields:
          username: Remote host login username (default: 'your-username')
          password: Remote host login password (default: None)
          address: Remote host IP/domain (default: 'localhost')
          port: Remote host SSH port (default: 22)
  --help                          Show this message and exit.

运行命令示例:

remote_tools remote-single -h address=192.168.1.100,port=2222,username=admin

输出同样是组装好的Host实例。

针对dataclass的适配

如果使用dataclass,只需将代码中model.model_fields替换为dataclasses.fields(model),并调整字段属性的获取方式(比如field.default、field.type),逻辑与上述一致。

内容的提问来源于stack exchange,提问作者nikoladsp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 22:20:31