Skip to content

Commit

Permalink
Add support for NOXPYTHON, NOXEXTRAPYTHON and NOXFORCEPYTHON (#688
Browse files Browse the repository at this point in the history
)
  • Loading branch information
edgarrmondragon committed Feb 15, 2023
1 parent 36202af commit 593017f
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 32 deletions.
4 changes: 4 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"sphinx.ext.autodoc",
"sphinx.ext.napoleon",
"myst_parser",
"sphinx_tabs.tabs",
]

# Add any paths that contain templates here, relative to this directory.
Expand Down Expand Up @@ -316,3 +317,6 @@

# If true, do not generate a @detailmenu in the "Top" node's menu.
# texinfo_no_detailmenu = False

# Disable tab closing by selecting the open tab
sphinx_tabs_disable_tab_closing = True
76 changes: 57 additions & 19 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,27 +52,35 @@ Specifying one or more sessions

By default Nox will run all sessions defined in the Noxfile. However, you can choose to run a particular set of them using ``--session``, ``-s``, or ``-e``:

.. code-block:: console
.. tabs::

nox --session tests
nox -s lint tests
nox -e lint
.. code-tab:: console CLI options

You can also use the ``NOXSESSION`` environment variable:
nox --session tests
nox -s lint tests
nox -e lint

.. code-block:: console
.. code-tab:: console Environment variables

NOXSESSION=lint nox
NOXSESSION=lint,tests nox
NOXSESSION=tests nox
NOXSESSION=lint nox
NOXSESSION=lint,tests nox

Nox will run these sessions in the same order they are specified.

If you have a :ref:`configured session's virtualenv <virtualenv config>`, you can choose to run only sessions with given Python versions:

.. code-block:: console
.. tabs::

.. code-tab:: console CLI options

nox --python 3.8
nox -p 3.7 3.8

.. code-tab:: console Environment variables

nox --python 3.8
nox -p 3.7 3.8
NOXPYTHON=3.8 nox
NOXPYTHON=3.7,3.8 nox

You can also use `pytest-style keywords`_ using ``-k`` or ``--keywords``, and
tags using ``-t`` or ``--tags`` to filter test sessions:
Expand Down Expand Up @@ -184,25 +192,55 @@ Running additional Python versions

In addition to Nox supporting executing single sessions, it also supports running Python versions that aren't specified using ``--extra-pythons``.

.. code-block:: console
.. tabs::

.. code-tab:: console CLI options

nox --extra-pythons 3.8 3.9 3.10

.. code-tab:: console Environment variables

NOXEXTRAPYTHON=3.8,3.9,3.10 nox

nox --extra-pythons 3.8 3.9 3.10

This will, in addition to specified Python versions in the Noxfile, also create sessions for the specified versions.

This option can be combined with ``--python`` to replace, instead of appending, the Python interpreter for a given session::
This option can be combined with ``--python`` to replace, instead of appending, the Python interpreter for a given session:

nox --python 3.11 --extra-python 3.11 -s lint
.. tabs::

Instead of passing both options, you can use the ``--force-python`` shorthand::
.. code-tab:: console CLI options

nox --force-python 3.11 -s lint
nox --python 3.11 --extra-python 3.11 -s lint

.. code-tab:: console Environment variables

NOXPYTHON=3.11 NOXEXTRAPYTHON=3.11 NOXSESSION=lint nox

Instead of passing both options, you can use the ``--force-python`` shorthand:

.. tabs::

.. code-tab:: console CLI options

nox --force-python 3.11 -s lint

.. code-tab:: console Environment variables

NOXFORCEPYTHON=3.11 NOXSESSION=lint nox

Also, you can specify ``python`` in place of a specific version. This will run the session
using the ``python`` specified for the current ``PATH``::
using the ``python`` specified for the current ``PATH``:

.. tabs::

.. code-tab:: console CLI options

nox --force-python python -s lint

nox --force-python python -s lint
.. code-tab:: console Environment variables

NOXFORCEPYTHON=python NOXSESSION=lint nox

.. _opt-stop-on-first-error:

Expand Down
27 changes: 20 additions & 7 deletions nox/_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import functools
import os
import sys
from typing import Any, Sequence
from typing import Any, Callable, Sequence

