如何版本插件

时间:2014-10-08 17:01:29

标签: python

如何在Python中处理插件的版本控制?

我有一个基于插件的库,在这些早期阶段,库经常发生变化。我希望插件保持现有状态,即使它们在更新后松散与库的兼容性,以便允许用户对特定插件的警告不再是最新的

使用requirements.txt语法

的示例

每个插件都是它自己的类,并定义了一个requires字符串,例如 pyblish< = 1 。然后有一个库的当前版本。以下is_compatible允许将requirements.txt样式字符串与任意version_info样式版本进行比较。

"""Library versioning using the default Python syntax

Example:
    >>> is_compatible("pyblish<=1", (0, 9, 0))
    True
    >>> is_compatible("pyblish>=1.1, <2.1", (2, 0, 0))
    True

"""

import re
import operator


def is_compatible(requirement, version):
    """Return whether or not `requirement` is compatible with `version`

    Example:
        >>> is_compatible("pyblish<=1", (0, 9, 0))
        True
        >>> is_compatible("pyblish>=1, <1.3", (1, 2, 0))
        True
        >>> is_compatible("pyblish>=0.9.9", (1, 0, 0))
        True
        >>> is_compatible("pyblish>=1.1, <2.1", (2, 0, 0))
        True
        >>> is_compatible("pyblish==1.0.0", (1, 0, 0))
        True
        >>> is_compatible("pyblish==1.0.0", (1, 0, 1))
        False

    """

    results = list()

    for operator_string, requirement_string in parse_requirements(requirement):
        operator = operators[operator_string]
        required = string_to_tuple(requirement_string)
        result = operator(version, required)

        results.append(result)

    return all(results)


def parse_requirements(line):
    """From pkg_utils.parse_requirements

    Example:
        >>> parse_requirements("pyblish==1.0.0")
        [('==', '1.0.0')]
        >>> parse_requirements("pyblish>=1.1.0")
        [('>=', '1.1.0')]
        >>> parse_requirements("pyblish>=1.1.0, <1.2")
        [('>=', '1.1.0'), ('<', '1.2')]

    """

    LINE_END = re.compile(r"\s*(#.*)?$")
    DISTRO = re.compile(r"\s*((\w|[-.])+)")
    VERSION = re.compile(r"\s*(<=?|>=?|==|!=)\s*((\w|[-.])+)")
    COMMA = re.compile(r"\s*,")

    match = DISTRO.match(line)
    p = match.end()
    specs = list()

    while not LINE_END.match(line, p):
        match = VERSION.match(line, p)
        if not match:
            raise ValueError(
                "Expected version spec in",
                line, "at", line[p:])

        specs.append(match.group(*(1, 2)))
        p = match.end()

        match = COMMA.match(line, p)
        if match:
            p = match.end()  # Skip comma
        elif not LINE_END.match(line, p):
            raise ValueError(
                "Expected ',' or end-of-list in",
                line, "at", line[p:])

    return specs


def string_to_tuple(version):
    """Convert version as string to tuple

    Example:
        >>> string_to_tuple("1.0.0")
        (1, 0, 0)
        >>> string_to_tuple("2.5")
        (2, 5)

    """

    return tuple(map(int, version.split(".")))


operators = {"<":   operator.lt,
             "<=":  operator.le,
             "==":  operator.eq,
             "!=":  operator.ne,
             ">=":  operator.ge,
             ">":   operator.gt}


if __name__ == '__main__':
    import doctest
    doctest.testmod()

问题

你好吗?是否存在处理此类版本控制的现有推荐方法?还有哪些其他语法?

参考文献:requirements.txtrezcondarequirements-parser

由于

1 个答案:

答案 0 :(得分:0)

在更好的事情出现之前,我已经在GitHub上传了上述示例的精炼版本,以及通过pit / PyPI进行的文档和安装,在MIT下获得许可,可在此处获取:

基本用法

$ pip install iscompatible
$ python

>>> from iscompatible import iscompatible
>>> iscompatible("foo>=5", (5, 6, 1))
True
>>> iscompatible("foo>=5.6.1, <5.7", (5, 0, 0))
False
>>> MyPlugin = type("MyPlugin", (), {'version': (5, 6, 1)})
>>> iscompatible("foo==5.6.1", MyPlugin.version)
True

我仍然对现有的解决方案或技巧和窍门感兴趣!也许这个包可以帮助更好地定义我的要求。