2828 run-notebook-tests :
2929 required : true
3030 type : string
31+ # Whether THIS matrix entry measures coverage. Callers set it true for exactly
32+ # one job (ubuntu + highest Python, where coverage.py's sysmon core keeps the
33+ # tracer cheap on 3.12+). CI never uploads the report, so measuring it on every
34+ # job is pure overhead; one job preserves a human-readable number in the logs.
35+ run-coverage :
36+ required : false
37+ type : string
38+ default : ' false'
3139
3240env :
3341 SKIP_DEAP : 1
3442 PYGSTI_NO_CUSTOMLM_SIGINT : 1
43+ # Resolve PyTorch (an explicit CI-build test dependency) from the CPU-only wheel index
44+ # instead of pip's default CUDA build. The latter drags in ~2.5 GB of nvidia-* wheels
45+ # that CI never uses. uv honors this for every resolution in the job.
46+ UV_TORCH_BACKEND : cpu
47+ # Use coverage.py's sys.monitoring core (PEP 669) for --cov runs. Python 3.12's
48+ # specializing adaptive interpreter de-optimizes the legacy C trace function,
49+ # which made coverage of call-heavy tests (e.g. the errgenproptools error-generator
50+ # composition tests) ~40x slower on 3.12 than on 3.9 -- a Python-version effect
51+ # previously misread as a numpy-2 regression. sysmon restores near-native speed;
52+ # it falls back gracefully (with a CoverageWarning) on Python < 3.12.
53+ COVERAGE_CORE : sysmon
3554
3655jobs :
3756 build-and-test :
@@ -56,25 +75,39 @@ jobs:
5675 uses : actions/setup-python@v5
5776 with :
5877 python-version : ${{ inputs.python-version }}
59- - name : Cache pip packages
78+ # uv gives fast, parallel installs and CPU-only torch resolution (see env above).
79+ # The astral-sh/setup-uv action is blocked by the org Actions allowlist, so we
80+ # bootstrap uv from PyPI with the stock pip (a `run:` step is not an action) and
81+ # cache its downloads with the GitHub-owned actions/cache.
82+ - name : Set up uv
83+ run : python -m pip install --upgrade pip uv
84+ - name : Cache uv downloads
6085 uses : actions/cache@v4
6186 with :
62- path : ~/.cache/pip
63- key : ${{ runner.os }}-pip-${{ hashFiles('setup.py') }}-${{ hashFiles('**/*requirements.txt') }}
64- - name : Install pip packages
65- run : |
66- python -m pip install --upgrade pip
67- python -m pip install wheel
68- python -m pip install flake8
87+ # Default uv cache dir, listed for each OS; non-matching paths are skipped.
88+ path : |
89+ ~/.cache/uv
90+ ~/Library/Caches/uv
91+ ~\AppData\Local\uv\cache
92+ # Key on the real dependency manifests (deps live in pyproject.toml).
93+ key : ${{ runner.os }}-uv-${{ hashFiles('pyproject.toml', 'setup.py') }}
94+ restore-keys : |
95+ ${{ runner.os }}-uv-
96+ - name : Install build and lint tools
97+ # flake8 for the lint step; setuptools/wheel kept on hand for any dependency that
98+ # still imports pkg_resources at runtime.
99+ run : uv pip install --system setuptools wheel flake8
69100 - name : Install package (Cython)
70101 if : ${{ inputs.use-cython == 'true' }}
102+ # The PEP 660 editable install compiles the Cython extensions in-place via build
103+ # isolation, so a separate `setup.py build_ext --inplace` is redundant (verified:
104+ # the editable install alone yields importable .so for all 19 extensions).
71105 run : |
72- python -m pip install -e .[testing]
73- python setup.py build_ext --inplace
106+ uv pip install --system -e .[testing,pytorch]
74107 - name : Install package (No Cython, Linux only)
75108 if : ${{ inputs.use-cython != 'true' && inputs.os == 'ubuntu-latest' }}
76109 run : |
77- PYGSTI_CYTHON_SKIP=1 python -m pip install -e .[testing_no_cython]
110+ PYGSTI_CYTHON_SKIP=1 uv pip install --system - e .[testing_no_cython,pytorch ]
78111 - name : Lint with flake8 (Linux only)
79112 if : ${{ inputs.os == 'ubuntu-latest'}}
80113 run : |
@@ -84,25 +117,42 @@ jobs:
84117 flake8 . --exit-zero --statistics
85118 - name : Run unit tests
86119 if : ${{ inputs.run-unit-tests == 'true' }}
120+ # bash on every runner (Git Bash on Windows) so $COV_FLAG expands portably.
121+ shell : bash
122+ env :
123+ COV_FLAG : ${{ inputs.run-coverage == 'true' && '--cov=pygsti' || '' }}
87124 run : |
88125 python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)"
89- python -m pytest -n auto --dist loadscope --cov=pygsti --durations=25 test/unit
126+ python -m pytest -n auto --dist loadscope $COV_FLAG --durations=25 test/unit
90127 - name : Run workflow tests
91128 if : ${{ inputs.run-integration-tests == 'true' }}
129+ shell : bash
130+ env :
131+ COV_FLAG : ${{ inputs.run-coverage == 'true' && '--cov=pygsti' || '' }}
92132 run : |
93133 python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)"
94- python -m pytest -n auto --dist loadscope --cov=pygsti test/integration
134+ python -m pytest -n auto --dist loadscope $COV_FLAG test/integration
95135 - name : Run test_packages
96136 if : ${{ inputs.run-extra-tests == 'true' }}
97137 run : |
98138 python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)"
99139 python -m pytest -v -n auto --dist loadscope --ignore=test/test_packages/notebooks --durations=25 test/test_packages
100140 - name : Run notebook regression
101- if : ${{ inputs.run-notebook-tests == 'true' }}
141+ # Linux-only: this step compiles CHP with gcc and writes it to /usr/local/bin,
142+ # so it cannot run on the Windows/macOS runners even if a caller requests it.
143+ if : ${{ inputs.run-notebook-tests == 'true' && inputs.os == 'ubuntu-latest' }}
102144 run : |
103- # If we are running notebooks, we also need to download and compile CHP
104- curl -o ./jupyter_notebooks/Tutorials/algorithms/advanced/chp.c https://www.scottaaronson.com/chp/chp.c
105- gcc -o ./jupyter_notebooks/Tutorials/algorithms/advanced/chp ./jupyter_notebooks/Tutorials/algorithms/advanced/chp.c
145+ # Tutorials live as MyST Markdown under docs/markdown/; jupytext pairs each
146+ # .md with an .ipynb sitting NEXT TO IT in the same directory (see
147+ # docs/jupytext.toml), so the materialized notebooks land back under
148+ # docs/markdown/ for nbval to consume.
149+ uv pip install --system -e .[docs]
150+ (cd docs && jupytext --sync 'markdown/**/*.md')
151+
152+ # Download and compile CHP for the Clifford-simulation notebook;
153+ # put the binary on PATH so pygsti.evotypes.chp.chpexe = 'chp' resolves.
154+ curl -o /tmp/chp.c https://www.scottaaronson.com/chp/chp.c
155+ gcc -o /usr/local/bin/chp /tmp/chp.c
106156
107157 python -Ic "import pygsti; print(pygsti.__version__); print(pygsti.__path__)"
108- python -m pytest -n auto --nbval-lax --dist loadscope --nbval-current-env --durations=25 jupyter_notebooks
158+ python -m pytest -n auto --nbval-lax --dist loadscope --nbval-current-env --durations=25 docs/markdown
0 commit comments