isolate 0.12.3__tar.gz → 0.12.5__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.

Potentially problematic release.


This version of isolate might be problematic. Click here for more details.

Files changed (53) hide show
  1. {isolate-0.12.3 → isolate-0.12.5}/PKG-INFO +1 -3
  2. {isolate-0.12.3 → isolate-0.12.5}/README.md +0 -2
  3. {isolate-0.12.3 → isolate-0.12.5}/pyproject.toml +1 -1
  4. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/backends/common.py +15 -0
  5. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/backends/conda.py +6 -19
  6. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/backends/virtualenv.py +32 -1
  7. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/server/server.py +3 -1
  8. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/__init__.py +0 -0
  9. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/backends/__init__.py +0 -0
  10. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/backends/_base.py +0 -0
  11. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/backends/local.py +0 -0
  12. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/backends/pyenv.py +0 -0
  13. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/backends/remote.py +0 -0
  14. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/backends/settings.py +0 -0
  15. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/common/__init__.py +0 -0
  16. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/common/timestamp.py +0 -0
  17. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/__init__.py +0 -0
  18. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/_local/__init__.py +0 -0
  19. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/_local/_base.py +0 -0
  20. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/_local/agent_startup.py +0 -0
  21. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/common.py +1 -1
  22. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/grpc/__init__.py +0 -0
  23. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/grpc/_base.py +0 -0
  24. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/grpc/agent.py +0 -0
  25. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/grpc/configuration.py +0 -0
  26. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/grpc/definitions/__init__.py +0 -0
  27. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/grpc/definitions/agent.proto +0 -0
  28. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/grpc/definitions/agent_pb2.py +0 -0
  29. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/grpc/definitions/agent_pb2.pyi +0 -0
  30. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/grpc/definitions/agent_pb2_grpc.py +0 -0
  31. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/grpc/definitions/common.proto +0 -0
  32. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/grpc/definitions/common_pb2.py +0 -0
  33. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/grpc/definitions/common_pb2.pyi +0 -0
  34. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/grpc/definitions/common_pb2_grpc.py +0 -0
  35. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/grpc/interface.py +0 -0
  36. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/ipc/__init__.py +0 -0
  37. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/ipc/_base.py +0 -0
  38. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/connections/ipc/agent.py +0 -0
  39. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/logs.py +0 -0
  40. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/registry.py +0 -0
  41. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/server/__init__.py +0 -0
  42. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/server/definitions/__init__.py +0 -0
  43. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/server/definitions/server.proto +0 -0
  44. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/server/definitions/server_pb2.py +0 -0
  45. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/server/definitions/server_pb2.pyi +0 -0
  46. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/server/definitions/server_pb2_grpc.py +0 -0
  47. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/server/health/__init__.py +0 -0
  48. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/server/health/health.proto +0 -0
  49. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/server/health/health_pb2.py +0 -0
  50. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/server/health/health_pb2.pyi +0 -0
  51. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/server/health/health_pb2_grpc.py +0 -0
  52. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/server/health_server.py +0 -0
  53. {isolate-0.12.3 → isolate-0.12.5}/src/isolate/server/interface.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: isolate
3
- Version: 0.12.3
3
+ Version: 0.12.5
4
4
  Summary: Managed isolated environments for Python
5
5
  Author: Features & Labels
6
6
  Author-email: hello@fal.ai
@@ -25,8 +25,6 @@ Description-Content-Type: text/markdown
25
25
 
26
26
  # Isolate
27
27
 
28
- > :warning: **Isolate** is still very young, and none of the APIs should be considered stable.
29
-
30
28
  Run any Python function, with any dependencies, in any machine you want. Isolate offers a
31
29
  pluggable end-to-end solution for building, managing, and using isolated environments (virtualenv,
32
30
  conda, remote, and more).
@@ -1,7 +1,5 @@
1
1
  # Isolate
2
2
 
3
- > :warning: **Isolate** is still very young, and none of the APIs should be considered stable.
4
-
5
3
  Run any Python function, with any dependencies, in any machine you want. Isolate offers a
6
4
  pluggable end-to-end solution for building, managing, and using isolated environments (virtualenv,
7
5
  conda, remote, and more).
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "isolate"
3
- version = "0.12.3"
3
+ version = "0.12.5"
4
4
  readme = "README.md"
5
5
  description = "Managed isolated environments for Python"
6
6
  authors = ["Features & Labels <hello@fal.ai>"]
@@ -238,3 +238,18 @@ def optional_import(module_name: str) -> ModuleType:
238
238
  f"accessing {module_name!r} import functionality. Please try: "
