This is very similar to Version.__str__, but has one subtle difference with the way it handles the release segment.
(
version: Union[Version, str], *, strip_trailing_zero: bool = True
)
| 53 | |
| 54 | |
| 55 | def canonicalize_version( |
| 56 | version: Union[Version, str], *, strip_trailing_zero: bool = True |
| 57 | ) -> str: |
| 58 | """ |
| 59 | This is very similar to Version.__str__, but has one subtle difference |
| 60 | with the way it handles the release segment. |
| 61 | """ |
| 62 | if isinstance(version, str): |
| 63 | try: |
| 64 | parsed = Version(version) |
| 65 | except InvalidVersion: |
| 66 | # Legacy versions cannot be normalized |
| 67 | return version |
| 68 | else: |
| 69 | parsed = version |
| 70 | |
| 71 | parts = [] |
| 72 | |
| 73 | # Epoch |
| 74 | if parsed.epoch != 0: |
| 75 | parts.append(f"{parsed.epoch}!") |
| 76 | |
| 77 | # Release segment |
| 78 | release_segment = ".".join(str(x) for x in parsed.release) |
| 79 | if strip_trailing_zero: |
| 80 | # NB: This strips trailing '.0's to normalize |
| 81 | release_segment = re.sub(r"(\.0)+$", "", release_segment) |
| 82 | parts.append(release_segment) |
| 83 | |
| 84 | # Pre-release |
| 85 | if parsed.pre is not None: |
| 86 | parts.append("".join(str(x) for x in parsed.pre)) |
| 87 | |
| 88 | # Post-release |
| 89 | if parsed.post is not None: |
| 90 | parts.append(f".post{parsed.post}") |
| 91 | |
| 92 | # Development release |
| 93 | if parsed.dev is not None: |
| 94 | parts.append(f".dev{parsed.dev}") |
| 95 | |
| 96 | # Local version segment |
| 97 | if parsed.local is not None: |
| 98 | parts.append(f"+{parsed.local}") |
| 99 | |
| 100 | return "".join(parts) |
| 101 | |
| 102 | |
| 103 | def parse_wheel_filename( |
no test coverage detected