DEBUG.WIKI
OnlineSIM:在线接收短信,虚拟号码租用
RackNerd;$21.99/年 · 1GB KVM
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证

packaging 解析超长版本号报 ValueError,为什么没进入 InvalidVersion 分支

版本数字段触发 Python 整数转换资源限制时,packaging 可抛普通 ValueError。用应用输入长度政策和明确失败边界处理,不关闭全进程保护。

版本字符串很长时,packaging.version.Version() 可能抛出普通 ValueError,而不是代码里专门捕获的 InvalidVersion。日志常包含整数转换的数字位数限制,随后请求直接失败。

这条表现明确出现于 packaging 26.0 与 Python 3.12.7;26.3 的正式实现仍会保留这种资源限制异常。全是数字的超长字符串不一定先违反版本语法,但将它转换成 Python 整数时会撞上解释器的限制。

不要只在版本语法错误处分流

对普通的 not-a-version,捕获 InvalidVersion 可以解释为格式无效;对于一个几千位的数字段,失败点可能是 int() 转换。两种错误恰好都发生在版本解析入口,原因却不同。

检查异常文本、输入长度和当前解释器的整数转换限制即可,不必把整段异常输入打印进日志。默认限制、运行配置以及 Python 构建可能不同,不应把某次观察到的 4300 位写成所有服务的固定阈值。

import sys

limit = sys.get_int_max_str_digits()

这个读取接口用于提供它的 Python 版本,例如本题的 Python 3.12。返回值为零表示关闭该项限制,不代表应用可以无成本接受任意长度版本号。

在输入边界先实施自己的长度政策

如果字段由外部请求提供,可以在进入解析器前限制它的长度,并保留资源异常的失败分支。下面是仅用于单个版本字段的示例;256 是示例应用的政策,不是 PEP 440 的最大长度:

from packaging.version import InvalidVersion, Version

def parse_version_field(text: str) -> Version:
    if len(text) > 256:
        raise ValueError("version field exceeds the application limit")
    try:
        return Version(text)
    except InvalidVersion:
        raise ValueError("version field has invalid syntax") from None
    except ValueError:
        raise ValueError("version field exceeds a runtime conversion limit") from None

调用方仍须把这些失败送到原来的输入拒绝流程,而不是返回一个默认版本。输入类型检查应由现有字段校验负责;不要把任意对象先转成字符串,从而让错误的请求类型通过。

长度政策要根据真实版本数据制定,并覆盖已经存储的数据、批量导入及其他入口。截断版本号不是等价处理,可能把一个不同或无效的输入改成可接受版本。

如果处理的是 SpecifierSet,还要覆盖随后执行 contains()、filter() 的阶段。约束中的版本有些会延迟到比较时才转换,构造约束成功并不保证后续不会遇到同类资源限制。不要把上面的单版本函数直接当作整条约束表达式解析器。

关闭全进程的整数位数保护会扩大其他整数解析入口的成本,不适合作为外部版本字段的默认修复。用有界输入和明确错误响应恢复原功能;升级 packaging 时仍保留这项边界检查。

验证要同时包括正常版本、正常语法错误、超过应用上限的字段,以及各调用阶段的错误处理。确认失败没有被当作“版本满足要求”,日志也没有因为记录超长输入再次膨胀。