Coverage for pyTooling/Versioning/__init__.py: 88%

675 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-04-25 22:22 +0000

1# ==================================================================================================================== # 

2# _____ _ _ __ __ _ _ # 

3# _ __ _ |_ _|__ ___ | (_)_ __ __ \ \ / /__ _ __ ___(_) ___ _ __ (_)_ __ __ _ # 

4# | '_ \| | | || |/ _ \ / _ \| | | '_ \ / _` \ \ / / _ \ '__/ __| |/ _ \| '_ \| | '_ \ / _` | # 

5# | |_) | |_| || | (_) | (_) | | | | | | (_| |\ V / __/ | \__ \ | (_) | | | | | | | | (_| | # 

6# | .__/ \__, ||_|\___/ \___/|_|_|_| |_|\__, (_)_/ \___|_| |___/_|\___/|_| |_|_|_| |_|\__, | # 

7# |_| |___/ |___/ |___/ # 

8# ==================================================================================================================== # 

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

13# ==================================================================================================================== # 

14# Copyright 2020-2025 Patrick Lehmann - Bötzingen, Germany # 

15# # 

16# Licensed under the Apache License, Version 2.0 (the "License"); # 

17# you may not use this file except in compliance with the License. # 

18# You may obtain a copy of the License at # 

19# # 

20# http://www.apache.org/licenses/LICENSE-2.0 # 

21# # 

22# Unless required by applicable law or agreed to in writing, software # 

23# distributed under the License is distributed on an "AS IS" BASIS, # 

24# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

25# See the License for the specific language governing permissions and # 

26# limitations under the License. # 

27# # 

28# SPDX-License-Identifier: Apache-2.0 # 

29# ==================================================================================================================== # 

30# 

31""" 

32Implementation of semantic and date versioning version-numbers. 

33 

34.. hint:: See :ref:`high-level help <VERSIONING>` for explanations and usage examples. 

35""" 

36from enum import Flag, Enum 

37from re import compile as re_compile 

38from sys import version_info # needed for versions before Python 3.11 

39from typing import Optional as Nullable, Union, Callable, Any 

40 

41try: 

42 from pyTooling.Decorators import export, readonly 

43 from pyTooling.MetaClasses import ExtendedType, abstractmethod, mustoverride 

44 from pyTooling.Exceptions import ToolingException 

45 from pyTooling.Common import getFullyQualifiedName 

46except (ImportError, ModuleNotFoundError): # pragma: no cover 

47 print("[pyTooling.Versioning] Could not import from 'pyTooling.*'!") 

48 

49 try: 

50 from Decorators import export, readonly 

51 from MetaClasses import ExtendedType, abstractmethod, mustoverride 

52 from Exceptions import ToolingException 

53 from Common import getFullyQualifiedName 

54 except (ImportError, ModuleNotFoundError) as ex: # pragma: no cover 

55 print("[pyTooling.Versioning] Could not import directly!") 

56 raise ex 

57 

58 

59@export 

60class Parts(Flag): 

61 """Enumeration describing parts of a version number that can be present.""" 

62 Unknown = 0 #: Undocumented 

63 Major = 1 #: Major number is present. (e.g. X in ``vX.0.0``). 

64 Year = 1 #: Year is present. (e.g. X in ``XXXX.10``). 

65 Minor = 2 #: Minor number is present. (e.g. Y in ``v0.Y.0``). 

66 Month = 2 #: Month is present. (e.g. X in ``2024.YY``). 

67 Week = 2 #: Week is present. (e.g. X in ``2024.YY``). 

68 Micro = 4 #: Patch number is present. (e.g. Z in ``v0.0.Z``). 

69 Patch = 4 #: Patch number is present. (e.g. Z in ``v0.0.Z``). 

70 Day = 4 #: Day is present. (e.g. X in ``2024.10.ZZ``). 

71 Level = 8 #: Release level is present. 

72 Dev = 16 #: Development part is present. 

73 Build = 32 #: Build number is present. (e.g. bbbb in ``v0.0.0.bbbb``) 

74 Post = 64 #: Post-release number is present. 

75 Prefix = 128 #: Prefix is present. 

76 Postfix = 256 #: Postfix is present. 

77 Hash = 512 #: Hash is present. 

78# AHead = 256 

79 

80 

81@export 

82class ReleaseLevel(Enum): 

83 """Enumeration describing the version's maturity level.""" 

84 Final = 0 #: 

85 ReleaseCandidate = -10 #: 

86 Development = -20 #: 

87 Gamma = -30 #: 

88 Beta = -40 #: 

89 Alpha = -50 #: 

90 

91 def __eq__(self, other: Any): 

92 if isinstance(other, str): 92 ↛ 93line 92 didn't jump to line 93 because the condition on line 92 was never true

93 other = ReleaseLevel(other) 

94 if not isinstance(other, ReleaseLevel): 94 ↛ 95line 94 didn't jump to line 95 because the condition on line 94 was never true

95 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by == operator.") 

96 if version_info >= (3, 11): # pragma: no cover 

97 ex.add_note(f"Supported types for second operand: {self.__class__.__name__}") 

98 raise ex 

99 

100 return self is other 

101 

102 def __ne__(self, other: Any): 

103 if isinstance(other, str): 

104 other = ReleaseLevel(other) 

105 if not isinstance(other, ReleaseLevel): 

106 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by == operator.") 

107 if version_info >= (3, 11): # pragma: no cover 

108 ex.add_note(f"Supported types for second operand: {self.__class__.__name__}") 

109 raise ex 

110 

111 return self is not other 

112 

113 def __lt__(self, other: Any): 

114 if isinstance(other, str): 114 ↛ 115line 114 didn't jump to line 115 because the condition on line 114 was never true

115 other = ReleaseLevel(other) 

116 if not isinstance(other, ReleaseLevel): 116 ↛ 117line 116 didn't jump to line 117 because the condition on line 116 was never true

117 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by == operator.") 

118 if version_info >= (3, 11): # pragma: no cover 

119 ex.add_note(f"Supported types for second operand: {self.__class__.__name__}") 

120 raise ex 

121 

122 return self.value < other.value 

123 

124 def __le__(self, other: Any): 

125 if isinstance(other, str): 

126 other = ReleaseLevel(other) 

127 if not isinstance(other, ReleaseLevel): 

128 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by == operator.") 

129 if version_info >= (3, 11): # pragma: no cover 

130 ex.add_note(f"Supported types for second operand: {self.__class__.__name__}") 

131 raise ex 

132 

133 return self.value <= other.value 

134 

135 def __gt__(self, other: Any): 

136 if isinstance(other, str): 136 ↛ 137line 136 didn't jump to line 137 because the condition on line 136 was never true

137 other = ReleaseLevel(other) 

138 if not isinstance(other, ReleaseLevel): 138 ↛ 139line 138 didn't jump to line 139 because the condition on line 138 was never true

139 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by == operator.") 

140 if version_info >= (3, 11): # pragma: no cover 

141 ex.add_note(f"Supported types for second operand: {self.__class__.__name__}") 

142 raise ex 

143 

144 return self.value > other.value 

145 

146 def __ge__(self, other: Any): 

147 if isinstance(other, str): 

148 other = ReleaseLevel(other) 

149 if not isinstance(other, ReleaseLevel): 

150 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by == operator.") 

151 if version_info >= (3, 11): # pragma: no cover 

152 ex.add_note(f"Supported types for second operand: {self.__class__.__name__}") 

153 raise ex 

154 

155 return self.value >= other.value 

156 

157 def __hash__(self) -> int: 

158 return hash(self.value) 

159 

160 def __str__(self) -> str: 

161 if self is ReleaseLevel.Final: 

162 return "final" 

163 elif self is ReleaseLevel.ReleaseCandidate: 

164 return "rc" 

165 elif self is ReleaseLevel.Development: 165 ↛ 166line 165 didn't jump to line 166 because the condition on line 165 was never true

166 return "dev" 

167 elif self is ReleaseLevel.Beta: 167 ↛ 168line 167 didn't jump to line 168 because the condition on line 167 was never true

168 return "beta" 

169 elif self is ReleaseLevel.Alpha: 169 ↛ 172line 169 didn't jump to line 172 because the condition on line 169 was always true

170 return "alpha" 

171 

172 raise ToolingException(f"Unknown ReleaseLevel '{self.name}'.") 

173 

174 

175@export 

176class Flags(Flag): 

177 """State enumeration, if a (tagged) version is build from a clean or dirty working directory.""" 

178 NoVCS = 0 #: No Version Control System VCS 

179 Clean = 1 #: A versioned build was created from a *clean* working directory. 

180 Dirty = 2 #: A versioned build was created from a *dirty* working directory. 

181 

182 CVS = 16 #: Concurrent Versions System (CVS) 

183 SVN = 32 #: Subversion (SVN) 

184 Git = 64 #: Git 

185 Hg = 128 #: Mercurial (Hg) 

186 

187 

188@export 

189def WordSizeValidator( 

190 bits: Nullable[int] = None, 

191 majorBits: Nullable[int] = None, 

192 minorBits: Nullable[int] = None, 

193 microBits: Nullable[int] = None, 

194 buildBits: Nullable[int] = None 

195): 

