pydantic-settings 2.16.0 元组位置参数错位,报 variadic 参数冲突
固定长度 tuple 和 NamedTuple 在 2.16.0 被误判为可变位置参数,可能吞掉后续值或报 SettingsError。2.16.1 已修复;保留 JSON 参数边界与原类型约束。
pydantic-settings 从 2.15.0 升到 2.16.0 后,原来一个 JSON 参数表示的二元组可能吞掉后面的姓名,或者在创建 CLI 时就报:
SettingsError: TwoPairs has multiple variadic positional arguments: src, dst
这个回归涉及 CliPositionalArg[tuple[int, int]]、固定长度元组以及 NamedTuple。当它们旁边还有另一个位置参数或子命令时,固定元组被误当成可变长度参数,参数排序和消耗方式都会改变。正式 2.16.1 已修复这项分类。
保持固定元组作为一个 JSON 值传入
适用于正式 2.16.1 的简化示例:
from pydantic_settings import BaseSettings, CliApp, CliPositionalArg
class PairAndName(BaseSettings):
pair: CliPositionalArg[tuple[int, int]]
name: CliPositionalArg[str]
settings = CliApp.run(
PairAndName,
cli_args=["[1,2]", "bob"],
cli_exit_on_error=False,
)
assert settings.pair == (1, 2)
assert settings.name == "bob"
这里 [1,2] 是一个参数字符串。真实 shell 调用时,仍应按 shell 的引号规则把 JSON 保持为单个参数,不能拆成两个位置参数 1 2。CliApp.run 的列表示例直接给出参数边界,不依赖 shell 如何展开。
2.16.0 把所有相关 Sequence 子类都归到可变长度位置参数,固定元组于是可能排到普通位置参数之后。在上述布局里,bob 进入元组后,错误也可能表现为整数解析失败,而非 SettingsError。仅改成 tuple[str, str] 会改变业务类型,并不能恢复位置参数契约。
不要顺带改变真正的可变参数
2.16.1 区分固定长度元组与 tuple[int, ...]。后者仍可变;显式包装为 CliVariadicArg 也仍表达可变参数意图。两个固定元组、固定元组后接子命令、NamedTuple 和带 None 的联合类型,都需要按自己的声明核对。
如果项目暂时不能升级,可在兼容约束允许时锁回先前的 2.15.0,连同依赖锁文件一起恢复,再检查所有 CLI 入口。2.16.1 要求 Python 3.11 及以上;旧 Python 环境不应只改一个包版本就忽略解释器限制。
不要照着 2.16.0 的错误结果调换业务参数顺序,也不要删除元组长度约束来迁就解析器。这样的 CLI 一旦换到修复版本,可能再次把参数送错字段。
更新后检查模型解析出的每个字段,不能只看退出码。参数值类型相同的情况下,错位可能不触发验证错误;还应保留固定元组和后续参数都含不同标记值的用例,确认顺序与内容一致。


