Skip to content

Commit d709ab5

Browse files
committed
Merge branch 'main' into hanch/infra-220-timeout
2 parents 29bca03 + c43d3c2 commit d709ab5

File tree

5 files changed

+96
-12
lines changed

5 files changed

+96
-12
lines changed

.github/workflows/lint.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Lint
2+
3+
permissions:
4+
contents: read
5+
6+
on:
7+
push:
8+
branches:
9+
- main
10+
pull_request:
11+
branches:
12+
schedule:
13+
- cron: '30 5 * * *' # every day at 5:30 UTC
14+
15+
concurrency:
16+
group: ${{ github.workflow }}-${{ github.ref }}
17+
cancel-in-progress: true
18+
19+
jobs:
20+
lint:
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v3
24+
25+
- uses: actions/setup-python@v3
26+
with:
27+
python-version: "3.11"
28+
29+
- name: Install dependencies
30+
run: |
31+
python -m pip install -e ".[test]"
32+
33+
- name: Install uv
34+
run: |
35+
python -m pip install uv
36+
37+
- uses: pre-commit/action@v3.0.1

.github/workflows/test.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ jobs:
6060
run: |
6161
python -m pip install uv
6262
63-
- uses: pre-commit/action@v3.0.1
64-
6563
- name: Test
6664
run: |
6765
export ISOLATE_PYENV_EXECUTABLE=pyenv/bin/pyenv

src/isolate/backends/container.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class ContainerizedPythonEnvironment(BaseEnvironment[Path]):
1818
image: dict[str, Any] = field(default_factory=dict)
1919
python_version: str | None = None
2020
requirements: list[str] = field(default_factory=list)
21+
install_requirements: list[str] = field(default_factory=list)
2122
tags: list[str] = field(default_factory=list)
2223
resolver: str | None = None
2324

