_version.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. """Utility to compare (Numpy) version strings.
  2. The NumpyVersion class allows properly comparing numpy version strings.
  3. The LooseVersion and StrictVersion classes that distutils provides don't
  4. work; they don't recognize anything like alpha/beta/rc/dev versions.
  5. """
  6. import re
  7. from scipy._lib.six import string_types
  8. __all__ = ['NumpyVersion']
  9. class NumpyVersion():
  10. """Parse and compare numpy version strings.
  11. Numpy has the following versioning scheme (numbers given are examples; they
  12. can be >9) in principle):
  13. - Released version: '1.8.0', '1.8.1', etc.
  14. - Alpha: '1.8.0a1', '1.8.0a2', etc.
  15. - Beta: '1.8.0b1', '1.8.0b2', etc.
  16. - Release candidates: '1.8.0rc1', '1.8.0rc2', etc.
  17. - Development versions: '1.8.0.dev-f1234afa' (git commit hash appended)
  18. - Development versions after a1: '1.8.0a1.dev-f1234afa',
  19. '1.8.0b2.dev-f1234afa',
  20. '1.8.1rc1.dev-f1234afa', etc.
  21. - Development versions (no git hash available): '1.8.0.dev-Unknown'
  22. Comparing needs to be done against a valid version string or other
  23. `NumpyVersion` instance.
  24. Parameters
  25. ----------
  26. vstring : str
  27. Numpy version string (``np.__version__``).
  28. Notes
  29. -----
  30. All dev versions of the same (pre-)release compare equal.
  31. Examples
  32. --------
  33. >>> from scipy._lib._version import NumpyVersion
  34. >>> if NumpyVersion(np.__version__) < '1.7.0':
  35. ... print('skip')
  36. skip
  37. >>> NumpyVersion('1.7') # raises ValueError, add ".0"
  38. """
  39. def __init__(self, vstring):
  40. self.vstring = vstring
  41. ver_main = re.match(r'\d[.]\d+[.]\d+', vstring)
  42. if not ver_main:
  43. raise ValueError("Not a valid numpy version string")
  44. self.version = ver_main.group()
  45. self.major, self.minor, self.bugfix = [int(x) for x in
  46. self.version.split('.')]
  47. if len(vstring) == ver_main.end():
  48. self.pre_release = 'final'
  49. else:
  50. alpha = re.match(r'a\d', vstring[ver_main.end():])
  51. beta = re.match(r'b\d', vstring[ver_main.end():])
  52. rc = re.match(r'rc\d', vstring[ver_main.end():])
  53. pre_rel = [m for m in [alpha, beta, rc] if m is not None]
  54. if pre_rel:
  55. self.pre_release = pre_rel[0].group()
  56. else:
  57. self.pre_release = ''
  58. self.is_devversion = bool(re.search(r'.dev', vstring))
  59. def _compare_version(self, other):
  60. """Compare major.minor.bugfix"""
  61. if self.major == other.major:
  62. if self.minor == other.minor:
  63. if self.bugfix == other.bugfix:
  64. vercmp = 0
  65. elif self.bugfix > other.bugfix:
  66. vercmp = 1
  67. else:
  68. vercmp = -1
  69. elif self.minor > other.minor:
  70. vercmp = 1
  71. else:
  72. vercmp = -1
  73. elif self.major > other.major:
  74. vercmp = 1
  75. else:
  76. vercmp = -1
  77. return vercmp
  78. def _compare_pre_release(self, other):
  79. """Compare alpha/beta/rc/final."""
  80. if self.pre_release == other.pre_release:
  81. vercmp = 0
  82. elif self.pre_release == 'final':
  83. vercmp = 1
  84. elif other.pre_release == 'final':
  85. vercmp = -1
  86. elif self.pre_release > other.pre_release:
  87. vercmp = 1
  88. else:
  89. vercmp = -1
  90. return vercmp
  91. def _compare(self, other):
  92. if not isinstance(other, (string_types, NumpyVersion)):
  93. raise ValueError("Invalid object to compare with NumpyVersion.")
  94. if isinstance(other, string_types):
  95. other = NumpyVersion(other)
  96. vercmp = self._compare_version(other)
  97. if vercmp == 0:
  98. # Same x.y.z version, check for alpha/beta/rc
  99. vercmp = self._compare_pre_release(other)
  100. if vercmp == 0:
  101. # Same version and same pre-release, check if dev version
  102. if self.is_devversion is other.is_devversion:
  103. vercmp = 0
  104. elif self.is_devversion:
  105. vercmp = -1
  106. else:
  107. vercmp = 1
  108. return vercmp
  109. def __lt__(self, other):
  110. return self._compare(other) < 0
  111. def __le__(self, other):
  112. return self._compare(other) <= 0
  113. def __eq__(self, other):
  114. return self._compare(other) == 0
  115. def __ne__(self, other):
  116. return self._compare(other) != 0
  117. def __gt__(self, other):
  118. return self._compare(other) > 0
  119. def __ge__(self, other):
  120. return self._compare(other) >= 0
  121. def __repr__(self):
  122. return "NumpyVersion(%s)" % self.vstring