version.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. """Version comparison utilities for semantic versioning.
  2. This module provides utilities for parsing and comparing semantic version strings.
  3. Supports version strings in the format: major.minor (e.g., "1.0", "1.2")
  4. """
  5. from __future__ import annotations
  6. import logging
  7. import re
  8. logger = logging.getLogger(__name__)
  9. def parse_version(version_str: str) -> tuple[int, int]:
  10. """Parse a semantic version string into a tuple of integers.
  11. Args:
  12. version_str: Version string in format "major.minor" (e.g., "1.0", "1.2")
  13. Returns:
  14. Tuple of (major, minor) as integers
  15. Raises:
  16. ValueError: If version string is not in valid semantic version format
  17. Examples:
  18. >>> parse_version("1.0")
  19. (1, 0)
  20. >>> parse_version("1.2")
  21. (1, 2)
  22. """
  23. if not version_str:
  24. raise ValueError("Version string cannot be empty")
  25. # Remove 'v' prefix if present
  26. version_str = version_str.lstrip("v")
  27. # Match semantic version pattern: major.minor
  28. pattern = r"^(\d+)\.(\d+)$"
  29. match = re.match(pattern, version_str)
  30. if not match:
  31. raise ValueError(f"Invalid version format '{version_str}'. Expected format: major.minor (e.g., '1.0', '1.2')")
  32. major, minor = match.groups()
  33. return (int(major), int(minor))
  34. def compare_versions(version1: str, version2: str) -> int:
  35. """Compare two semantic version strings.
  36. Args:
  37. version1: First version string
  38. version2: Second version string
  39. Returns:
  40. -1 if version1 < version2
  41. 0 if version1 == version2
  42. 1 if version1 > version2
  43. Raises:
  44. ValueError: If either version string is invalid
  45. Examples:
  46. >>> compare_versions("1.0", "0.9")
  47. 1
  48. >>> compare_versions("1.0", "1.0")
  49. 0
  50. >>> compare_versions("1.0", "1.1")
  51. -1
  52. """
  53. v1 = parse_version(version1)
  54. v2 = parse_version(version2)
  55. if v1 < v2:
  56. return -1
  57. if v1 > v2:
  58. return 1
  59. return 0
  60. def is_compatible(current_version: str, required_version: str) -> bool:
  61. """Check if current version meets the minimum required version.
  62. Args:
  63. current_version: Current version
  64. required_version: Minimum required version
  65. Returns:
  66. True if current_version >= required_version, False otherwise
  67. Examples:
  68. >>> is_compatible("1.0", "0.9")
  69. True
  70. >>> is_compatible("1.0", "1.0")
  71. True
  72. >>> is_compatible("1.0", "1.1")
  73. False
  74. """
  75. try:
  76. return compare_versions(current_version, required_version) >= 0
  77. except ValueError as e:
  78. logger.warning("Version compatibility check failed: %s", e)
  79. # If we can't parse versions, assume incompatible for safety
  80. return False