196 """ 

197 A factory function to return a validator for Version instances for a positive integer range based on word-sizes in bits. 

198 

199 :param bits: Number of bits to encode any positive version number part. 

200 :param majorBits: Number of bits to encode a positive major number in a version. 

201 :param minorBits: Number of bits to encode a positive minor number in a version. 

202 :param microBits: Number of bits to encode a positive micro number in a version. 

203 :param buildBits: Number of bits to encode a positive build number in a version. 

204 :return: A validation function for Version instances. 

205 """ 

206 majorMax = minorMax = microMax = buildMax = -1 

207 if bits is not None: 

208 majorMax = minorMax = microMax = buildMax = 2**bits - 1 

209 

210 if majorBits is not None: 

211 majorMax = 2**majorBits - 1 

212 if minorBits is not None: 

213 minorMax = 2**minorBits - 1 

214 if microBits is not None: 

215 microMax = 2 ** microBits - 1 

216 if buildBits is not None: 216 ↛ 217line 216 didn't jump to line 217 because the condition on line 216 was never true

217 buildMax = 2**buildBits - 1 

218 

219 def validator(version: SemanticVersion) -> bool: 

220 if Parts.Major in version._parts and version._major > majorMax: 

221 raise ValueError(f"Field 'Version.Major' > {majorMax}.") 

222 

223 if Parts.Minor in version._parts and version._minor > minorMax: 

224 raise ValueError(f"Field 'Version.Minor' > {minorMax}.") 

225 

226 if Parts.Micro in version._parts and version._micro > microMax: 

227 raise ValueError(f"Field 'Version.Micro' > {microMax}.") 

228 

229 if Parts.Build in version._parts and version._build > buildMax: 229 ↛ 230line 229 didn't jump to line 230 because the condition on line 229 was never true

230 raise ValueError(f"Field 'Version.Build' > {buildMax}.") 

231 

232 return True 

233 

234 return validator 

235 

236 

237@export 

238def MaxValueValidator( 

239 max: Nullable[int] = None, 

240 majorMax: Nullable[int] = None, 

241 minorMax: Nullable[int] = None, 

242 microMax: Nullable[int] = None, 

243 buildMax: Nullable[int] = None 

244): 

245 """ 

246 A factory function to return a validator for Version instances checking for a positive integer range [0..max]. 

247 

248 :param max: The upper bound for any positive version number part. 

249 :param majorMax: The upper bound for the positive major number. 

250 :param minorMax: The upper bound for the positive minor number. 

251 :param microMax: The upper bound for the positive micro number. 

252 :param buildMax: The upper bound for the positive build number. 

253 :return: A validation function for Version instances. 

254 """ 

255 if max is not None: 255 ↛ 258line 255 didn't jump to line 258 because the condition on line 255 was always true

256 majorMax = minorMax = microMax = buildMax = max 

257 

258 def validator(version: SemanticVersion) -> bool: 

259 if Parts.Major in version._parts and version._major > majorMax: 

260 raise ValueError(f"Field 'Version.Major' > {majorMax}.") 

261 

262 if Parts.Minor in version._parts and version._minor > minorMax: 

263 raise ValueError(f"Field 'Version.Minor' > {minorMax}.") 

264 

265 if Parts.Micro in version._parts and version._micro > microMax: 

266 raise ValueError(f"Field 'Version.Micro' > {microMax}.") 

267 

268 if Parts.Build in version._parts and version._build > buildMax: 268 ↛ 269line 268 didn't jump to line 269 because the condition on line 268 was never true

269 raise ValueError(f"Field 'Version.Build' > {buildMax}.") 

270 

271 return True 

272 

273 return validator 

274 

275 

276@export 

277class Version(metaclass=ExtendedType, slots=True): 

278 """Base-class for a version representation.""" 

279 

280 __hash: Nullable[int] #: once computed hash of the object 

281 

282 _parts: Parts #: Integer flag enumeration of present parts in a version number. 

283 _prefix: str #: Prefix string 

284 _major: int #: Major number part of the version number. 

285 _minor: int #: Minor number part of the version number. 

286 _micro: int #: Micro number part of the version number. 

287 _releaseLevel: ReleaseLevel #: Release level (alpha, beta, rc, final, ...). 

288 _releaseNumber: int #: Release number (Python calls this a serial). 

289 _post: int #: Post-release version number part. 

290 _dev: int #: Development number 

291 _build: int #: Build number part of the version number. 

292 _postfix: str #: Postfix string 

293 _hash: str #: Hash from version control system. 

294 _flags: Flags #: State if the version in a working directory is clean or dirty compared to a tagged version. 

295 

296 def __init__( 

297 self, 

298 major: int, 

299 minor: Nullable[int] = None, 

300 micro: Nullable[int] = None, 

301 level: Nullable[ReleaseLevel] = ReleaseLevel.Final, 

302 number: Nullable[int] = None, 

303 post: Nullable[int] = None, 

304 dev: Nullable[int] = None, 

305 *, 

306 build: Nullable[int] = None, 

307 postfix: Nullable[str] = None, 

308 prefix: Nullable[str] = None, 

309 hash: Nullable[str] = None, 

310 flags: Flags = Flags.NoVCS 

311 ) -> None: 

312 """ 

313 Initializes a version number representation. 

314 

315 :param major: Major number part of the version number. 

316 :param minor: Minor number part of the version number. 

317 :param micro: Micro (patch) number part of the version number. 

318 :param level: Release level (alpha, beta, release candidate, final, ...) of the version number. 

319 :param number: Release number part (in combination with release level) of the version number. 

320 :param post: Post number part of the version number. 

321 :param dev: Development number part of the version number. 

322 :param build: Build number part of the version number. 

323 :param postfix: The version number's postfix. 

324 :param prefix: The version number's prefix. 

325 :param hash: Postfix string. 

326 :param flags: The version number's flags. 

327 :raises TypeError: If parameter 'major' is not of type int. 

328 :raises ValueError: If parameter 'major' is a negative number. 

329 :raises TypeError: If parameter 'minor' is not of type int. 

330 :raises ValueError: If parameter 'minor' is a negative number. 

331 :raises TypeError: If parameter 'micro' is not of type int. 

332 :raises ValueError: If parameter 'micro' is a negative number. 

333 :raises TypeError: If parameter 'build' is not of type int. 

334 :raises ValueError: If parameter 'build' is a negative number. 

335 :raises TypeError: If parameter 'prefix' is not of type str. 

336 :raises TypeError: If parameter 'postfix' is not of type str. 

337 """ 

338 self.__hash = None 

339 

340 if not isinstance(major, int): 

341 raise TypeError("Parameter 'major' is not of type 'int'.") 

342 elif major < 0: 

343 raise ValueError("Parameter 'major' is negative.") 

344 

345 self._parts = Parts.Major 

346 self._major = major 

347 

348 if minor is not None: 

349 if not isinstance(minor, int): 

350 raise TypeError("Parameter 'minor' is not of type 'int'.") 

351 elif minor < 0: 

352 raise ValueError("Parameter 'minor' is negative.") 

353 

354 self._parts |= Parts.Minor 

355 self._minor = minor 

356 else: 

357 self._minor = 0 

358 

359 if micro is not None: 

360 if not isinstance(micro, int): 

361 raise TypeError("Parameter 'micro' is not of type 'int'.") 

362 elif micro < 0: 

363 raise ValueError("Parameter 'micro' is negative.") 

364 

365 self._parts |= Parts.Micro 

366 self._micro = micro 

367 else: 

368 self._micro = 0 

369 

370 if level is None: 

371 raise ValueError("Parameter 'level' is None.") 

372 elif not isinstance(level, ReleaseLevel): 

373 raise TypeError("Parameter 'level' is not of type 'ReleaseLevel'.") 

374 elif level is ReleaseLevel.Final: 

375 if number is not None: 

376 raise ValueError("Parameter 'number' must be None, if parameter 'level' is 'Final'.") 

377 

378 self._parts |= Parts.Level 

379 self._releaseLevel = level 

380 self._releaseNumber = 0 

381 else: 

382 self._parts |= Parts.Level 

383 self._releaseLevel = level 

384 

385 if number is not None: 

386 if not isinstance(number, int): 

387 raise TypeError("Parameter 'number' is not of type 'int'.") 

388 elif number < 0: 

389 raise ValueError("Parameter 'number' is negative.") 

390 

391 self._releaseNumber = number 

392 else: 

393 self._releaseNumber = 0 

394 

395 if dev is not None: 

396 if not isinstance(dev, int): 

397 raise TypeError("Parameter 'dev' is not of type 'int'.") 

398 elif dev < 0: 

399 raise ValueError("Parameter 'dev' is negative.") 

400 

401 self._parts |= Parts.Dev 

402 self._dev = dev 

403 else: 

404 self._dev = 0 

405 

406 if post is not None: 

407 if not isinstance(post, int): 

408 raise TypeError("Parameter 'post' is not of type 'int'.") 

409 elif post < 0: 

410 raise ValueError("Parameter 'post' is negative.") 

411 

412 self._parts |= Parts.Post 

413 self._post = post 

414 else: 

415 self._post = 0 

416 

417 if build is not None: 

418 if not isinstance(build, int): 

419 raise TypeError("Parameter 'build' is not of type 'int'.") 

420 elif build < 0: 

421 raise ValueError("Parameter 'build' is negative.") 

422 

423 self._build = build 

424 self._parts |= Parts.Build 

425 else: 

426 self._build = 0 

427 

428 if postfix is not None: 

429 if not isinstance(postfix, str): 

430 raise TypeError("Parameter 'postfix' is not of type 'str'.") 

