Skip to content

Instantly share code, notes, and snippets.

@mottosso
Last active August 29, 2015 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mottosso/f4cb1c636fae3fc63ab0 to your computer and use it in GitHub Desktop.
Save mottosso/f4cb1c636fae3fc63ab0 to your computer and use it in GitHub Desktop.
Library versioning example
"""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()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment