nox-uv 0.2.3__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@ name: CI
3
3
  on: [push, pull_request]
4
4
 
5
5
  env:
6
- UV_VERSION: "0.6.12"
6
+ UV_VERSION: "0.7.3"
7
7
 
8
8
  jobs:
9
9
  test:
nox_uv-0.4.0/PKG-INFO ADDED
@@ -0,0 +1,136 @@
1
+ Metadata-Version: 2.4
2
+ Name: nox-uv
3
+ Version: 0.4.0
4
+ Summary: Facilitate nox integration with uv for Python projects
5
+ Project-URL: Homepage, https://github.com/dantebben/nox-uv
6
+ Project-URL: Repository, https://github.com/dantebben/nox-uv
7
+ Project-URL: Issues, https://github.com/dantebben/nox-uv/issues
8
+ Author-email: Dan Tebben <dantebben@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE.txt
11
+ Keywords: nox,uv
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Software Development :: Testing
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.9
26
+ Requires-Dist: nox>=2025.05.01
27
+ Description-Content-Type: text/markdown
28
+
29
+ ## Intro
30
+
31
+ [![GitHub Actions][github-actions-badge]](https://github.com/dantebben/nox-uv/actions)
32
+ [![PyPI version][pypi-version-badge]](https://pypi.python.org/pypi/nox-uv)
33
+ [![Python versions][python-versions-badge]](https://pypi.python.org/pypi/nox-uv)
34
+ [![uv][uv-badge]](https://github.com/astral-sh/uv)
35
+ [![Nox][nox-badge]](https://github.com/wntrblm/nox)
36
+ [![Ruff][ruff-badge]](https://github.com/astral-sh/ruff)
37
+ [![Type checked with mypy][mypy-badge]](https://mypy-lang.org/)
38
+
39
+ [github-actions-badge]: https://github.com/dantebben/nox-uv/workflows/CI/badge.svg
40
+ [pypi-version-badge]: https://img.shields.io/pypi/v/nox-uv.svg
41
+ [python-versions-badge]: https://img.shields.io/pypi/pyversions/nox-uv.svg
42
+ [uv-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json
43
+ [nox-badge]: https://img.shields.io/badge/%F0%9F%A6%8A-Nox-D85E00.svg
44
+ [ruff-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
45
+ [mypy-badge]: https://www.mypy-lang.org/static/mypy_badge.svg
46
+
47
+ `nox-uv` is a simple drop-in replacement for [nox](https://nox.thea.codes/)'s `@nox.session` that installs
48
+ dependencies constrained by [uv](https://docs.astral.sh/uv/)'s lockfile.
49
+
50
+ ## Usage
51
+
52
+ Add `nox-uv` as a development dependency. The following example adds it into a `nox`
53
+ `dependency-group`.
54
+
55
+ ```shell
56
+ uv add --group nox nox-uv
57
+ ```
58
+
59
+ Using the following configuration within `pyproject.toml` as an example:
60
+
61
+ ```toml
62
+ [dependency-groups]
63
+ nox = [
64
+ "nox-uv",
65
+ ]
66
+ test = [
67
+ "pytest",
68
+ "pytest-cov",
69
+ ]
70
+ type_check = [
71
+ "mypy",
72
+ ]
73
+ lint = [
74
+ "ruff",
75
+ ]
76
+ ```
77
+
78
+ Within, your `noxfile.py`:
79
+
80
+ 1. Import `session` from `nox_uv`.
81
+ 2. Set `venv_backend` to `"uv"`. This can be done globally using
82
+ `options.default_venv_backend = "uv"`.
83
+ 3. Use the new [`uv_*` parameters](#added-parameters) to `session` to control which dependencies
84
+ are synced into the session's virtual environment in addition to the project's main
85
+ dependencies.
86
+ - `uv sync` is used to install dependencies so that their versions are constrained by
87
+ `uv.lock`.
88
+
89
+ ```py
90
+ from nox import Session, options
91
+ from nox_uv import session
92
+
93
+ options.default_venv_backend = "uv"
94
+
95
+
96
+ @session(
97
+ python=["3.10", "3.11", "3.12", "3.13"],
98
+ uv_groups=["test"],
99
+ )
100
+ def test(s: Session) -> None:
101
+ s.run("python", "-m", "pytest")
102
+
103
+
104
+ @session(uv_groups=["type_check"])
105
+ def type_check(s: Session) -> None:
106
+ s.run("mypy", "src")
107
+
108
+
109
+ @session(uv_only_groups=["lint"])
110
+ def type_check(s: Session) -> None:
111
+ s.run("ruff", "check", ".")
112
+ s.run("ruff", "format", "--check", ".")
113
+ ```
114
+
115
+ > [!NOTE]
116
+ > All `@session(...)` parameters are keywords only, no positional parameters are allowed.
117
+
118
+ > [!NOTE]
119
+ > The `default_groups` defined in `pyproject.toml` are _not_ installed by default. The
120
+ > user must explicitly list the desired groups in the `uv_groups` parameter.
121
+
122
+ ### Added parameters
123
+
124
+ - `uv_groups`: list of `uv` _dependency-groups_
125
+ - `uv_extras`: list of `uv` _optional-dependencies_
126
+ - `uv_only_groups`: list of `uv` _only-groups_ to include. Prevents installation of project
127
+ _dependencies_.
128
+ - `uv_all_extras`: boolean to install all _optional-dependencies_ from `pyproject.toml`
129
+ - `uv_all_groups`: boolean to install all _dependency-groups_
130
+ - `uv_sync_locked`: boolean to validate that `uv.lock` is up-to-date
131
+
132
+
133
+ ## Inspiration
134
+
135
+ This is heavily influenced by, but much more limited than,
136
+ [nox-poetry](https://nox-poetry.readthedocs.io).
nox_uv-0.4.0/README.md ADDED
@@ -0,0 +1,108 @@
1
+ ## Intro
2
+
3
+ [![GitHub Actions][github-actions-badge]](https://github.com/dantebben/nox-uv/actions)
4
+ [![PyPI version][pypi-version-badge]](https://pypi.python.org/pypi/nox-uv)
5
+ [![Python versions][python-versions-badge]](https://pypi.python.org/pypi/nox-uv)
6
+ [![uv][uv-badge]](https://github.com/astral-sh/uv)
7
+ [![Nox][nox-badge]](https://github.com/wntrblm/nox)
8
+ [![Ruff][ruff-badge]](https://github.com/astral-sh/ruff)
9
+ [![Type checked with mypy][mypy-badge]](https://mypy-lang.org/)
10
+
11
+ [github-actions-badge]: https://github.com/dantebben/nox-uv/workflows/CI/badge.svg
12
+ [pypi-version-badge]: https://img.shields.io/pypi/v/nox-uv.svg
13
+ [python-versions-badge]: https://img.shields.io/pypi/pyversions/nox-uv.svg
14
+ [uv-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json
15
+ [nox-badge]: https://img.shields.io/badge/%F0%9F%A6%8A-Nox-D85E00.svg
16
+ [ruff-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
17
+ [mypy-badge]: https://www.mypy-lang.org/static/mypy_badge.svg
18
+
19
+ `nox-uv` is a simple drop-in replacement for [nox](https://nox.thea.codes/)'s `@nox.session` that installs
20
+ dependencies constrained by [uv](https://docs.astral.sh/uv/)'s lockfile.
21
+
22
+ ## Usage
23
+
24
+ Add `nox-uv` as a development dependency. The following example adds it into a `nox`
25
+ `dependency-group`.
26
+
27
+ ```shell
28
+ uv add --group nox nox-uv
29
+ ```
30
+
31
+ Using the following configuration within `pyproject.toml` as an example:
32
+
33
+ ```toml
34
+ [dependency-groups]
35
+ nox = [
36
+ "nox-uv",
37
+ ]
38
+ test = [
39
+ "pytest",
40
+ "pytest-cov",
41
+ ]
42
+ type_check = [
43
+ "mypy",
44
+ ]
45
+ lint = [
46
+ "ruff",
47
+ ]
48
+ ```
49
+
50
+ Within, your `noxfile.py`:
51
+
52
+ 1. Import `session` from `nox_uv`.
53
+ 2. Set `venv_backend` to `"uv"`. This can be done globally using
54
+ `options.default_venv_backend = "uv"`.
55
+ 3. Use the new [`uv_*` parameters](#added-parameters) to `session` to control which dependencies
56
+ are synced into the session's virtual environment in addition to the project's main
57
+ dependencies.
58
+ - `uv sync` is used to install dependencies so that their versions are constrained by
59
+ `uv.lock`.
60
+
61
+ ```py
62
+ from nox import Session, options
63
+ from nox_uv import session
64
+
65
+ options.default_venv_backend = "uv"
66
+
67
+
68
+ @session(
69
+ python=["3.10", "3.11", "3.12", "3.13"],
70
+ uv_groups=["test"],
71
+ )
72
+ def test(s: Session) -> None:
73
+ s.run("python", "-m", "pytest")
74
+
75
+
76
+ @session(uv_groups=["type_check"])
77
+ def type_check(s: Session) -> None:
78
+ s.run("mypy", "src")
79
+
80
+
81
+ @session(uv_only_groups=["lint"])
82
+ def type_check(s: Session) -> None:
83
+ s.run("ruff", "check", ".")
84
+ s.run("ruff", "format", "--check", ".")
85
+ ```
86
+
87
+ > [!NOTE]
88
+ > All `@session(...)` parameters are keywords only, no positional parameters are allowed.
89
+
90
+ > [!NOTE]
91
+ > The `default_groups` defined in `pyproject.toml` are _not_ installed by default. The
92
+ > user must explicitly list the desired groups in the `uv_groups` parameter.
93
+
94
+ ### Added parameters
95
+
96
+ - `uv_groups`: list of `uv` _dependency-groups_
97
+ - `uv_extras`: list of `uv` _optional-dependencies_
98
+ - `uv_only_groups`: list of `uv` _only-groups_ to include. Prevents installation of project
99
+ _dependencies_.
100
+ - `uv_all_extras`: boolean to install all _optional-dependencies_ from `pyproject.toml`
101
+ - `uv_all_groups`: boolean to install all _dependency-groups_
102
+ - `uv_sync_locked`: boolean to validate that `uv.lock` is up-to-date
103
+
104
+
105
+ ## Inspiration
106
+
107
+ This is heavily influenced by, but much more limited than,
108
+ [nox-poetry](https://nox-poetry.readthedocs.io).
@@ -3,7 +3,6 @@ from nox import Session, options, parametrize
3
3
  from nox_uv import session
4
4
 
5
5
  options.error_on_external_run = True
6
- options.reuse_existing_virtualenvs = False
7
6
  options.default_venv_backend = "uv"
8
7
  options.sessions = ["uv_lock_check", "lint", "type_check", "test"]
9
8
 
@@ -23,8 +22,10 @@ def test(s: Session) -> None:
23
22
  "-m",
24
23
  "pytest",
25
24
  "--cov=nox_uv",
25
+ "--cov-branch",
26
26
  "--cov-report=html",
27
27
  "--cov-report=term",
28
+ "--cov-fail-under=100",
28
29
  "tests",
29
30
  *s.posargs,
30
31
  )
@@ -1,7 +1,8 @@
1
1
  [project]
2
2
  name = "nox-uv"
3
- version = "0.2.3"
3
+ version = "0.4.0"
4
4
  description = "Facilitate nox integration with uv for Python projects"
5
+ keywords = ["nox", "uv"]
5
6
  readme = "README.md"
6
7
  authors = [
7
8
  { name = "Dan Tebben", email = "dantebben@gmail.com" }
@@ -26,18 +27,13 @@ classifiers = [
26
27
 
27
28
  requires-python = ">=3.9"
28
29
  dependencies = [
29
- "nox>=2025.2.9",
30
+ "nox>=2025.05.01",
30
31
  ]
31
32
 
32
- # These optional dependencies are only for testing ability to include/exclude extras.
33
- [project.optional-dependencies]
34
- pyyaml = ["pyyaml"]
35
- scapy = ["scapy"]
36
-
37
-
38
-
39
33
  [project.urls]
40
34
  Homepage = "https://github.com/dantebben/nox-uv"
35
+ Repository = "https://github.com/dantebben/nox-uv"
36
+ Issues = "https://github.com/dantebben/nox-uv/issues"
41
37
 
42
38
  [build-system]
43
39
  requires = ["hatchling"]
@@ -54,18 +50,8 @@ type-check = [
54
50
  "mypy>=1.15.0",
55
51
  ]
56
52
 
57
- never-used = [
58
- "networkx"
59
- ]
60
-
61
-
62
53
  [tool.uv]
63
- default-groups = [
64
- "lint",
65
- "test",
66
- "type-check",
67
- ]
68
-
54
+ default-groups = "all"
69
55
 
70
56
  [tool.mypy]
71
57
  ignore_missing_imports = true
@@ -115,9 +101,6 @@ split-on-trailing-comma = false
115
101
  [tool.ruff.lint.flake8-tidy-imports]
116
102
  ban-relative-imports = "all"
117
103
 
118
- [tool.ruff.lint.flake8-bugbear]
119
- extend-immutable-calls = ["typer.Argument"]
120
-
121
104
  [tool.pytest.ini_options]
122
105
  addopts = [
123
106
  "--strict-config",
@@ -131,4 +114,3 @@ parallel = true
131
114
  # The nox session that calls coverage does not find "src/nox_uv", but it is found in the
132
115
  # subprocess. Coverage generates a warning that the module was not found, but coverage is actually
133
116
  # run and determined in the "parallel" subprocess.
134
- disable_warnings = ["module-not-imported", "no-data-collected"]
@@ -16,15 +16,17 @@ def session(
16
16
  python: Python | None = None,
17
17
  reuse_venv: bool | None = None,
18
18
  name: str | None = None,
19
- venv_backend: Any | None = None,
19
+ venv_backend: str | None = None,
20
20
  venv_params: Sequence[str] = (),
21
21
  tags: Sequence[str] | None = None,
22
22
  default: bool = True,
23
23
  requires: Sequence[str] | None = None,
24
24
  uv_groups: Sequence[str] = (),
25
25
  uv_extras: Sequence[str] = (),
26
+ uv_only_groups: Sequence[str] = (),
26
27
  uv_all_extras: bool = False,
27
28
  uv_all_groups: bool = False,
29
+ uv_sync_locked: bool = True,
28
30
  **kwargs: dict[str, Any],
29
31
  ) -> Callable[..., Callable[..., R]]:
30
32
  """Drop-in replacement for the :func:`nox.session` decorator to add support for `uv`.
@@ -52,27 +54,37 @@ def session(
52
54
  uv_extras=uv_extras,
53
55
  uv_all_extras=uv_all_extras,
54
56
  uv_all_groups=uv_all_groups,
57
+ uv_only_groups=uv_only_groups,
58
+ uv_sync_locked=uv_sync_locked,
55
59
  **kwargs,
56
60
  ) # type: ignore
57
61
 
58
62
  [function] = args
59
63
 
60
64
  # Create the `uv sync` command
61
- sync_cmd = ["uv", "sync", "--no-default-groups", "--locked"]
65
+ sync_cmd = ["uv", "sync", "--no-default-groups"]
66
+ extended_cmd: list[str] = []
67
+
68
+ # Add the --locked flag
69
+ if uv_sync_locked:
70
+ sync_cmd.append("--locked")
62
71
 
63
72
  # Add the groups
64
- for g in uv_groups:
65
- sync_cmd.append(f"--group={g}")
73
+ extended_cmd.extend([f"--group={g}" for g in uv_groups])
66
74
 
67
75
  # Add the extras
68
- for e in uv_extras:
69
- sync_cmd.append(f"--extra={e}")
76
+ extended_cmd.extend([f"--extra={e}" for e in uv_extras])
77
+
78
+ # Add the only-groups
79
+ extended_cmd.extend([f"--only-group={g}" for g in uv_only_groups])
70
80
 
71
81
  if uv_all_groups:
72
- sync_cmd.append("--all-groups")
82
+ extended_cmd.append("--all-groups")
73
83
 
74
84
  if uv_all_extras:
75
- sync_cmd.append("--all-extras")
85
+ extended_cmd.append("--all-extras")
86
+
87
+ sync_cmd += extended_cmd
76
88
 
77
89
  @functools.wraps(function)
78
90
  def wrapper(s: nox.Session, *_args: Any, **_kwargs: Any) -> None:
@@ -87,6 +99,13 @@ def session(
87
99
  s.env["UV_PYTHON"] = str(s.python)
88
100
 
89
101
  s.run_install(*sync_cmd)
102
+ else:
103
+ if len(extended_cmd) > 0:
104
+ raise s.error(
105
+ 'Using "uv" specific paramaters is not allowed outside of a "uv" '
106
+ "venv_backend.\n"
107
+ f"Check the venv_backend, or the {extended_cmd} parameters."
108
+ )
90
109
 
91
110
  function(nox.Session(s._runner), *_args, **_kwargs)
92
111
 
@@ -0,0 +1 @@
1
+ 3.12
File without changes
@@ -0,0 +1,6 @@
1
+ def main() -> None:
2
+ print("Hello from subproject!")
3
+
4
+
5
+ if __name__ == "__main__":
6
+ main()
@@ -7,10 +7,13 @@ options.reuse_existing_virtualenvs = False
7
7
 
8
8
  options.sessions = [
9
9
  "check_python_version",
10
- "only_test_group",
10
+ "install_nothing",
11
+ "test_group",
11
12
  "all_groups",
12
13
  "all_extras",
14
+ "one_extra",
13
15
  "correct_python",
16
+ "only_groups",
14
17
  ]
15
18
 
16
19
 
@@ -19,20 +22,36 @@ def check_python_version(s: Session) -> None:
19
22
  s.run("python3", "--version")
20
23
 
21
24
 
25
+ @session
26
+ def install_nothing(s: Session) -> None:
27
+ r = s.run("uv", "pip", "list", silent=True)
28
+ assert isinstance(r, str)
29
+ assert "nox-uv" in r
30
+ assert "scapy" not in r
31
+ assert "pyyaml" not in r
32
+ assert "networkx" not in r
33
+ assert "ruff" not in r
34
+ assert "pytest-cov" not in r
35
+ assert "mypy" not in r
36
+
37
+
22
38
  @session(uv_groups=["test"])
23
- def only_test_group(s: Session) -> None:
39
+ def test_group(s: Session) -> None:
24
40
  r = s.run("uv", "pip", "list", silent=True)
25
41
  assert isinstance(r, str)
26
42
  assert "pytest-cov" in r
27
43
  assert "networkx" not in r
44
+ assert "ruff" not in r
28
45
 
29
46
 
30
47
  @session(uv_all_groups=True)
31
48
  def all_groups(s: Session) -> None:
32
49
  r = s.run("uv", "pip", "list", silent=True)
33
50
  assert isinstance(r, str)
34
- assert "pytest-cov" in r
35
51
  assert "networkx" in r
52
+ assert "ruff" in r
53
+ assert "pytest-cov" in r
54
+ assert "mypy" in r
36
55
 
37
56
 
38
57
  @session(uv_all_extras=True)
@@ -40,14 +59,14 @@ def all_extras(s: Session) -> None:
40
59
  r = s.run("uv", "pip", "list", silent=True)
41
60
  assert isinstance(r, str)
42
61
  assert "networkx" not in r
62
+ assert "scapy" in r
43
63
  assert "pyyaml" in r
44
64
 
45
65
 
46
- @session(uv_extras=["pyyaml"])
47
- def only_one_extra(s: Session) -> None:
66
+ @session(uv_extras=["pyyaml"], uv_sync_locked=False) # Test without the --locked flag
67
+ def one_extra(s: Session) -> None:
48
68
  r = s.run("uv", "pip", "list", silent=True)
49
69
  assert isinstance(r, str)
50
- assert "scapy" not in r
51
70
  assert "networkx" not in r
52
71
  assert "pyyaml" in r
53
72
 
@@ -60,3 +79,21 @@ def correct_python(s: Session) -> None:
60
79
  assert "Python 3.10" in v
61
80
  else:
62
81
  raise RuntimeError("Python version was not returned.")
82
+
83
+
84
+ @session(uv_only_groups=["lint"])
85
+ def only_groups(s: Session) -> None:
86
+ r = s.run("uv", "pip", "list", silent=True)
87
+ assert isinstance(r, str)
88
+ assert "ruff" in r
89
+ assert "nox-uv" not in r
90
+
91
+
92
+ @session(uv_groups=["type-check"], venv_backend="virtualenv")
93
+ def failed_virtualenv(s: Session) -> None:
94
+ pass
95
+
96
+
97
+ @session(uv_groups=["type-check"], venv_backend="none")
98
+ def failed_venv_none(s: Session) -> None:
99
+ pass
@@ -0,0 +1,41 @@
1
+ [project]
2
+ name = "subproject"
3
+ version = "0.1.0"
4
+ description = "Project for testing nox-uv"
5
+ readme = "README.md"
6
+ requires-python = ">=3.9"
7
+ classifiers = [
8
+ "Private: Do Not Upload",
9
+ ]
10
+ dependencies = [
11
+ "nox-uv",
12
+ ]
13
+
14
+ [tool.uv.sources]
15
+ nox-uv = { path = "../../", editable = true }
16
+
17
+ [project.optional-dependencies]
18
+ pyyaml = ["pyyaml"]
19
+ scapy = ["scapy"]
20
+
21
+ [dependency-groups]
22
+ never-used = [
23
+ "networkx"
24
+ ]
25
+
26
+ lint = [
27
+ "ruff>=0.9.7",
28
+ ]
29
+ test = [
30
+ "pytest-cov>=6.0.0",
31
+ ]
32
+ type-check = [
33
+ "mypy>=1.15.0",
34
+ ]
35
+
36
+ [tool.uv]
37
+ default-groups = [
38
+ "lint",
39
+ "test",
40
+ "type-check",
41
+ ]