通过比较python存根文件

时间:2018-01-23 12:52:49

标签: python stub semantic-versioning mypy typeshed

我正在尝试确定python包的公共部分的接口更改为以前的版本。这是为了帮助进行语义版本控制(MAJOR_CHANGE.MINOR_CHANGE.PATCH)我能想到的最好方法是:

  1. 为新版本的软件包生成存根文件(您可以使用stubgen执行此操作。这为您提供了整个软件包,子软件包和模块的公共接口......
  2. 比较新旧版本软件包的存根。
    • 如果没有更改界面,则新版本只会+1到PATCH编号
    • 如果原始界面保持不变但是添加了新的功能(或属性),这将是一个小的改动,所以+1到MINOR
    • 如果原始界面的任何部分发生变化,那将是一次重大改变,所以+1到MAJOR
  3. 基本上,问题是,对于这些更改,比较2个存根文件包的最佳方法是什么?我们可以比较AST文件,虽然这些文件不包含类型信息(我们可以尝试使用它来解决https://github.com/python/typed_ast

    此处的示例存根文件:

    # Stubs for positioning.point (Python 3.6)
    #
    # NOTE: This dynamically typed stub was automatically generated by stubgen.
    
    import numpy as np
    from .exceptions import UnacceptableCartesianCoordinates
    from .frame import Frame
    from .methods import check_frames_have_common_parent, get_coordinates_of_point_in_frame, lowest_common_parent
    from typing import Any
    
    class Point:
        def __init__(self, frame: Frame, point_coordinates: np.ndarray) -> None: ...
        @classmethod
        def from_cartesian(cls: Any, frame: Frame, x: float, y: float, z: float) -> Point: ...
        @classmethod
        def from_cylindrical(cls: Any, frame: Frame, r: float, phi: float, z: float) -> Point: ...
        @classmethod
        def from_spherical(cls: Any, frame: Frame, r: float, theta: float, phi: float) -> Point: ...
        @classmethod
        def from_old_point_in_new_frame(cls: Any, old_point: Point, new_frame: Frame) -> Point: ...
        @classmethod
        def at_origin(cls: Any, frame: Frame) -> Point: ...
        @property
        def frame(self): ...
        def __eq__(self, other: Any) -> bool: ...
    

    编辑:

    要更加清晰(并使用花哨的图表!)我希望比较2个包A和B之间的公共接口。使用类型信息生成公共接口的最佳方法是使用stubgen。因此,包的公共接口将由.pyi个文件包定义。

    然后我们使用一个新的魔术工具(称为snappy,如interface-diff)来比较A和B的两个接口。在最高级别,我们将比较接口时有4个潜在的结果。

    1)主要 - 从A中删除的东西而不是添加到B的东西

    enter image description here

    2)主要 - 从A中删除的东西和添加到B的东西

    enter image description here

    3)MINOR - 将事物添加到B而不是从A

    中删除

    enter image description here

    4)PATCH - A == B

    enter image description here

    如果有人能让我走上正确的路线,我很高兴自己写这个:)

1 个答案:

答案 0 :(得分:0)

您需要的是每个存根的抽象语法树(AST)。没有新节点意味着补丁,新叶节点可能意味着较小(取决于节点的语言和位置),新的非叶节点意味着主要节点。但这并不是真正的整个解决方案,因为并非所有重大变化都会出现在接口存根上。您还需要进行功能验证,即现有接口的任何新实现,实际上满足记录的行为(合同)以及使用任何新接口都不会破坏旧接口。

您应该能够在公开的Python实现中找到好的解析器/ AST实现。您可以使用旧的和新的实现的AST来查找现有接口背后的潜在重大变化!