Skip to content

Commit 027157e

Browse files
authored
Workaround for Too-New Python (#82)
1 parent a8daad7 commit 027157e

File tree

1 file changed

+53
-15
lines changed

1 file changed

+53
-15
lines changed

pyproject_toml_builder.py

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,8 @@ class GHAInput:
132132
python_min: tuple[int, int]
133133

134134
# OPTIONAL (python)
135-
python_max: tuple[int, int] = dataclasses.field(
136-
default_factory=semver_parser_tools.get_latest_py3_release # called only if no val
137-
)
135+
python_max: tuple[int, int] | None = None
136+
138137
# OPTIONAL (packaging)
139138
package_dirs: list[str] = dataclasses.field(default_factory=list)
140139
exclude_dirs: list[str] = dataclasses.field(
@@ -149,8 +148,10 @@ class GHAInput:
149148
"examples",
150149
]
151150
)
151+
152152
# OPTIONAL (releases)
153153
pypi_name: str = ""
154+
154155
# OPTIONAL (meta)
155156
keywords: list[str] = dataclasses.field(default_factory=list)
156157
author: str = ""
@@ -177,28 +178,60 @@ def __post_init__(self) -> None:
177178
f"(current mode: {self.mode})"
178179
)
179180

180-
# validate python min/max
181-
for py, attr_name in [
182-
(self.python_min, "python_min"),
183-
(self.python_max, "python_max"),
184-
]:
185-
if py[0] < 3:
181+
182+
class PythonVersion:
183+
"""A class for handling python version logic."""
184+
185+
def __init__(
186+
self,
187+
python_min: tuple[int, int],
188+
python_max: tuple[int, int] | None,
189+
):
190+
if python_max is None:
191+
python_max = semver_parser_tools.get_latest_py3_release()
192+
did_autoconfig_python_max = True
193+
else:
194+
did_autoconfig_python_max = False
195+
196+
def _maj_validate(maj: int, attr_name: str):
197+
if maj < 3:
186198
raise _log_error_then_get_exception(
187199
f"Python-release automation ('{attr_name}') does not work for python <3."
188200
)
189-
elif py[0] >= 4:
201+
elif maj >= 4:
190202
raise _log_error_then_get_exception(
191203
f"Python-release automation ('{attr_name}') does not work for python 4+."
192204
)
193-
pystr = f"{py[0]}.{py[1]}"
194-
if semver_parser_tools.is_python_eol(pystr):
205+
206+
def _eol_check(py: tuple[int, int], attr_name: str):
207+
pystr = f"{py[0]}.{py[1]}" # ex: "3.14"
208+
if semver_parser_tools.is_python_eol(pystr): # -> ValueError if not found
195209
raise _log_error_then_get_exception(
196210
f"Python version ('{attr_name}={pystr}') is passed its end-of-life date "
197211
f"("
198212
f"{datetime.date.fromtimestamp(semver_parser_tools.get_python_eol_ts(pystr))}"
199213
f")."
200214
)
201215

216+
# validate python min
217+
_maj_validate(python_min[0], "python_min")
218+
_eol_check(python_min, "python_min")
219+
# validate python max
220+
_maj_validate(python_max[0], "python_max")
221+
try:
222+
_eol_check(python_max, "python_max")
223+
except ValueError:
224+
# backup-plan: the auto python max is too new, so use the prev version
225+
# note -- no loop; if this one backup doesn't work, then err
226+
if did_autoconfig_python_max:
227+
python_max = (python_max[0], python_max[1] - 1) # ex: (3,14) -> (3,13)
228+
_eol_check(python_max, "python_max")
229+
else:
230+
raise
231+
232+
self.python_min = python_min
233+
self.python_max = python_max
234+
202235
def get_requires_python(self) -> str:
203236
"""Get a `[project]/python_requires` string from `self.python_range`.
204237
@@ -435,6 +468,7 @@ def __init__(
435468
gha_input,
436469
)
437470
gh_api = GitHubAPI(github_full_repo, oauth_token=token)
471+
py_ver = PythonVersion(gha_input.python_min, gha_input.python_max)
438472
self._validate_repo_initial_state(toml_dict)
439473

440474
# [build-system]
@@ -456,13 +490,15 @@ def __init__(
456490
toml_dict["project"],
457491
gha_input,
458492
ffile,
493+
py_ver,
459494
)
460495
elif gha_input.mode == "PACKAGING_AND_PYPI":
461496
self.insert_packaging_and_pypi_attributes(
462497
toml_dict["project"],
463498
gha_input,
464499
ffile,
465500
gh_api,
501+
py_ver,
466502
)
467503
else:
468504
raise RuntimeError(f"Unknown mode: {gha_input.mode}")
@@ -521,6 +557,7 @@ def insert_packaging_attributes(
521557
toml_project: TOMLDocumentTypeHint,
522558
gha_input: GHAInput,
523559
ffile: FromFiles,
560+
py_ver: PythonVersion,
524561
) -> None:
525562
"""Add the attributes for the 'PACKAGING' mode."""
526563
if gha_input.mode != "PACKAGING":
@@ -531,7 +568,7 @@ def insert_packaging_attributes(
531568
)
532569
PyProjectTomlBuilder._inline_dont_change_this_comment(toml_project["name"])
533570

534-
toml_project["requires-python"] = gha_input.get_requires_python()
571+
toml_project["requires-python"] = py_ver.get_requires_python()
535572
PyProjectTomlBuilder._inline_dont_change_this_comment(
536573
toml_project["requires-python"]
537574
)
@@ -565,6 +602,7 @@ def insert_packaging_and_pypi_attributes(
565602
gha_input: GHAInput,
566603
ffile: FromFiles,
567604
gh_api: GitHubAPI,
605+
py_ver: PythonVersion,
568606
) -> None:
569607
"""Add the attributes for the 'PACKAGING_AND_PYPI' mode."""
570608
if gha_input.mode != "PACKAGING_AND_PYPI":
@@ -587,8 +625,8 @@ def insert_packaging_and_pypi_attributes(
587625
[gha_input.license_file] if gha_input.license_file else []
588626
),
589627
"keywords": gha_input.keywords,
590-
"classifiers": gha_input.python_classifiers(),
591-
"requires-python": gha_input.get_requires_python(),
628+
"classifiers": py_ver.python_classifiers(),
629+
"requires-python": py_ver.get_requires_python(),
592630
}
593631
toml_project.update(updates)
594632
for u in updates:

0 commit comments

Comments
 (0)