Coverage for src / bioimageio / spec / _internal / version_type.py: 93%

61 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-02-23 10:51 +0000

1from __future__ import annotations 

2 

3from typing import Any, Optional, Tuple, Union 

4 

5import packaging.version 

6from pydantic import PrivateAttr, RootModel 

7 

8 

9class Version(RootModel[Union[str, int, float]]): 

10 """wraps a packaging.version.Version instance for validation in pydantic models""" 

11 

12 _version: packaging.version.Version = PrivateAttr() 

13 

14 def __str__(self): 

15 return str(self._version) 

16 

17 def model_post_init(self, __context: Any) -> None: 

18 """set `_version` attribute @private""" 

19 self._version = packaging.version.Version(str(self.root)) 

20 return super().model_post_init(__context) 

21 

22 def __lt__(self, other: Any): 

23 if not isinstance(other, Version): 

24 return NotImplemented 

25 

26 return self._version < other._version 

27 

28 def __eq__(self, other: Any): 

29 if not isinstance(other, Version): 

30 return NotImplemented 

31 return self._version == other._version 

32 

33 # the properties below are adopted from and mirror properties of packaging.version.Version 

34 @property 

35 def epoch(self) -> int: 

36 """The epoch of the version. 

37 

38 >>> Version("2.0.0").epoch 

39 0 

40 >>> Version("1!2.0.0").epoch 

41 1 

42 """ 

43 return self._version.epoch 

44 

45 @property 

46 def release(self) -> Tuple[int, ...]: 

47 """The components of the "release" segment of the version. 

48 

49 >>> Version("1.2.3").release 

50 (1, 2, 3) 

51 >>> Version("2.0.0").release 

52 (2, 0, 0) 

53 >>> Version("1!2.0.0.post0").release 

54 (2, 0, 0) 

55 

56 Includes trailing zeroes but not the epoch or any pre-release / development / 

57 post-release suffixes. 

58 """ 

59 return self._version.release 

60 

61 @property 

62 def pre(self) -> Optional[Tuple[str, int]]: 

63 """The pre-release segment of the version. 

64 

65 >>> print(Version("1.2.3").pre) 

66 None 

67 >>> Version("1.2.3a1").pre 

68 ('a', 1) 

69 >>> Version("1.2.3b1").pre 

70 ('b', 1) 

71 >>> Version("1.2.3rc1").pre 

72 ('rc', 1) 

73 """ 

74 return self._version.pre 

75 

76 @property 

77 def post(self) -> Optional[int]: 

78 """The post-release number of the version. 

79 

80 >>> print(Version("1.2.3").post) 

81 None 

82 >>> Version("1.2.3.post1").post 

83 1 

84 """ 

85 return self._version.post 

86 

87 @property 

88 def dev(self) -> Optional[int]: 

89 """The development number of the version. 

90 

91 >>> print(Version("1.2.3").dev) 

92 None 

93 >>> Version("1.2.3.dev1").dev 

94 1 

95 """ 

96 return self._version.dev 

97 

98 @property 

99 def local(self) -> Optional[str]: 

100 """The local version segment of the version. 

101 

102 >>> print(Version("1.2.3").local) 

103 None 

104 >>> Version("1.2.3+abc").local 

105 'abc' 

106 """ 

107 return self._version.local 

108 

109 @property 

110 def public(self) -> str: 

111 """The public portion of the version. 

112 

113 >>> Version("1.2.3").public 

114 '1.2.3' 

115 >>> Version("1.2.3+abc").public 

116 '1.2.3' 

117 >>> Version("1.2.3+abc.dev1").public 

118 '1.2.3' 

119 """ 

120 return self._version.public 

121 

122 @property 

123 def base_version(self) -> str: 

124 """The "base version" of the version. 

125 

126 >>> Version("1.2.3").base_version 

127 '1.2.3' 

128 >>> Version("1.2.3+abc").base_version 

129 '1.2.3' 

130 >>> Version("1!1.2.3+abc.dev1").base_version 

131 '1!1.2.3' 

132 

133 The "base version" is the public version of the project without any pre or post 

134 release markers. 

135 """ 

136 return self._version.base_version 

137 

138 @property 

139 def is_prerelease(self) -> bool: 

140 """Whether this version is a pre-release. 

141 

142 >>> Version("1.2.3").is_prerelease 

143 False 

144 >>> Version("1.2.3a1").is_prerelease 

145 True 

146 >>> Version("1.2.3b1").is_prerelease 

147 True 

148 >>> Version("1.2.3rc1").is_prerelease 

149 True 

150 >>> Version("1.2.3dev1").is_prerelease 

151 True 

152 """ 

153 return self._version.is_prerelease 

154 

155 @property 

156 def is_postrelease(self) -> bool: 

157 """Whether this version is a post-release. 

158 

159 >>> Version("1.2.3").is_postrelease 

160 False 

161 >>> Version("1.2.3.post1").is_postrelease 

162 True 

163 """ 

164 return self._version.is_postrelease 

165 

166 @property 

167 def is_devrelease(self) -> bool: 

168 """Whether this version is a development release. 

169 

170 >>> Version("1.2.3").is_devrelease 

171 False 

172 >>> Version("1.2.3.dev1").is_devrelease 

173 True 

174 """ 

175 return self._version.is_devrelease 

176 

177 @property 

178 def major(self) -> int: 

179 """The first item of :attr:`release` or ``0`` if unavailable. 

180 

181 >>> Version("1.2.3").major 

182 1 

183 """ 

184 return self._version.major 

185 

186 @property 

187 def minor(self) -> int: 

188 """The second item of :attr:`release` or ``0`` if unavailable. 

189 

190 >>> Version("1.2.3").minor 

191 2 

192 >>> Version("1").minor 

193 0 

194 """ 

195 return self._version.minor 

196 

197 @property 

198 def micro(self) -> int: 

199 """The third item of :attr:`release` or ``0`` if unavailable. 

200 

201 >>> Version("1.2.3").micro 

202 3 

203 >>> Version("1").micro 

204 0 

205 """ 

206 return self._version.micro