1- from .string import ToStringMixin
2-
3-
4- class Version (ToStringMixin ):
1+ class Version :
52 """
6- Assists in checking the version of a Python package based on the __version__ attribute
3+ Represents a version, specifically the numeric components of a version string.
4+
5+ Suffixes like "rc1" or "-dev" are ignored, i.e. for a version string like "1.2.3rc1",
6+ the components are [1, 2, 3].
77 """
8- def __init__ (self , package ):
8+
9+ def __init__ (self , package_or_version : object | str ):
910 """
10- :param package: the package object
11+ :param package_or_version: a package object (with a `__version__` attribute) or a version string like "1.2.3".
12+ If a version contains a suffix (like "1.2.3rc1" or "1.2.3-dev"), the suffix is ignored.
1113 """
12- self .components = package .__version__ .split ("." )
14+ if isinstance (package_or_version , str ):
15+ version_string = package_or_version
16+ elif hasattr (package_or_version , "__version__" ):
17+ package_version_string = getattr (package_or_version , "__version__" , None )
18+ if package_version_string is None :
19+ raise ValueError (f"The given package object { package_or_version } has no __version__ attribute" )
20+ version_string = package_version_string
21+ else :
22+ raise ValueError ("The given argument must be either a version string or a package object with a __version__ attribute" )
23+ self .version_string = version_string
24+ self .components = self ._get_version_components (version_string )
25+
26+ def __str__ (self ) -> str :
27+ return self .version_string
1328
14- def __str__ (self ):
15- return "." .join (self .components )
29+ @staticmethod
30+ def _get_version_components (version_string : str ) -> list [int ]:
31+ components = version_string .split ("." )
32+ int_components = []
33+ for c in components :
34+ num_str = ""
35+ for ch in c :
36+ if ch .isdigit ():
37+ num_str += ch
38+ else :
39+ break
40+ if num_str == "" :
41+ break
42+ int_components .append (int (num_str ))
43+ return int_components
1644
17- def is_at_least (self , * components : int ):
45+ def is_at_least (self , * components : int ) -> bool :
1846 """
1947 Checks this version against the given version components.
2048 This version object must contain at least the respective number of components
@@ -23,14 +51,14 @@ def is_at_least(self, *components: int):
2351 :return: True if the version is at least the given version, False otherwise
2452 """
2553 for i , desired_min_version in enumerate (components ):
26- actual_version = int ( self .components [i ])
54+ actual_version = self .components [i ]
2755 if actual_version < desired_min_version :
2856 return False
2957 elif actual_version > desired_min_version :
3058 return True
3159 return True
3260
33- def is_at_most (self , * components : int ):
61+ def is_at_most (self , * components : int ) -> bool :
3462 """
3563 Checks this version against the given version components.
3664 This version object must contain at least the respective number of components
@@ -39,19 +67,19 @@ def is_at_most(self, *components: int):
3967 :return: True if the version is at most the given version, False otherwise
4068 """
4169 for i , desired_max_version in enumerate (components ):
42- actual_version = int ( self .components [i ])
70+ actual_version = self .components [i ]
4371 if actual_version > desired_max_version :
4472 return False
4573 elif actual_version < desired_max_version :
4674 return True
4775 return True
4876
49- def is_equal (self , * components : int ):
77+ def is_equal (self , * components : int ) -> bool :
5078 """
5179 Checks this version against the given version components.
5280 This version object must contain at least the respective number of components
5381
5482 :param components: version components in order (i.e. major, minor, patch, etc.)
5583 :return: True if the version is the given version, False otherwise
5684 """
57- return self .components [:len (components )] == list (components )
85+ return self .components [: len (components )] == list (components )
0 commit comments