Skip to content

Commit f9e9e1e

Browse files
cidrblockQalthos
authored andcommitted
Cleanup uv compatibility
1 parent e00102a commit f9e9e1e

File tree

5 files changed

+58
-62
lines changed

5 files changed

+58
-62
lines changed

.config/requirements.in

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
ansible-builder
2+
bindep
23
pyyaml
34
subprocess-tee

src/ansible_dev_environment/config.py

+39-39
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
from __future__ import annotations
44

55
import json
6-
import logging
76
import os
87
import shutil
98
import subprocess
109
import sys
1110

11+
from functools import cached_property
1212
from pathlib import Path
1313
from typing import TYPE_CHECKING
1414

@@ -22,38 +22,8 @@
2222
from .utils import TermFeatures
2323

2424

25-
_logger = logging.getLogger(__name__)
26-
27-
28-
def use_uv() -> bool:
29-
"""Return whether to use uv commands like venv or pip.
30-
31-
Returns:
32-
True if uv is to be used.
33-
"""
34-
if int(os.environ.get("SKIP_UV", "0")):
35-
return False
36-
try:
37-
import uv # noqa: F401
38-
except ImportError: # pragma: no cover
39-
return False
40-
else:
41-
_logger.info(
42-
"UV detected and will be used instead of venv/pip. To disable that define SKIP_UP=1 in your environment.",
43-
)
44-
return True
45-
46-
4725
class Config: # pylint: disable=too-many-instance-attributes
48-
"""The application configuration.
49-
50-
Attributes:
51-
pip_cmd: The pip command.
52-
venv_cmd: The venv command.
53-
"""
54-
55-
pip_cmd: str
56-
venv_cmd: str
26+
"""The application configuration."""
5727

