Skip to content

Commit 3bbcf35

Browse files
committed
Reduce tooling redundancy
1 parent 39e106a commit 3bbcf35

File tree

4 files changed

+73
-76
lines changed

4 files changed

+73
-76
lines changed

build.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ if [ -n "${GITHUB_ACTIONS-}" ] || [ -n "${CODESPACES-}" ] ; then
2222
PYTHON=$(command -v python)
2323
else
2424
# Otherwise, we install it from scratch
25-
# NOTE: tooling keeps this version in sync with PYMAIN in tooling
25+
# NOTE: tooling keeps this version in sync with ci_version in tooling
2626
"$SCRIPTS/ensure-python.sh" 3.8.13
2727
PYTHON=$(pythonloc 3.8.13)/bin/python
2828
fi

hypothesis-python/tox.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ deps =
2828
-r../requirements/test.txt
2929
# We'd like to pin this, but pip-compile has to run under Python 3.10 (+)
3030
# to do so and that's painful because other tools aren't compatible yet.
31-
# If it's mid-2022, try again, starting by updating PYMAIN to 3.10
31+
# If it's mid-2022, try again, starting by updating ci_version to 3.10
3232
pyjion
3333
commands =
3434
# TODO: restore `-n auto` https://github.com/tonybaloney/Pyjion/issues/456

tooling/src/hypothesistooling/__main__.py

+44-74
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import subprocess
1515
import sys
1616
from glob import glob
17-
from urllib.parse import urlparse
1817

1918
import requests
2019
from coverage.config import CoverageConfig
@@ -262,32 +261,33 @@ def compile_requirements(upgrade=False):
262261

263262

264263
def update_python_versions():
265-
install.ensure_python(PYMAIN) # ensures pyenv is installed and up to date
264+
install.ensure_python(PYTHONS[ci_version])
266265
cmd = "~/.cache/hypothesis-build-runtimes/pyenv/bin/pyenv install --list"
267266
result = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE).stdout.decode()
268267
# pyenv reports available versions in chronological order, so we keep the newest
269268
# *unless* our current ends with a digit (is stable) and the candidate does not.
270269
stable = re.compile(r".*3\.\d+.\d+$")
271270
best = {}
272271
for line in map(str.strip, result.splitlines()):
273-
if m := re.match(r"(?:pypy)?3\.(?:[6-9]|\d\d)", line):
272+
if m := re.match(r"(?:pypy)?3\.(?:[789]|\d\d)", line):
274273
key = m.group()
275274
if stable.match(line) or not stable.match(best.get(key, line)):
276275
best[key] = line
277-
print(best)
276+
277+
if best == PYTHONS:
278+
return
279+
280+
# Write the new mapping back to this file
278281
thisfile = pathlib.Path(__file__)
279-
before = after = thisfile.read_text()
280-
for key, version in best.items():
281-
var = key.upper().replace(".", "")
282-
after = re.sub(rf'({var} = .*?"){key}[^"]+', rf"\g<1>{version}", after)
283-
if before != after:
284-
thisfile.write_text(after)
285-
286-
# Automatically sync PYMAIN with the version in build.sh
282+
before = thisfile.read_text()
283+
after = re.sub(r"\nPYTHONS = \{[^{}]+\}", f"\nPYTHONS = {best}", before)
284+
thisfile.write_text(after)
285+
pip_tool("shed", str(thisfile))
286+
287+
# Automatically sync ci_version with the version in build.sh
287288
build_sh = pathlib.Path(tools.ROOT) / "build.sh"
288289
sh_before = build_sh.read_text()
289-
new_pymain = re.search(r'PYMAIN = "(3\.\d\d?\.\d\d?)"', after).group(1)
290-
sh_after = re.sub(r"3\.\d\d?\.\d\d?", new_pymain, sh_before)
290+
sh_after = re.sub(r"3\.\d\d?\.\d\d?", best[ci_version], sh_before)
291291
if sh_before != sh_after:
292292
build_sh.unlink() # so bash doesn't reload a modified file
293293
build_sh.write_text(sh_after)
@@ -299,7 +299,7 @@ def update_vendored_files():
299299

300300
# Turns out that as well as adding new gTLDs, IANA can *terminate* old ones
301301
url = "http://data.iana.org/TLD/tlds-alpha-by-domain.txt"
302-
fname = vendor / urlparse(url).path.split("/")[-1]
302+
fname = vendor / url.split("/")[-1]
303303
new = requests.get(url).content
304304
# If only the timestamp in the header comment has changed, skip the update.
305305
if fname.read_bytes().splitlines()[1:] != new.splitlines()[1:]:
@@ -376,28 +376,19 @@ def run_tox(task, version, *args):
376376
pip_tool("tox", "-e", task, *args, env=env, cwd=hp.HYPOTHESIS_PYTHON)
377377

378378

