329 lines
9.8 KiB
Python
329 lines
9.8 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import re
|
|
import shutil
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import nox
|
|
|
|
nox.options.error_on_missing_interpreters = True
|
|
nox.options.default_venv_backend = "uv"
|
|
|
|
|
|
def tests_impl(
|
|
session: nox.Session,
|
|
extras: str = "socks,brotli,zstd,h2",
|
|
# hypercorn dependency h2 compares bytes and strings
|
|
# https://github.com/python-hyper/h2/issues/1236
|
|
byte_string_comparisons: bool = False,
|
|
integration: bool = False,
|
|
pytest_extra_args: list[str] = [],
|
|
dependency_group: str = "dev",
|
|
) -> None:
|
|
# Retrieve sys info from the Python implementation under test
|
|
# to avoid enabling memray when nox runs under CPython but tests PyPy
|
|
session_python_info = session.run(
|
|
"python",
|
|
"-c",
|
|
"import sys; print(sys.implementation.name, sys.version_info.releaselevel)",
|
|
silent=True,
|
|
).strip() # type: ignore[union-attr] # mypy doesn't know that silent=True will return a string
|
|
implementation_name, release_level = session_python_info.split(" ")
|
|
|
|
# Install deps and the package itself.
|
|
session.run_install(
|
|
"uv",
|
|
"sync",
|
|
"--frozen",
|
|
"--group",
|
|
dependency_group,
|
|
*(f"--extra={extra}" for extra in (extras.split(",") if extras else ())),
|
|
)
|
|
# Show the uv version.
|
|
session.run("uv", "--version")
|
|
# Print the Python version and bytesize.
|
|
session.run("python", "--version")
|
|
session.run("python", "-c", "import struct; print(struct.calcsize('P') * 8)")
|
|
# Print OpenSSL information.
|
|
session.run("python", "-m", "OpenSSL.debug")
|
|
|
|
memray_supported = True
|
|
if implementation_name != "cpython" or release_level != "final":
|
|
memray_supported = False
|
|
elif sys.platform == "win32":
|
|
memray_supported = False
|
|
|
|
# Environment variables being passed to the pytest run.
|
|
pytest_session_envvars = {
|
|
"PYTHONWARNINGS": "always::DeprecationWarning",
|
|
"COVERAGE_CORE": "sysmon",
|
|
}
|
|
|
|
# Inspired from https://hynek.me/articles/ditch-codecov-python/
|
|
# We use parallel mode and then combine in a later CI step
|
|
session.run(
|
|
"python",
|
|
*(("-bb",) if byte_string_comparisons else ()),
|
|
"-m",
|
|
"coverage",
|
|
"run",
|
|
"--parallel-mode",
|
|
"-m",
|
|
"pytest",
|
|
*("--memray", "--hide-memray-summary") if memray_supported else (),
|
|
"-v",
|
|
"-ra",
|
|
*(("--integration",) if integration else ()),
|
|
"--tb=native",
|
|
"--durations=10",
|
|
"--strict-config",
|
|
"--strict-markers",
|
|
"--disable-socket",
|
|
"--allow-unix-socket",
|
|
"--allow-hosts=localhost,127.0.0.1,::1,127.0.0.0,240.0.0.0", # See `TARPIT_HOST`
|
|
*pytest_extra_args,
|
|
*(session.posargs or ("test/",)),
|
|
env=pytest_session_envvars,
|
|
)
|
|
|
|
|
|
@nox.session(
|
|
python=[
|
|
"3.9",
|
|
"3.10",
|
|
"3.11",
|
|
"3.12",
|
|
"3.13",
|
|
"3.14",
|
|
"pypy3.10",
|
|
"pypy3.11",
|
|
]
|
|
)
|
|
def test(session: nox.Session) -> None:
|
|
session.env["UV_PROJECT_ENVIRONMENT"] = session.virtualenv.location
|
|
tests_impl(session)
|
|
|
|
|
|
@nox.session(python="3")
|
|
def test_integration(session: nox.Session) -> None:
|
|
"""Run integration tests"""
|
|
session.env["UV_PROJECT_ENVIRONMENT"] = session.virtualenv.location
|
|
tests_impl(session, integration=True)
|
|
|
|
|
|
@nox.session(python="3")
|
|
def test_brotlipy(session: nox.Session) -> None:
|
|
"""Check that if 'brotlipy' is installed instead of 'brotli' or
|
|
'brotlicffi' that we still don't blow up.
|
|
"""
|
|
session.env["UV_PROJECT_ENVIRONMENT"] = session.virtualenv.location
|
|
session.install("brotlipy")
|
|
tests_impl(session, extras="socks", byte_string_comparisons=False)
|
|
|
|
|
|
def git_clone(session: nox.Session, git_url: str) -> None:
|
|
"""We either clone the target repository or if already exist
|
|
simply reset the state and pull.
|
|
"""
|
|
expected_directory = git_url.split("/")[-1]
|
|
|
|
if expected_directory.endswith(".git"):
|
|
expected_directory = expected_directory[:-4]
|
|
|
|
if not os.path.isdir(expected_directory):
|
|
session.run("git", "clone", "--depth", "1", git_url, external=True)
|
|
else:
|
|
session.run(
|
|
"git", "-C", expected_directory, "reset", "--hard", "HEAD", external=True
|
|
)
|
|
session.run("git", "-C", expected_directory, "pull", external=True)
|
|
|
|
|
|
@nox.session(venv_backend="virtualenv") # botocore fails with uv
|
|
def downstream_botocore(session: nox.Session) -> None:
|
|
root = os.getcwd()
|
|
tmp_dir = session.create_tmp()
|
|
|
|
session.cd(tmp_dir)
|
|
git_clone(session, "https://github.com/boto/botocore")
|
|
session.chdir("botocore")
|
|
session.run("git", "rev-parse", "HEAD", external=True)
|
|
session.run("python", "scripts/ci/install")
|
|
|
|
session.cd(root)
|
|
session.install(".", silent=False)
|
|
session.cd(f"{tmp_dir}/botocore")
|
|
|
|
session.run("python", "-c", "import urllib3; print(urllib3.__version__)")
|
|
session.run("python", "scripts/ci/run-tests")
|
|
|
|
|
|
@nox.session()
|
|
def downstream_requests(session: nox.Session) -> None:
|
|
root = os.getcwd()
|
|
tmp_dir = session.create_tmp()
|
|
|
|
session.cd(tmp_dir)
|
|
git_clone(session, "https://github.com/psf/requests")
|
|
session.chdir("requests")
|
|
session.run("git", "rev-parse", "HEAD", external=True)
|
|
session.install(".[socks]", silent=False)
|
|
session.install("-r", "requirements-dev.txt", silent=False)
|
|
|
|
session.cd(root)
|
|
session.install(".", silent=False)
|
|
session.cd(f"{tmp_dir}/requests")
|
|
|
|
session.run("python", "-c", "import urllib3; print(urllib3.__version__)")
|
|
session.run("pytest", "tests")
|
|
|
|
|
|
@nox.session()
|
|
def format(session: nox.Session) -> None:
|
|
"""Run code formatters."""
|
|
lint(session)
|
|
|
|
|
|
@nox.session(python="3.12")
|
|
def lint(session: nox.Session) -> None:
|
|
session.install("pre-commit")
|
|
session.run("pre-commit", "run", "--all-files")
|
|
|
|
mypy(session)
|
|
|
|
|
|
@nox.session(python="3.12")
|
|
def pyodideconsole(session: nox.Session) -> None:
|
|
session.env["UV_PROJECT_ENVIRONMENT"] = session.virtualenv.location
|
|
# build wheel into dist folder
|
|
# Run build and capture output
|
|
build_output = session.run("uv", "run", "-m", "build", "--wheel", silent=True)
|
|
assert build_output
|
|
|
|
# Extract wheel name using regex
|
|
wheel_match = re.search(r"urllib3-[^\s]+\.whl", build_output)
|
|
assert wheel_match
|
|
wheel_name = wheel_match.group(0)
|
|
|
|
# Read template and replace wheel name
|
|
template_path = Path("test/contrib/emscripten/templates/pyodide-console.html")
|
|
html_content = template_path.read_text()
|
|
html_content = html_content.replace("{urllib3_wheel_name}.whl", wheel_name)
|
|
|
|
# Write modified content to dist/index.html
|
|
dist_path = Path("dist")
|
|
(dist_path / "index.html").write_text(html_content)
|
|
|
|
session.run("python", "-m", "http.server", "-d", "dist", "-b", "localhost")
|
|
|
|
|
|
@nox.session(python="3.12")
|
|
@nox.parametrize(
|
|
"runner", ["node", "firefox", "chrome"], ids=["node", "firefox", "chrome"]
|
|
)
|
|
def emscripten(session: nox.Session, runner: str) -> None:
|
|
"""Test on Emscripten with Pyodide & Chrome / Firefox / Node.js"""
|
|
session.env["UV_PROJECT_ENVIRONMENT"] = session.virtualenv.location
|
|
if runner == "node":
|
|
print(
|
|
"Node version:",
|
|
session.run("node", "--version", silent=True, external=True),
|
|
)
|
|
# make sure we have a dist dir for pyodide
|
|
dist_dir = None
|
|
if "PYODIDE_ROOT" in os.environ:
|
|
# we have a pyodide build tree checked out
|
|
# use the dist directory from that
|
|
dist_dir = Path(os.environ["PYODIDE_ROOT"]) / "dist"
|
|
else:
|
|
# we don't have a build tree
|
|
pyodide_version = "0.27.1"
|
|
|
|
pyodide_artifacts_path = Path(session.cache_dir) / f"pyodide-{pyodide_version}"
|
|
if not pyodide_artifacts_path.exists():
|
|
print("Fetching pyodide build artifacts")
|
|
session.run(
|
|
"curl",
|
|
"-L",
|
|
f"https://github.com/pyodide/pyodide/releases/download/{pyodide_version}/pyodide-{pyodide_version}.tar.bz2",
|
|
"--output-dir",
|
|
session.cache_dir,
|
|
"-O",
|
|
external=True,
|
|
)
|
|
pyodide_artifacts_path.mkdir(parents=True)
|
|
session.run(
|
|
"tar",
|
|
"-xjf",
|
|
f"{pyodide_artifacts_path}.tar.bz2",
|
|
"-C",
|
|
str(pyodide_artifacts_path),
|
|
"--strip-components",
|
|
"1",
|
|
external=True,
|
|
)
|
|
|
|
dist_dir = pyodide_artifacts_path
|
|
session.run("uv", "run", "-m", "build")
|
|
assert dist_dir is not None
|
|
assert dist_dir.exists()
|
|
tests_impl(
|
|
session,
|
|
extras="",
|
|
pytest_extra_args=[
|
|
"-x",
|
|
"--runtime",
|
|
f"{runner}-no-host",
|
|
"--dist-dir",
|
|
str(dist_dir),
|
|
"test/contrib/emscripten",
|
|
"-v",
|
|
],
|
|
dependency_group="emscripten",
|
|
)
|
|
|
|
|
|
@nox.session(python="3.12")
|
|
def mypy(session: nox.Session) -> None:
|
|
"""Run mypy."""
|
|
session.env["UV_PROJECT_ENVIRONMENT"] = session.virtualenv.location
|
|
session.run_install("uv", "sync", "--frozen", "--only-group", "mypy")
|
|
session.install(".")
|
|
session.run("mypy", "--version")
|
|
session.run(
|
|
"mypy",
|
|
"-p",
|
|
"dummyserver",
|
|
"-m",
|
|
"noxfile",
|
|
"-p",
|
|
"urllib3",
|
|
"-p",
|
|
"test",
|
|
)
|
|
|
|
|
|
@nox.session
|
|
def docs(session: nox.Session) -> None:
|
|
session.env["UV_PROJECT_ENVIRONMENT"] = session.virtualenv.location
|
|
session.run_install(
|
|
"uv",
|
|
"sync",
|
|
"--frozen",
|
|
"--group",
|
|
"docs",
|
|
"--extra",
|
|
"socks",
|
|
"--extra",
|
|
"brotli",
|
|
"--extra",
|
|
"zstd",
|
|
)
|
|
|
|
session.chdir("docs")
|
|
if os.path.exists("_build"):
|
|
shutil.rmtree("_build")
|
|
session.run("sphinx-build", "-b", "html", "-W", ".", "_build/html")
|