from nox import _option_set
from nox.tasks import discover_manifest, filter_manifest, load_nox_module
Expand Down Expand Up @@ -142,11 +142,21 @@ def _envdir_merge_func(
return command_args.envdir or noxfile_args.envdir or ".nox"


def _sessions_default() -> list[str] | None:
"""Looks at the NOXSESSION env var to set the default value for sessions."""
nox_env = os.environ.get("NOXSESSION")
env_sessions = nox_env.split(",") if nox_env else None
return env_sessions
def default_env_var_list_factory(env_var: str) -> Callable[[], list[str] | None]:
"""Looks at the env var to set the default value for a list of env vars.
Args:
env_var (str): The name of the environment variable to look up.
Returns:
A callback that retrieves a list from a comma-delimited environment variable.
"""

def _default_list() -> list[str] | None:
env_value = os.environ.get(env_var)
return env_value.split(",") if env_value else None

return _default_list


def _color_finalizer(value: bool, args: argparse.Namespace) -> bool:
Expand Down Expand Up @@ -264,7 +274,7 @@ def _session_completer(
noxfile=True,
merge_func=functools.partial(_sessions_and_keywords_merge_func, "sessions"),
nargs="*",
default=_sessions_default,
default=default_env_var_list_factory("NOXSESSION"),
help="Which sessions to run. By default, all sessions will run.",
completer=_session_completer,
),
Expand All @@ -276,6 +286,7 @@ def _session_completer(
group=options.groups["python"],
noxfile=True,
nargs="*",
default=default_env_var_list_factory("NOXPYTHON"),
help="Only run sessions that use the given python interpreter versions.",
),
_option_set.Option(
Expand Down Expand Up @@ -406,6 +417,7 @@ def _session_completer(
"--extra-python",
group=options.groups["python"],
nargs="*",
default=default_env_var_list_factory("NOXEXTRAPYTHON"),
help="Additionally, run sessions using the given python interpreter versions.",
),
_option_set.Option(
Expand All @@ -414,6 +426,7 @@ def _session_completer(
"--force-python",
group=options.groups["python"],
nargs="*",
default=default_env_var_list_factory("NOXFORCEPYTHON"),
help=(
"Run sessions with the given interpreters instead of those listed in the"
" Noxfile. This is a shorthand for ``--python=X.Y --extra-python=X.Y``."
Expand Down
1 change: 1 addition & 0 deletions requirements-test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ pytest>=6.0
pytest-cov
sphinx>=3.0
sphinx-autobuild
sphinx-tabs
witchhazel
33 changes: 27 additions & 6 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,30 @@ def test_main_explicit_sessions_with_spaces_in_names(monkeypatch):


@pytest.mark.parametrize(
"env,sessions", [("foo", ["foo"]), ("foo,bar", ["foo", "bar"])]
"var,option,env,values",
[
("NOXSESSION", "sessions", "foo", ["foo"]),
("NOXSESSION", "sessions", "foo,bar", ["foo", "bar"]),
("NOXPYTHON", "pythons", "3.9", ["3.9"]),
("NOXPYTHON", "pythons", "3.9,3.10", ["3.9", "3.10"]),
("NOXEXTRAPYTHON", "extra_pythons", "3.9", ["3.9"]),
("NOXEXTRAPYTHON", "extra_pythons", "3.9,3.10", ["3.9", "3.10"]),
("NOXFORCEPYTHON", "force_pythons", "3.9", ["3.9"]),
("NOXFORCEPYTHON", "force_pythons", "3.9,3.10", ["3.9", "3.10"]),
],
ids=[
"single_session",
"multiple_sessions",
"single_python",
"multiple_pythons",
"single_extra_python",
"multiple_extra_pythons",
"single_force_python",
"multiple_force_pythons",
],
)
def test_main_session_from_nox_env_var(monkeypatch, env, sessions):
monkeypatch.setenv("NOXSESSION", env)
def test_main_list_option_from_nox_env_var(monkeypatch, var, option, env, values):
monkeypatch.setenv(var, env)
monkeypatch.setattr(sys, "argv", [sys.executable])

with mock.patch("nox.workflow.execute") as execute:
Expand All @@ -234,9 +254,10 @@ def test_main_session_from_nox_env_var(monkeypatch, env, sessions):

# Verify that the sessions from the env var are listed in the config.
config = execute.call_args[1]["global_config"]
assert len(config.sessions) == len(sessions)
for session in sessions:
assert session in config.sessions
config_values = getattr(config, option)
assert len(config_values) == len(values)
for value in values:
assert value in config_values


def test_main_positional_args(capsys, monkeypatch):
Expand Down

0 comments on commit 593017f

Please sign in to comment.