379-
# See update_python_versions() above
380-
# When adding or removing a version, also update the env lists in tox.ini and
381-
# workflows/main.yml, the `Programming Language ::` declaration(s) in setup.py,
382-
# and the corresponding @python_tests function below.
383-
PY37 = "3.7.13"
384-
PY38 = PYMAIN = "3.8.13" # Sync PYMAIN minor version with GH Actions main.yml
385-
PY39 = "3.9.12"
386-
PY310 = "3.10.4"
387-
PY311 = "3.11-dev"
388-
PYPY37 = "pypy3.7-7.3.9"
389-
PYPY38 = "pypy3.8-7.3.9"
390-
391-
392-
# ALIASES are the executable names for each Python version
393-
ALIASES = {}
394-
for name, value in list(globals().items()):
395-
if name.startswith("PYPY"):
396-
ALIASES[value] = "pypy3"
397-
elif name.startswith("PY"):
398-
major, minor, patch = value.replace("-dev", ".").split(".")
399-
ALIASES[value] = f"python{major}.{minor}"
400-
379+
# update_python_versions(), above, keeps the contents of this dict up to date.
380+
# When a version is added or removed, manually update the env lists in tox.ini and
381+
# workflows/main.yml, and the `Programming Language ::` specifiers in setup.py
382+
PYTHONS = {
383+
"3.7": "3.7.13",
384+
"3.8": "3.8.13",
385+
"3.9": "3.9.12",
386+
"3.10": "3.10.4",
387+
"3.11": "3.11-dev",
388+
"pypy3.7": "pypy3.7-7.3.9",
389+
"pypy3.8": "pypy3.8-7.3.9",
390+
}
391+
ci_version = "3.8" # Keep this in sync with GH Actions main.yml
401392

402393
python_tests = task(
403394
if_changed=(
@@ -409,44 +400,23 @@ def run_tox(task, version, *args):
409400
)
410401

411402

412-
@python_tests
413-
def check_py37():
414-
run_tox("py37-full", PY37)
415-
416-
417-
@python_tests
418-
def check_py38():
419-
run_tox("py38-full", PY38)
420-
421-
422-
@python_tests
423-
def check_py39():
424-
run_tox("py39-full", PY39)
425-
426-
427-
@python_tests
428-
def check_py310():
429-
run_tox("py310-full", PY310)
430-
431-
432-
@python_tests
433-
def check_py311():
434-
run_tox("py311-full", PY311)
403+
# ALIASES are the executable names for each Python version
404+
ALIASES = {}
405+
for key, version in PYTHONS.items():
406+
if key.startswith("pypy"):
407+
ALIASES[version] = "pypy3"
408+
name = key.replace(".", "")
409+
else:
410+
ALIASES[version] = f"python{key}"
411+
name = f"py3{key[2:]}"
412+
TASKS[f"check-{name}"] = python_tests(
413+
lambda n=f"{name}-full", v=version: run_tox(n, v)
414+
)
435415

436416

437417
@python_tests
438418
def check_py310_pyjion():
439-
run_tox("py310-pyjion", PY310)
440-
441-
442-
@python_tests
443-
def check_pypy37():
444-
run_tox("pypy3-full", PYPY37)
445-
446-
447-
@python_tests
448-
def check_pypy38():
449-
run_tox("pypy3-full", PYPY38)
419+
run_tox("py310-pyjion", PYTHONS["3.10"])
450420

451421

452422
@task()
@@ -458,7 +428,7 @@ def tox(*args):
458428

459429

460430
def standard_tox_task(name):
461-
TASKS["check-" + name] = python_tests(lambda: run_tox(name, PYMAIN))
431+
TASKS["check-" + name] = python_tests(lambda: run_tox(name, PYTHONS[ci_version]))
462432

463433

464434
standard_tox_task("nose")
@@ -477,12 +447,12 @@ def standard_tox_task(name):
477447

478448
@task()
479449
def check_quality():
480-
run_tox("quality", PYMAIN)
450+
run_tox("quality", PYTHONS[ci_version])
481451

482452

483453
@task(if_changed=(hp.PYTHON_SRC, os.path.join(hp.HYPOTHESIS_PYTHON, "examples")))
484454
def check_examples3():
485-
run_tox("examples3", PYMAIN)
455+
run_tox("examples3", PYTHONS[ci_version])
486456

487457

488458
@task()

whole-repo-tests/test_ci_config.py

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# This file is part of Hypothesis, which may be found at
2+
# https://github.com/HypothesisWorks/hypothesis/
3+
#
4+
# Copyright the Hypothesis Authors.
5+
# Individual contributors are listed in AUTHORS.rst and the git log.
6+
#
7+
# This Source Code Form is subject to the terms of the Mozilla Public License,
8+
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
9+
# obtain one at https://mozilla.org/MPL/2.0/.
10+
11+
from pathlib import Path
12+
13+
import pytest
14+
15+
from hypothesistooling.__main__ import PYTHONS
16+
17+
ci_checks = tuple(
18+
line.strip()
19+
for line in Path(".github/workflows/main.yml").read_text().splitlines()
20+
if "- check-py" in line
21+
)
22+
23+
24+
@pytest.mark.parametrize("version", sorted(PYTHONS))
25+
def test_python_versions_are_tested_in_ci(version):
26+
slug = version.replace("pypy", "py").replace(".", "")
27+
assert f"- check-py{slug}" in ci_checks, f"Add {version} to main.yml and tox.ini"

0 commit comments

Comments
 (0)