431 

432 self._parts |= Parts.Postfix 

433 self._postfix = postfix 

434 else: 

435 self._postfix = "" 

436 

437 if prefix is not None: 

438 if not isinstance(prefix, str): 

439 raise TypeError("Parameter 'prefix' is not of type 'str'.") 

440 

441 self._parts |= Parts.Prefix 

442 self._prefix = prefix 

443 else: 

444 self._prefix = "" 

445 

446 if hash is not None: 

447 if not isinstance(hash, str): 

448 raise TypeError("Parameter 'hash' is not of type 'str'.") 

449 

450 self._parts |= Parts.Hash 

451 self._hash = hash 

452 else: 

453 self._hash = "" 

454 

455 if flags is None: 

456 raise ValueError("Parameter 'flags' is None.") 

457 elif not isinstance(flags, Flags): 

458 raise TypeError("Parameter 'flags' is not of type 'Flags'.") 

459 

460 self._flags = flags 

461 

462 @classmethod 

463 @abstractmethod 

464 def Parse(cls, versionString: Nullable[str], validator: Nullable[Callable[["SemanticVersion"], bool]] = None) -> "Version": 

465 """Parse a version string and return a Version instance.""" 

466 

467 @readonly 

468 def Parts(self) -> Parts: 

469 """ 

470 Read-only property to access the used parts of this version number. 

471 

472 :return: A flag enumeration of used version number parts. 

473 """ 

474 return self._parts 

475 

476 @readonly 

477 def Prefix(self) -> str: 

478 """ 

479 Read-only property to access the version number's prefix. 

480 

481 :return: The prefix of the version number. 

482 """ 

483 return self._prefix 

484 

485 @readonly 

486 def Major(self) -> int: 

487 """ 

488 Read-only property to access the major number. 

489 

490 :return: The major number. 

491 """ 

492 return self._major 

493 

494 @readonly 

495 def Minor(self) -> int: 

496 """ 

497 Read-only property to access the minor number. 

498 

499 :return: The minor number. 

500 """ 

501 return self._minor 

502 

503 @readonly 

504 def Micro(self) -> int: 

505 """ 

506 Read-only property to access the micro number. 

507 

508 :return: The micro number. 

509 """ 

510 return self._micro 

511 

512 @readonly 

513 def ReleaseLevel(self) -> ReleaseLevel: 

514 """ 

515 Read-only property to access the release level. 

516 

517 :return: The release level. 

518 """ 

519 return self._releaseLevel 

520 

521 @readonly 

522 def ReleaseNumber(self) -> int: 

523 """ 

524 Read-only property to access the release number. 

525 

526 :return: The release number. 

527 """ 

528 return self._releaseNumber 

529 

530 @readonly 

531 def Post(self) -> int: 

532 """ 

533 Read-only property to access the post number. 

534 

535 :return: The post number. 

536 """ 

537 return self._post 

538 

539 @readonly 

540 def Dev(self) -> int: 

541 """ 

542 Read-only property to access the development number. 

543 

544 :return: The development number. 

545 """ 

546 return self._dev 

547 

548 @readonly 

549 def Build(self) -> int: 

550 """ 

551 Read-only property to access the build number. 

552 

553 :return: The build number. 

554 """ 

555 return self._build 

556 

557 @readonly 

558 def Postfix(self) -> str: 

559 """ 

560 Read-only property to access the version number's postfix. 

561 

562 :return: The postfix of the version number. 

563 """ 

564 return self._postfix 

565 

566 @readonly 

567 def Hash(self) -> str: 

568 """ 

569 Read-only property to access the version number's hash. 

570 

571 :return: The hash. 

572 """ 

573 return self._hash 

574 

575 @readonly 

576 def Flags(self) -> Flags: 

577 """ 

578 Read-only property to access the version number's flags. 

579 

580 :return: The flags of the version number. 

581 """ 

582 return self._flags 

583 

584 def _equal(self, left: "Version", right: "Version") -> Nullable[bool]: 

585 """ 

586 Private helper method to compute the equality of two :class:`Version` instances. 

587 

588 :param left: Left parameter. 

589 :param right: Right parameter. 

590 :returns: ``True``, if ``left`` is equal to ``right``, otherwise it's ``False``. 

591 """ 

592 return ( 

593 (left._major == right._major) and 

594 (left._minor == right._minor) and 

595 (left._micro == right._micro) and 

596 (left._releaseLevel == right._releaseLevel) and 

597 (left._releaseNumber == right._releaseNumber) and 

598 (left._post == right._post) and 

599 (left._dev == right._dev) and 

600 (left._build == right._build) and 

601 (left._postfix == right._postfix) 

602 ) 

603 

604 def _compare(self, left: "Version", right: "Version") -> Nullable[bool]: 

605 """ 

606 Private helper method to compute the comparison of two :class:`Version` instances. 

607 

608 :param left: Left parameter. 

609 :param right: Right parameter. 

610 :returns: ``True``, if ``left`` is smaller than ``right``. |br| 

611 False if ``left`` is greater than ``right``. |br| 

612 Otherwise it's None (both parameters are equal). 

613 """ 

614 if left._major < right._major: 

615 return True 

616 elif left._major > right._major: 

617 return False 

618 

619 if left._minor < right._minor: 

620 return True 

621 elif left._minor > right._minor: 

622 return False 

623 

624 if left._micro < right._micro: 

625 return True 

626 elif left._micro > right._micro: 

627 return False 

628 

629 if left._releaseLevel < right._releaseLevel: 629 ↛ 630line 629 didn't jump to line 630 because the condition on line 629 was never true

630 return True 

631 elif left._releaseLevel > right._releaseLevel: 631 ↛ 632line 631 didn't jump to line 632 because the condition on line 631 was never true

632 return False 

633 

634 if left._releaseNumber < right._releaseNumber: 634 ↛ 635line 634 didn't jump to line 635 because the condition on line 634 was never true

635 return True 

636 elif left._releaseNumber > right._releaseNumber: 636 ↛ 637line 636 didn't jump to line 637 because the condition on line 636 was never true

637 return False 

638 

639 if left._post < right._post: 639 ↛ 640line 639 didn't jump to line 640 because the condition on line 639 was never true

640 return True 

641 elif left._post > right._post: 641 ↛ 642line 641 didn't jump to line 642 because the condition on line 641 was never true

642 return False 

643 

644 if left._dev < right._dev: 644 ↛ 645line 644 didn't jump to line 645 because the condition on line 644 was never true

645 return True 

646 elif left._dev > right._dev: 646 ↛ 647line 646 didn't jump to line 647 because the condition on line 646 was never true

647 return False 

648 

649 if left._build < right._build: 649 ↛ 650line 649 didn't jump to line 650 because the condition on line 649 was never true

650 return True 

651 elif left._build > right._build: 651 ↛ 652line 651 didn't jump to line 652 because the condition on line 651 was never true

652 return False 

653 

654 return None 

655 

656 def _minimum(self, actual: "Version", expected: "Version") -> Nullable[bool]: 

657 exactMajor = Parts.Minor in expected._parts 

658 exactMinor = Parts.Micro in expected._parts 

659 

660 if exactMajor and actual._major != expected._major: 660 ↛ 661line 660 didn't jump to line 661 because the condition on line 660 was never true

661 return False 

662 elif not exactMajor and actual._major < expected._major: 

663 return False 

664 

665 if exactMinor and actual._minor != expected._minor: 665 ↛ 666line 665 didn't jump to line 666 because the condition on line 665 was never true

666 return False 

667 elif not exactMinor and actual._minor < expected._minor: 

668 return False 

669 

670 if Parts.Micro in expected._parts: 

671 return actual._micro >= expected._micro 

672 

673 return True 

674 

675 def _format(self, formatSpec: str) -> str: 

676 """ 

677 Return a string representation of this version number according to the format specification. 

678 

679 .. topic:: Format Specifiers 

680 

681 * ``%p`` - prefix 

682 * ``%M`` - major number 

683 * ``%m`` - minor number 

684 * ``%u`` - micro number 

685 * ``%b`` - build number 

686 

687 :param formatSpec: The format specification. 

688 :return: Formatted version number. 

689 """ 

690 if formatSpec == "": 

691 return self.__str__() 

692 

693 result = formatSpec 

694 result = result.replace("%p", str(self._prefix)) 

695 result = result.replace("%M", str(self._major)) 

696 result = result.replace("%m", str(self._minor)) 

697 result = result.replace("%u", str(self._micro)) 

698 result = result.replace("%b", str(self._build)) 

699 result = result.replace("%r", str(self._releaseLevel)[0]) 

700 result = result.replace("%R", str(self._releaseLevel)) 

701 result = result.replace("%n", str(self._releaseNumber)) 

702 result = result.replace("%d", str(self._dev)) 

703 result = result.replace("%P", str(self._postfix)) 

704 

705 return result 

706 

707 @mustoverride 

708 def __eq__(self, other: Union["Version", str, int, None]) -> bool: 

709 """ 

710 Compare two version numbers for equality. 

711 

712 The second operand should be an instance of :class:`Version`, but ``str`` and ``int`` are accepted, too. |br| 

713 In case of ``str``, it's tried to parse the string as a version number. In case of ``int``, a single major 

714 number is assumed (all other parts are zero). 

715 

716 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

717 number. 

718 

719 :param other: Parameter to compare against. 

720 :returns: ``True``, if both version numbers are equal. 

721 :raises ValueError: If parameter ``other`` is None. 

722 :raises TypeError: If parameter ``other`` is not of type :class:`Version`, :class:`str` or :class:`ìnt`. 

723 """ 