@@ -46,6 +47,7 @@ def key(self) -> str:
4647
dockerfile_str = self.image.get("dockerfile_str", "")
4748
return sha256_digest_of(
4849
dockerfile_str,
50+
*self.install_requirements,
4951
*self.requirements,
5052
*sorted(self.tags),
5153
*extras,

src/isolate/backends/virtualenv.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class VirtualPythonEnvironment(BaseEnvironment[Path]):
3030
BACKEND_NAME: ClassVar[str] = "virtualenv"
3131

3232
requirements: list[str] = field(default_factory=list)
33+
install_requirements: list[str] = field(default_factory=list)
3334
constraints_file: os.PathLike | None = None
3435
python_version: str | None = None
3536
extra_index_urls: list[str] = field(default_factory=list)
@@ -65,6 +66,7 @@ def key(self) -> str:
6566
active_python_version = self.python_version or active_python()
6667
return sha256_digest_of(
6768
active_python_version,
69+
*self.install_requirements,
6870
*self.requirements,
6971
*constraints,
7072
*self.extra_index_urls,
@@ -74,17 +76,17 @@ def key(self) -> str:
7476
*extras,
7577
)
7678

77-
def install_requirements(self, path: Path) -> None:
79+
def _install_packages(self, path: Path, requirements: list[str]) -> None:
7880
"""Install the requirements of this environment using 'pip' to the
7981
given virtualenv path.
8082
8183
If there are any constraint files specified, they will be also passed to
8284
the package resolver.
8385
"""
84-
if not self.requirements:
86+
if not requirements:
8587
return None
8688

87-
self.log(f"Installing requirements: {', '.join(self.requirements)}")
89+
self.log(f"Installing requirements: {', '.join(requirements)}")
8890
environ = os.environ.copy()
8991

9092
if self.resolver == "uv":
@@ -102,7 +104,7 @@ def install_requirements(self, path: Path) -> None:
102104
pip_cmd: list[str | os.PathLike] = [
103105
*base_pip_cmd, # type: ignore
104106
"install",
105-
*self.requirements,
107+
*requirements,
106108
]
107109
if self.constraints_file:
108110
pip_cmd.extend(["-c", self.constraints_file])
@@ -125,8 +127,8 @@ def _install_python_through_pyenv(self) -> str:
125127
from isolate.backends.pyenv import PyenvEnvironment
126128

127129
self.log(
128-
f"Requested Python version of {self.python_version} is not available "
129-
"in the system, attempting to install it through pyenv."
130+
f"Requested Python version of {self.python_version} is not available,"
131+
"attempting to install it through pyenv."
130132
)
131133

132134
pyenv = PyenvEnvironment.from_config(
@@ -147,8 +149,10 @@ def _decide_python(self) -> str:
147149
_get_pyenv_executable()
148150
except Exception:
149151
raise EnvironmentCreationError(
150-
f"Python {self.python_version} is not available in your "
151-
"system. Please install it first."
152+
f"Your local Python version {self.python_version} is not "
153+
"available in the app environment. "
154+
"Please either downgrade your local version of Python or use a Docker "
155+
f"image with Python {self.python_version}."
152156
) from None
153157
else:
154158
return self._install_python_through_pyenv()
@@ -181,7 +185,8 @@ def create(self, *, force: bool = False) -> Path:
181185
f"Failed to create the environment at '{venv_path}': {exc}"
182186
)
183187

184-
self.install_requirements(venv_path)
188+
self._install_packages(venv_path, self.install_requirements)
189+
self._install_packages(venv_path, self.requirements)
185190
completion_marker.touch()
186191

187192
self.log(f"New environment cached at '{venv_path}'")

tests/test_backends.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,11 @@ def test_invalid_python_version_raises(self, tmp_path, monkeypatch):
362362
environment = self.get_environment(tmp_path, {"python_version": "9.9.9"})
363363
with pytest.raises(
364364
EnvironmentCreationError,
365-
match="Python 9.9.9 is not available",
365+
match=(
366+
"Your local Python version 9.9.9 is not available in the app "
367+
"environment. Please either downgrade your local version of "
368+
"Python or use a Docker image with Python 9.9.9"
369+
),
366370
):
367371
environment.create()
368372

@@ -388,6 +392,44 @@ def test_tags_in_key(self, tmp_path, monkeypatch):
388392
tagged_environment.key == tagged_environment_2.key
389393
), "Tag order should not matter"
390394

395+
def test_install_requirements_in_key(self, tmp_path):
396+
base = self.get_environment(tmp_path, {"requirements": ["pyjokes==0.6.0"]})
397+
with_install = self.get_environment(
398+
tmp_path,
399+
{
400+
"requirements": ["pyjokes==0.6.0"],
401+
"install_requirements": ["pip==23.0.1"],
402+
},
403+
)
404+
assert base.key != with_install.key
405+
406+
def test_install_requirements_order(self, tmp_path, monkeypatch):
407+
installed = []
408+
409+
def fake_install_packages(self, path, requirements):
410+
installed.append(list(requirements))
411+
412+
class DummyVirtualenv:
413+
@staticmethod
414+
def cli_run(args):
415+
Path(args[0]).mkdir(parents=True, exist_ok=True)
416+
417+
monkeypatch.setattr(
418+
"isolate.backends.virtualenv.optional_import", lambda _: DummyVirtualenv
419+
)
420+
monkeypatch.setattr(
421+
VirtualPythonEnvironment, "_install_packages", fake_install_packages
422+
)
423+
424+
environment = VirtualPythonEnvironment(
425+
requirements=["pyjokes==0.6.0"],
426+
install_requirements=["pip==23.0.1"],
427+
)
428+
environment.apply_settings(IsolateSettings(Path(tmp_path)))
429+
environment.create()
430+
431+
assert installed == [["pip==23.0.1"], ["pyjokes==0.6.0"]]
432+
391433
@pytest.mark.skipif(not UV_PATH, reason="uv is not available")
392434
def test_try_using_uv(self, tmp_path):
393435
environment = self.get_environment(

0 commit comments

Comments
 (0)