ARTICLE DETAIL

资讯详情

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

PyGithub 类成员顺序规范化:`sort_class.py` 方法排序工具实战指南

PyGithub 类成员顺序规范化:`sort_class.py` 方法排序工具实战指南 开发工具【免费下载链接】PyGithubTyped interactions with the GitHub API v3项目地址https://gitcode.com/gh_mirrors/py/PyGithub点击查看免费下载本文面向 PyGithub 的维护者与二次开发者系统讲解如何利用scripts/sort_class.py让所有继承GithubObject的类严格遵循 ARCHITECTURE.md 中定义的 “Internal Class Order” 约定并在--dry-run只读模式下安全预览改动、确认后再落盘。读完本文你将掌握该脚本的命令行用法、参数语义、底层排序逻辑基于 libcst 的 AST 重排以及它与openapi.py索引机制之间的协作关系可直接接入现有开发与贡献流程。一、背景为什么 PyGithub 需要对类成员排序PyGithub 是 GitHub REST API v3 的 Python 类型化客户端其github/目录下存在大量继承GithubObject的类如Autolink、HookDelivery、Repository等每个类都要维护私有属性声明、特殊方法、property访问器、公开方法和_useAttributes回填逻辑。随着openapi.py脚本从 GitHub REST API 的 OpenAPI 规范自动生成、更新代码成员顺序很容易被打乱。sort_class.py的目的正是“让 PyGithub 类符合既定的方法与方法顺序约定”Sort methods in PyGithub classes从而保证全仓库代码风格统一降低人工 review 负担让openapi.py脚本基于稳定结构做增量更新见 doc/scripts.rst 中 Thescripts/openapi.pyscript works best when attributes and methods are sorted. 的说明使 diff 更小、更可读便于维护者逐类审查自动生成的改动。注意该脚本只适用于继承GithubObject含CompletableGithubObject、NonCompletableGithubObject等派生基类的类普通辅助类不在排序范围内详见下文源码解析中的基类判定逻辑。二、先决条件openapi.index索引文件脚本的第一个位置参数是索引文件路径通常名为openapi.index它由scripts/openapi.py的index命令生成python3 scripts/openapi.py index github/ api.github.com.2022-11-28.json openapi.index该索引是一个 JSON 文件记录了 OpenAPI spec 与 PyGithub 代码库的映射关系。SKILL 文档明确提示如果索引文件尚不存在必须先用openapi.py创建它具体工作流参见 .claude/skills/openapi/SKILL.md。该 SKILL 还强调索引文件与生成它所使用的 OpenAPI spec 文件如api.github.com.2022-11-28.json是紧密绑定的更换 spec 就需要重新生成索引。SKILL 文档的 frontmatter 开头有一行from scripts import openapi/from scripts.sort_class import sort_class这指示本技能依赖scripts/目录下的两个模块即openapi.py负责生成索引与sort_class.py负责排序两者必须配套使用。三、命令行用法与参数详解3.1 基本调用形式SKILL 文档给出的标准命令为python scripts/sort_class.py --dry-run openapi.index class1 class2 ...从 doc/scripts.rst 与脚本自带的 argparse 帮助可以还原出完整的 usageusage: sort_class.py [-h] [--dry-run] index_filename class_name [class_name ...] Sorts methods of GithubObject classes, also sorts attributes in _initAttributes and _useAttributes positional arguments: index_filename Path of index file class_name GithubObject class to sort, e.g. HookDelivery or github.HookDelivery.HookDeliverySummary options: -h, --help show this help message and exit --dry-run show prospect changes and do not modify the file参数语义与 scripts/sort_class.py 中parse_args()的实现一一对应参数类型说明index_filename位置参数openapi.index索引文件路径用于将类名解析为源文件路径class_name位置参数nargs可传多个要排序的GithubObject类名可传简单类名如HookDelivery或全限定名如github.HookDelivery.HookDeliverySummary--dry-run布尔开关默认False只展示将产生的改动unified diff不修改任何文件class_name的两种写法说明简单类名脚本会到索引的classes表中查package、module、name拼出全限定名scripts/sort_class.py全限定名含.直接按package.module.Class三段拆分适用于需要精确指定嵌套类如github.HookDelivery.HookDeliverySummary对应 github/HookDelivery.py 中的嵌套类的场景。脚本根据解析结果把文件定位到{package}/{module}.py例如github/Autolink.py。若传了多个类会打印Sorting N Python files的提示并使用multiprocessing.Pool对多个文件并行排序main()中每个文件分配独立的manager.Lock防并发写冲突见 scripts/sort_class.py。3.2 干跑dry-run与正式应用SKILL 文档强调了一条安全工作流始终先用--dry-run只读预览——它不会改动任何文件只输出类名和对应的 unified diff将改动展示给用户评审征得同意后再执行正式命令若用户明确同意应用且无需再次评审去掉--dry-run重新执行即可落盘。对应实现dry_runTrue时脚本用difflib.unified_diff打印旧代码与新代码的差异通过stdout锁串行输出避免多进程交错只有dry_runFalse且tree_updated.deep_equals(tree)为假时才真正写回文件scripts/sort_class.py。# 1. 只读预览推荐 python scripts/sort_class.py --dry-run openapi.index Autolink HookDelivery # 2. 评审通过后正式应用 python scripts/sort_class.py openapi.index Autolink HookDelivery3.3 一次性排序所有类虽然 SKILL 文档的调用形式是按类名逐个排序但仓库中的 scripts/openapi-update-classes.sh 展示了批量场景该脚本用jq从索引读取GithubObject的所有子孙类class_to_descendants过滤掉继承自ABC的抽象类后把全部具体类一次性传给sort_class.py见 scripts/openapi-update-classes.sh 与update()中的调用。这印证了脚本nargs设计就是为了支持“给定一个类或多个类或全部类”的批量需求。四、排序规则Internal Class Order排序逻辑并非随意为之而是严格遵循 ARCHITECTURE.md 中 Internal Class Order 一节的约定。该约定要求的类内成员顺序为_initAttributes() dunder methods (alphabetical: __eq__, __hash__, __repr__, __str__, …) property (one per attribute, alphabetical by name) public methods _useAttributes()补充约束_useAttributes永远是类中最后一个方法Dunder 方法__name__形式的特殊方法紧跟在_initAttributes()之后按字母序排列。PyGithub 类中最常见的有__eq__(self, other)自定义相等性如NamedUser按login与id比较__hash__(self)凡定义__eq__必须同时定义__repr__(self)每个类都有通常使用self.get__repr__({key: self._key.value})__str__(self)需要人类可读的单行字符串时使用如CodeScanAlertInstanceLocation公开方法拥有大量方法的类会把相关操作聚成一块放在主方法之后例如所有 reaction 方法get_reactions→create_reaction→delete_reaction作为一组sub-issue 方法同理。五、源码级实现原理libcst AST 重排排序能力由 scripts/sort_class.py 中的SortMethodsTransformer继承cst.CSTTransformer实现它用libcst把 Python 源码解析成具体语法树CST在保留注释、空白、引号风格的前提下安全地重排节点。核心流程如下5.1 类级排序leave_ClassDef范围过滤若指定了class_name仅处理当前类否则处理所有类scripts/sort_class.py基类判定检查类的所有基类名是否以GithubObject结尾含cst.Name与属性访问两种形态不满足则跳过——这正是“只作用于 GithubObject 类”的机制scripts/sort_class.py健壮性校验若类中没有任何函数、或函数不构成连续块中间夹杂非函数语句直接抛出ValueError防止破坏代码结构scripts/sort_class.py分桶重排把函数块拆成prolog函数前的类级语句如 docstring、__init__、_initAttributes、dunder 方法集合、property方法集合、其余公开方法、_useAttributes、epilog函数后的尾随语句然后按约定顺序重组prolog __init__ _initAttributes dunders(字母序) properties(字母序) public methods _useAttributes epilogscripts/sort_class.py其中 dunder 与 property 集合会按方法名做字母排序sort_func_defs而公开方法仅在sort_funcsTrue时排序默认保持原有相对顺序以尊重人工对方法分组/cluster 的编排ARCHITECTURE 中提到的方法聚类惯例。5.2 属性级排序leave_FunctionDefSortMethodsTransformer还深入两个特殊方法的函数体内部_initAttributes找出函数体中连续的AnnAssign带类型注解的赋值语句块按属性名self._xxx的xxx字母序排序scripts/sort_class.py。这对应 ARCHITECTURE 的要求“所有私有属性字段按字母序每个都带类型并初始化为NotSet”_useAttributes找出函数体中连续的if xxx in attributes分支块按分支测试的属性名排序scripts/sort_class.py。5.3 一个已排序的范例以 github/Autolink.py 为例其成员顺序完全符合约定class Autolink(NonCompletableGithubObject): ... def _initAttributes(self) - None: # 1. 属性声明字母序 self._id: Attribute[int] NotSet self._is_alphanumeric: Attribute[bool] NotSet self._key_prefix: Attribute[str] NotSet self._updated_at: Attribute[datetime] NotSet self._url_template: Attribute[str] NotSet def __repr__(self) - str: # 2. dunder return self.get__repr__({id: self._id.value}) property # 3. property 访问器字母序 def id(self) - int: return self._id.value property def is_alphanumeric(self) - bool: return self._is_alphanumeric.value # ... key_prefix / updated_at / url_template 依次排列 def _useAttributes(self, attributes: dict[str, Any]) - None: # 4. 最后一个方法 if id in attributes: # pragma no branch self._id self._makeIntAttribute(attributes[id]) if is_alphanumeric in attributes: # pragma no branch self._is_alphanumeric self._makeBoolAttribute(attributes[is_alphanumeric]) # ...可以看到_useAttributes中的if分支同样按属性名字母序排列。这正是运行sort_class.py之后类应呈现的标准形态。六、实际工作流在 OpenAPI 更新流程中的位置sort_class.py并非孤立工具它是 PyGithub 自动化更新管线的一环。在 scripts/openapi-update-classes.sh 的update()函数中每个类的处理顺序为openapi.py suggest schemas --add # 为类补充 OpenAPI schema openapi.py index # 重建索引 sort_class.py index classes # 先排序类成员本次主题 openapi.py apply properties # 应用属性到源码 openapi.py apply properties --tests # 同步测试文件 prepare-for-update-assertions.py update-assertions.sh # 更新断言 pytest testAttributes # 运行属性测试每一步之后都会以 “Sort attributes and methods in $class” 之类的信息提交。从该脚本还可以看到sort_class.py被独立运行$python $sort_class $index ${classes[]}即排序是先于schema 应用执行的、独立的代码整理步骤——先保证结构稳定再做增量修改。因此如果参与 PyGithub 的贡献流程推荐的手动操作序列为# 0) 确保索引存在若缺失 python3 scripts/openapi.py index github/ api.github.com.2022-11-28.json openapi.index # 1) 预览指定类的排序改动 python scripts/sort_class.py --dry-run openapi.index HookDelivery # 2) 评审后正式应用 python scripts/sort_class.py openapi.index HookDelivery # 3) 运行 lint 与类型检查openapi 技能要求 pre-commit run --all-files mypy github tests七、常见问题与注意事项索引缺失直接运行sort_class.py会因找不到openapi.index而报错。先按 .claude/skills/openapi/SKILL.md 的initfetch index流程生成索引文件索引过期任何对 PyGithub 源码的改动新增类、改名、移动文件都要求重新执行openapi.py index更新索引否则类名解析可能失败或指向错误文件类名不存在简单类名在索引的classes中查不到时main()会抛出ValueError(fClass {class_name} does not exist in index)scripts/sort_class.py--dry-run是安全边界建议把它当作默认习惯正式应用前务必确认 diff 内容符合 Internal Class Order 预期非 GithubObject 类会被自动跳过不需要手工规避脚本按基类名自动判断多类并行同时传入多个类时脚本并行排序但通过文件级锁保证同一文件不会被并发写坏可以放心批量使用。八、小结sort_class.py以一行命令将 PyGithub 类成员顺序收敛到 ARCHITECTURE.md 规定的统一形态是 OpenAPI 自动更新体系中的“稳定器”先排序、再应用 schema、最后同步测试与断言。其核心实现libcst AST 变换 多进程并行 文件锁既保证了重排的安全性也保证了批量处理的效率。维护者与贡献者只要遵循“先--dry-run评审、再正式应用”的流程即可让仓库中每一个GithubObject类都保持清晰、一致、可机器处理的结构。参考资源技能文档.claude/skills/sorted-classes/SKILL.md脚本源码scripts/sort_class.py排序约定ARCHITECTURE.mdInternal Class Order 一节索引生成前置.claude/skills/openapi/SKILL.md 与 scripts/openapi.py文档说明doc/scripts.rstScript sort_class.py 一节集成脚本scripts/openapi-update-classes.sh已排序范例github/Autolink.py赞分享开发工具【免费下载链接】PyGithubTyped interactions with the GitHub API v3项目地址https://gitcode.com/gh_mirrors/py/PyGithub点击查看免费下载相关推荐Terminal.Gui 代码布局规范Backing Field 与成员排序的工程实践指南Terminal.Gui 代码布局规范Backing Field 与成员排序的工程实践指南 本篇技术指南聚焦于 Terminal.Gui.NET 跨平台终端UI组件跨平台桌面应用VisiData 排序完全指南列类型、多级排序与排序顺序查看VisiData 排序完全指南列类型、多级排序与排序顺序查看 VisiData 是一款终端电子表格工具其内置排序体系围绕类型化值 排序优先级 内部数据分析CLI数据可视化eslint-plugin-unicorn 类成员顺序规则实战consistent-class-member-order 与快照测试深度剖析eslint plugin unicorn 类成员顺序规则实战consistent class member order 与快照测试深度剖析 本篇文章以 esLint代码质量上一篇5个实战技巧深度优化macOS鼠标体验的开源利器下一篇VoiceFixer终极指南免费AI音频修复工具拯救受损声音的完整教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表