724 if other is None: 

725 raise ValueError(f"Second operand is None.") 

726 elif isinstance(other, self.__class__): 

727 pass 

728 elif isinstance(other, str): 

729 other = self.__class__.Parse(other) 

730 elif isinstance(other, int): 

731 other = self.__class__(major=other) 

732 else: 

733 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by == operator.") 

734 if version_info >= (3, 11): # pragma: no cover 

735 ex.add_note(f"Supported types for second operand: {self.__class__.__name__}, str, int") 

736 raise ex 

737 

738 return self._equal(self, other) 

739 

740 @mustoverride 

741 def __ne__(self, other: Union["Version", str, int, None]) -> bool: 

742 """ 

743 Compare two version numbers for inequality. 

744 

745 The second operand should be an instance of :class:`Version`, but ``str`` and ``int`` are accepted, too. |br| 

746 In case of ``str``, it's tried to parse the string as a version number. In case of ``int``, a single major 

747 number is assumed (all other parts are zero). 

748 

749 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

750 number. 

751 

752 :param other: Parameter to compare against. 

753 :returns: ``True``, if both version numbers are not equal. 

754 :raises ValueError: If parameter ``other`` is None. 

755 :raises TypeError: If parameter ``other`` is not of type :class:`Version`, :class:`str` or :class:`ìnt`. 

756 """ 

757 if other is None: 

758 raise ValueError(f"Second operand is None.") 

759 elif isinstance(other, self.__class__): 

760 pass 

761 elif isinstance(other, str): 

762 other = self.__class__.Parse(other) 

763 elif isinstance(other, int): 

764 other = self.__class__(major=other) 

765 else: 

766 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by == operator.") 

767 if version_info >= (3, 11): # pragma: no cover 

768 ex.add_note(f"Supported types for second operand: {self.__class__.__name__}, str, int") 

769 raise ex 

770 

771 return not self._equal(self, other) 

772 

773 @mustoverride 

774 def __lt__(self, other: Union["Version", str, int, None]) -> bool: 

775 """ 

776 Compare two version numbers if the version is less than the second operand. 

777 

778 The second operand should be an instance of :class:`Version`, but ``str`` and ``int`` are accepted, too. |br| 

779 In case of ``str``, it's tried to parse the string as a version number. In case of ``int``, a single major 

780 number is assumed (all other parts are zero). 

781 

782 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

783 number. 

784 

785 :param other: Parameter to compare against. 

786 :returns: ``True``, if version is less than the second operand. 

787 :raises ValueError: If parameter ``other`` is None. 

788 :raises TypeError: If parameter ``other`` is not of type :class:`Version`, :class:`str` or :class:`ìnt`. 

789 """ 

790 if other is None: 

791 raise ValueError(f"Second operand is None.") 

792 elif isinstance(other, self.__class__): 

793 pass 

794 elif isinstance(other, str): 

795 other = self.__class__.Parse(other) 

796 elif isinstance(other, int): 

797 other = self.__class__(major=other) 

798 else: 

799 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by < operator.") 

800 if version_info >= (3, 11): # pragma: no cover 

801 ex.add_note(f"Supported types for second operand: {self.__class__.__name__}, str, int") 

802 raise ex 

803 

804 result = self._compare(self, other) 

805 return result if result is not None else False 

806 

807 @mustoverride 

808 def __le__(self, other: Union["Version", str, int, None]) -> bool: 

809 """ 

810 Compare two version numbers if the version is less than or equal the second operand. 

811 

812 The second operand should be an instance of :class:`Version`, but ``str`` and ``int`` are accepted, too. |br| 

813 In case of ``str``, it's tried to parse the string as a version number. In case of ``int``, a single major 

814 number is assumed (all other parts are zero). 

815 

816 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

817 number. 

818 

819 :param other: Parameter to compare against. 

820 :returns: ``True``, if version is less than or equal the second operand. 

821 :raises ValueError: If parameter ``other`` is None. 

822 :raises TypeError: If parameter ``other`` is not of type :class:`Version`, :class:`str` or :class:`ìnt`. 

823 """ 

824 if other is None: 

825 raise ValueError(f"Second operand is None.") 

826 elif isinstance(other, self.__class__): 

827 pass 

828 elif isinstance(other, str): 

829 other = self.__class__.Parse(other) 

830 elif isinstance(other, int): 

831 other = self.__class__(major=other) 

832 else: 

833 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by <= operator.") 

834 if version_info >= (3, 11): # pragma: no cover 

835 ex.add_note(f"Supported types for second operand: {self.__class__.__name__}, str, int") 

836 raise ex 

837 

838 result = self._compare(self, other) 

839 return result if result is not None else True 

840 

841 @mustoverride 

842 def __gt__(self, other: Union["Version", str, int, None]) -> bool: 

843 """ 

844 Compare two version numbers if the version is greater than the second operand. 

845 

846 The second operand should be an instance of :class:`Version`, but ``str`` and ``int`` are accepted, too. |br| 

847 In case of ``str``, it's tried to parse the string as a version number. In case of ``int``, a single major 

848 number is assumed (all other parts are zero). 

849 

850 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

851 number. 

852 

853 :param other: Parameter to compare against. 

854 :returns: ``True``, if version is greater than the second operand. 

855 :raises ValueError: If parameter ``other`` is None. 

856 :raises TypeError: If parameter ``other`` is not of type :class:`Version`, :class:`str` or :class:`ìnt`. 

857 """ 

858 if other is None: 

859 raise ValueError(f"Second operand is None.") 

860 elif isinstance(other, self.__class__): 

861 pass 

862 elif isinstance(other, str): 

863 other = self.__class__.Parse(other) 

864 elif isinstance(other, int): 

865 other = self.__class__(major=other) 

866 else: 

867 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by > operator.") 

868 if version_info >= (3, 11): # pragma: no cover 

869 ex.add_note(f"Supported types for second operand: {self.__class__.__name__}, str, int") 

870 raise ex 

871 

872 return not self.__le__(other) 

873 

874 @mustoverride 

875 def __ge__(self, other: Union["Version", str, int, None]) -> bool: 

876 """ 

877 Compare two version numbers if the version is greater than or equal the second operand. 

878 

879 The second operand should be an instance of :class:`Version`, but ``str`` and ``int`` are accepted, too. |br| 

880 In case of ``str``, it's tried to parse the string as a version number. In case of ``int``, a single major 

881 number is assumed (all other parts are zero). 

882 

883 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

884 number. 

885 

886 :param other: Parameter to compare against. 

887 :returns: ``True``, if version is greater than or equal the second operand. 

888 :raises ValueError: If parameter ``other`` is None. 

889 :raises TypeError: If parameter ``other`` is not of type :class:`Version`, :class:`str` or :class:`ìnt`. 

890 """ 

891 if other is None: 

892 raise ValueError(f"Second operand is None.") 

893 elif isinstance(other, self.__class__): 

894 pass 

895 elif isinstance(other, str): 

896 other = self.__class__.Parse(other) 

897 elif isinstance(other, int): 

898 other = self.__class__(major=other) 

899 else: 

900 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by >= operator.") 

901 if version_info >= (3, 11): # pragma: no cover 

902 ex.add_note(f"Supported types for second operand: {self.__class__.__name__}, str, int") 

903 raise ex 

904 

905 return not self.__lt__(other) 

906 

907 def __rshift__(self, other: Union["Version", str, int, None]) -> bool: 

908 if other is None: 

909 raise ValueError(f"Second operand is None.") 

910 elif isinstance(other, self.__class__): 

911 pass 

912 elif isinstance(other, str): 

913 other = self.__class__.Parse(other) 

914 elif isinstance(other, int): 

915 other = self.__class__(major=other) 

916 else: 

917 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by %= operator.") 

918 if version_info >= (3, 11): # pragma: no cover 

919 ex.add_note(f"Supported types for second operand: {self.__class__.__name__}, str, int") 

920 raise ex 

921 

922 return self._minimum(self, other) 

923 

924 def __hash__(self) -> int: 

925 if self.__hash is None: 925 ↛ 940line 925 didn't jump to line 940 because the condition on line 925 was always true

926 self.__hash = hash(( 

927 self._prefix, 

928 self._major, 

929 self._minor, 

930 self._micro, 

931 self._releaseLevel, 

932 self._releaseNumber, 

933 self._post, 

934 self._dev, 

935 self._build, 

936 self._postfix, 

937 self._hash, 

938 self._flags 

939 )) 

940 return self.__hash 

941 

942 

943@export 

944class SemanticVersion(Version): 

945 """Representation of a semantic version number like ``3.7.12``.""" 

946 

947 _PATTERN = re_compile( 

948 r"^" 

949 r"(?P<prefix>[a-zA-Z]*)" 

950 r"(?P<major>\d+)" 

951 r"(?:\.(?P<minor>\d+))?" 

952 r"(?:\.(?P<micro>\d+))?" 

953 r"(?:" 

954 r"(?:\.(?P<build>\d+))" 

955 r"|" 

956 r"(?:[-](?P<release>dev|final))" 

957 r"|" 

958 r"(?:(?P<delim1>[\.\-]?)(?P<level>alpha|beta|gamma|a|b|c|rc|pl)(?P<number>\d+))" 

959 r")?" 

960 r"(?:(?P<delim2>[\.\-]post)(?P<post>\d+))?" 

961 r"(?:(?P<delim3>[\.\-]dev)(?P<dev>\d+))?" 

962 r"(?:(?P<delim4>[\.\-\+])(?P<postfix>\w+))?" 

963 r"$" 

964 ) 

