首页
/ Polars 版本管理策略解析:语义化版本、破坏性变更政策与弃用周期

Polars 版本管理策略解析:语义化版本、破坏性变更政策与弃用周期

2026-09-05 22:17:02作者:卓炯娓

Polars 在 API 演进上奉行"认真对待向后兼容、但不惧做出更好的改变"的原则,其完整的版本策略集中记载于 docs/source/development/versioning.md。本文以该文档为主体,结合 Python/Rust 两侧的配置与工具源码,完整梳理 Polars 的语义化版本规则、破坏性变更的判定标准、不稳定功能(unstable)与弃用(deprecation)机制的实现细节,以及预发布与破坏性版本发布的节奏,帮助你在升级 Polars 大版本时有据可依、平稳迁移。

一、语义化版本:Major / Minor / Patch 的分级规则

Polars 遵循语义化版本(Semantic Versioning,semver)规范,版本号形如 主版本.次版本.补丁版本,各级递增对应不同类型的变更:

变更类型 版本号变化 示例
破坏性变更(Breaking changes) 主版本递增 1.0.02.0.0
新功能与性能改进 次版本递增 1.1.01.2.0
其他修复类变更 补丁版本递增 1.0.11.0.2

这条规则在仓库当前版本状态中可以直接得到印证:Rust 工作区 Cargo.tomlcrates/polars 工作区的版本为 0.55.1,而 Python 包 py-polars/pyproject.toml 的版本字段为 2.0.0rc1——后者正处于一个主版本(破坏性)版本的前夜,与该文档"破坏性版本"一节所述节奏完全吻合。

二、破坏性变更政策

2.1 设计哲学:宁可修正,也不背负历史包袱

原文档明确表达了维护团队的立场:

  • 并非所有设计都能一次做对,Polars 在推进中从用户反馈不断学习,有时为了快速推出新功能而没有充分评估所有影响;
  • 一旦出现这类失误,团队会修正错误并引入破坏性变更。多数情况下代价很小——用户收到弃用警告后,在代码库中做一次快速的查找替换即可;
  • 偶尔问题会更严重,例如查询引擎(query engine)层面的改动会动摇数据管道的既有假设。团队不会轻易做这类改动,但"如果相信它能让 Polars 变得更好,就会去做";
  • "从过去的失当决定中解放出来"是让 Polars 持续前进的关键。虽然用户跟进新版本需要时间与精力,但一个尽可能优秀的产品最终惠及所有人。

2.2 什么才算破坏性变更

文档给出了判定标准(原文加粗强调):

当公共 API(public API)中的某个既有组件被修改或移除时,即构成破坏性变更。

一个功能是否属于公共 API,以它是否出现在 API 参考文档中为准。据此,文档列出了正反两组示例:

属于破坏性变更:

  • 移除一个已被弃用(deprecated)的函数或方法;
  • 某个参数的默认值被改变;
  • 由于查询引擎的改动,某个查询的结果发生变化。

不属于破坏性变更:

  • 移除一个未被文档记载的函数;
  • 公共类的模块路径(import 路径)发生变化;
  • 为既有方法新增一个可选参数

此外有一条常被忽略的细则:Bug 修复不算破坏性变更,尽管它可能影响部分用户的工作流。

2.3 不稳定功能(Unstable Functionality)及其实现

文档指出,部分公共 API 会被标记为 unstable,识别方式有两种:API 参考文档中的警告,或开启 warn_unstable 配置项时运行时发出的警告。功能被标记为不稳定的常见原因有三类:

  1. 对精确的 API 形态尚无把握——名称、函数签名或实现未来可能改变;
  2. 功能尚未经过充分测试,真实场景下可能出现 Bug;
  3. 功能与 Polars 完整 API 的整合尚不完善——可能在一个上下文中可用,在另一个上下文中失效。

以 unstable 形式发布功能可以让维护团队收集真实场景下的反馈,在"最终定稿"前精细打磨;而只关心稳定、经过充分测试功能的用户,则可以回避这部分 API。关键规则:标记为 unstable 的功能随时可能发生变化,且该变化不会被视为破坏性变更。

