PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/lib-python/2.7/distutils/versionpredicate.py

https://bitbucket.org/bwesterb/pypy
Python | 164 lines | 141 code | 10 blank | 13 comment | 2 complexity | 8df46ce8d68714877df6f2598b812442 MD5 | raw file
  1. """Module for parsing and testing package version predicate strings.
  2. """
  3. import re
  4. import distutils.version
  5. import operator
  6. re_validPackage = re.compile(r"(?i)^\s*([a-z_]\w*(?:\.[a-z_]\w*)*)(.*)")
  7. # (package) (rest)
  8. re_paren = re.compile(r"^\s*\((.*)\)\s*$") # (list) inside of parentheses
  9. re_splitComparison = re.compile(r"^\s*(<=|>=|<|>|!=|==)\s*([^\s,]+)\s*$")
  10. # (comp) (version)
  11. def splitUp(pred):
  12. """Parse a single version comparison.
  13. Return (comparison string, StrictVersion)
  14. """
  15. res = re_splitComparison.match(pred)
  16. if not res:
  17. raise ValueError("bad package restriction syntax: %r" % pred)
  18. comp, verStr = res.groups()
  19. return (comp, distutils.version.StrictVersion(verStr))
  20. compmap = {"<": operator.lt, "<=": operator.le, "==": operator.eq,
  21. ">": operator.gt, ">=": operator.ge, "!=": operator.ne}
  22. class VersionPredicate:
  23. """Parse and test package version predicates.
  24. >>> v = VersionPredicate('pyepat.abc (>1.0, <3333.3a1, !=1555.1b3)')
  25. The `name` attribute provides the full dotted name that is given::
  26. >>> v.name
  27. 'pyepat.abc'
  28. The str() of a `VersionPredicate` provides a normalized
  29. human-readable version of the expression::
  30. >>> print v
  31. pyepat.abc (> 1.0, < 3333.3a1, != 1555.1b3)
  32. The `satisfied_by()` method can be used to determine with a given
  33. version number is included in the set described by the version
  34. restrictions::
  35. >>> v.satisfied_by('1.1')
  36. True
  37. >>> v.satisfied_by('1.4')
  38. True
  39. >>> v.satisfied_by('1.0')
  40. False
  41. >>> v.satisfied_by('4444.4')
  42. False
  43. >>> v.satisfied_by('1555.1b3')
  44. False
  45. `VersionPredicate` is flexible in accepting extra whitespace::
  46. >>> v = VersionPredicate(' pat( == 0.1 ) ')
  47. >>> v.name
  48. 'pat'
  49. >>> v.satisfied_by('0.1')
  50. True
  51. >>> v.satisfied_by('0.2')
  52. False
  53. If any version numbers passed in do not conform to the
  54. restrictions of `StrictVersion`, a `ValueError` is raised::
  55. >>> v = VersionPredicate('p1.p2.p3.p4(>=1.0, <=1.3a1, !=1.2zb3)')
  56. Traceback (most recent call last):
  57. ...
  58. ValueError: invalid version number '1.2zb3'
  59. It the module or package name given does not conform to what's
  60. allowed as a legal module or package name, `ValueError` is
  61. raised::
  62. >>> v = VersionPredicate('foo-bar')
  63. Traceback (most recent call last):
  64. ...
  65. ValueError: expected parenthesized list: '-bar'
  66. >>> v = VersionPredicate('foo bar (12.21)')
  67. Traceback (most recent call last):
  68. ...
  69. ValueError: expected parenthesized list: 'bar (12.21)'
  70. """
  71. def __init__(self, versionPredicateStr):
  72. """Parse a version predicate string.
  73. """
  74. # Fields:
  75. # name: package name
  76. # pred: list of (comparison string, StrictVersion)
  77. versionPredicateStr = versionPredicateStr.strip()
  78. if not versionPredicateStr:
  79. raise ValueError("empty package restriction")
  80. match = re_validPackage.match(versionPredicateStr)
  81. if not match:
  82. raise ValueError("bad package name in %r" % versionPredicateStr)
  83. self.name, paren = match.groups()
  84. paren = paren.strip()
  85. if paren:
  86. match = re_paren.match(paren)
  87. if not match:
  88. raise ValueError("expected parenthesized list: %r" % paren)
  89. str = match.groups()[0]
  90. self.pred = [splitUp(aPred) for aPred in str.split(",")]
  91. if not self.pred:
  92. raise ValueError("empty parenthesized list in %r"
  93. % versionPredicateStr)
  94. else:
  95. self.pred = []
  96. def __str__(self):
  97. if self.pred:
  98. seq = [cond + " " + str(ver) for cond, ver in self.pred]
  99. return self.name + " (" + ", ".join(seq) + ")"
  100. else:
  101. return self.name
  102. def satisfied_by(self, version):
  103. """True if version is compatible with all the predicates in self.
  104. The parameter version must be acceptable to the StrictVersion
  105. constructor. It may be either a string or StrictVersion.
  106. """
  107. for cond, ver in self.pred:
  108. if not compmap[cond](version, ver):
  109. return False
  110. return True
  111. _provision_rx = None
  112. def split_provision(value):
  113. """Return the name and optional version number of a provision.
  114. The version number, if given, will be returned as a `StrictVersion`
  115. instance, otherwise it will be `None`.
  116. >>> split_provision('mypkg')
  117. ('mypkg', None)
  118. >>> split_provision(' mypkg( 1.2 ) ')
  119. ('mypkg', StrictVersion ('1.2'))
  120. """
  121. global _provision_rx
  122. if _provision_rx is None:
  123. _provision_rx = re.compile(
  124. "([a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*)(?:\s*\(\s*([^)\s]+)\s*\))?$")
  125. value = value.strip()
  126. m = _provision_rx.match(value)
  127. if not m:
  128. raise ValueError("illegal provides specification: %r" % value)
  129. ver = m.group(2) or None
  130. if ver:
  131. ver = distutils.version.StrictVersion(ver)
  132. return m.group(1), ver