Conversation
See scientific-python/cookie#348. Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* Replaced `NotImplementedError` with `NotImplemented` Signed-off-by: fazledyn-or <ataf@openrefactory.com> * Fix tests for wntrblm#749 --------- Signed-off-by: fazledyn-or <ataf@openrefactory.com> Co-authored-by: Edgar Ramírez Mondragón <edgarrm358@gmail.com>
* feat: rename run_always to run_install Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * Update docs/usage.rst --------- Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* feat: add envdir and report completions * feat: add python completions * feat: add tag completion * feat: add keywords non-completion This will actually only prevent completions with bash if the completion was registered using `register-python-argcomplete --complete-arguments -- nox` (i.e. with _all_ fallback completions disabled, not just the readline ones). But it does not hurt if registered without doing so. * refactor: return Iterables from completers kislyuk/argcomplete#422 * style: simplify completer functions Co-authored-by: Stanislav Filin <stasfilin@hotmail.com> * fix: return type hint for completer callables (`Iterable[str]`) kislyuk/argcomplete#422 * chore: appease mypy in completers code * test: add python and tag completer tests --------- Co-authored-by: Stanislav Filin <stasfilin@hotmail.com>
Co-authored-by: Christopher Wilcox <crwilcox@google.com>
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* ci: fix coverage combine for different OS's Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * tests: remove some coverage ignore pragmas Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * ci: manually ignore broken path on Windows Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * ci: try to fix paths again Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * WIP: add some debugging info Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * WIP: fixup Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * WIP: try non-editable install Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * ci: use module vs. path Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * ci: require proper version of coverage Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * ci: drop relative paths Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * ci: editable install with non-rel paths Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * ci: clean up changes Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * ci: try adding sources for coverage Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * ci: try manually fixing the coverage files on Windows Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * ci: try omit instead of changing the sqlite file Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * revert: previous commit --------- Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* ci: speed up runs Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * ci: only run tox-to-nox tests twice Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> --------- Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* feat: support for reuse_venv option * typing: adding Literal for reuse_venv choices * chore: ruff-format * chore: codespell * chore: move `generate_noxfile_options` fixture to `conftest.py` * chore: ruff-format * chore: fix lints Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * docs: clarify reuse_existing_venv function decision matrix * chore: remove ``# pragma: no cover` due to recent main branch changes * docs: call out that --reuse-existing-virtualenvs/--no-reuse-existing-virtualenvs is alias to --reuse-venv=yes|no in usage.rst * docs: small update to config.rst --------- Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* fix: rebuild env if making an incompatible change Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * tests: restore windows skip * fix: support conda switching properly Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * fix: make stale Python check opt-in again Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * tests: increase coverage of check again Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * refactor: unify function Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * Update tests/test_virtualenv.py Co-authored-by: Claudio Jolowicz <cjolowicz@gmail.com> --------- Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> Co-authored-by: Claudio Jolowicz <cjolowicz@gmail.com>
* refactor: pull out env selection to dict Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * feat: support fallback for nox/mamba/conda Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> --------- Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* feat: add venv_backend property Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * tests: add a couple of checks Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * docs: update for venv_backend Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * tests: add one more test for coverage Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> * Update test_virtualenv.py * Update test_virtualenv.py * Update test_virtualenv.py --------- Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* chore(ci): test action on macos-14 * temp: python 3.8 & 3.9 missing on macos-14 * temp: don't use pipx * fix: use local python and try step shell * Update action.yml * Update action.yml * Apply suggestions from code review --------- Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
…rblm#1104) Accessing session.cache_dir before the environment directory exists (for example in a venv_backend="none" session on a clean checkout) raised FileNotFoundError because the .cache directory was created without parents=True. Create the parent directories as needed. Assisted-by: ClaudeCode:claude-fable-5
- _find_pbs_python now finds exact-version installs: pbs_installer with version_dir=True creates directories named exactly "cpython@3.13.2", but the lookup only matched names with a trailing dot, so full X.Y.Z requests were never found and re-downloaded on every run. - pbs_install_python no longer raises AttributeError when the optional implementation group is absent (e.g. "3.12" or ""); a bare version defaults to CPython, and a missing version takes the normal "not a valid version" warning path. - The Windows py-launcher 32-bit suffix regex matched "X.Y-3" as well as "X.Y-32" due to a stray "?"; only a literal "-32" is accepted now. Assisted-by: ClaudeCode:claude-fable-5
…ir (wntrblm#1108) A session name with no ASCII word characters (e.g. "测试") was reduced to the empty string by NFKD normalization, ascii-ignore encoding, and the regex substitutions in _normalize_path. The resulting virtualenv location was the envdir itself (e.g. .nox/), so two such sessions silently shared one environment, and VirtualEnv._clean_location() would shutil.rmtree() the entire envdir, deleting every other session's venv. When the normalized name comes out empty, fall back to the same sha1 hash used for over-long names, hashing the original (UTF-8) name so the result is a stable, unique subdirectory of envdir. Assisted-by: ClaudeCode:claude-fable-5
…ist (wntrblm#1109) A noxfile with a zero-parameter parametrize, e.g. @nox.session @nox.parametrize("x", []) def empty(session, x): ... made every nox invocation (including `nox -l`) fail with "Error while resolving session dependencies." The placeholder session created for an empty parametrize has no signatures, so it never entered the dependency graph built from `all_sessions_by_signature`, and the resolver raised a raw KeyError for the queued session. Include any queued sessions missing from the dependency graph so that the placeholder is resolved normally again: it shows up in listings and reports as skipped ("This session had no parameters available.") while other sessions run, matching the behavior of nox 2024.4.15. Assisted-by: ClaudeCode:claude-fable-5
…back (wntrblm#1110) Two fixes for PEP 723 script mode in run_script_mode/_main: - Resolve pip via shutil.which() against the script environment's PATH before invoking it. On Windows, CreateProcess searches the parent process's PATH rather than the child env's, so the bare "pip" command could resolve to an outer pip (installing script dependencies into the wrong environment) or fail entirely. This matches the existing pattern used to locate the nox executable. - Make --download-python (and NOX_DOWNLOAD_PYTHON) work as a fallback in script mode. The TOML lookup used a truthy default of "auto", which made the 'or args.download_python' fallback unreachable. Precedence is now: NOX_SCRIPT_DOWNLOAD_PYTHON > tool.nox.script-download-python > --download-python/NOX_DOWNLOAD_PYTHON > "auto". Assisted-by: ClaudeCode:claude-fable-5
…covery, and metadata reads (wntrblm#1113) * perf: cache session-name normalization in manifest filtering _normalize_arg runs ast.parse + ast.dump (~10us) for every (specified name x queued session x signature) pair, plus the missing-session check. Cache it with functools.cache (pure function of a string) and hoist the needle normalization out of the signature loop. A 600-session noxfile with 20 -s selections drops from ~400ms to ~10ms in filter_by_name. Assisted-by: ClaudeCode:claude-fable-5 * perf: detect uv lazily instead of at import time find_uv() spawns 'uv self version' (two subprocesses for uv<0.7) at module import, so every nox invocation -- including --version and --list, and every 'import nox' in a noxfile -- paid that cost even when uv was never used. HAS_UV, UV, UV_VERSION, and OPTIONAL_VENVS (which depends on HAS_UV) are now served by a module-level __getattr__ (PEP 562) and find_uv() is cached. allowed_globals becomes a property so the uv path is read at use time rather than captured at class creation; internal readers go through the module attributes so monkeypatching them in tests (and noxfiles) keeps working. A test asserts that importing nox.virtualenv spawns no subprocess. Assisted-by: ClaudeCode:claude-fable-5 * perf: cache interpreter discovery across sessions Each session constructs a fresh VirtualEnv, so the per-instance _resolved cache never helps across sessions: N sessions on the same interpreter repeat the PATH lookup, and on Windows a PATH miss spawns 'py -X.Y -c ...' (~50-100 ms) per session. Cache the module-level _find_python with functools.cache instead. Tests clear the cache around each test since they monkeypatch PATH and _PLATFORM. Assisted-by: ClaudeCode:claude-fable-5 * perf: avoid re-reading metadata for repeated requirements get_dependencies() called importlib.metadata.metadata() (a dist-info scan) on every visit and re-walked shared dependencies reachable through multiple extras; this runs at startup whenever the noxfile has a PEP 723 script block. Track visited (canonical name, extras) pairs so each package's metadata is read and expanded once. Repeated requirements are still yielded so every specifier is checked, and the seen-set also terminates dependency-graph cycles, which previously recursed forever. Assisted-by: ClaudeCode:claude-fable-5 * test: keep uv detection out of mocked shutil.which windows The autouse fixture cleared find_uv's cache around every test, so the first lazy HAS_UV access inside a test that mocks shutil.which or subprocess.run re-ran uv detection against the mocks, leaking a stray which('uv') call into assert_called_once_with checks (order-dependent under xdist). Warm find_uv() once per session/worker before any mocking instead, and keep per-test cache clearing only for _find_python. test_find_uv now calls find_uv.__wrapped__ so it still exercises the real detection logic under its mocks without touching the warmed cache. Assisted-by: ClaudeCode:claude-fable-5
* fix: remove duplicated --download-python flag string in --help
The flag string was passed twice to the Option, rendering as
"--download-python, --download-python" in the help output.
Assisted-by: ClaudeCode:claude-fable-5
* refactor: deduplicate repeated logic
- virtualenv: factor the duplicated uv/python-build-standalone install
blocks in VirtualEnv._resolved_interpreter into a private
_install_python helper; the match now only needs the download_python
value.
- logger: factor the identical OUTPUT-passthrough format() bodies of
NoxFormatter and NoxColoredFormatter into a mixin, and register the
custom level names once at module import next to the level constants
instead of on every logger instantiation (addLevelName is idempotent).
- registry: compute the session name once instead of twice.
- manifest: __contains__/__getitem__ iterate with itertools.chain
instead of building throwaway concatenated lists, and __contains__
shares the same match expression via any().
- _parametrize: build Param.__str__ with a single generator expression.
Assisted-by: ClaudeCode:claude-fable-5
* refactor: assorted micro-simplifications
- virtualenv: CondaEnv.is_offline() checked `gethostbyname(...) is
None`, but gethostbyname returns a string or raises, so the result
is always False; return False directly. Drop a redundant f-string
around an existing string in locate_using_path_and_version, and use
list(venv_params) instead of `venv_params or []` so the stored
params are always an owned list.
- command/_option_set: drop runtime collections.abc imports duplicated
by TYPE_CHECKING imports (annotation-only names under
`from __future__ import annotations`).
- sessions: load_toml() always returns a dict, so drop the `or {}`
fallback; use the codebase's usual startswith("win") platform check.
- _resolver: remove a no-op trailing `else: return` and an unneeded
`nonlocal`, and replace the root filter's redundant
`hash(node) == hash(root)` clause (equality already implies equal
hashes) with a plain generator expression.
- manifest: truthiness check instead of len() in __next__.
- tox_to_nox: collapse the skip_install/use_develop if/else into a
single boolean expression.
- project: list comprehension instead of list(filter(lambda ...)).
- tests: give the SessionRunner mock func a real venv_params list to
match the Func API.
Assisted-by: ClaudeCode:claude-fable-5
* refactor: remove Python 2 leftovers and an unused alias
- sessions: _normalize_path only ever receives str (the bytes decode
branch was a Python 2 leftover); narrow the annotation and drop the
branch, removing the corresponding bytes case from its unit test.
- manifest: remove Manifest.next(), a Python 2-style alias for
__next__ that was only exercised by its own test (not referenced in
docs); the test now uses the next() builtin.
- _decorators: fold the one-method FunctionDecorator base class into
Func, its only subclass anywhere, and drop the now-unneeded cast.
Assisted-by: ClaudeCode:claude-fable-5
* fix: use Iterator instead of undefined Generator in get_dependencies
The inner expand() helper was annotated with Generator, which is not
imported (only Iterator is). Use Iterator to match the enclosing
get_dependencies signature and the existing import.
Assisted-by: ClaudeCode:claude-opus-4.8
…ntrblm#1116) * fix: prevent coverage data corruption from artifact name collisions The macos-latest (arm64) and macos-15-intel (x86_64) jobs both run Python 3.12 and both produced `.coverage.pypi.darwin.3.12`. With `merge-multiple: true`, download-artifact extracts artifacts concurrently into one directory, so two jobs writing the same path could tear the SQLite data file ("database disk image is malformed") in the cover job, or silently clobber one job's data. Add `platform.machine()` to the coverage filenames so the architectures no longer collide, and drop `merge-multiple` so each artifact lands in its own `coverage-*` subdirectory; the cover session now combines those subdirs. Assisted-by: ClaudeCode:claude-opus-4.8 Signed-off-by: Henry Schreiner <henryfs@princeton.edu> * Apply suggestion from @henryiii --------- Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
uv can't inspect the MSYS2/MinGW interpreter (it reports an unknown operating system like `mingw_x86_64_ucrt_gnu`), so passing `-p sys.executable` made `uv venv` fail in script mode. Skip `-p` on MinGW when no interpreter is requested and let uv pick the default, which works. uv also builds a Windows-style venv (`Scripts`/`python.exe`) even under MinGW, unlike the native interpreter and virtualenv/venv which use a POSIX layout. A new `_windows_layout` property captures this so `bin_paths` and the reuse check pick the right directory per backend. Assisted-by: ClaudeCode:claude-opus-4.8
…windows (wntrblm#1120) * ci: reduce the number of times we contact conda-forge servers Assisted-by: ClaudeCode:claude-opus-4.8 Signed-off-by: Henry Schreiner <henryfs@princeton.edu> * docs: drop not useful comment Signed-off-by: Henry Schreiner <henryfs@princeton.edu> --------- Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
* chore: update dependabot (1M, pre-commit, 7days) Signed-off-by: Henry Schreiner <henryfs@princeton.edu> * chore: bump pre-commit Signed-off-by: Henry Schreiner <henryfs@princeton.edu> --------- Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
…1121) Bumps the pre-commit group with 1 update: dependency-groups. Updates `dependency-groups` from 1.2 to 1.3.1 --- updated-dependencies: - dependency-name: dependency-groups dependency-version: 1.3.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: pre-commit ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
Exercise the MinGW-specific code paths in nox.virtualenv (the _IS_MINGW branches) on a real MSYS2 runner. Until now those paths were only covered by mocked unit tests. The job is continue-on-error / non-blocking until it proves stable, and feeds its coverage into the cover job. Assisted-by: ClaudeCode:claude-opus-4.8
Assisted-by: ClaudeCode:claude-opus-4.8
uv ships no MinGW wheel and fails to build from source there; the uv tests already skip via @has_uv when the command is absent. Assisted-by: ClaudeCode:claude-opus-4.8
Assisted-by: ClaudeCode:claude-opus-4.8
|
🤖 AI text below 🤖 MSYS2 job is now standing up and running the full suiteStatus after toolchain fixes: 702 passed, 8 failed, 28 skipped under genuine MinGW Python 3.14 ( A. Tests that assume Windows ≠ MinGW (real portability gaps — these never actually ran on a MinGW host before):
B. uv/interpreter-dependent tests missing a guard (uv has no MinGW wheel, so it is not installed):
The job is |
…MinGW Assisted-by: ClaudeCode:claude-opus-4.8
Assisted-by: ClaudeCode:claude-opus-4.8
Assisted-by: ClaudeCode:claude-opus-4.8
uv on PATH made nox build the session venv with uv, which silently used a non-MinGW interpreter (_IS_MINGW=False) and hid the MinGW code paths. Force virtualenv for the session; uv stays available for the uv-backend tests. Assisted-by: ClaudeCode:claude-opus-4.8
|
🤖 AI text below 🤖 Now genuinely exercising wntrblm#1117 — down to 3 real test bugsMerged wntrblm#1117 into this branch and got a real uv CLI onto the runner. Key learnings:
Result: 723 passed, 15 skipped (was 28), 3 failed. The 15→ drop means the uv-under-MinGW tests now run for real and pass — wntrblm#1117 has real-host coverage for the first time. Having uv present also cleared all of the earlier bucket-B Remaining 3 failures are all bucket A — tests that assume Windows ⇒
Proposed fix: pin the intended scenario in each ( |
On a real MSYS2/MinGW host sys.platform is win32 but the native venv uses a POSIX bin/ layout, so the Windows-layout assertions must exclude MinGW. Assisted-by: ClaudeCode:claude-opus-4.8
Assisted-by: ClaudeCode:claude-opus-4.8
Assisted-by: ClaudeCode:claude-opus-4.8
|
🤖 AI text below 🤖 ✅ Fully greenLatest run: all jobs pass, including the The MSYS2/MINGW64 job now runs the full suite under genuine MinGW Python 3.14 ( Three test fixes were needed — all genuine MinGW-portability bugs this run exposed:
The job is still Open decisions
|
|
Superseded by wntrblm#1122 (same branch, opened against upstream). |
🤖 AI text below 🤖
Adds an experimental, non-blocking (
continue-on-error: true) CI job that runs the test suite under a real MSYS2 MINGW64 Python.Why
nox/virtualenv.pyhas MinGW-specific logic gated on_IS_MINGW(theLibrary/mingw-w64/binpath handling, bin-dir / launcher branches) added in wntrblm#901, but it is currently only covered by mocked unit tests (@mock.patch("nox.virtualenv._IS_MINGW", new=True)). Nothing ever runs it with_IS_MINGWactuallyTrue. This job exercises that path on a genuine MSYS2 runner and feeds its coverage into thecoverjob.Notes / expected rough edges
virtualenvbackend (uv has no MinGW build;default_venv_backend = "uv|virtualenv"falls through automatically).filterwarnings = ["error"]may surface MinGW-only warnings; some extras/tests may not survive the first run — that is what this trial is for.