_version.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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. __all__ = ['NumpyVersion']
  8. class NumpyVersion:
  9. """Parse and compare numpy version strings.
  10. NumPy has the following versioning scheme (numbers given are examples; they
  11. can be > 9 in principle):
  12. - Released version: '1.8.0', '1.8.1', etc.
  13. - Alpha: '1.8.0a1', '1.8.0a2', etc.
  14. - Beta: '1.8.0b1', '1.8.0b2', etc.
  15. - Release candidates: '1.8.0rc1', '1.8.0rc2', etc.
  16. - Development versions: '1.8.0.dev-f1234afa' (git commit hash appended)
  17. - Development versions after a1: '1.8.0a1.dev-f1234afa',
  18. '1.8.0b2.dev-f1234afa', '1.8.1rc1.dev-f1234afa', etc.
  19. - Development versions (no git hash available): '1.8.0.dev-Unknown'
  20. Comparing needs to be done against a valid version string or other
  21. `NumpyVersion` instance. Note that all development versions of the same
  22. (pre-)release compare equal.
  23. Parameters
  24. ----------
  25. vstring : str
  26. NumPy version string (``np.__version__``).
  27. Examples
  28. --------
  29. >>> from numpy.lib import NumpyVersion
  30. >>> if NumpyVersion(np.__version__) < '1.7.0':
  31. ... print('skip')
  32. >>> # skip
  33. >>> NumpyVersion('1.7') # raises ValueError, add ".0"
  34. Traceback (most recent call last):
  35. ...
  36. ValueError: Not a valid numpy version string
  37. """
  38. __module__ = "numpy.lib"
  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, (str, NumpyVersion)):
  93. raise ValueError("Invalid object to compare with NumpyVersion.")
  94. if isinstance(other, str):
  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 f"NumpyVersion({self.vstring})"