239
239
  f"'$ pip install \"isolate[build]\"' to install it."
240
240
  ) from exc
241
+
242
+
243
+ @lru_cache(4)
244
+ def get_executable(command: str, home: str | None = None) -> Path:
245
+ for path in [home, None]:
246
+ binary_path = shutil.which(command, path=path)
247
+ if binary_path is not None:
248
+ return Path(binary_path)
249
+ else:
250
+ # TODO: we should probably show some instructions on how you
251
+ # can install conda here.
252
+ raise FileNotFoundError(
253
+ f"Could not find {command} executable. If {command} executable is not available by default, please point isolate "
254
+ f" to the path where conda binary is available '{home}'."
255
+ )
@@ -14,6 +14,7 @@ from typing import Any, ClassVar, Dict, List, Optional, Union
14
14
  from isolate.backends import BaseEnvironment, EnvironmentCreationError
15
15
  from isolate.backends.common import (
16
16
  active_python,
17
+ get_executable,
17
18
  logged_io,
18
19
  optional_import,
19
20
  sha256_digest_of,
@@ -48,7 +49,6 @@ class CondaEnvironment(BaseEnvironment[Path]):
48
49
  _exec_home: Optional[str] = _ISOLATE_MAMBA_HOME
49
50
  _exec_command: Optional[str] = _MAMBA_COMMAND
50
51
 
51
-
52
52
  @classmethod
53
53
  def from_config(
54
54
  cls,
@@ -162,15 +162,17 @@ class CondaEnvironment(BaseEnvironment[Path]):
162
162
 
163
163
  def _run_create(self, env_path: str, env_name: str) -> None:
164
164
  if self._exec_command == "conda":
165
- self._run_conda("env", "create", "--force", "--prefix", env_path, "-f", env_name)
165
+ self._run_conda(
166
+ "env", "create", "--force", "--prefix", env_path, "-f", env_name
167
+ )
166
168
  else:
167
169
  self._run_conda("env", "create", "--prefix", env_path, "-f", env_name)
168
170
 
169
171
  def _run_destroy(self, connection_key: str) -> None:
170
- self._run_conda("remove","--yes","--all","--prefix", connection_key)
172
+ self._run_conda("remove", "--yes", "--all", "--prefix", connection_key)
171
173
 
172
174
  def _run_conda(self, *args: Any) -> None:
173
- conda_executable = _get_executable(self._exec_command, self._exec_home)
175
+ conda_executable = get_executable(self._exec_command, self._exec_home)
174
176
  with logged_io(partial(self.log, level=LogLevel.INFO)) as (stdout, stderr):
175
177
  subprocess.check_call(
176
178
  [conda_executable, *args],
@@ -186,21 +188,6 @@ class CondaEnvironment(BaseEnvironment[Path]):
186
188
  return PythonIPC(self, connection_key)
187
189
 
188
190
 
189
- @functools.lru_cache(1)
190
- def _get_executable(command: str, home: str | None = None) -> Path:
191
- for path in [home, None]:
192
- conda_path = shutil.which(command, path=path)
193
- if conda_path is not None:
194
- return Path(conda_path)
195
- else:
196
- # TODO: we should probably show some instructions on how you
197
- # can install conda here.
198
- raise FileNotFoundError(
199
- "Could not find conda executable. If conda executable is not available by default, please point isolate "
200
- " to the path where conda binary is available 'ISOLATE_CONDA_HOME'."
201
- )
202
-
203
-
204
191
  def _depends_on(
205
192
  dependencies: List[Union[str, Dict[str, List[str]]]],
206
193
  package_name: str,
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import os
4
+ import shlex
4
5
  import shutil
5
6
  import subprocess
6
7
  from dataclasses import dataclass, field
@@ -11,6 +12,7 @@ from typing import Any, ClassVar, Dict, List, Optional, Union
11
12
  from isolate.backends import BaseEnvironment, EnvironmentCreationError
12
13
  from isolate.backends.common import (
13
14
  active_python,
15
+ get_executable,
14
16
  get_executable_path,
15
17
  logged_io,
16
18
  optional_import,
@@ -20,6 +22,9 @@ from isolate.backends.settings import DEFAULT_SETTINGS, IsolateSettings
20
22
  from isolate.connections import PythonIPC
21
23
  from isolate.logs import LogLevel
22
24
 
25
+ _UV_RESOLVER_EXECUTABLE = os.environ.get("ISOLATE_UV_EXE", "uv")
26
+ _UV_RESOLVER_HOME = os.getenv("ISOLATE_UV_HOME")
27
+
23
28
 
24
29
  @dataclass
25
30
  class VirtualPythonEnvironment(BaseEnvironment[Path]):
@@ -30,6 +35,7 @@ class VirtualPythonEnvironment(BaseEnvironment[Path]):
30
35
  python_version: Optional[str] = None
31
36
  extra_index_urls: List[str] = field(default_factory=list)
32
37
  tags: List[str] = field(default_factory=list)
38
+ resolver: Optional[str] = None
33
39
 
34
40
  @classmethod
35
41
  def from_config(
@@ -39,6 +45,10 @@ class VirtualPythonEnvironment(BaseEnvironment[Path]):
39
45
  ) -> BaseEnvironment:
40
46
  environment = cls(**config)
41
47
  environment.apply_settings(settings)
48
+ if environment.resolver not in ("uv", None):
49
+ raise ValueError(
50
+ "Only 'uv' is supported as a resolver for virtualenv environments."
51
+ )
42
52
  return environment
43
53
 
44
54
  @property
@@ -49,6 +59,10 @@ class VirtualPythonEnvironment(BaseEnvironment[Path]):
49
59
  else:
50
60
  constraints = []
51
61
 
62
+ extras = []
63
+ if self.resolver is not None:
64
+ extras.append(f"resolver={self.resolver}")
65
+
52
66
  active_python_version = self.python_version or active_python()
53
67
  return sha256_digest_of(
54
68
  active_python_version,
@@ -56,6 +70,9 @@ class VirtualPythonEnvironment(BaseEnvironment[Path]):
56
70
  *constraints,
57
71
  *self.extra_index_urls,
58
72
  *sorted(self.tags),
73
+ # This is backwards compatible with environments not using
74
+ # the 'resolver' field.
75
+ *extras,
59
76
  )
60
77
 
61
78
  def install_requirements(self, path: Path) -> None:
@@ -69,9 +86,22 @@ class VirtualPythonEnvironment(BaseEnvironment[Path]):
69
86
  return None
70
87
 
71
88
  self.log(f"Installing requirements: {', '.join(self.requirements)}")
89
+ environ = os.environ.copy()
90
+
91
+ if self.resolver == "uv":
92
+ # Set VIRTUAL_ENV to the actual path of the environment since that is
93
+ # how uv discovers the environment. This is necessary when using uv
94
+ # as the resolver.
95
+ environ["VIRTUAL_ENV"] = str(path)
96
+ base_pip_cmd = [
97
+ get_executable(_UV_RESOLVER_EXECUTABLE, _UV_RESOLVER_HOME),
98
+ "pip",
99
+ ]
100
+ else:
101
+ base_pip_cmd = [get_executable_path(path, "pip")]
72
102
 
73
103
  pip_cmd: List[Union[str, os.PathLike]] = [
74
- get_executable_path(path, "pip"),
104
+ *base_pip_cmd, # type: ignore
75
105
  "install",
76
106
  *self.requirements,
77
107
  ]
@@ -87,6 +117,7 @@ class VirtualPythonEnvironment(BaseEnvironment[Path]):
87
117
  pip_cmd,
88
118
  stdout=stdout,
89
119
  stderr=stderr,
120
+ env=environ,
90
121
  )
91
122
  except subprocess.SubprocessError as exc:
92
123
  raise EnvironmentCreationError(f"Failure during 'pip install': {exc}")
@@ -134,7 +134,9 @@ class BridgeManager:
134
134
  agent.terminate()
135
135
 
136
136
  bound_context = ExitStack()
137
- stub = bound_context.enter_context(connection._establish_bridge(max_wait_timeout=MAX_GRPC_WAIT_TIMEOUT))
137
+ stub = bound_context.enter_context(
138
+ connection._establish_bridge(max_wait_timeout=MAX_GRPC_WAIT_TIMEOUT)
139
+ )
138
140
  return RunnerAgent(stub, queue, bound_context)
139
141
 
140
142
  def _identify(self, connection: LocalPythonGRPC) -> Tuple[Any, ...]:
@@ -2,8 +2,8 @@ from __future__ import annotations
2
2
 
3
3
  import importlib
4
4
  import os
5
- from dataclasses import dataclass
6
5
  from contextlib import contextmanager
6
+ from dataclasses import dataclass
7
7
  from typing import TYPE_CHECKING, Any, Iterator, Optional, cast
8
8
 
9
9
  from tblib import Traceback, TracebackParseError
File without changes