这一机制在仓库中有完整的代码实现,可以逐层印证:

  • Python 端警告工具 py-polars/src/polars/_utils/unstable.py 提供了 issue_unstable_warning()unstable() 装饰器。unstable() 装饰器会在被装饰函数被调用时先发出警告再执行原函数;警告文本统一追加一句 "It may be changed at any point without it being considered a breaking change.",与文档表述逐字对应。该函数通过读取环境变量 POLARS_WARN_UNSTABLE 判断是否启用,未启用时静默返回,警告类型为 UnstableWarning(定义于 py-polars/src/polars/exceptions.py)。
  • 用户侧开关 py-polars/src/polars/config.py 中的 Config.warn_unstable 类方法负责设置/清除 POLARS_WARN_UNSTABLE 环境变量,并调用 plr.config_reload_env_var 让 Rust 侧即时感知。文档示例:
>>> pl.Config.warn_unstable(True)  # doctest: +SKIP
>>> pl.col("a").qcut(5)  # doctest: +SKIP
UnstableWarning: `qcut` is considered unstable. It may be changed at any point without it being considered a breaking change.
  • Rust 配置层 crates/polars-config/src/lib.rs 定义了常量 WARN_UNSTABLE: &str = "POLARS_WARN_UNSTABLE"DEFAULT_WARN_UNSTABLE: bool = true,并用 AtomicBool 存储该开关(第 24、25、217、297 行附近),提供 warn_unstable() 读取接口。从源码结构看,Rust 侧默认值为 true,而 Python 的 issue_unstable_warning 在未设置环境变量时按 0(关闭)处理——即在 Python 环境中需要显式调用 pl.Config.warn_unstable(True) 才会触发警告。
  • 行为验证 py-polars/tests/unit/meta/test_config.py 中的 test_warn_unstable 测试精确验证了三段行为:默认(未开启)时 issue_unstable_warning() 不产生警告;warn_unstable(True) 后再调用会产生 1 条警告;warn_unstable(False) 后则保持静默。

2.4 弃用警告(Deprecation Warnings)

文档的弃用策略是:如果决定引入破坏性变更,只要可行,就先弃用既有行为。例如决定重命名函数时,新函数会与旧函数并存一段时间,继续调用旧函数会触发弃用警告。

并非所有变更都能"优雅弃用"——查询引擎的改动可能波及 API 的大片区域,这类变更不会发警告,但一定会写入 changelog 与迁移指南(migration guide)。

针对 Rust 用户有一条特别规定(原文档以警告框形式标注):

Rust API 的破坏性变更不做先弃用,但会列入 changelog。 原因是当前阶段支持弃用功能会过于拖慢开发速度。

Python 端为弃用流程提供了一整套工具,位于 py-polars/src/polars/_utils/deprecation.py

  • issue_deprecation_warning(message, version=""):发出弃用警告的基础函数,可附带"自某版本起被弃用"的版本信息;
  • _deprecate_function / deprecated:将函数整体标记为弃用的装饰器;
  • deprecate_renamed_parameter(old_name, new_name):处理参数重命名场景,警告文案形如 "the argument old_name was deprecated in version X, use new_name instead",并在文档中追加 .. versionchanged:: 指令;
  • deprecate_nonkeyword_arguments(allowed_args, version):处理"仅允许关键字传参"这类迁移;
  • deprecate_parameter_as_multi_positional(old_name):处理参数从单值变多值(multi-positional)的场景。

这套工具正对应文档中"重命名函数时新旧并存"的具体工程做法:每一次弃用警告都携带明确的版本与替代方案,用户的"查找替换"迁移因此可以精准执行。

2.5 弃用周期:两个主版本

文档给出了明确的量化规则:

基本规则:被弃用的功能会在弃用发生后,保留到其后第二个破坏性(major)版本再被移除。

  • 例如在 1.2.3 中被弃用的函数,会保留到 2.0.0,在 3.0.0 中被移除。

例外规则:破坏性版本中引入的弃用会缩短。

  • 例如在 2.0.0(本身是破坏性版本)中弃用的函数,会在下一个破坏性版本 3.0.0 中直接移除。