965# QUESTION: was this how many commits a version is ahead of the last tagged version? 

966# ahead: int = 0 

967 

968 def __init__( 

969 self, 

970 major: int, 

971 minor: Nullable[int] = None, 

972 micro: Nullable[int] = None, 

973 level: Nullable[ReleaseLevel] = ReleaseLevel.Final, 

974 number: Nullable[int] = None, 

975 post: Nullable[int] = None, 

976 dev: Nullable[int] = None, 

977 *, 

978 build: Nullable[int] = None, 

979 postfix: Nullable[str] = None, 

980 prefix: Nullable[str] = None, 

981 hash: Nullable[str] = None, 

982 flags: Flags = Flags.NoVCS 

983 ) -> None: 

984 """ 

985 Initializes a semantic version number representation. 

986 

987 :param major: Major number part of the version number. 

988 :param minor: Minor number part of the version number. 

989 :param micro: Micro (patch) number part of the version number. 

990 :param build: Build number part of the version number. 

991 :param level: tbd 

992 :param number: tbd 

993 :param post: Post number part of the version number. 

994 :param dev: Development number part of the version number. 

995 :param prefix: The version number's prefix. 

996 :param postfix: The version number's postfix. 

997 :param flags: The version number's flags. 

998 :param hash: tbd 

999 :raises TypeError: If parameter 'major' is not of type int. 

1000 :raises ValueError: If parameter 'major' is a negative number. 

1001 :raises TypeError: If parameter 'minor' is not of type int. 

1002 :raises ValueError: If parameter 'minor' is a negative number. 

1003 :raises TypeError: If parameter 'micro' is not of type int. 

1004 :raises ValueError: If parameter 'micro' is a negative number. 

1005 :raises TypeError: If parameter 'build' is not of type int. 

1006 :raises ValueError: If parameter 'build' is a negative number. 

1007 :raises TypeError: If parameter 'post' is not of type int. 

1008 :raises ValueError: If parameter 'post' is a negative number. 

1009 :raises TypeError: If parameter 'dev' is not of type int. 

1010 :raises ValueError: If parameter 'dev' is a negative number. 

1011 :raises TypeError: If parameter 'prefix' is not of type str. 

1012 :raises TypeError: If parameter 'postfix' is not of type str. 

1013 """ 

1014 super().__init__(major, minor, micro, level, number, post, dev, build=build, postfix=postfix, prefix=prefix, hash=hash, flags=flags) 

1015 

1016 @classmethod 

1017 def Parse(cls, versionString: Nullable[str], validator: Nullable[Callable[["SemanticVersion"], bool]] = None) -> "SemanticVersion": 

1018 """ 

1019 Parse a version string and return a :class:`SemanticVersion` instance. 

1020 

1021 Allowed prefix characters: 

1022 

1023 * ``v|V`` - version, public version, public release 

1024 * ``i|I`` - internal version, internal release 

1025 * ``r|R`` - release, revision 

1026 * ``rev|REV`` - revision 

1027 

1028 :param versionString: The version string to parse. 

1029 :returns: An object representing a semantic version. 

1030 :raises TypeError: If parameter ``other`` is not a string. 

1031 :raises ValueError: If parameter ``other`` is None. 

1032 :raises ValueError: If parameter ``other`` is empty. 

1033 """ 

1034 if versionString is None: 

1035 raise ValueError("Parameter 'versionString' is None.") 

1036 elif not isinstance(versionString, str): 

1037 ex = TypeError(f"Parameter 'versionString' is not of type 'str'.") 

1038 if version_info >= (3, 11): # pragma: no cover 

1039 ex.add_note(f"Got type '{getFullyQualifiedName(versionString)}'.") 

1040 raise ex 

1041 

1042 versionString = versionString.strip() 

1043 if versionString == "": 

1044 raise ValueError("Parameter 'versionString' is empty.") 

1045 

1046 match = cls._PATTERN.match(versionString) 

1047 if match is None: 

1048 raise ValueError(f"Syntax error in parameter 'versionString': '{versionString}'") 

1049 

1050 def toInt(value: Nullable[str]) -> Nullable[int]: 

1051 if value is None or value == "": 

1052 return None 

1053 try: 

1054 return int(value) 

1055 except ValueError as ex: # pragma: no cover 

1056 raise ValueError(f"Invalid part '{value}' in version number '{versionString}'.") from ex 

1057 

1058 release = match["release"] 

1059 if release is not None: 

1060 if release == "dev": 1060 ↛ 1062line 1060 didn't jump to line 1062 because the condition on line 1060 was always true

1061 releaseLevel = ReleaseLevel.Development 

1062 elif release == "final": 

1063 releaseLevel = ReleaseLevel.Final 

1064 else: # pragma: no cover 

1065 raise ValueError(f"Unknown release level '{release}' in version number '{versionString}'.") 

1066 else: 

1067 level = match["level"] 

1068 if level is not None: 

1069 level = level.lower() 

1070 if level == "a" or level == "alpha": 

1071 releaseLevel = ReleaseLevel.Alpha 

1072 elif level == "b" or level == "beta": 

1073 releaseLevel = ReleaseLevel.Beta 

1074 elif level == "c" or level == "gamma": 

1075 releaseLevel = ReleaseLevel.Gamma 

1076 elif level == "rc": 

1077 releaseLevel = ReleaseLevel.ReleaseCandidate 

1078 else: # pragma: no cover 

1079 raise ValueError(f"Unknown release level '{level}' in version number '{versionString}'.") 

1080 else: 

1081 releaseLevel = ReleaseLevel.Final 

1082 

1083 version = cls( 

1084 major=toInt(match["major"]), 

1085 minor=toInt(match["minor"]), 

1086 micro=toInt(match["micro"]), 

1087 level=releaseLevel, 

1088 number=toInt(match["number"]), 

1089 post=toInt(match["post"]), 

1090 dev=toInt(match["dev"]), 

1091 build=toInt(match["build"]), 

1092 postfix=match["postfix"], 

1093 prefix=match["prefix"], 

1094 # hash=match["hash"], 

1095 flags=Flags.Clean 

1096 ) 

1097 if validator is not None and not validator(version): 

1098 raise ValueError(f"Failed to validate version string '{versionString}'.") # pragma: no cover 

1099 

1100 return version 

1101 

1102 @readonly 

1103 def Patch(self) -> int: 

1104 """ 

1105 Read-only property to access the patch number. 

1106 

1107 The patch number is identical to the micro number. 

1108 

1109 :return: The patch number. 

1110 """ 

1111 return self._micro 

1112 

1113 def _equal(self, left: "SemanticVersion", right: "SemanticVersion") -> Nullable[bool]: 

1114 """ 

1115 Private helper method to compute the equality of two :class:`SemanticVersion` instances. 

1116 

1117 :param left: Left parameter. 

1118 :param right: Right parameter. 

1119 :returns: ``True``, if ``left`` is equal to ``right``, otherwise it's ``False``. 

1120 """ 

1121 return super()._equal(left, right) 

1122 

1123 def _compare(self, left: "SemanticVersion", right: "SemanticVersion") -> Nullable[bool]: 

1124 """ 

1125 Private helper method to compute the comparison of two :class:`SemanticVersion` instances. 

1126 

1127 :param left: Left parameter. 

1128 :param right: Right parameter. 

1129 :returns: ``True``, if ``left`` is smaller than ``right``. |br| 

1130 False if ``left`` is greater than ``right``. |br| 

1131 Otherwise it's None (both parameters are equal). 

1132 """ 

1133 return super()._compare(left, right) 

1134 

1135 def __eq__(self, other: Union["SemanticVersion", str, int, None]) -> bool: 

1136 """ 

1137 Compare two version numbers for equality. 

1138 

1139 The second operand should be an instance of :class:`SemanticVersion`, but ``str`` and ``int`` are accepted, too. |br| 

1140 In case of ``str``, it's tried to parse the string as a semantic version number. In case of ``int``, a single major 

1141 number is assumed (all other parts are zero). 

1142 

1143 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

1144 number. 

1145 

1146 :param other: Parameter to compare against. 

1147 :returns: ``True``, if both version numbers are equal. 

1148 :raises ValueError: If parameter ``other`` is None. 

1149 :raises TypeError: If parameter ``other`` is not of type :class:`SemanticVersion`, :class:`str` or :class:`ìnt`. 

1150 """ 

1151 return super().__eq__(other) 

1152 

1153 def __ne__(self, other: Union["SemanticVersion", str, int, None]) -> bool: 

1154 """ 

1155 Compare two version numbers for inequality. 

1156 

1157 The second operand should be an instance of :class:`SemanticVersion`, but ``str`` and ``int`` are accepted, too. |br| 

1158 In case of ``str``, it's tried to parse the string as a semantic version number. In case of ``int``, a single major 

1159 number is assumed (all other parts are zero). 

1160 

1161 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

1162 number. 

1163 

1164 :param other: Parameter to compare against. 

1165 :returns: ``True``, if both version numbers are not equal. 

1166 :raises ValueError: If parameter ``other`` is None. 

1167 :raises TypeError: If parameter ``other`` is not of type :class:`SemanticVersion`, :class:`str` or :class:`ìnt`. 

1168 """ 

