Repository: wntrblm/nox
Pull request #929 (2025-02-10 23:48:19)

tests: make skips a bit smarter
See #926.



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 23850f7..a370680 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -95,7 +95,7 @@ Documentation:
 * Added warning about uv and local packages by @henryiii in https://github.com/wntrblm/nox/pull/830
 * Fixed contribution guidelines by @Wurstnase in https://github.com/wntrblm/nox/pull/850
 * Fixed typos by @ember91 in https://github.com/wntrblm/nox/pull/839
-* Fixed typoss in cookbook by @hmd101 in https://github.com/wntrblm/nox/pull/837
+* Fixed typos in cookbook by @hmd101 in https://github.com/wntrblm/nox/pull/837
 * Added missing cookbook recipe snippet imports by @KasperZutterman in https://github.com/wntrblm/nox/pull/853
 * Cleaned up `dev` recipe by @henryiii in https://github.com/wntrblm/nox/pull/862
 * Added note about `uv reinstall` by @henryiii in https://github.com/wntrblm/nox/pull/863
diff --git a/nox/_option_set.py b/nox/_option_set.py
index 873a701..74d91a5 100644
--- a/nox/_option_set.py
+++ b/nox/_option_set.py
@@ -21,6 +21,7 @@ from __future__ import annotations
 import argparse
 import collections
 import functools
+import os
 from argparse import ArgumentError, ArgumentParser, Namespace
 from collections.abc import Callable, Iterable
 from typing import TYPE_CHECKING, Any, Literal
@@ -47,6 +48,7 @@ def __dir__() -> list[str]:
 
 
 av_opt_str = av.optional(av.instance_of(str))
+av_opt_path = av.optional(av.or_(av.instance_of(str), av.instance_of(os.PathLike)))
 av_opt_list_str = av.optional(
     av.deep_iterable(
         member_validator=av.instance_of(str),
@@ -59,7 +61,7 @@ av_bool = av.instance_of(bool)
 @attrs.define(slots=True, kw_only=True)
 class NoxOptions:
     default_venv_backend: None | str = attrs.field(validator=av_opt_str)
-    envdir: None | str = attrs.field(validator=av_opt_str)
+    envdir: None | str | os.PathLike[str] = attrs.field(validator=av_opt_path)
     error_on_external_run: bool = attrs.field(validator=av_bool)
     error_on_missing_interpreters: bool = attrs.field(validator=av_bool)
     force_venv_backend: None | str = attrs.field(validator=av_opt_str)
diff --git a/nox/_options.py b/nox/_options.py
index adb0e2a..7ce89ec 100644
--- a/nox/_options.py
+++ b/nox/_options.py
@@ -157,7 +157,7 @@ def _envdir_merge_func(
         noxfile_Args (NoxOptions): The options specified in the
             Noxfile.
     """
-    return command_args.envdir or noxfile_args.envdir or ".nox"
+    return os.fspath(command_args.envdir or noxfile_args.envdir or ".nox")
 
 
 def _reuse_venv_merge_func(


Test patch:
diff --git a/tests/test__option_set.py b/tests/test__option_set.py
index 3035d84..8d21a02 100644
--- a/tests/test__option_set.py
+++ b/tests/test__option_set.py
@@ -154,3 +154,6 @@ class TestOptionSet:
         options.sessions = ("testytest",)
         with pytest.raises(ValueError):  # noqa: PT011
             options.sessions = "testytest"
+
+        options.envdir = "envdir"
+        options.envdir = Path("envdir")
diff --git a/tests/test_main.py b/tests/test_main.py
index 16258f4..8334167 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -16,6 +16,7 @@ from __future__ import annotations
 
 import contextlib
 import os
+import shutil
 import subprocess
 import sys
 from importlib import metadata
@@ -527,12 +528,18 @@ def test_main_with_bad_session_names(
     assert session in stderr
 
 
+py39py310 = pytest.mark.skipif(
+    shutil.which("python3.10") is None or shutil.which("python3.9") is None,
+    reason="Python 3.9 and 3.10 required",
+)
+
+
 @pytest.mark.parametrize(
     ("sessions", "expected_order"),
     [
         (("g", "a", "d"), ("b", "c", "h", "g", "a", "e", "d")),
-        (("m",), ("k-3.9", "k-3.10", "m")),
-        (("n",), ("k-3.10", "n")),
+        pytest.param(("m",), ("k-3.9", "k-3.10", "m"), marks=py39py310),
+        pytest.param(("n",), ("k-3.10", "n"), marks=py39py310),
         (("v",), ("u(django='1.9')", "u(django='2.0')", "v")),
         (("w",), ("u(django='1.9')", "u(django='2.0')", "w")),
     ],
@@ -1022,7 +1029,8 @@ def test_symlink_sym_not(monkeypatch: pytest.MonkeyPatch) -> None:
     assert res.returncode == 1
 
 
-def test_noxfile_script_mode() -> None:
+def test_noxfile_script_mode(monkeypatch: pytest.MonkeyPatch) -> None:
+    monkeypatch.delenv("NOX_SCRIPT_MODE", raising=False)
     job = subprocess.run(
         [
             sys.executable,
@@ -1044,9 +1052,8 @@ def test_noxfile_script_mode() -> None:
     assert "hello_world" in job.stdout
 
 
-def test_noxfile_no_script_mode() -> None:
-    env = os.environ.copy()
-    env["NOX_SCRIPT_MODE"] = "none"
+def test_noxfile_no_script_mode(monkeypatch: pytest.MonkeyPatch) -> None:
+    monkeypatch.setenv("NOX_SCRIPT_MODE", "none")
     job = subprocess.run(
         [
             sys.executable,
@@ -1057,7 +1064,6 @@ def test_noxfile_no_script_mode() -> None:
             "-s",
             "example",
         ],
-        env=env,
         check=False,
         capture_output=True,
         text=True,
diff --git a/tests/test_tox_to_nox.py b/tests/test_tox_to_nox.py
index 1775146..6a3498c 100644
--- a/tests/test_tox_to_nox.py
+++ b/tests/test_tox_to_nox.py
@@ -15,6 +15,7 @@
 from __future__ import annotations
 
 import os
+import shutil
 import sys
 import textwrap
 from pathlib import Path
@@ -22,11 +23,14 @@ from typing import TYPE_CHECKING
 
 import pytest
 
+# Jinja2 might be missing
+tox_to_nox = pytest.importorskip("nox.tox_to_nox")
+
 if TYPE_CHECKING:
     from collections.abc import Callable
 
 
-tox_to_nox = pytest.importorskip("nox.tox_to_nox")
+pytestmark = pytest.mark.skipif(shutil.which("tox") is None, reason="Tox not available")
 
 PYTHON_VERSION = f"{sys.version_info.major}.{sys.version_info.minor}"
 PYTHON_VERSION_NODOT = PYTHON_VERSION.replace(".", "")