由此可以推出一个实用的升级判断依据:如果你的程序不产生任何弃用警告,升级到下一个主版本基本是安全的。由于破坏性版本大约每六个月发布一次,用户实际有 6 到 12 个月的缓冲期来应对尚未落地的破坏性变更。

文档还保留了政策弹性:个别情况下弃用周期可能被调整——如果保留弃用功能阻塞了其他改进,团队可能将弃用周期缩短为一个破坏性版本,且这一点会在警告消息中说明;反之,如果弃用影响面很大,也可能延长周期。

三、发布频率与预发布流程

3.1 发布频率

Polars 没有固定的发布日程,而是"觉得有新鲜且有价值的内容时"就发版。实际节奏为:新的次版本(minor)大约每两周发布一次

3.2 预发布(Pre-releases)与冷却期

为降低回归风险,Polars 的发布流程是:

  1. 先发布一个 pre-release 版本(如当前仓库中的 2.0.0rc1 即属此类 release candidate);
  2. 随后进入持续数天的冷却期,期间阻止可能引入不稳定性的 pull request 合入;
  3. 冷却期内报告的回归 Bug 更可能在正式发布前得到修复;
  4. 官方鼓励用户主动测试预发布版本,以提升最终版本的稳定性。

3.3 破坏性版本的节奏

随着时间推移,会积累一些必须通过破坏性变更才能解决的问题;积累到足够多时,就发布一个破坏性版本。截至该文档撰写时:

  • 破坏性版本历史节奏为约每三到六个月一次
  • 随着 Polars 日趋成熟,破坏性变更的频率与严重度预计会持续下降;
  • 从该节点起,新的主版本预计约每六个月发布一次

四、配套的仓库资源:升级指南与 Changelog

围绕上述版本策略,仓库中还有两类配套文档值得结合使用:

  • 升级指南(Upgrade Guide) 位于 docs/source/releases/upgrade/index.md。每随一个破坏性版本发布,就会附带一份帮助从旧版本升级的指南,内容涵盖所有此前未经弃用的破坏性变更以及重要的新弃用。已发布的历史指南包括 0.19.md0.20.md1.md2.md。该页面还给出两条实操建议:
    • 在升级到新的大版本之前,先升级到最新的非破坏性版本,运行代码并处理全部弃用警告,新大版本的升级会顺畅得多;
    • 针对 Rust 用户,与 versioning.md 的 Rust 条款 一致:Rust 发布目前尚无升级指南,待 Rust API 破坏性变更速率放缓、并引入弃用政策后会补充。
  • Changelogdocs/source/releases/changelog.md。Polars 使用 GitHub 的 Releases 页面统一管理 Python 与 Rust 的版本变更日志,每个版本的 changelog 都在那里归档——这正是文档中"引擎级变更虽无警告、但一定进 changelog"承诺的落点。

五、总结:面向用户的升级决策清单

综合本文各节,可以提炼出面向 Polars 用户的版本决策要点:

  1. 看版本号定风险:minor 版本(约两周一次)带来新功能与性能改进,升级风险低;major 版本(约六个月一次)承载破坏性变更,需要对照升级指南评估。
  2. 盯弃用警告:升级前先跑一次最新 minor 版本,把代码中所有 deprecation warning 处理干净,大版本迁移基本无痛。
  3. 慎用不稳定功能:对 API 稳定性敏感的项目应开启 pl.Config.warn_unstable(True)(对应环境变量 POLARS_WARN_UNSTABLE),让 unstable 功能的每次调用都显式暴露;被标记 unstable 的 API 随时可能变,且不算破坏性变更。
  4. 记住例外条款:破坏性版本中引入的弃用只保留一个主版本;个别情况下弃用周期可能被缩短或延长,以警告消息和 changelog 的说明为准。
  5. Rust 用户须知:Rust API 破坏性变更不做预弃用、暂无升级指南,只能依赖 changelog;而 Python 用户拥有完整的弃用装饰器体系与逐版本升级指南两套保障。
登录后查看全文
热门项目推荐
相关项目推荐