1169 return super().__ne__(other) 

1170 

1171 def __lt__(self, other: Union["SemanticVersion", str, int, None]) -> bool: 

1172 """ 

1173 Compare two version numbers if the version is less than the second operand. 

1174 

1175 The second operand should be an instance of :class:`SemanticVersion`, but ``str`` and ``int`` are accepted, too. |br| 

1176 In case of ``str``, it's tried to parse the string as a semantic version number. In case of ``int``, a single major 

1177 number is assumed (all other parts are zero). 

1178 

1179 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

1180 number. 

1181 

1182 :param other: Parameter to compare against. 

1183 :returns: ``True``, if version is less than the second operand. 

1184 :raises ValueError: If parameter ``other`` is None. 

1185 :raises TypeError: If parameter ``other`` is not of type :class:`SemanticVersion`, :class:`str` or :class:`ìnt`. 

1186 """ 

1187 return super().__lt__(other) 

1188 

1189 def __le__(self, other: Union["SemanticVersion", str, int, None]) -> bool: 

1190 """ 

1191 Compare two version numbers if the version is less than or equal the second operand. 

1192 

1193 The second operand should be an instance of :class:`SemanticVersion`, but ``str`` and ``int`` are accepted, too. |br| 

1194 In case of ``str``, it's tried to parse the string as a semantic version number. In case of ``int``, a single major 

1195 number is assumed (all other parts are zero). 

1196 

1197 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

1198 number. 

1199 

1200 :param other: Parameter to compare against. 

1201 :returns: ``True``, if version is less than or equal the second operand. 

1202 :raises ValueError: If parameter ``other`` is None. 

1203 :raises TypeError: If parameter ``other`` is not of type :class:`SemanticVersion`, :class:`str` or :class:`ìnt`. 

1204 """ 

1205 return super().__le__(other) 

1206 

1207 def __gt__(self, other: Union["SemanticVersion", str, int, None]) -> bool: 

1208 """ 

1209 Compare two version numbers if the version is greater than the second operand. 

1210 

1211 The second operand should be an instance of :class:`SemanticVersion`, but ``str`` and ``int`` are accepted, too. |br| 

1212 In case of ``str``, it's tried to parse the string as a semantic version number. In case of ``int``, a single major 

1213 number is assumed (all other parts are zero). 

1214 

1215 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

1216 number. 

1217 

1218 :param other: Parameter to compare against. 

1219 :returns: ``True``, if version is greater than the second operand. 

1220 :raises ValueError: If parameter ``other`` is None. 

1221 :raises TypeError: If parameter ``other`` is not of type :class:`SemanticVersion`, :class:`str` or :class:`ìnt`. 

1222 """ 

1223 return super().__gt__(other) 

1224 

1225 def __ge__(self, other: Union["SemanticVersion", str, int, None]) -> bool: 

1226 """ 

1227 Compare two version numbers if the version is greater than or equal the second operand. 

1228 

1229 The second operand should be an instance of :class:`SemanticVersion`, but ``str`` and ``int`` are accepted, too. |br| 

1230 In case of ``str``, it's tried to parse the string as a semantic version number. In case of ``int``, a single major 

1231 number is assumed (all other parts are zero). 

1232 

1233 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

1234 number. 

1235 

1236 :param other: Parameter to compare against. 

1237 :returns: ``True``, if version is greater than or equal the second operand. 

1238 :raises ValueError: If parameter ``other`` is None. 

1239 :raises TypeError: If parameter ``other`` is not of type :class:`SemanticVersion`, :class:`str` or :class:`ìnt`. 

1240 """ 

1241 return super().__ge__(other) 

1242 

1243 def __rshift__(self, other: Union["SemanticVersion", str, int, None]) -> bool: 

1244 return super().__rshift__(other) 

1245 

1246 def __hash__(self) -> int: 

1247 return super().__hash__() 

1248 

1249 def __format__(self, formatSpec: str) -> str: 

1250 result = self._format(formatSpec) 

1251 

1252 if (pos := result.find("%")) != -1 and result[pos + 1] != "%": # pragma: no cover 

1253 raise ValueError(f"Unknown format specifier '%{result[pos + 1]}' in '{formatSpec}'.") 

1254 

1255 return result.replace("%%", "%") 

1256 

1257 def __repr__(self) -> str: 

1258 """ 

1259 Return a string representation of this version number without prefix ``v``. 

1260 

1261 :returns: Raw version number representation without a prefix. 

1262 """ 

1263 return f"{self._prefix if Parts.Prefix in self._parts else ''}{self._major}.{self._minor}.{self._micro}" 

1264 

1265 def __str__(self) -> str: 

1266 """ 

1267 Return a string representation of this version number. 

1268 

1269 :returns: Version number representation. 

1270 """ 

1271 result = self._prefix if Parts.Prefix in self._parts else "" 

1272 result += f"{self._major}" # major is always present 

1273 result += f".{self._minor}" if Parts.Minor in self._parts else "" 

1274 result += f".{self._micro}" if Parts.Micro in self._parts else "" 

1275 result += f".{self._build}" if Parts.Build in self._parts else "" 

1276 if self._releaseLevel is ReleaseLevel.Development: 

1277 result += "-dev" 

1278 elif self._releaseLevel is ReleaseLevel.Alpha: 

1279 result += f".alpha{self._releaseNumber}" 

1280 elif self._releaseLevel is ReleaseLevel.Beta: 

1281 result += f".beta{self._releaseNumber}" 

1282 elif self._releaseLevel is ReleaseLevel.Gamma: 1282 ↛ 1283line 1282 didn't jump to line 1283 because the condition on line 1282 was never true

1283 result += f".gamma{self._releaseNumber}" 

1284 elif self._releaseLevel is ReleaseLevel.ReleaseCandidate: 

1285 result += f".rc{self._releaseNumber}" 

1286 result += f".post{self._post}" if Parts.Post in self._parts else "" 

1287 result += f".dev{self._dev}" if Parts.Dev in self._parts else "" 

1288 result += f"+{self._postfix}" if Parts.Postfix in self._parts else "" 

1289 

1290 return result 

1291 

1292 

1293@export 

1294class PythonVersion(SemanticVersion): 

1295 @classmethod 

1296 def FromSysVersionInfo(cls) -> "PythonVersion": 

1297 from sys import version_info 

1298 

1299 if version_info.releaselevel == "final": 

1300 rl = ReleaseLevel.Final 

1301 number = None 

1302 else: # pragma: no cover 

1303 number = version_info.serial 

1304 

1305 if version_info.releaselevel == "alpha": 

1306 rl = ReleaseLevel.Alpha 

1307 elif version_info.releaselevel == "beta": 

1308 rl = ReleaseLevel.Beta 

1309 elif version_info.releaselevel == "candidate": 

1310 rl = ReleaseLevel.ReleaseCandidate 

1311 else: # pragma: no cover 

1312 raise ToolingException(f"Unsupported release level '{version_info.releaselevel}'.") 

1313 

1314 return cls(version_info.major, version_info.minor, version_info.micro, level=rl, number=number) 

1315 

1316 def __hash__(self) -> int: 

1317 return super().__hash__() 

1318 

1319 def __str__(self) -> str: 

1320 """ 

1321 Return a string representation of this version number. 

1322 

1323 :returns: Version number representation. 

1324 """ 

1325 result = self._prefix if Parts.Prefix in self._parts else "" 

1326 result += f"{self._major}" # major is always present 

1327 result += f".{self._minor}" if Parts.Minor in self._parts else "" 

1328 result += f".{self._micro}" if Parts.Micro in self._parts else "" 

1329 if self._releaseLevel is ReleaseLevel.Alpha: 

1330 result += f"a{self._releaseNumber}" 

1331 elif self._releaseLevel is ReleaseLevel.Beta: 

1332 result += f"b{self._releaseNumber}" 

1333 elif self._releaseLevel is ReleaseLevel.Gamma: 

1334 result += f"c{self._releaseNumber}" 

1335 elif self._releaseLevel is ReleaseLevel.ReleaseCandidate: 

1336 result += f"rc{self._releaseNumber}" 

1337 result += f".post{self._post}" if Parts.Post in self._parts else "" 

1338 result += f".dev{self._dev}" if Parts.Dev in self._parts else "" 

1339 result += f"+{self._postfix}" if Parts.Postfix in self._parts else "" 

1340 

1341 return result 

1342 

1343@export 

1344class CalendarVersion(Version): 

1345 """Representation of a calendar version number like ``2021.10``.""" 

1346 

1347 def __init__( 

1348 self, 

1349 major: int, 

1350 minor: Nullable[int] = None, 

1351 micro: Nullable[int] = None, 

1352 build: Nullable[int] = None, 

1353 flags: Flags = Flags.Clean, 

1354 prefix: Nullable[str] = None, 

1355 postfix: Nullable[str] = None 

1356 ) -> None: 

