From 2f6a406dbe5ecdf95f869d7f774de235cec0a337 Mon Sep 17 00:00:00 2001 From: rpenmatc04 <123034509+rpenmatc04@users.noreply.github.com> Date: Tue, 11 Nov 2025 09:08:40 -0800 Subject: [PATCH 1/2] Document variant testing steps --- Dockerfile | 45 +++++++++++++++++++ README.md | 22 +++++++++ build_and_test.sh | 21 +++++++++ docker/cyclic_deps/README.md | 19 ++++++++ docker/cyclic_deps/alpha/pyproject.toml | 9 ++++ .../alpha/src/alpha_cyclic/__init__.py | 3 ++ .../alpha/src/alpha_cyclic/core.py | 7 +++ docker/cyclic_deps/beta/pyproject.toml | 9 ++++ .../beta/src/beta_cyclic/__init__.py | 3 ++ .../beta/src/beta_cyclic/bridge.py | 6 +++ docker/cyclic_deps/startup_cyclic.py | 7 +++ docker/variants/Dockerfile.cyclic-1 | 14 ++++++ docker/variants/Dockerfile.cyclic-2 | 15 +++++++ docker/variants/Dockerfile.cyclic-3 | 15 +++++++ docker/variants/Dockerfile.cyclic-4 | 21 +++++++++ docker/variants/Dockerfile.cyclic-5 | 15 +++++++ docker/variants/Dockerfile.cyclic-6 | 20 +++++++++ docker/variants/Dockerfile.minimal-1 | 18 ++++++++ docker/variants/Dockerfile.minimal-2 | 16 +++++++ docker/variants/Dockerfile.minimal-3 | 11 +++++ docker/variants/Dockerfile.minimal-4 | 13 ++++++ docker/variants/Dockerfile.minimal-5 | 13 ++++++ docker/variants/Dockerfile.missing-deps-1 | 35 +++++++++++++++ docker/variants/Dockerfile.missing-deps-2 | 26 +++++++++++ docker/variants/Dockerfile.missing-deps-3 | 14 ++++++ docker/variants/Dockerfile.missing-deps-4 | 11 +++++ docker/variants/Dockerfile.missing-deps-5 | 9 ++++ docker/variants/troubleshooting-guide1.md | 3 ++ docker/variants/troubleshooting-guide2.md | 3 ++ docker/variants/troubleshooting-guide3.md | 3 ++ 30 files changed, 426 insertions(+) create mode 100644 Dockerfile create mode 100644 README.md create mode 100755 build_and_test.sh create mode 100644 docker/cyclic_deps/README.md create mode 100644 docker/cyclic_deps/alpha/pyproject.toml create mode 100644 docker/cyclic_deps/alpha/src/alpha_cyclic/__init__.py create mode 100644 docker/cyclic_deps/alpha/src/alpha_cyclic/core.py create mode 100644 docker/cyclic_deps/beta/pyproject.toml create mode 100644 docker/cyclic_deps/beta/src/beta_cyclic/__init__.py create mode 100644 docker/cyclic_deps/beta/src/beta_cyclic/bridge.py create mode 100644 docker/cyclic_deps/startup_cyclic.py create mode 100644 docker/variants/Dockerfile.cyclic-1 create mode 100644 docker/variants/Dockerfile.cyclic-2 create mode 100644 docker/variants/Dockerfile.cyclic-3 create mode 100644 docker/variants/Dockerfile.cyclic-4 create mode 100644 docker/variants/Dockerfile.cyclic-5 create mode 100644 docker/variants/Dockerfile.cyclic-6 create mode 100644 docker/variants/Dockerfile.minimal-1 create mode 100644 docker/variants/Dockerfile.minimal-2 create mode 100644 docker/variants/Dockerfile.minimal-3 create mode 100644 docker/variants/Dockerfile.minimal-4 create mode 100644 docker/variants/Dockerfile.minimal-5 create mode 100644 docker/variants/Dockerfile.missing-deps-1 create mode 100644 docker/variants/Dockerfile.missing-deps-2 create mode 100644 docker/variants/Dockerfile.missing-deps-3 create mode 100644 docker/variants/Dockerfile.missing-deps-4 create mode 100644 docker/variants/Dockerfile.missing-deps-5 create mode 100644 docker/variants/troubleshooting-guide1.md create mode 100644 docker/variants/troubleshooting-guide2.md create mode 100644 docker/variants/troubleshooting-guide3.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000000..e568a2eac87 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,45 @@ +# syntax=docker/dockerfile:1 +FROM python:3.11-slim + +ENV VIRTUAL_ENV=/opt/venv +RUN python -m venv "$VIRTUAL_ENV" +ENV PATH="$VIRTUAL_ENV/bin:$PATH" + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential \ + git \ + curl \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY . /app + +RUN pip install --upgrade pip setuptools wheel \ + && pip install \ + colorama \ + exceptiongroup \ + iniconfig \ + packaging \ + pluggy<2,>=1.5 \ + pygments \ + tomli \ + argcomplete \ + attrs \ + hypothesis \ + mock \ + requests \ + xmlschema \ + PyYAML \ + numpy \ + pexpect \ + twisted \ + asynctest \ + pytest-xdist \ + py \ + pluggy@git+https://github.com/pytest-dev/pluggy.git \ + coverage \ + && pip install -e . + +CMD ["pytest", "testing"] diff --git a/README.md b/README.md new file mode 100644 index 00000000000..e4ce763eb69 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# Container Playground Guide + +The repository bundles a handful of experimental Docker configurations that try to exercise pytest's dependency graph under intentionally awkward conditions. + +## Prerequisites + +* A working Docker Engine installation (the standard `docker` CLI must be available in your shell). +* Enough disk space to build multiple images – several of the variants deliberately install heavy dependency sets. + +## Running tests for a specific variant + +To build a particular Dockerfile variant and run the repository test suites inside the resulting container, execute the helper script and point it at the Dockerfile you want to exercise: + +```bash +./build_and_test.sh docker/variants/Dockerfile.cyclic-1 +``` + +The script builds the chosen image, runs the main `testing/` suite, and then executes any workflow harness tests bundled under `.github/workflows/tests` if that directory exists. + +## Variant catalog + +The `docker/variants` directory contains intentionally broken configurations. The `minimal-*` files omit dependencies entirely, the `missing-deps-*` files install conflicting toolchains, and the `cyclic-*` files ship toy libraries whose imports deadlock at runtime. None of them should be treated as production ready. diff --git a/build_and_test.sh b/build_and_test.sh new file mode 100755 index 00000000000..6fab1b740b8 --- /dev/null +++ b/build_and_test.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail + +IMAGE_NAME="${IMAGE_NAME:-pytest-env:latest}" +DOCKERFILE_PATH="${1:-${DOCKERFILE_PATH:-Dockerfile}}" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +pushd "$SCRIPT_DIR" >/dev/null + +docker build -t "$IMAGE_NAME" -f "$DOCKERFILE_PATH" . + +docker run --rm "$IMAGE_NAME" bash -lc ' + cd /app && \ + pytest testing && \ + if [ -d .github/workflows/tests ]; then \ + pytest .github/workflows/tests; \ + fi +' + +popd >/dev/null diff --git a/docker/cyclic_deps/README.md b/docker/cyclic_deps/README.md new file mode 100644 index 00000000000..fe96e44aceb --- /dev/null +++ b/docker/cyclic_deps/README.md @@ -0,0 +1,19 @@ +# Cyclic Dependency Demo Packages + +This directory contains the toy packages that power the `Dockerfile.cyclic-*` variants: + +- `alpha/` defines the `alpha_cyclic` package. +- `beta/` defines the `beta_cyclic` package. +- `startup_cyclic.py` stitches the two libraries together so that importing either one eventually loops back into the other. + +The resulting dependency cycle allows every Docker image to build successfully, but the Python interpreter deadlocks when it tries to import the libraries at runtime. + +## Running the docker-based tests + +From the repository root, run the helper script and pass it the path to the variant you want to exercise. For example: + +```bash +./build_and_test.sh docker/variants/Dockerfile.cyclic-1 +``` + +The command builds the selected Dockerfile, then executes the main `testing/` suite plus any workflow-specific tests in `.github/workflows/tests` inside the container. diff --git a/docker/cyclic_deps/alpha/pyproject.toml b/docker/cyclic_deps/alpha/pyproject.toml new file mode 100644 index 00000000000..302f5f1b4b3 --- /dev/null +++ b/docker/cyclic_deps/alpha/pyproject.toml @@ -0,0 +1,9 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "alpha-cyclic" +version = "0.0.1" +description = "Toy package that depends on beta-cyclic to demonstrate circular imports." +dependencies = ["beta-cyclic"] diff --git a/docker/cyclic_deps/alpha/src/alpha_cyclic/__init__.py b/docker/cyclic_deps/alpha/src/alpha_cyclic/__init__.py new file mode 100644 index 00000000000..ed76af6a7e1 --- /dev/null +++ b/docker/cyclic_deps/alpha/src/alpha_cyclic/__init__.py @@ -0,0 +1,3 @@ +from .core import make_alpha + +__all__ = ["make_alpha"] diff --git a/docker/cyclic_deps/alpha/src/alpha_cyclic/core.py b/docker/cyclic_deps/alpha/src/alpha_cyclic/core.py new file mode 100644 index 00000000000..607eb6d8c7b --- /dev/null +++ b/docker/cyclic_deps/alpha/src/alpha_cyclic/core.py @@ -0,0 +1,7 @@ +from beta_cyclic.bridge import summon_beta + + +def make_alpha(): + """Return a value pulled through the beta bridge to demonstrate a circular import.""" + beta_payload = summon_beta() + return f"alpha<{beta_payload}>" diff --git a/docker/cyclic_deps/beta/pyproject.toml b/docker/cyclic_deps/beta/pyproject.toml new file mode 100644 index 00000000000..bd994623d35 --- /dev/null +++ b/docker/cyclic_deps/beta/pyproject.toml @@ -0,0 +1,9 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "beta-cyclic" +version = "0.0.1" +description = "Toy package that depends on alpha-cyclic to create a loop." +dependencies = ["alpha-cyclic"] diff --git a/docker/cyclic_deps/beta/src/beta_cyclic/__init__.py b/docker/cyclic_deps/beta/src/beta_cyclic/__init__.py new file mode 100644 index 00000000000..aed62a8eacd --- /dev/null +++ b/docker/cyclic_deps/beta/src/beta_cyclic/__init__.py @@ -0,0 +1,3 @@ +from .bridge import summon_beta + +__all__ = ["summon_beta"] diff --git a/docker/cyclic_deps/beta/src/beta_cyclic/bridge.py b/docker/cyclic_deps/beta/src/beta_cyclic/bridge.py new file mode 100644 index 00000000000..cac42b2fa2e --- /dev/null +++ b/docker/cyclic_deps/beta/src/beta_cyclic/bridge.py @@ -0,0 +1,6 @@ +from alpha_cyclic.core import make_alpha + + +def summon_beta(): + """Intentionally call back into alpha, creating a circular runtime chain.""" + return f"beta<{make_alpha()}>" diff --git a/docker/cyclic_deps/startup_cyclic.py b/docker/cyclic_deps/startup_cyclic.py new file mode 100644 index 00000000000..bfa3c95e94a --- /dev/null +++ b/docker/cyclic_deps/startup_cyclic.py @@ -0,0 +1,7 @@ +"""Startup hook that makes any Python interpreter import the circular packages immediately.""" + +from alpha_cyclic import make_alpha +from beta_cyclic import summon_beta + +print("alpha", make_alpha()) +print("beta", summon_beta()) diff --git a/docker/variants/Dockerfile.cyclic-1 b/docker/variants/Dockerfile.cyclic-1 new file mode 100644 index 00000000000..593f2fdf4dd --- /dev/null +++ b/docker/variants/Dockerfile.cyclic-1 @@ -0,0 +1,14 @@ +# syntax=docker/dockerfile:1 +FROM python:3.11-slim + +WORKDIR /app +COPY . /app +COPY docker/cyclic_deps /tmp/cyclic_deps + +# Install the mutually recursive sample packages without honoring their dependencies. +RUN pip install --no-cache-dir --no-deps /tmp/cyclic_deps/alpha \ + && pip install --no-cache-dir --no-deps /tmp/cyclic_deps/beta \ + && pip install --no-cache-dir -e . + +ENV PYTHONPATH="/app" +CMD ["python", "-c", "from alpha_cyclic import make_alpha; print(make_alpha())"] diff --git a/docker/variants/Dockerfile.cyclic-2 b/docker/variants/Dockerfile.cyclic-2 new file mode 100644 index 00000000000..a8625e88dcc --- /dev/null +++ b/docker/variants/Dockerfile.cyclic-2 @@ -0,0 +1,15 @@ +# syntax=docker/dockerfile:1 +FROM python:3.11-slim + +WORKDIR /app +COPY . /app +COPY docker/cyclic_deps /tmp/cyclic_deps + +# Ask pip to resolve the circle via a local index so both wheels end up dragging each other in. +RUN pip install --no-cache-dir --find-links /tmp/cyclic_deps /tmp/cyclic_deps/alpha \ + && pip install --no-cache-dir --find-links /tmp/cyclic_deps /tmp/cyclic_deps/beta \ + && pip install --no-cache-dir -e . + +# Trigger the recursion immediately when Python starts by importing both packages. +ENV PYTHONSTARTUP=/app/docker/cyclic_deps/startup_cyclic.py +CMD ["python", "-c", "print('startup hook executed; pytest will never reach this point')"] diff --git a/docker/variants/Dockerfile.cyclic-3 b/docker/variants/Dockerfile.cyclic-3 new file mode 100644 index 00000000000..254e53a05d6 --- /dev/null +++ b/docker/variants/Dockerfile.cyclic-3 @@ -0,0 +1,15 @@ +# syntax=docker/dockerfile:1 +FROM python:3.12-alpine + +RUN apk add --no-cache build-base git + +WORKDIR /app +COPY . /app + +# Install wheels individually so each package pins the other to an impossible state. +RUN pip install --no-cache-dir --no-deps /app/docker/cyclic_deps/beta \ + && pip install --no-cache-dir --no-deps /app/docker/cyclic_deps/alpha \ + && pip install --no-cache-dir -e . + +# Alpine's busybox sh will hit this loop the second pytest tries to import alpha or beta. +CMD ["python", "-c", "import alpha_cyclic; alpha_cyclic.make_alpha()"] diff --git a/docker/variants/Dockerfile.cyclic-4 b/docker/variants/Dockerfile.cyclic-4 new file mode 100644 index 00000000000..419e694720b --- /dev/null +++ b/docker/variants/Dockerfile.cyclic-4 @@ -0,0 +1,21 @@ +# syntax=docker/dockerfile:1 +FROM debian:bookworm-slim + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update \ + && apt-get install -y --no-install-recommends python3 python3-venv python3-pip build-essential git \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY . /app + +RUN python3 -m venv /venv +ENV PATH="/venv/bin:$PATH" + +# Pre-build both wheels, then install them twice so the metadata constantly overwrites itself. +RUN pip install --no-cache-dir --no-deps /app/docker/cyclic_deps/alpha \ + && pip install --no-cache-dir --no-deps /app/docker/cyclic_deps/beta \ + && pip install --no-cache-dir /app/docker/cyclic_deps/alpha \ + && pip install --no-cache-dir -e . + +CMD ["python", "-c", "import beta_cyclic; beta_cyclic.summon_beta()"] diff --git a/docker/variants/Dockerfile.cyclic-5 b/docker/variants/Dockerfile.cyclic-5 new file mode 100644 index 00000000000..e0f444fe1bd --- /dev/null +++ b/docker/variants/Dockerfile.cyclic-5 @@ -0,0 +1,15 @@ +# syntax=docker/dockerfile:1 +FROM python:3.11-slim + +WORKDIR /workspace +COPY . /workspace + +# Drop both packages onto the path in editable mode to guarantee the import cycle is hit at development time. +RUN pip install --no-cache-dir --no-deps -e /workspace/docker/cyclic_deps/alpha \ + && pip install --no-cache-dir --no-deps -e /workspace/docker/cyclic_deps/beta \ + && pip install --no-cache-dir -e . + +# Pretend to help by hinting at the issue in a sitecustomize hook. +RUN printf 'import alpha_cyclic\nalpha_cyclic.make_alpha()\n' > /usr/local/lib/python3.11/site-packages/sitecustomize.py + +CMD ["python", "-m", "pytest", "testing"] diff --git a/docker/variants/Dockerfile.cyclic-6 b/docker/variants/Dockerfile.cyclic-6 new file mode 100644 index 00000000000..232abf06ac6 --- /dev/null +++ b/docker/variants/Dockerfile.cyclic-6 @@ -0,0 +1,20 @@ +# syntax=docker/dockerfile:1 +FROM ubuntu:22.04 + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update \ + && apt-get install -y --no-install-recommends python3 python3-pip python3-venv build-essential git \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /srv/pytest +COPY . /srv/pytest + +RUN python3 -m venv /opt/env +ENV PATH="/opt/env/bin:$PATH" + +# Manufacture a wheelhouse and install everything from there so the resolver keeps chasing its own tail. +RUN python -m pip wheel --no-deps -w /tmp/wheels /srv/pytest/docker/cyclic_deps/alpha /srv/pytest/docker/cyclic_deps/beta \ + && python -m pip install --no-cache-dir --no-deps /tmp/wheels/*.whl \ + && python -m pip install --no-cache-dir -e . + +CMD ["python", "-c", "import alpha_cyclic, beta_cyclic; print(alpha_cyclic.make_alpha())"] diff --git a/docker/variants/Dockerfile.minimal-1 b/docker/variants/Dockerfile.minimal-1 new file mode 100644 index 00000000000..8c09be9c4b0 --- /dev/null +++ b/docker/variants/Dockerfile.minimal-1 @@ -0,0 +1,18 @@ +FROM debian:bookworm-slim + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + python3 \ + python3-venv \ + python3-pip \ + git \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY . /app + +RUN python3 -m pip install --upgrade pip \ + && python3 -m pip install pytest \ + && python3 -m pip install -e . + +CMD ["python3", "-m", "pytest", "testing"] diff --git a/docker/variants/Dockerfile.minimal-2 b/docker/variants/Dockerfile.minimal-2 new file mode 100644 index 00000000000..2411238bf4d --- /dev/null +++ b/docker/variants/Dockerfile.minimal-2 @@ -0,0 +1,16 @@ +FROM ubuntu:24.04 + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + python3 \ + python3-pip \ + curl \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY . /app + +RUN python3 -m pip install pytest \ + && python3 -m pip install -e . + +CMD ["python3", "-m", "pytest", "testing"] diff --git a/docker/variants/Dockerfile.minimal-3 b/docker/variants/Dockerfile.minimal-3 new file mode 100644 index 00000000000..d5878f23cda --- /dev/null +++ b/docker/variants/Dockerfile.minimal-3 @@ -0,0 +1,11 @@ +FROM alpine:3.19 + +RUN apk add --no-cache python3 py3-pip + +WORKDIR /app +COPY . /app + +RUN python3 -m pip install pytest \ + && python3 -m pip install -e . + +CMD ["python3", "-m", "pytest", "testing"] diff --git a/docker/variants/Dockerfile.minimal-4 b/docker/variants/Dockerfile.minimal-4 new file mode 100644 index 00000000000..06592e2cc93 --- /dev/null +++ b/docker/variants/Dockerfile.minimal-4 @@ -0,0 +1,13 @@ +FROM amazonlinux:2023 + +RUN yum update -y \ + && yum install -y python3 python3-pip \ + && yum clean all + +WORKDIR /app +COPY . /app + +RUN python3 -m pip install pytest \ + && python3 -m pip install -e . + +CMD ["python3", "-m", "pytest", "testing"] diff --git a/docker/variants/Dockerfile.minimal-5 b/docker/variants/Dockerfile.minimal-5 new file mode 100644 index 00000000000..dff2c74be65 --- /dev/null +++ b/docker/variants/Dockerfile.minimal-5 @@ -0,0 +1,13 @@ +FROM rockylinux:9 + +RUN dnf -y update \ + && dnf -y install python3 python3-pip \ + && dnf clean all + +WORKDIR /app +COPY . /app + +RUN python3 -m pip install pytest \ + && python3 -m pip install -e . + +CMD ["python3", "-m", "pytest", "testing"] diff --git a/docker/variants/Dockerfile.missing-deps-1 b/docker/variants/Dockerfile.missing-deps-1 new file mode 100644 index 00000000000..7b0abe553eb --- /dev/null +++ b/docker/variants/Dockerfile.missing-deps-1 @@ -0,0 +1,35 @@ +# syntax=docker/dockerfile:1 +FROM python:3.11-slim + +ENV VIRTUAL_ENV=/opt/venv +RUN python -m venv "$VIRTUAL_ENV" +ENV PATH="$VIRTUAL_ENV/bin:$PATH" + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential \ + git \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY . /app + +RUN pip install --upgrade pip setuptools wheel \ + && pip install \ + colorama \ + iniconfig \ + packaging \ + pluggy<2,>=1.5 \ + pygments \ + argcomplete \ + attrs \ + hypothesis \ + requests \ + xmlschema \ + PyYAML \ + pexpect \ + pytest-xdist \ + coverage \ + && pip install -e . + +CMD ["pytest", "testing"] diff --git a/docker/variants/Dockerfile.missing-deps-2 b/docker/variants/Dockerfile.missing-deps-2 new file mode 100644 index 00000000000..beae9416c17 --- /dev/null +++ b/docker/variants/Dockerfile.missing-deps-2 @@ -0,0 +1,26 @@ +# syntax=docker/dockerfile:1 +FROM python:3.11-slim + +ENV VIRTUAL_ENV=/opt/venv +RUN python -m venv "$VIRTUAL_ENV" +ENV PATH="$VIRTUAL_ENV/bin:$PATH" + +RUN apt-get update && apt-get install -y --no-install-recommends git && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY . /app + +RUN pip install --upgrade pip setuptools \ + && pip install \ + iniconfig \ + packaging \ + pluggy<2,>=1.5 \ + pygments \ + argcomplete \ + attrs \ + hypothesis \ + requests \ + coverage \ + && pip install -e . + +CMD ["pytest", "testing"] diff --git a/docker/variants/Dockerfile.missing-deps-3 b/docker/variants/Dockerfile.missing-deps-3 new file mode 100644 index 00000000000..4fb53545a1f --- /dev/null +++ b/docker/variants/Dockerfile.missing-deps-3 @@ -0,0 +1,14 @@ +# syntax=docker/dockerfile:1 +FROM python:3.11-slim + +WORKDIR /app +COPY . /app + +RUN pip install --upgrade pip \ + && pip install \ + packaging \ + pluggy<2,>=1.5 \ + attrs \ + && pip install -e . + +CMD ["pytest", "testing"] diff --git a/docker/variants/Dockerfile.missing-deps-4 b/docker/variants/Dockerfile.missing-deps-4 new file mode 100644 index 00000000000..1ee42730592 --- /dev/null +++ b/docker/variants/Dockerfile.missing-deps-4 @@ -0,0 +1,11 @@ +# syntax=docker/dockerfile:1 +FROM python:3.11-slim + +WORKDIR /app +COPY . /app + +RUN pip install --upgrade pip \ + && pip install pluggy<2,>=1.5 \ + && pip install -e . + +CMD ["pytest", "testing"] diff --git a/docker/variants/Dockerfile.missing-deps-5 b/docker/variants/Dockerfile.missing-deps-5 new file mode 100644 index 00000000000..f8f056d130b --- /dev/null +++ b/docker/variants/Dockerfile.missing-deps-5 @@ -0,0 +1,9 @@ +# syntax=docker/dockerfile:1 +FROM python:3.11-slim + +WORKDIR /app +COPY . /app + +RUN pip install -e . + +CMD ["pytest", "testing"] diff --git a/docker/variants/troubleshooting-guide1.md b/docker/variants/troubleshooting-guide1.md new file mode 100644 index 00000000000..b21459ff122 --- /dev/null +++ b/docker/variants/troubleshooting-guide1.md @@ -0,0 +1,3 @@ +# Troubleshooting Notes (Easy) + +If the container bails immediately, check whether `sitecustomize.py` imported `alpha_cyclic`. Recursion errors usually mean both packages were imported eagerly. diff --git a/docker/variants/troubleshooting-guide2.md b/docker/variants/troubleshooting-guide2.md new file mode 100644 index 00000000000..076bea3c160 --- /dev/null +++ b/docker/variants/troubleshooting-guide2.md @@ -0,0 +1,3 @@ +# Troubleshooting Notes (Medium) + +Use `pip show alpha-cyclic` and `pip show beta-cyclic` to inspect the `Requires` metadata; both insist on each other, so the resolver can never converge without manual intervention. diff --git a/docker/variants/troubleshooting-guide3.md b/docker/variants/troubleshooting-guide3.md new file mode 100644 index 00000000000..1ec361084e8 --- /dev/null +++ b/docker/variants/troubleshooting-guide3.md @@ -0,0 +1,3 @@ +# Troubleshooting Notes (Hard) + +You can temporarily break the cycle by editing `/usr/local/lib/python*/site-packages/alpha_cyclic/core.py` to lazy-import `beta_cyclic` inside `make_alpha`. Doing so lets the interpreter finish initialization without infinite recursion. From 5ee077acb9f0c2a3fb1c90ce936adb284a232b5a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 17:11:12 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docker/cyclic_deps/alpha/pyproject.toml | 12 ++++++++++-- .../cyclic_deps/alpha/src/alpha_cyclic/__init__.py | 3 +++ docker/cyclic_deps/alpha/src/alpha_cyclic/core.py | 2 ++ docker/cyclic_deps/beta/pyproject.toml | 12 ++++++++++-- docker/cyclic_deps/beta/src/beta_cyclic/__init__.py | 3 +++ docker/cyclic_deps/beta/src/beta_cyclic/bridge.py | 2 ++ docker/cyclic_deps/startup_cyclic.py | 3 +++ 7 files changed, 33 insertions(+), 4 deletions(-) diff --git a/docker/cyclic_deps/alpha/pyproject.toml b/docker/cyclic_deps/alpha/pyproject.toml index 302f5f1b4b3..921479d6cff 100644 --- a/docker/cyclic_deps/alpha/pyproject.toml +++ b/docker/cyclic_deps/alpha/pyproject.toml @@ -1,9 +1,17 @@ [build-system] -requires = ["setuptools"] build-backend = "setuptools.build_meta" +requires = [ "setuptools" ] [project] name = "alpha-cyclic" version = "0.0.1" description = "Toy package that depends on beta-cyclic to demonstrate circular imports." -dependencies = ["beta-cyclic"] +classifiers = [ + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", +] +dependencies = [ "beta-cyclic" ] diff --git a/docker/cyclic_deps/alpha/src/alpha_cyclic/__init__.py b/docker/cyclic_deps/alpha/src/alpha_cyclic/__init__.py index ed76af6a7e1..e15af50dfb6 100644 --- a/docker/cyclic_deps/alpha/src/alpha_cyclic/__init__.py +++ b/docker/cyclic_deps/alpha/src/alpha_cyclic/__init__.py @@ -1,3 +1,6 @@ +from __future__ import annotations + from .core import make_alpha + __all__ = ["make_alpha"] diff --git a/docker/cyclic_deps/alpha/src/alpha_cyclic/core.py b/docker/cyclic_deps/alpha/src/alpha_cyclic/core.py index 607eb6d8c7b..5624ff48684 100644 --- a/docker/cyclic_deps/alpha/src/alpha_cyclic/core.py +++ b/docker/cyclic_deps/alpha/src/alpha_cyclic/core.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from beta_cyclic.bridge import summon_beta diff --git a/docker/cyclic_deps/beta/pyproject.toml b/docker/cyclic_deps/beta/pyproject.toml index bd994623d35..703cf16ca22 100644 --- a/docker/cyclic_deps/beta/pyproject.toml +++ b/docker/cyclic_deps/beta/pyproject.toml @@ -1,9 +1,17 @@ [build-system] -requires = ["setuptools"] build-backend = "setuptools.build_meta" +requires = [ "setuptools" ] [project] name = "beta-cyclic" version = "0.0.1" description = "Toy package that depends on alpha-cyclic to create a loop." -dependencies = ["alpha-cyclic"] +classifiers = [ + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", +] +dependencies = [ "alpha-cyclic" ] diff --git a/docker/cyclic_deps/beta/src/beta_cyclic/__init__.py b/docker/cyclic_deps/beta/src/beta_cyclic/__init__.py index aed62a8eacd..78b5f357027 100644 --- a/docker/cyclic_deps/beta/src/beta_cyclic/__init__.py +++ b/docker/cyclic_deps/beta/src/beta_cyclic/__init__.py @@ -1,3 +1,6 @@ +from __future__ import annotations + from .bridge import summon_beta + __all__ = ["summon_beta"] diff --git a/docker/cyclic_deps/beta/src/beta_cyclic/bridge.py b/docker/cyclic_deps/beta/src/beta_cyclic/bridge.py index cac42b2fa2e..5dfdb1d7a72 100644 --- a/docker/cyclic_deps/beta/src/beta_cyclic/bridge.py +++ b/docker/cyclic_deps/beta/src/beta_cyclic/bridge.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from alpha_cyclic.core import make_alpha diff --git a/docker/cyclic_deps/startup_cyclic.py b/docker/cyclic_deps/startup_cyclic.py index bfa3c95e94a..4649118fc85 100644 --- a/docker/cyclic_deps/startup_cyclic.py +++ b/docker/cyclic_deps/startup_cyclic.py @@ -1,7 +1,10 @@ """Startup hook that makes any Python interpreter import the circular packages immediately.""" +from __future__ import annotations + from alpha_cyclic import make_alpha from beta_cyclic import summon_beta + print("alpha", make_alpha()) print("beta", summon_beta())