ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FreeCAD Python API 弃用清单工具(python_api)使用与原理深度解析

FreeCAD Python API 弃用清单工具(python_api)使用与原理深度解析 FreeCAD Python API 弃用清单工具python_api使用与原理深度解析【免费下载链接】FreeCADOfficial source code of FreeCAD, a free and opensource multiplatform 3D parametric modeler.项目地址: https://gitcode.com/GitHub_Trending/fr/FreeCAD导读FreeCAD 是一个跨平台的开源参数化 3D 建模软件其庞大的 Python API 面向脚本编写者和二次开发者。随着版本迭代API 必然经历废弃与淘汰而手动维护一份准确的弃用清单既不现实也容易出错。src/Tools/python_api/README.md 描述了一套直接从 FreeCAD 源码中自动发现 Python API 弃用信息的工具它基于源码装饰器decorator扫描整个仓库输出确定性的 JSON 索引并提供check、manifest、list三个 CLI 子命令。本文将以该 README 为主线结合其源码实现cli.py、deprecations.py、model.py与测试用例test_python_api_deprecations.py完整讲解工具的使用方式、元数据约定、严格校验规则与底层实现原理。读完本文你将能运行该工具生成仓库的弃用索引、按版本筛选待移除 API并理解其静态扫描、零导入、强校验的设计哲学。一、工具定位与设计原则1.1 从源码中发现弃用信息而非手写清单README 开篇即点明工具的核心定位直接directly从 FreeCAD 源文件中发现 Python API 弃用信息。这意味着源码装饰器是权威authoritative一处标记处处生效杜绝了清单与源码不同步的问题JSON 输出只是确定性的索引deterministic indexREADME 明确说明 JSON 输出not intended to be edited or committed即产物不应被人工修改或提交进仓库它只是供下游消费的快照。1.2 边界明确不做什么README 在结尾明确划定了工具的功能边界Git 历史、API 签名跟踪、跨版本存储cross-release storage刻意不在其范围内。从源码看这一边界是真实的——scan_repository 只做当前工作区的一次性快照扫描没有任何依赖 Git 历史或版本数据库的逻辑。读者应据此判断该工具的适用场景它是一把当下状态检查器而非历史迁移分析器。1.3 测试保障README 声称仓库扫描由 src/Tools 测试套件覆盖这在 test_repository_scan_has_no_errors 中得到验证该测试对真实仓库根目录执行scan_repository断言零错误并抽查了DraftVecUtils.precision、Part.Face.Wire以及DraftUtils.readDXF、FreeCADGui._MDIView.message、Part.insert、Part.open、PathApp.fromShape等真实存在的弃用记录。二、快速上手三个 CLI 子命令README 给出四种典型用法均需在仓库根目录执行对应 cli.py 中定义的子命令解析逻辑# 校验全仓库的弃用元数据打印诊断信息并统计 python -m src.Tools.python_api check # 生成确定性 JSON 清单写入指定文件 python -m src.Tools.python_api manifest --output python-api-deprecations.json # 列出全部弃用记录表格形式 python -m src.Tools.python_api list # 按移除版本筛选只列出将在 27.2 及更早版本中被移除的 API python -m src.Tools.python_api list --remove-by 27.22.1 check校验元数据质量check遍历仓库打印全部诊断diagnostics最后输出统计Found N deprecations and M errors.退出码与错误数绑定有 error 级诊断时返回 1否则返回 0见 main 的return 1 if errors else 0因此它天然适合接入 CI 门禁。2.2 manifest生成确定性 JSON 索引manifest把扫描结果序列化为缩进 2、按键排序sort_keysTrue的 JSON{ schema_version: 1, deprecations: [ { symbol: ..., kind: ..., deprecated_in: ..., removed_in: ..., replacement: ..., details: null, source: ..., line: 42 } ] }--output缺省为-输出到 stdout指定文件路径时_write_manifest 会自动创建父目录测试 test_manifest_creates_parent_directories 验证了这一点。确定性由两方面保证记录按(symbol, kind, deprecated_in, removed_in, replacement, details, source, line)排序_record_sort_key且多条相同元数据只保留行号最小的一条测试 test_manifest_is_deterministic 对同一仓库两次生成并断言 JSON 完全相等同时确认输出中不包含metadata_kind、message这类运行时字段。2.3 list人类可读的表格list默认以表格输出表头为Symbol Deprecated Removal Replacement每条记录打印symbol / deprecated_in / removed_in / replacement无替代方案时 replacement 显示-空结果打印No matching deprecations.。--remove-by 27.2筛选removed_in 27.2的记录_release_key 做版本归一化比较若版本号不匹配^\d\.\d(\.\d)?$格式命令返回退出码 2 并向 stderr 报错invalid release: ...。--format json以asdict输出完整记录 JSON。测试 test_list_filters_by_removal_release 展示了--remove-by 27.1无匹配、--remove-by 27.2命中Example.old_api与FreeCADGui.hide的行为差异。2.4 通用选项三个子命令都接受--root指定仓库根目录默认Path.cwd()。这意味着你可以在任意目录下对指定仓库副本执行扫描例如python -m src.Tools.python_api --root /path/to/freecad check入口链为 __main__.pyraise SystemExit(main())将返回值直接作为进程退出码。三、扫描范围与文件类型3.1 扫描三类文件且不导入模块README 明确扫描器读取常规 Python.py、绑定.pyi、以及.module.pyi文件且不会导入importing它们。从源码看scan_repository 对src下每个.py/.pyi文件调用ast.parse构建语法树——纯静态分析不执行任何代码因此扫描对构建环境零依赖速度也更快。3.2 排除规则_source_paths 中通过SKIPPED_PARTS排除以下目录出现在相对路径任意层级即跳过3rdParty SCL_output generated tests __pycache__另外src/Tools自身rel.parts[0] Tools也被排除避免工具扫描自身造成循环噪声。这也解释了为何测试目录src/Tools/tests/中的弃用示例不会污染真实仓库清单。3.3 模块名推导规则_module_name 决定每条记录的symbol前缀.module.pyi文件直接以文件名去掉.module.pyi后缀作为模块名如src/Gui/FreeCADGui.module.pyi→FreeCADGuisrc/Mod/Workbench/App/...下的文件取App之后的路径如src/Mod/Part/App/Thing.pyi→Part.Thingsrc/App、src/Base、src/Gui下的文件去掉首层目录如src/App/Example.py→Example普通__init__.py/__init__.pyi只贡献目录路径其余文件名去掉后缀参与拼接。测试 test_workbench_module_stubs_use_public_module_names 验证了PathApp、Part这类工作台公开模块名的正确推导。四、元数据约定deprecated 与 deprecated_attributes4.1 结构化生命周期元数据README 强调结构化生命周期元数据会被校验Structured lifecycle metadata is validated。所有deprecated装饰器必须使用关键字参数形式合法字段恰好四个STRUCTURED_FIELDS字段必填类型说明deprecated_in是str开始弃用的版本须匹配^\d\.\d(\.\d)?$如26.3removed_in是str计划移除的版本必须晚于deprecated_inreplacement否str 或 None替代 API 的调用建议如new_api()details否str 或 None附加说明文本运行时装饰器实现在 src/Ext/freecad/deprecation.py_validate_lifecycle对空字符串、非法版本格式如next以及removed_in deprecated_in均抛出ValueErrorreplacement/details非字符串时抛TypeError。其生成的弃用警告消息格式为module.name is deprecated since FreeCAD deprecated_in and will be removed in FreeCAD removed_in; use replacement instead; details.测试 test_decorator_warns_with_lifecycle_and_replacement 验证了DeprecationWarning类别、消息内容以及__deprecated__属性的一致性test_message_does_not_duplicate_terminal_punctuation 则保证句尾标点不重复。4.2 运行时行为与静态索引的关系值得注意deprecated装饰器在运行时通过typing_extensions.deprecatedPEP 702实现真正的DeprecationWarning触发并借助_WRAPPER_CODES集合与_unwrap_deprecated_frame让警告堆栈直接指向调用者而非装饰器包装层。而src/Tools/python_api的扫描器只做语法层面的发现与校验两者互为印证装饰器是运行时真相扫描器是静态索引。4.3 类级属性弃用deprecated_attributes属性弃用通过类装饰器deprecated_attributes声明其参数是属性名到结构化元数据映射_scan_attributesfrom Base.Metadata import deprecated, deprecated_attributes, export export(PythonNamePart.Thing) deprecated_attributes( old_attr{ deprecated_in: 26.3, removed_in: 27.2, replacement: new_attr, }, ) class ThingSpec: old_attr: int每个属性值必须是字典结构化映射非字典会被报错metadata must be a structured mapping每个属性的 symbol 为类符号.属性名kind 记为attribute。测试 fixture 中的Part.Thing.old_attr正是此路径的覆盖样例。五、严格校验哪些写法会被拒绝README 点名的三类拒绝为错误rejected as errors均有对应实现与测试5.1 位置参数形式的 PEP 702 装饰器from typing_extensions import deprecated deprecated(Use replacement instead.) def old_function(): ..._scan_decorators 检测到deprecated(...)带位置参数decorator.args非空即报错deprecated() requires structured keyword-only lifecycle metadata测试 test_rejects_legacy_deprecation_metadata。5.2 字符串形式的 deprecated_attributes 元数据deprecated_attributes(old_attrsome string)这类非映射值会被判定为错误见 4.3 节。更一般地_literal_keywords要求所有参数值可被ast.literal_eval求值关键字解包**kwargs报keyword unpacking is not supported非常量表达式报field must be a literal value。5.3 仅存在于 docstring 的弃用说明def old_docstring(): Deprecated -- use replacement instead. ..._scan_docstring 用LEGACY_DOC_RE大小写不敏感匹配deprecated后跟:/--/-扫描函数、方法、类的 docstring命中即报错symbol uses docstring-only deprecation metadata。注意该规则并非禁止 docstring 中出现Deprecated字样而是禁止以 docstring 作为唯一的弃用声明途径。5.4 其他元数据一致性问题未知字段如deadline28.1会报unknown deprecation field deadlinetest_reports_invalid_lifecycle_metadata版本倒挂removed_in deprecated_in报removed_in must be later than deprecated_in非字面量/非字符串字段deprecated_in、removed_in必须是非空字符串replacement、details必须是字符串或 null同名符号的冲突元数据同一 symbol 若出现多套不同的(deprecated_in, removed_in, replacement, details)生命周期组合scan_repository 会报conflicting metadata for symbol语法解析失败无法ast.parse的文件报cannot parse source: ...。六、真实仓库中的使用样例6.1 符号命名与导出绑定类binding classes的公开名若与原生包装名不同必须用export(PythonName...)声明README 明确要求。_class_public_name 解析PythonName与Name两种键缺省回退到绑定模块.类名。该逻辑仅在.pyi非.module.pyi的顶层类上生效见 visit_ClassDefFreeCADGui/FreeCAD绑定模块的映射见 _binding_module。.module.pyi中的函数属于模块级公开 API如FreeCADGui.hide。6.2 重载overload折叠同一函数的多个overload变体若携带完全相同的弃用元数据会合并为一条记录test_matching_overload_metadata_collapses_to_one_record保证清单里每个 symbol 至多一条记录。6.3 完整 fixture 示例以下组合展示了kind的四种取值function / method / class / attribute以及.py、.pyi、.module.pyi三种文件的混用来自测试夹具 _fixture# src/App/Example.py —— 模块级函数kindfunction from freecad.deprecation import deprecated deprecated(deprecated_in26.3, removed_in27.2, replacementnew_api()) def old_api(): ... # src/Mod/Part/App/Thing.pyi —— 类、方法、属性kindclass/method/attribute from Base.Metadata import deprecated, deprecated_attributes, export export(PythonNamePart.Thing) deprecated_attributes(old_attr{deprecated_in: 26.3, removed_in: 27.2, replacement: new_attr}) deprecated(deprecated_in26.3, removed_in28.1, replacementBetterThing) class ThingSpec: old_attr: int deprecated(deprecated_in26.3, removed_in27.2, replacementnew_method()) def old_method(self) - None: ... # src/Gui/FreeCADGui.module.pyi —— 模块级 API绑定模块 from Base.Metadata import deprecated deprecated(deprecated_in26.3, removed_in27.2, replacementhideObject) def hide() - None: ...扫描结果 symbol 集合为Example.old_api、Example.older_api、FreeCADGui.hide、Part.Thing、Part.Thing.old_attr、Part.Thing.old_method。七、数据模型与 CLI 退出码速查7.1 数据模型model.py 定义了三个冻结数据类DeprecationRecordsymbol、kind、deprecated_in、removed_in、replacement、details、source仓库相对路径、lineDiagnosticsource、line、severityerror 级决定退出码、messageScanResultrecords与diagnostics的只读元组。7.2 退出码约定退出码场景0check/manifest/list正常完成manifest/list即使有 error 诊断也返回 0仅check与错误数绑定1check发现至少一条 error 级诊断2list --remove-by传入非法版本号八、总结与延伸阅读src.Tools.python_api是 FreeCAD 将Python API 弃用管理工程化的落点以源码装饰器为单一事实源通过纯 AST 静态扫描生成确定性索引用严格校验把元数据质量问题消灭在提交之前。它不追踪历史、不跨版本存储但足以支撑当前仓库弃用面盘点与某版本前移除 API 清单这两类高频需求。工具入口与 CLIcli.py、__main__.py扫描与校验核心deprecations.py数据模型model.py运行时装饰器运行时警告的真实来源deprecation.py测试套件test_python_api_deprecations.py、test_deprecation.py若你正在维护 FreeCAD 的 Python 绑定或工作台模块请遵循本文第四节的元数据约定标注弃用 API并定期在 CI 中运行check即可确保仓库的弃用索引始终权威、一致、可机器消费。【免费下载链接】FreeCADOfficial source code of FreeCAD, a free and opensource multiplatform 3D parametric modeler.项目地址: https://gitcode.com/GitHub_Trending/fr/FreeCAD创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表