1357 """ 

1358 Initializes a calendar version number representation. 

1359 

1360 :param major: Major number part of the version number. 

1361 :param minor: Minor number part of the version number. 

1362 :param micro: Micro (patch) number part of the version number. 

1363 :param build: Build number part of the version number. 

1364 :param flags: The version number's flags. 

1365 :param prefix: The version number's prefix. 

1366 :param postfix: The version number's postfix. 

1367 :raises TypeError: If parameter 'major' is not of type int. 

1368 :raises ValueError: If parameter 'major' is a negative number. 

1369 :raises TypeError: If parameter 'minor' is not of type int. 

1370 :raises ValueError: If parameter 'minor' is a negative number. 

1371 :raises TypeError: If parameter 'micro' is not of type int. 

1372 :raises ValueError: If parameter 'micro' is a negative number. 

1373 :raises TypeError: If parameter 'build' is not of type int. 

1374 :raises ValueError: If parameter 'build' is a negative number. 

1375 :raises TypeError: If parameter 'prefix' is not of type str. 

1376 :raises TypeError: If parameter 'postfix' is not of type str. 

1377 """ 

1378 super().__init__(major, minor, micro, build=build, postfix=postfix, prefix=prefix, flags=flags) 

1379 

1380 @classmethod 

1381 def Parse(cls, versionString: Nullable[str], validator: Nullable[Callable[["CalendarVersion"], bool]] = None) -> "CalendarVersion": 

1382 """ 

1383 Parse a version string and return a :class:`CalendarVersion` instance. 

1384 

1385 :param versionString: The version string to parse. 

1386 :returns: An object representing a calendar version. 

1387 :raises TypeError: If parameter ``other`` is not a string. 

1388 :raises ValueError: If parameter ``other`` is None. 

1389 :raises ValueError: If parameter ``other`` is empty. 

1390 """ 

1391 parts = Parts.Unknown 

1392 

1393 if versionString is None: 

1394 raise ValueError("Parameter 'versionString' is None.") 

1395 elif not isinstance(versionString, str): 

1396 ex = TypeError(f"Parameter 'versionString' is not of type 'str'.") 

1397 if version_info >= (3, 11): # pragma: no cover 

1398 ex.add_note(f"Got type '{getFullyQualifiedName(versionString)}'.") 

1399 raise ex 

1400 elif versionString == "": 

1401 raise ValueError("Parameter 'versionString' is empty.") 

1402 

1403 split = versionString.split(".") 

1404 length = len(split) 

1405 major = int(split[0]) 

1406 minor = 0 

1407 parts |= Parts.Major 

1408 

1409 if length >= 2: 

1410 minor = int(split[1]) 

1411 parts |= Parts.Minor 

1412 

1413 flags = Flags.Clean 

1414 

1415 version = cls(major, minor, 0, 0, flags) 

1416 if validator is not None and not validator(version): 

1417 raise ValueError(f"Failed to validate version string '{versionString}'.") # pragma: no cover 

1418 

1419 return version 

1420 

1421 @property 

1422 def Year(self) -> int: 

1423 """ 

1424 Read-only property to access the year part. 

1425 

1426 :return: The year part. 

1427 """ 

1428 return self._major 

1429 

1430 def _equal(self, left: "CalendarVersion", right: "CalendarVersion") -> Nullable[bool]: 

1431 """ 

1432 Private helper method to compute the equality of two :class:`CalendarVersion` instances. 

1433 

1434 :param left: Left parameter. 

1435 :param right: Right parameter. 

1436 :returns: ``True``, if ``left`` is equal to ``right``, otherwise it's ``False``. 

1437 """ 

1438 return ( 

1439 (left._major == right._major) and 

1440 (left._minor == right._minor) 

1441 ) 

1442 

1443 def _compare(self, left: "CalendarVersion", right: "CalendarVersion") -> Nullable[bool]: 

1444 """ 

1445 Private helper method to compute the comparison of two :class:`CalendarVersion` instances. 

1446 

1447 :param left: Left parameter. 

1448 :param right: Right parameter. 

1449 :returns: ``True``, if ``left`` is smaller than ``right``. |br| 

1450 False if ``left`` is greater than ``right``. |br| 

1451 Otherwise it's None (both parameters are equal). 

1452 """ 

1453 if left._major < right._major: 

1454 return True 

1455 elif left._major > right._major: 

1456 return False 

1457 

1458 if left._minor < right._minor: 

1459 return True 

1460 elif left._minor > right._minor: 

1461 return False 

1462 

1463 return None 

1464 

1465 def __eq__(self, other: Union["CalendarVersion", str, int, None]) -> bool: 

1466 """ 

1467 Compare two version numbers for equality. 

1468 

1469 The second operand should be an instance of :class:`CalendarVersion`, but ``str`` and ``int`` are accepted, too. |br| 

1470 In case of ``str``, it's tried to parse the string as a calendar version number. In case of ``int``, a single major 

1471 number is assumed (all other parts are zero). 

1472 

1473 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

1474 number. 

1475 

1476 :param other: Parameter to compare against. 

1477 :returns: ``True``, if both version numbers are equal. 

1478 :raises ValueError: If parameter ``other`` is None. 

1479 :raises TypeError: If parameter ``other`` is not of type :class:`CalendarVersion`, :class:`str` or :class:`ìnt`. 

1480 """ 

1481 return super().__eq__(other) 

1482 

1483 def __ne__(self, other: Union["CalendarVersion", str, int, None]) -> bool: 

1484 """ 

1485 Compare two version numbers for inequality. 

1486 

1487 The second operand should be an instance of :class:`CalendarVersion`, but ``str`` and ``int`` are accepted, too. |br| 

1488 In case of ``str``, it's tried to parse the string as a calendar version number. In case of ``int``, a single major 

1489 number is assumed (all other parts are zero). 

1490 

1491 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

1492 number. 

1493 

1494 :param other: Parameter to compare against. 

1495 :returns: ``True``, if both version numbers are not equal. 

1496 :raises ValueError: If parameter ``other`` is None. 

1497 :raises TypeError: If parameter ``other`` is not of type :class:`CalendarVersion`, :class:`str` or :class:`ìnt`. 

1498 """ 

1499 return super().__ne__(other) 

1500 

1501 def __lt__(self, other: Union["CalendarVersion", str, int, None]) -> bool: 

1502 """ 

1503 Compare two version numbers if the version is less than the second operand. 

1504 

1505 The second operand should be an instance of :class:`CalendarVersion`, but ``str`` and ``int`` are accepted, too. |br| 

1506 In case of ``str``, it's tried to parse the string as a semantic version number. In case of ``int``, a single major 

1507 number is assumed (all other parts are zero). 

1508 

1509 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

1510 number. 

1511 

1512 :param other: Parameter to compare against. 

1513 :returns: ``True``, if version is less than the second operand. 

1514 :raises ValueError: If parameter ``other`` is None. 

1515 :raises TypeError: If parameter ``other`` is not of type :class:`CalendarVersion`, :class:`str` or :class:`ìnt`. 

1516 """ 

1517 return super().__lt__(other) 

1518 

1519 def __le__(self, other: Union["CalendarVersion", str, int, None]) -> bool: 

1520 """ 

1521 Compare two version numbers if the version is less than or equal the second operand. 

1522 

1523 The second operand should be an instance of :class:`CalendarVersion`, but ``str`` and ``int`` are accepted, too. |br| 

1524 In case of ``str``, it's tried to parse the string as a semantic version number. In case of ``int``, a single major 

1525 number is assumed (all other parts are zero). 

1526 

1527 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

1528 number. 

1529 

1530 :param other: Parameter to compare against. 

1531 :returns: ``True``, if version is less than or equal the second operand. 

1532 :raises ValueError: If parameter ``other`` is None. 

1533 :raises TypeError: If parameter ``other`` is not of type :class:`CalendarVersion`, :class:`str` or :class:`ìnt`. 

1534 """ 

1535 return super().__le__(other) 

1536 

1537 def __gt__(self, other: Union["CalendarVersion", str, int, None]) -> bool: 

1538 """ 

1539 Compare two version numbers if the version is greater than the second operand. 

1540 

1541 The second operand should be an instance of :class:`CalendarVersion`, but ``str`` and ``int`` are accepted, too. |br| 

1542 In case of ``str``, it's tried to parse the string as a semantic version number. In case of ``int``, a single major 

1543 number is assumed (all other parts are zero). 

1544 

1545 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

1546 number. 

1547 

1548 :param other: Parameter to compare against. 

1549 :returns: ``True``, if version is greater than the second operand. 

1550 :raises ValueError: If parameter ``other`` is None. 

1551 :raises TypeError: If parameter ``other`` is not of type :class:`CalendarVersion`, :class:`str` or :class:`ìnt`. 

1552 """ 

1553 return super().__gt__(other) 

1554 

1555 def __ge__(self, other: Union["CalendarVersion", str, int, None]) -> bool: 

1556 """ 

1557 Compare two version numbers if the version is greater than or equal the second operand. 

1558 

1559 The second operand should be an instance of :class:`CalendarVersion`, but ``str`` and ``int`` are accepted, too. |br| 

1560 In case of ``str``, it's tried to parse the string as a semantic version number. In case of ``int``, a single major 

1561 number is assumed (all other parts are zero). 

1562 

1563 ``float`` is not supported, due to rounding issues when converting the fractional part of the float to a minor 

1564 number. 

1565 

1566 :param other: Parameter to compare against. 

1567 :returns: ``True``, if version is greater than or equal the second operand. 

1568 :raises ValueError: If parameter ``other`` is None. 

1569 :raises TypeError: If parameter ``other`` is not of type :class:`CalendarVersion`, :class:`str` or :class:`ìnt`. 

1570 """ 

