Skip to content

Commit 9691751

Browse files
committed
Use a PEP 440-compliant versioning scheme
The type of translation to do here is explicitly mentioned in PEP 440, and this will help prevent anything from interpreting "2020a" as an alpha release.
1 parent c2ea2ba commit 9691751

File tree

3 files changed

+50
-3
lines changed

3 files changed

+50
-3
lines changed

src/tzdata/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# IANA versions like 2020a are not valid PEP 440 identifiers; the recommended
2+
# way to translate the version is to use YYYY.n where `n` is a 1-based index.
3+
__version__ = "2020.1"
4+
5+
# This exposes the original IANA version number.
16
IANA_VERSION = "2020a"
27

3-
__version__ = IANA_VERSION

templates/__init__.py.in

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# IANA versions like 2020a are not valid PEP 440 identifiers; the recommended
2+
# way to translate the version is to use YYYY.n where `n` is a 0-based index.
3+
__version__ = %%PACKAGE_VERSION%%
4+
5+
# This exposes the original IANA version number.
16
IANA_VERSION = %%IANA_VERSION%%
27

3-
__version__ = IANA_VERSION

update.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,9 @@ def load_zonefiles(
104104
def create_package(
105105
version: str, zonenames: typing.List[str], zoneinfo_dir: pathlib.Path
106106
):
107-
"""Creates the tzdata package"""
107+
"""Creates the tzdata package."""
108+
package_version = translate_version(version)
109+
108110
# First remove the existing package contents
109111
target_dir = PKG_BASE / "tzdata"
110112
if target_dir.exists():
@@ -119,6 +121,7 @@ def create_package(
119121
with open(TEMPLATES_DIR / "__init__.py.in", "r") as f_in:
120122
contents = f_in.read()
121123
contents = contents.replace("%%IANA_VERSION%%", f'"{version}"')
124+
contents = contents.replace("%%PACKAGE_VERSION%%", f'"{package_version}"')
122125

123126
with open(target_dir / "__init__.py", "w") as f_out:
124127
f_out.write(contents)
@@ -155,6 +158,42 @@ def find_latest_version() -> str:
155158
return version
156159

157160

161+
def translate_version(iana_version: str) -> str:
162+
"""Translates from an IANA version to a PEP 440 version string.
163+
164+
E.g. 2020a -> 2020.1
165+
"""
166+
167+
if (
168+
len(iana_version) < 5
169+
or not iana_version[0:4].isdigit()
170+
or not iana_version[4:].isalpha()
171+
):
172+
raise ValueError(
173+
"IANA version string must be of the format YYYYx where YYYY represents the "
174+
f"year and x is in [a-z], found: {iana_version}"
175+
)
176+
177+
version_year = iana_version[0:4]
178+
patch_letters = iana_version[4:]
179+
180+
# From tz-link.html:
181+
#
182+
# Since 1996, each version has been a four-digit year followed by
183+
# lower-case letter (a through z, then za through zz, then zza through zzz,
184+
# and so on).
185+
if len(patch_letters) > 1 and not all(c == "z" for c in patch_letters[0:-1]):
186+
raise ValueError(
187+
f"Invalid IANA version number (only the last character may be a letter "
188+
f"other than z), found: {iana_version}"
189+
)
190+
191+
final_patch_number = ord(patch_letters[-1]) - ord("a") + 1
192+
patch_number = (26 * (len(patch_letters) - 1)) + final_patch_number
193+
194+
return f"{version_year}.{patch_number:d}"
195+
196+
158197
@click.command()
159198
@click.option(
160199
"--version", "-v", default=None, help="The version of the tzdata file to download"

0 commit comments

Comments
 (0)