nox-uv 0.3.0__tar.gz → 0.5.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.
- {nox_uv-0.3.0 → nox_uv-0.5.0}/.github/workflows/ci.yml +1 -3
- nox_uv-0.5.0/PKG-INFO +136 -0
- nox_uv-0.5.0/README.md +108 -0
- {nox_uv-0.3.0 → nox_uv-0.5.0}/noxfile.py +7 -24
- {nox_uv-0.3.0 → nox_uv-0.5.0}/pyproject.toml +8 -6
- {nox_uv-0.3.0 → nox_uv-0.5.0}/src/nox_uv/__init__.py +32 -11
- {nox_uv-0.3.0 → nox_uv-0.5.0}/tests/subproject/noxfile.py +26 -9
- {nox_uv-0.3.0 → nox_uv-0.5.0}/tests/subproject/pyproject.toml +3 -3
- {nox_uv-0.3.0 → nox_uv-0.5.0}/tests/subproject/uv.lock +7 -4
- nox_uv-0.5.0/tests/test_lib.py +35 -0
- nox_uv-0.5.0/uv.lock +429 -0
- nox_uv-0.3.0/PKG-INFO +0 -50
- nox_uv-0.3.0/README.md +0 -25
- nox_uv-0.3.0/tests/test_lib.py +0 -16
- nox_uv-0.3.0/uv.lock +0 -412
- {nox_uv-0.3.0 → nox_uv-0.5.0}/.editorconfig +0 -0
- {nox_uv-0.3.0 → nox_uv-0.5.0}/.gitignore +0 -0
- {nox_uv-0.3.0 → nox_uv-0.5.0}/.python-version +0 -0
- {nox_uv-0.3.0 → nox_uv-0.5.0}/LICENSE.txt +0 -0
- {nox_uv-0.3.0 → nox_uv-0.5.0}/src/nox_uv/py.typed +0 -0
- {nox_uv-0.3.0 → nox_uv-0.5.0}/tests/__init__.py +0 -0
- {nox_uv-0.3.0 → nox_uv-0.5.0}/tests/subproject/.python-version +0 -0
- {nox_uv-0.3.0 → nox_uv-0.5.0}/tests/subproject/README.md +0 -0
- {nox_uv-0.3.0 → nox_uv-0.5.0}/tests/subproject/main.py +0 -0
|
@@ -3,7 +3,7 @@ name: CI
|
|
|
3
3
|
on: [push, pull_request]
|
|
4
4
|
|
|
5
5
|
env:
|
|
6
|
-
UV_VERSION: "0.
|
|
6
|
+
UV_VERSION: "0.7.12"
|
|
7
7
|
|
|
8
8
|
jobs:
|
|
9
9
|
test:
|
|
@@ -15,8 +15,6 @@ jobs:
|
|
|
15
15
|
- uses: actions/checkout@v4
|
|
16
16
|
- name: Install uv
|
|
17
17
|
uses: astral-sh/setup-uv@v5
|
|
18
|
-
# Caching is enabled by default for GitHub-hosted runners:
|
|
19
|
-
# https://github.com/astral-sh/setup-uv?tab=readme-ov-file#enable-caching
|
|
20
18
|
with:
|
|
21
19
|
version: ${{ env.UV_VERSION }}
|
|
22
20
|
- name: Set up Python ${{ matrix.python-version }}
|
nox_uv-0.5.0/PKG-INFO
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nox-uv
|
|
3
|
+
Version: 0.5.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.5.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,14 +3,8 @@ 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
|
-
options.sessions = ["
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@session(venv_backend="none")
|
|
12
|
-
def uv_lock_check(s: Session) -> None:
|
|
13
|
-
s.run("uv", "lock", "--check")
|
|
7
|
+
options.sessions = ["lint", "type_check", "test"]
|
|
14
8
|
|
|
15
9
|
|
|
16
10
|
@session(
|
|
@@ -23,16 +17,16 @@ def test(s: Session) -> None:
|
|
|
23
17
|
"-m",
|
|
24
18
|
"pytest",
|
|
25
19
|
"--cov=nox_uv",
|
|
20
|
+
"--cov-branch",
|
|
26
21
|
"--cov-report=html",
|
|
27
22
|
"--cov-report=term",
|
|
23
|
+
"--cov-fail-under=100",
|
|
28
24
|
"tests",
|
|
29
25
|
*s.posargs,
|
|
30
26
|
)
|
|
31
27
|
|
|
32
28
|
|
|
33
|
-
|
|
34
|
-
# environment. This requires that nox is run within `poetry shell` or using `poetry run nox ...`.
|
|
35
|
-
@session(venv_backend="none")
|
|
29
|
+
@session(uv_only_groups=["lint"])
|
|
36
30
|
@parametrize(
|
|
37
31
|
"command",
|
|
38
32
|
[
|
|
@@ -56,7 +50,7 @@ def fmt(s: Session, command: list[str]) -> None:
|
|
|
56
50
|
s.run(*command)
|
|
57
51
|
|
|
58
52
|
|
|
59
|
-
@session(
|
|
53
|
+
@session(uv_only_groups=["lint"])
|
|
60
54
|
@parametrize(
|
|
61
55
|
"command",
|
|
62
56
|
[
|
|
@@ -68,22 +62,11 @@ def lint(s: Session, command: list[str]) -> None:
|
|
|
68
62
|
s.run(*command)
|
|
69
63
|
|
|
70
64
|
|
|
71
|
-
@session(
|
|
65
|
+
@session(uv_only_groups=["lint"])
|
|
72
66
|
def lint_fix(s: Session) -> None:
|
|
73
67
|
s.run("ruff", "check", ".", "--extend-fixable", "F401", "--fix")
|
|
74
68
|
|
|
75
69
|
|
|
76
|
-
@session(
|
|
70
|
+
@session(uv_groups=["test", "type_check"])
|
|
77
71
|
def type_check(s: Session) -> None:
|
|
78
72
|
s.run("mypy", "src", "tests", "noxfile.py")
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
@session(venv_backend="none")
|
|
82
|
-
def simple_test(s: Session) -> None:
|
|
83
|
-
assert 1 == 1
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
@session(venv_backend="none")
|
|
87
|
-
def run_test_as_session(s: Session) -> None:
|
|
88
|
-
"""Test ability to call a nother session."""
|
|
89
|
-
simple_test(s)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "nox-uv"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.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" }
|
|
@@ -31,6 +32,8 @@ dependencies = [
|
|
|
31
32
|
|
|
32
33
|
[project.urls]
|
|
33
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"
|
|
34
37
|
|
|
35
38
|
[build-system]
|
|
36
39
|
requires = ["hatchling"]
|
|
@@ -41,9 +44,12 @@ lint = [
|
|
|
41
44
|
"ruff>=0.9.7",
|
|
42
45
|
]
|
|
43
46
|
test = [
|
|
47
|
+
# TODO: Remove this upper bound with pytest-cov fixes issues with filterwarnings = ["error"]
|
|
48
|
+
# https://github.com/pytest-dev/pytest-cov/issues/693
|
|
49
|
+
"pytest<8.4.0",
|
|
44
50
|
"pytest-cov>=6.0.0",
|
|
45
51
|
]
|
|
46
|
-
|
|
52
|
+
type_check = [
|
|
47
53
|
"mypy>=1.15.0",
|
|
48
54
|
]
|
|
49
55
|
|
|
@@ -98,9 +104,6 @@ split-on-trailing-comma = false
|
|
|
98
104
|
[tool.ruff.lint.flake8-tidy-imports]
|
|
99
105
|
ban-relative-imports = "all"
|
|
100
106
|
|
|
101
|
-
[tool.ruff.lint.flake8-bugbear]
|
|
102
|
-
extend-immutable-calls = ["typer.Argument"]
|
|
103
|
-
|
|
104
107
|
[tool.pytest.ini_options]
|
|
105
108
|
addopts = [
|
|
106
109
|
"--strict-config",
|
|
@@ -114,4 +117,3 @@ parallel = true
|
|
|
114
117
|
# The nox session that calls coverage does not find "src/nox_uv", but it is found in the
|
|
115
118
|
# subprocess. Coverage generates a warning that the module was not found, but coverage is actually
|
|
116
119
|
# run and determined in the "parallel" subprocess.
|
|
117
|
-
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:
|
|
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"
|
|
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
|
-
|
|
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
|
-
|
|
82
|
+
extended_cmd.append("--all-groups")
|
|
73
83
|
|
|
74
84
|
if uv_all_extras:
|
|
75
|
-
|
|
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:
|
|
@@ -82,11 +94,20 @@ def session(
|
|
|
82
94
|
# UV called from Nox does not respect the Python version set in the Nox session.
|
|
83
95
|
# We need to pass the Python version to UV explicitly.
|
|
84
96
|
if s.python is not None:
|
|
85
|
-
|
|
86
|
-
# for the type checker.
|
|
87
|
-
s.env["UV_PYTHON"] = str(s.python)
|
|
97
|
+
s.env["UV_PYTHON"] = s.virtualenv.location
|
|
88
98
|
|
|
99
|
+
s.debug(
|
|
100
|
+
f"UV_PYTHON={s.env['UV_PYTHON']} | "
|
|
101
|
+
f"UV_PROJECT_ENVIRONMENT={s.env['UV_PROJECT_ENVIRONMENT']}"
|
|
102
|
+
)
|
|
89
103
|
s.run_install(*sync_cmd)
|
|
104
|
+
else:
|
|
105
|
+
if len(extended_cmd) > 0:
|
|
106
|
+
raise s.error(
|
|
107
|
+
'Using "uv" specific paramaters is not allowed outside of a "uv" '
|
|
108
|
+
"venv_backend.\n"
|
|
109
|
+
f"Check the venv_backend, or the {extended_cmd} parameters."
|
|
110
|
+
)
|
|
90
111
|
|
|
91
112
|
function(nox.Session(s._runner), *_args, **_kwargs)
|
|
92
113
|
|
|
@@ -3,22 +3,21 @@ from nox import Session, options
|
|
|
3
3
|
from nox_uv import session
|
|
4
4
|
|
|
5
5
|
options.default_venv_backend = "uv"
|
|
6
|
-
options.reuse_existing_virtualenvs = False
|
|
7
|
-
|
|
8
6
|
options.sessions = [
|
|
9
7
|
"check_python_version",
|
|
10
8
|
"install_nothing",
|
|
11
|
-
"
|
|
9
|
+
"test_group",
|
|
12
10
|
"all_groups",
|
|
13
11
|
"all_extras",
|
|
14
|
-
"
|
|
12
|
+
"one_extra",
|
|
15
13
|
"correct_python",
|
|
14
|
+
"only_groups",
|
|
16
15
|
]
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
@session(venv_backend="none")
|
|
20
19
|
def check_python_version(s: Session) -> None:
|
|
21
|
-
s.run("
|
|
20
|
+
s.run("python", "--version")
|
|
22
21
|
|
|
23
22
|
|
|
24
23
|
@session
|
|
@@ -35,7 +34,7 @@ def install_nothing(s: Session) -> None:
|
|
|
35
34
|
|
|
36
35
|
|
|
37
36
|
@session(uv_groups=["test"])
|
|
38
|
-
def
|
|
37
|
+
def test_group(s: Session) -> None:
|
|
39
38
|
r = s.run("uv", "pip", "list", silent=True)
|
|
40
39
|
assert isinstance(r, str)
|
|
41
40
|
assert "pytest-cov" in r
|
|
@@ -62,8 +61,8 @@ def all_extras(s: Session) -> None:
|
|
|
62
61
|
assert "pyyaml" in r
|
|
63
62
|
|
|
64
63
|
|
|
65
|
-
@session(uv_extras=["pyyaml"])
|
|
66
|
-
def
|
|
64
|
+
@session(uv_extras=["pyyaml"], uv_sync_locked=False) # Test without the --locked flag
|
|
65
|
+
def one_extra(s: Session) -> None:
|
|
67
66
|
r = s.run("uv", "pip", "list", silent=True)
|
|
68
67
|
assert isinstance(r, str)
|
|
69
68
|
assert "networkx" not in r
|
|
@@ -73,8 +72,26 @@ def only_one_extra(s: Session) -> None:
|
|
|
73
72
|
@session(python=["3.10"])
|
|
74
73
|
def correct_python(s: Session) -> None:
|
|
75
74
|
assert s.python == "3.10"
|
|
76
|
-
v = s.run("
|
|
75
|
+
v = s.run("python", "--version", silent=True)
|
|
77
76
|
if isinstance(v, str):
|
|
78
77
|
assert "Python 3.10" in v
|
|
79
78
|
else:
|
|
80
79
|
raise RuntimeError("Python version was not returned.")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@session(uv_only_groups=["lint"])
|
|
83
|
+
def only_groups(s: Session) -> None:
|
|
84
|
+
r = s.run("uv", "pip", "list", silent=True)
|
|
85
|
+
assert isinstance(r, str)
|
|
86
|
+
assert "ruff" in r
|
|
87
|
+
assert "nox-uv" not in r
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@session(uv_groups=["type_check"], venv_backend="virtualenv")
|
|
91
|
+
def failed_virtualenv(s: Session) -> None:
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@session(uv_groups=["type_check"], venv_backend="none")
|
|
96
|
+
def failed_venv_none(s: Session) -> None:
|
|
97
|
+
pass
|
|
@@ -12,7 +12,7 @@ dependencies = [
|
|
|
12
12
|
]
|
|
13
13
|
|
|
14
14
|
[tool.uv.sources]
|
|
15
|
-
nox-uv = { path = "../../" }
|
|
15
|
+
nox-uv = { path = "../../", editable = true }
|
|
16
16
|
|
|
17
17
|
[project.optional-dependencies]
|
|
18
18
|
pyyaml = ["pyyaml"]
|
|
@@ -29,7 +29,7 @@ lint = [
|
|
|
29
29
|
test = [
|
|
30
30
|
"pytest-cov>=6.0.0",
|
|
31
31
|
]
|
|
32
|
-
|
|
32
|
+
type_check = [
|
|
33
33
|
"mypy>=1.15.0",
|
|
34
34
|
]
|
|
35
35
|
|
|
@@ -37,5 +37,5 @@ type-check = [
|
|
|
37
37
|
default-groups = [
|
|
38
38
|
"lint",
|
|
39
39
|
"test",
|
|
40
|
-
"
|
|
40
|
+
"type_check",
|
|
41
41
|
]
|
|
@@ -266,8 +266,8 @@ wheels = [
|
|
|
266
266
|
|
|
267
267
|
[[package]]
|
|
268
268
|
name = "nox-uv"
|
|
269
|
-
version = "0.
|
|
270
|
-
source = {
|
|
269
|
+
version = "0.5.0"
|
|
270
|
+
source = { editable = "../../" }
|
|
271
271
|
dependencies = [
|
|
272
272
|
{ name = "nox" },
|
|
273
273
|
]
|
|
@@ -277,7 +277,10 @@ requires-dist = [{ name = "nox", specifier = ">=2025.5.1" }]
|
|
|
277
277
|
|
|
278
278
|
[package.metadata.requires-dev]
|
|
279
279
|
lint = [{ name = "ruff", specifier = ">=0.9.7" }]
|
|
280
|
-
test = [
|
|
280
|
+
test = [
|
|
281
|
+
{ name = "pytest", specifier = "<8.4.0" },
|
|
282
|
+
{ name = "pytest-cov", specifier = ">=6.0.0" },
|
|
283
|
+
]
|
|
281
284
|
type-check = [{ name = "mypy", specifier = ">=1.15.0" }]
|
|
282
285
|
|
|
283
286
|
[[package]]
|
|
@@ -457,7 +460,7 @@ type-check = [
|
|
|
457
460
|
|
|
458
461
|
[package.metadata]
|
|
459
462
|
requires-dist = [
|
|
460
|
-
{ name = "nox-uv",
|
|
463
|
+
{ name = "nox-uv", editable = "../../" },
|
|
461
464
|
{ name = "pyyaml", marker = "extra == 'pyyaml'" },
|
|
462
465
|
{ name = "scapy", marker = "extra == 'scapy'" },
|
|
463
466
|
]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_1() -> None:
|
|
7
|
+
assert 5 == 5
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_run_uv_nox() -> None:
|
|
11
|
+
cur_folder = Path.cwd()
|
|
12
|
+
testing_folder = Path(__file__).parent / "subproject"
|
|
13
|
+
os.chdir(testing_folder)
|
|
14
|
+
a = subprocess.run(["uv", "run", "python", "-m", "nox"])
|
|
15
|
+
assert a.returncode == 0
|
|
16
|
+
os.chdir(cur_folder)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_run_failed_uv_venv() -> None:
|
|
20
|
+
cur_folder = Path.cwd()
|
|
21
|
+
testing_folder = Path(__file__).parent / "subproject"
|
|
22
|
+
os.chdir(testing_folder)
|
|
23
|
+
a = subprocess.run(
|
|
24
|
+
["uv", "run", "python", "-m", "nox", "-s", "failed_virtualenv"], capture_output=True
|
|
25
|
+
)
|
|
26
|
+
assert a.returncode == 1 # This test is expected to fail with a `Session.error` raised.
|
|
27
|
+
assert "is not allowed" in a.stderr.decode()
|
|
28
|
+
|
|
29
|
+
a = subprocess.run(
|
|
30
|
+
["uv", "run", "python", "-m", "nox", "-s", "failed_venv_none"], capture_output=True
|
|
31
|
+
)
|
|
32
|
+
assert a.returncode == 1 # This test is expected to fail with a `Session.error` raised.
|
|
33
|
+
assert "is not allowed" in a.stderr.decode()
|
|
34
|
+
|
|
35
|
+
os.chdir(cur_folder)
|