1571 return super().__ge__(other) 

1572 

1573 def __hash__(self) -> int: 

1574 return super().__hash__() 

1575 

1576 def __format__(self, formatSpec: str) -> str: 

1577 """ 

1578 Return a string representation of this version number according to the format specification. 

1579 

1580 .. topic:: Format Specifiers 

1581 

1582 * ``%M`` - major number (year) 

1583 * ``%m`` - minor number (month/week) 

1584 

1585 :param formatSpec: The format specification. 

1586 :return: Formatted version number. 

1587 """ 

1588 if formatSpec == "": 

1589 return self.__str__() 

1590 

1591 result = formatSpec 

1592 # result = result.replace("%P", str(self._prefix)) 

1593 result = result.replace("%M", str(self._major)) 

1594 result = result.replace("%m", str(self._minor)) 

1595 # result = result.replace("%p", str(self._pre)) 

1596 

1597 return result.replace("%%", "%") 

1598 

1599 def __repr__(self) -> str: 

1600 """ 

1601 Return a string representation of this version number without prefix ``v``. 

1602 

1603 :returns: Raw version number representation without a prefix. 

1604 """ 

1605 return f"{self._major}.{self._minor}" 

1606 

1607 def __str__(self) -> str: 

1608 """ 

1609 Return a string representation of this version number with prefix ``v``. 

1610 

1611 :returns: Version number representation including a prefix. 

1612 """ 

1613 result = f"{self._major}" 

1614 result += f".{self._minor}" if Parts.Minor in self._parts else "" 

1615 

1616 return result 

1617 

1618 

1619@export 

1620class YearMonthVersion(CalendarVersion): 

1621 """Representation of a calendar version number like ``2021.10``.""" 

1622 

1623 def __init__( 

1624 self, 

1625 year: int, 

1626 month: Nullable[int] = None, 

1627 build: Nullable[int] = None, 

1628 flags: Flags = Flags.Clean, 

1629 prefix: Nullable[str] = None, 

1630 postfix: Nullable[str] = None 

1631 ) -> None: 

1632 """ 

1633 Initializes a year-month version number representation. 

1634 

1635 :param year: Year part of the version number. 

1636 :param month: Month part of the version number. 

1637 :param build: Build number part of the version number. 

1638 :param flags: The version number's flags. 

1639 :param prefix: The version number's prefix. 

1640 :param postfix: The version number's postfix. 

1641 :raises TypeError: If parameter 'major' is not of type int. 

1642 :raises ValueError: If parameter 'major' is a negative number. 

1643 :raises TypeError: If parameter 'minor' is not of type int. 

1644 :raises ValueError: If parameter 'minor' is a negative number. 

1645 :raises TypeError: If parameter 'micro' is not of type int. 

1646 :raises ValueError: If parameter 'micro' is a negative number. 

1647 :raises TypeError: If parameter 'build' is not of type int. 

1648 :raises ValueError: If parameter 'build' is a negative number. 

1649 :raises TypeError: If parameter 'prefix' is not of type str. 

1650 :raises TypeError: If parameter 'postfix' is not of type str. 

1651 """ 

1652 super().__init__(year, month, 0, build, flags, prefix, postfix) 

1653 

1654 @property 

1655 def Month(self) -> int: 

1656 """ 

1657 Read-only property to access the month part. 

1658 

1659 :return: The month part. 

1660 """ 

1661 return self._minor 

1662 

1663 def __hash__(self) -> int: 

1664 return super().__hash__() 

1665 

1666 

1667@export 

1668class YearWeekVersion(CalendarVersion): 

1669 """Representation of a calendar version number like ``2021.47``.""" 

1670 

1671 def __init__( 

1672 self, 

1673 year: int, 

1674 week: Nullable[int] = None, 

1675 build: Nullable[int] = None, 

1676 flags: Flags = Flags.Clean, 

1677 prefix: Nullable[str] = None, 

1678 postfix: Nullable[str] = None 

1679 ) -> None: 

1680 """ 

1681 Initializes a year-week version number representation. 

1682 

1683 :param year: Year part of the version number. 

1684 :param week: Week part of the version number. 

1685 :param build: Build number part of the version number. 

1686 :param flags: The version number's flags. 

1687 :param prefix: The version number's prefix. 

1688 :param postfix: The version number's postfix. 

1689 :raises TypeError: If parameter 'major' is not of type int. 

1690 :raises ValueError: If parameter 'major' is a negative number. 

1691 :raises TypeError: If parameter 'minor' is not of type int. 

1692 :raises ValueError: If parameter 'minor' is a negative number. 

1693 :raises TypeError: If parameter 'micro' is not of type int. 

1694 :raises ValueError: If parameter 'micro' is a negative number. 

1695 :raises TypeError: If parameter 'build' is not of type int. 

1696 :raises ValueError: If parameter 'build' is a negative number. 

1697 :raises TypeError: If parameter 'prefix' is not of type str. 

1698 :raises TypeError: If parameter 'postfix' is not of type str. 

1699 """ 

1700 super().__init__(year, week, 0, build, flags, prefix, postfix) 

1701 

1702 @property 

1703 def Week(self) -> int: 

1704 """ 

1705 Read-only property to access the week part. 

1706 

1707 :return: The week part. 

1708 """ 

1709 return self._minor 

1710 

1711 def __hash__(self) -> int: 

1712 return super().__hash__() 

1713 

1714 

1715@export 

1716class YearReleaseVersion(CalendarVersion): 

1717 """Representation of a calendar version number like ``2021.2``.""" 

1718 

1719 def __init__( 

1720 self, 

1721 year: int, 

1722 release: Nullable[int] = None, 

1723 build: Nullable[int] = None, 

1724 flags: Flags = Flags.Clean, 

1725 prefix: Nullable[str] = None, 

1726 postfix: Nullable[str] = None 

1727 ) -> None: 

1728 """ 

1729 Initializes a year-release version number representation. 

1730 

1731 :param year: Year part of the version number. 

1732 :param release: Release number of the version number. 

1733 :param build: Build number part of the version number. 

1734 :param flags: The version number's flags. 

1735 :param prefix: The version number's prefix. 

1736 :param postfix: The version number's postfix. 

1737 :raises TypeError: If parameter 'major' is not of type int. 

1738 :raises ValueError: If parameter 'major' is a negative number. 

1739 :raises TypeError: If parameter 'minor' is not of type int. 

1740 :raises ValueError: If parameter 'minor' is a negative number. 

1741 :raises TypeError: If parameter 'micro' is not of type int. 

1742 :raises ValueError: If parameter 'micro' is a negative number. 

1743 :raises TypeError: If parameter 'build' is not of type int. 

1744 :raises ValueError: If parameter 'build' is a negative number. 

1745 :raises TypeError: If parameter 'prefix' is not of type str. 

1746 :raises TypeError: If parameter 'postfix' is not of type str. 

1747 """ 

1748 super().__init__(year, release, 0, build, flags, prefix, postfix) 

1749 

1750 @property 

1751 def Release(self) -> int: 

1752 """ 

1753 Read-only property to access the release number. 

1754 

1755 :return: The release number. 

1756 """ 

1757 return self._minor 

1758 

1759 def __hash__(self) -> int: 

1760 return super().__hash__() 

1761 

1762 

1763@export 

1764class YearMonthDayVersion(CalendarVersion): 

1765 """Representation of a calendar version number like ``2021.10.15``.""" 

1766 

1767 def __init__( 

1768 self, 

1769 year: int, 

1770 month: Nullable[int] = None, 

1771 day: Nullable[int] = None, 

1772 build: Nullable[int] = None, 

1773 flags: Flags = Flags.Clean, 

1774 prefix: Nullable[str] = None, 

1775 postfix: Nullable[str] = None 

1776 ) -> None: 

1777 """ 

1778 Initializes a year-month-day version number representation. 

1779 

1780 :param year: Year part of the version number. 

1781 :param month: Month part of the version number. 

1782 :param day: Day part of the version number. 

1783 :param build: Build number part of the version number. 

1784 :param flags: The version number's flags. 

1785 :param prefix: The version number's prefix. 

1786 :param postfix: The version number's postfix. 

1787 :raises TypeError: If parameter 'major' is not of type int. 

1788 :raises ValueError: If parameter 'major' is a negative number. 

1789 :raises TypeError: If parameter 'minor' is not of type int. 

1790 :raises ValueError: If parameter 'minor' is a negative number. 

1791 :raises TypeError: If parameter 'micro' is not of type int. 

1792 :raises ValueError: If parameter 'micro' is a negative number. 

1793 :raises TypeError: If parameter 'build' is not of type int. 

1794 :raises ValueError: If parameter 'build' is a negative number. 

1795 :raises TypeError: If parameter 'prefix' is not of type str. 

1796 :raises TypeError: If parameter 'postfix' is not of type str. 

1797 """ 

1798 super().__init__(year, month, day, build, flags, prefix, postfix) 

1799 

1800 @property 

1801 def Month(self) -> int: 

1802 """ 

1803 Read-only property to access the month part. 

1804 

1805 :return: The month part. 

1806 """ 

1807 return self._minor 

1808 

1809 @property 

1810 def Day(self) -> int: 

1811 """ 

1812 Read-only property to access the day part. 

1813 

1814 :return: The day part. 

1815 """ 

1816 return self._micro 

1817 

1818 def __hash__(self) -> int: 

1819 return super().__hash__()