22from __future__ import annotations
33
44import os
5+ import re
56import json
67import platform
78import subprocess
89from pathlib import Path
910import nox
1011
11- # Speed up reruns; reuse envs when deps unchanged
12- nox . options . reuse_existing_virtualenvs = False
12+ nox . options . reuse_existing_virtualenvs = True
13+ pyproject = nox . project . load_toml ()
1314
15+ PY_VERSIONS = nox .project .python_versions (pyproject )
16+ try :
17+ txt = Path ('.python-version' ).read_text (encoding = "utf-8" ).strip ().splitlines ()[0 ]
18+ m = re .search (r"(\d+)\.(\d+)" , txt ) # grab major.minor; ignore patch/suffix
19+ SYS_PYTHON = f"{ m .group (1 )} .{ m .group (2 )} " if m else PY_VERSIONS [- 1 ]
20+ except FileNotFoundError as e :
21+ SYS_PYTHON = PY_VERSIONS [- 1 ]
1422
15- PY_VERSIONS = [
16- # "3.10",
17- # "3.11",
18- # "3.12",
19- "3.13" ,
20- ]
21- PY_TARGET = PY_VERSIONS [- 1 ]
22-
23+ PROJECT_NAME = pyproject ["project" ]["name" ]
2324PROJECT_NAME_PATH = Path (__file__ ).parent .resolve ()
24- ARTIFACTS = PROJECT_NAME_PATH / ".nox" / "_artifacts"
25- WHEEL_DIR = ARTIFACTS / "wheels"
26- SDIST_DIR = ARTIFACTS / "sdist"
27- WHEELHOUSE_DIR = ARTIFACTS / "wheelhouse"
28- DOCDIST_DIR = ARTIFACTS / "docs"
25+ _ARTIFACTS = PROJECT_NAME_PATH / ".nox" / "_artifacts"
2926
30- pyproject = nox .project .load_toml ("pyproject.toml" )
31- PROJECT_NAME = pyproject ["project" ]["name" ]
32- CONDA_ENV_BUILD_COMPILERS = pyproject ["tool" ][PROJECT_NAME ].get ("conda" , [])
27+ WHEEL_DIR = _ARTIFACTS / "wheels"
28+ SDIST_DIR = _ARTIFACTS / "sdist"
29+ WHEELHOUSE_DIR = _ARTIFACTS / "wheelhouse"
30+ DOCDIST_DIR = _ARTIFACTS / "docs"
3331
3432REPAIR_TOOLS : dict [str , list [str ]] = {
3533 "linux" : ["auditwheel" ],
3634 "darwin" : ["delocate" ],
3735 "windows" : ["delvewheel" ],
3836}
3937
38+ SDIST_DIR .mkdir (parents = True , exist_ok = True )
4039WHEEL_DIR .mkdir (parents = True , exist_ok = True )
4140WHEELHOUSE_DIR .mkdir (parents = True , exist_ok = True )
4241DOCDIST_DIR .mkdir (parents = True , exist_ok = True )
@@ -49,15 +48,6 @@ def _darwin_sdk_env() -> dict[str, str]:
4948 # Prefer already-set values; otherwise best-effort defaults
5049 env = {}
5150 env .setdefault ("MACOSX_DEPLOYMENT_TARGET" , os .environ .get ("MACOSX_DEPLOYMENT_TARGET" , "11.0" ))
52- # SDKPROJECT_NAME_PATH may be needed for clang/gfortran during Meson sanity checks
53- # if "SDKPROJECT_NAME_PATH" not in os.environ:
54- # try:
55- # import subprocess
56- # sdk = subprocess.check_output(["xcrun", "--show-sdk-path"], text=True).strip()
57- # env["SDKPROJECT_NAME_PATH"] = sdk
58- # except Exception:
59- # pass
60- # return env
6151 try :
6252 sdk = subprocess .check_output (
6353 ["xcrun" , "--sdk" , "macosx" , "--show-sdk-path" ],
@@ -77,7 +67,7 @@ def _darwin_sdk_env() -> dict[str, str]:
7767def _build_env (session : nox .Session ) -> Path :
7868 """Build a wheel into ./dist and return its path."""
7969 session .conda_install (
80- * CONDA_ENV_BUILD_COMPILERS ,
70+ * pyproject [ "tool" ][ PROJECT_NAME ]. get ( "conda" , []) ,
8171 channel = "conda-forge"
8272 )
8373 session .env .update (_darwin_sdk_env ())
@@ -112,7 +102,8 @@ def build(session: nox.Session) -> None:
112102 external = False
113103 )
114104
115- @nox .session (python = PY_TARGET )
105+
106+ @nox .session (python = SYS_PYTHON )
116107def repair (session : nox .Session ) -> None :
117108 """Repair wheels in dist/ into wheelhouse/ using the OS-specific tool."""
118109 platform_id = platform .system ().lower ()
@@ -141,8 +132,6 @@ def test(session: nox.Session) -> None:
141132 """Build the wheel (with compilers), install it, then run pytest from a temp dir."""
142133 # Build wheel
143134 _dist_env (session )
144-
145- # Runtime/test deps
146135 session .install (* pyproject ["project" ].get ("optional-dependencies" , {}).get ("test" , []))
147136
148137 tmp = session .create_tmp ()
@@ -151,7 +140,8 @@ def test(session: nox.Session) -> None:
151140 # Pytest
152141 session .run ("pytest" , PROJECT_NAME_PATH .as_posix ())
153142
154- @nox .session (venv_backend = 'conda|mamba|micromamba' , python = PY_TARGET )
143+
144+ @nox .session (venv_backend = 'conda|mamba|micromamba' , python = SYS_PYTHON )
155145def sdist (session : nox .Session ) -> None :
156146 """Build the package wheel (with compilers)."""
157147 _build_env (session )
@@ -166,22 +156,25 @@ def sdist(session: nox.Session) -> None:
166156 external = False
167157 )
168158
169- @nox .session (python = PY_TARGET )
159+
160+ @nox .session (python = SYS_PYTHON )
170161def types (session : nox .Session ) -> None :
171162 """Mypy type checking (analyzes source tree)."""
172163 session .install (* pyproject ["project" ].get ("optional-dependencies" , {}).get ("types" , []))
173164
174165 session .run ("mypy" )
175166
176- @nox .session (python = PY_TARGET )
167+
168+ @nox .session (python = SYS_PYTHON )
177169def lint (session : nox .Session ) -> None :
178170 """Ruff lint + format check."""
179171 session .install (* pyproject ["project" ].get ("optional-dependencies" , {}).get ("lint" , []))
180172
181173 session .run ("ruff" , "check" , PROJECT_NAME )
182174 session .run ("ruff" , "format" , "--check" , PROJECT_NAME )
183175
184- @nox .session (python = PY_TARGET )
176+
177+ @nox .session (python = SYS_PYTHON )
185178def docs (session : nox .Session ) -> None :
186179 """Build Sphinx docs against the installed wheel."""
187180 _dist_env (session )
@@ -207,3 +200,40 @@ def docs(session: nox.Session) -> None:
207200 out_dir = DOCDIST_DIR / f"html-{ tag .get ('tags' , ['none' ])[0 ]} "
208201 src_dir = PROJECT_NAME_PATH / "docs" / "source"
209202 session .run ("sphinx-build" , src_dir .as_posix (), out_dir .as_posix (), * args )
203+
204+
205+ @nox .session (python = SYS_PYTHON )
206+ def build_matrix (session : nox .Session ) -> None :
207+ """Build, repair, and test in order (single entrypoint)."""
208+ session .notify ("sdist" )
209+ session .notify ("build" )
210+ session .notify ("repair" )
211+ session .notify ("test" )
212+
213+
214+ @nox .session (python = SYS_PYTHON )
215+ def build_target (session : nox .Session ) -> None :
216+ """Build, repair, and test in order (single entrypoint)."""
217+ session .notify ("sdist" )
218+ session .notify (f"build-{ session .python } " )
219+ session .notify ("repair" )
220+ session .notify (f"test-{ session .python } " )
221+
222+
223+ @nox .session (python = SYS_PYTHON )
224+ def build_docs (session : nox .Session ) -> None :
225+ """Build, repair, and test in order (single entrypoint)."""
226+ session .notify ("build_target" )
227+ session .notify ("docs" )
228+
229+
230+ @nox .session (python = SYS_PYTHON )
231+ def build_qa (session : nox .Session ) -> None :
232+ """Build, repair, and test in order (single entrypoint)."""
233+ session .notify ("build_target" )
234+ session .notify (f"types" )
235+ session .notify (f"lint" )
236+
237+
238+ if __name__ == "__main__" :
239+ nox .main ()
0 commit comments