5828
def __init__(
5929
self,
@@ -114,6 +84,38 @@ def venv_cache_dir(self) -> Path:
11484
"""Return the virtual environment cache directory."""
11585
return self.cache_dir
11686

87+
@property
88+
def venv_pip_install_cmd(self) -> str:
89+
"""Return the pip command for the virtual environment.
90+
91+
Returns:
92+
The pip install command for the virtual environment.
93+
"""
94+
if self.uv_available:
95+
return f"uv pip install --python {self.venv_interpreter}"
96+
return f"{self.venv}/bin/python -m pip install"
97+
98+
@cached_property
99+
def uv_available(self) -> bool:
100+
"""Return whether to use uv commands like venv or pip.
101+
102+
Returns:
103+
True if uv is to be used.
104+
"""
105+
if int(os.environ.get("SKIP_UV", "0")):
106+
self._output.debug("uv is disabled by SKIP_UV=1 in the environment.")
107+
return False
108+
109+
if not (uv_path := shutil.which("uv")):
110+
self._output.debug("uv is not available in the environment.")
111+
return False
112+
113+
self._output.debug(f"uv is available at {uv_path}")
114+
self._output.info(
115+
"uv is available and will be used instead of venv/pip. To disable that define SKIP_UV=1 in your environment.",
116+
)
117+
return True
118+
117119
@property
118120
def discovered_python_reqs(self) -> Path:
119121
"""Return the discovered python requirements file."""
@@ -174,18 +176,16 @@ def _set_interpreter(
174176
self,
175177
) -> None:
176178
"""Set the interpreter."""
177-
self.pip_cmd = f"{sys.executable} -m pip"
178-
self.venv_cmd = f"{sys.executable} -m venv"
179-
if use_uv():
180-
self.pip_cmd = f"{sys.executable} -m uv pip"
181-
# seed and python-preference make uv venv match python -m venv behavior:
182-
self.venv_cmd = f"{sys.executable} -m uv venv --seed --python-preference=system"
179+
if self.uv_available:
180+
venv_cmd = "uv venv --seed --python-preference=system"
181+
else:
182+
venv_cmd = f"{sys.executable} -m venv"
183183

184184
if not self.venv.exists():
185185
if self._create_venv:
186186
msg = f"Creating virtual environment: {self.venv}"
187187
self._output.debug(msg)
188-
command = f"{self.venv_cmd} {self.venv}"
188+
command = f"{venv_cmd} {self.venv}"
189189
msg = f"Creating virtual environment: {self.venv}"
190190
if self.args.system_site_packages:
191191
command = f"{command} --system-site-packages"

src/ansible_dev_environment/subcommands/checker.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import json
66
import subprocess
7+
import sys
78

89
from typing import TYPE_CHECKING
910

@@ -183,7 +184,7 @@ def system_deps(self) -> None:
183184
msg = "Checking system packages."
184185
self._output.info(msg)
185186

186-
command = f"bindep -b -f {self._config.discovered_bindep_reqs}"
187+
command = f"{sys.executable} -m bindep -b -f {self._config.discovered_bindep_reqs}"
187188
work = "Checking system package requirements"
188189
try:
189190
subprocess_run(

src/ansible_dev_environment/subcommands/installer.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def _install_core(self) -> None:
124124
return
125125
msg = "Installing ansible-core."
126126
self._output.debug(msg)
127-
command = f"{self._config.venv_interpreter} -m pip install ansible-core"
127+
command = f"{self._config.venv_pip_install_cmd} ansible-core"
128128
try:
129129
subprocess_run(
130130
command=command,
@@ -146,7 +146,7 @@ def _install_dev_tools(self) -> None:
146146
return
147147
msg = "Installing ansible-dev-tools."
148148
self._output.debug(msg)
149-
command = f"{self._config.venv_interpreter} -m pip install ansible-dev-tools"
149+
command = f"{self._config.venv_pip_install_cmd} ansible-dev-tools"
150150
try:
151151
subprocess_run(
152152
command=command,
@@ -522,7 +522,7 @@ def _pip_install(self) -> None:
522522
msg = "Installing python requirements."
523523
self._output.info(msg)
524524

525-
command = f"{self._config.pip_cmd} install -r {self._config.discovered_python_reqs}"
525+
command = f"{self._config.venv_pip_install_cmd} -r {self._config.discovered_python_reqs}"
526526

527527
msg = f"Installing python requirements from {self._config.discovered_python_reqs}"
528528
self._output.debug(msg)

tests/unit/test_config.py

+13-19
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ def test_paths(
5757
uv: bool,
5858
monkeypatch: pytest.MonkeyPatch,
5959
output: Output,
60-
caplog: pytest.LogCaptureFixture,
6160
) -> None:
6261
"""Test the paths.
6362
@@ -69,28 +68,23 @@ def test_paths(
6968
uv: Whether to use the uv module.
7069
monkeypatch: A pytest fixture for monkey patching.
7170
output: The output fixture.
72-
caplog: A pytest fixture for capturing logs.
7371
"""
74-
with caplog.at_level(10):
75-
monkeypatch.setenv("SKIP_UV", "0" if uv else "1")
76-
venv = tmpdir / "test_venv"
77-
args = gen_args(
78-
venv=str(venv),
79-
system_site_packages=system_site_packages,
80-
)
81-
82-
config = Config(args=args, output=output, term_features=output.term_features)
83-
config.init()
72+
monkeypatch.setenv("SKIP_UV", str(int(not uv)))
73+
venv = tmpdir / "test_venv"
74+
args = gen_args(
75+
venv=str(venv),
76+
system_site_packages=system_site_packages,
77+
)
78+
79+
config = Config(args=args, output=output, term_features=output.term_features)
80+
config.init()
8481

8582
if uv:
86-
assert len(caplog.messages) == 1
87-
assert "UV detected" in caplog.records[0].msg
88-
assert "-m uv venv" in config.venv_cmd
89-
assert "-m uv pip" in config.pip_cmd
83+
assert config.uv_available
84+
assert "uv pip install --python" in config.venv_pip_install_cmd
9085
else:
91-
assert len(caplog.messages) == 0
92-
assert "-m venv" in config.venv_cmd
93-
assert "-m pip" in config.pip_cmd
86+
assert not config.uv_available
87+
assert "-m pip install" in config.venv_pip_install_cmd
9488

9589
assert config.venv == venv
9690
for attr in (

0 commit comments

Comments
 (0)