isolate 0.12.15__tar.gz → 0.13.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.

Potentially problematic release.


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

Files changed (92) hide show
  1. {isolate-0.12.15 → isolate-0.13.0}/PKG-INFO +3 -2
  2. {isolate-0.12.15 → isolate-0.13.0}/pyproject.toml +4 -1
  3. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/_isolate_version.py +2 -2
  4. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/backends/common.py +5 -2
  5. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/backends/conda.py +1 -1
  6. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/backends/pyenv.py +2 -2
  7. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/backends/virtualenv.py +1 -1
  8. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/_local/_base.py +15 -6
  9. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/grpc/_base.py +7 -3
  10. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/grpc/agent.py +31 -36
  11. isolate-0.13.0/src/isolate/connections/grpc/definitions/agent_pb2.py +29 -0
  12. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/grpc/definitions/agent_pb2.pyi +8 -32
  13. isolate-0.13.0/src/isolate/connections/grpc/definitions/agent_pb2_grpc.py +104 -0
  14. isolate-0.13.0/src/isolate/connections/grpc/definitions/common_pb2.py +35 -0
  15. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/grpc/definitions/common_pb2.pyi +17 -84
  16. isolate-0.13.0/src/isolate/connections/grpc/definitions/common_pb2_grpc.py +29 -0
  17. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/ipc/_base.py +4 -15
  18. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/ipc/agent.py +29 -10
  19. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/server/definitions/server.proto +12 -0
  20. isolate-0.13.0/src/isolate/server/definitions/server_pb2.py +36 -0
  21. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/server/definitions/server_pb2.pyi +44 -52
  22. isolate-0.13.0/src/isolate/server/definitions/server_pb2_grpc.py +149 -0
  23. isolate-0.13.0/src/isolate/server/health/health_pb2.py +32 -0
  24. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/server/health/health_pb2.pyi +6 -14
  25. isolate-0.13.0/src/isolate/server/health/health_pb2_grpc.py +145 -0
  26. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/server/server.py +62 -26
  27. {isolate-0.12.15 → isolate-0.13.0}/src/isolate.egg-info/PKG-INFO +3 -2
  28. {isolate-0.12.15 → isolate-0.13.0}/src/isolate.egg-info/requires.txt +2 -1
  29. {isolate-0.12.15 → isolate-0.13.0}/tests/test_server.py +47 -7
  30. {isolate-0.12.15 → isolate-0.13.0}/tools/regen_grpc.py +12 -2
  31. isolate-0.12.15/src/isolate/connections/grpc/definitions/agent_pb2.py +0 -30
  32. isolate-0.12.15/src/isolate/connections/grpc/definitions/agent_pb2_grpc.py +0 -78
  33. isolate-0.12.15/src/isolate/connections/grpc/definitions/common_pb2.py +0 -38
  34. isolate-0.12.15/src/isolate/connections/grpc/definitions/common_pb2_grpc.py +0 -3
  35. isolate-0.12.15/src/isolate/server/definitions/server_pb2.py +0 -34
  36. isolate-0.12.15/src/isolate/server/definitions/server_pb2_grpc.py +0 -82
  37. isolate-0.12.15/src/isolate/server/health/health_pb2.py +0 -32
  38. isolate-0.12.15/src/isolate/server/health/health_pb2_grpc.py +0 -124
  39. {isolate-0.12.15 → isolate-0.13.0}/.github/workflows/release.yml +0 -0
  40. {isolate-0.12.15 → isolate-0.13.0}/.github/workflows/test.yml +0 -0
  41. {isolate-0.12.15 → isolate-0.13.0}/.gitignore +0 -0
  42. {isolate-0.12.15 → isolate-0.13.0}/.pre-commit-config.yaml +0 -0
  43. {isolate-0.12.15 → isolate-0.13.0}/LICENSE +0 -0
  44. {isolate-0.12.15 → isolate-0.13.0}/README.md +0 -0
  45. {isolate-0.12.15 → isolate-0.13.0}/setup.cfg +0 -0
  46. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/__init__.py +0 -0
  47. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/_version.py +0 -0
  48. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/backends/__init__.py +0 -0
  49. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/backends/_base.py +0 -0
  50. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/backends/container.py +0 -0
  51. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/backends/local.py +0 -0
  52. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/backends/remote.py +0 -0
  53. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/backends/settings.py +0 -0
  54. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/common/__init__.py +0 -0
  55. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/common/timestamp.py +0 -0
  56. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/__init__.py +0 -0
  57. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/_local/__init__.py +0 -0
  58. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/_local/agent_startup.py +0 -0
  59. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/common.py +0 -0
  60. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/grpc/__init__.py +0 -0
  61. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/grpc/configuration.py +0 -0
  62. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/grpc/definitions/__init__.py +0 -0
  63. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/grpc/definitions/agent.proto +0 -0
  64. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/grpc/definitions/common.proto +0 -0
  65. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/grpc/interface.py +0 -0
  66. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/connections/ipc/__init__.py +0 -0
  67. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/logs.py +0 -0
  68. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/py.typed +0 -0
  69. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/registry.py +0 -0
  70. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/server/__init__.py +0 -0
  71. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/server/definitions/__init__.py +0 -0
  72. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/server/health/__init__.py +0 -0
  73. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/server/health/health.proto +0 -0
  74. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/server/health_server.py +0 -0
  75. {isolate-0.12.15 → isolate-0.13.0}/src/isolate/server/interface.py +0 -0
  76. {isolate-0.12.15 → isolate-0.13.0}/src/isolate.egg-info/SOURCES.txt +0 -0
  77. {isolate-0.12.15 → isolate-0.13.0}/src/isolate.egg-info/dependency_links.txt +0 -0
  78. {isolate-0.12.15 → isolate-0.13.0}/src/isolate.egg-info/entry_points.txt +0 -0
  79. {isolate-0.12.15 → isolate-0.13.0}/src/isolate.egg-info/top_level.txt +0 -0
  80. {isolate-0.12.15 → isolate-0.13.0}/tests/__init__.py +0 -0
  81. {isolate-0.12.15 → isolate-0.13.0}/tests/conftest.py +0 -0
  82. {isolate-0.12.15 → isolate-0.13.0}/tests/test_backends.py +0 -0
  83. {isolate-0.12.15 → isolate-0.13.0}/tests/test_concurrency.py +0 -0
  84. {isolate-0.12.15 → isolate-0.13.0}/tests/test_connections.py +0 -0
  85. {isolate-0.12.15 → isolate-0.13.0}/tests/test_isolate.py +0 -0
  86. {isolate-0.12.15 → isolate-0.13.0}/tests/test_log.py +0 -0
  87. {isolate-0.12.15 → isolate-0.13.0}/tests/test_serialization.py +0 -0
  88. {isolate-0.12.15 → isolate-0.13.0}/tools/Dockerfile +0 -0
  89. {isolate-0.12.15 → isolate-0.13.0}/tools/agent_requirements.txt +0 -0
  90. {isolate-0.12.15 → isolate-0.13.0}/tools/protobuf-requirements.txt +0 -0
  91. {isolate-0.12.15 → isolate-0.13.0}/tools/requirements.txt +0 -0
  92. {isolate-0.12.15 → isolate-0.13.0}/tools/test_agent_requirements.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: isolate
3
- Version: 0.12.15
3
+ Version: 0.13.0
4
4
  Summary: Managed isolated environments for Python
5
5
  Author-email: Features & Labels <hello@fal.ai>
6
6
  Project-URL: Issues, https://github.com/fal-ai/isolate/issues
@@ -8,7 +8,7 @@ Project-URL: Source, https://github.com/fal-ai/isolate
8
8
  Requires-Python: >=3.8
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENSE
11
- Requires-Dist: grpcio>=1.49
11
+ Requires-Dist: grpcio==1.64.0
12
12
  Requires-Dist: protobuf
13
13
  Requires-Dist: tblib>=1.7.0
14
14
  Requires-Dist: platformdirs
@@ -24,6 +24,7 @@ Requires-Dist: dill>=0.3.5.1; extra == "test"
24
24
  Requires-Dist: pytest-rerunfailures; extra == "test"
25
25
  Provides-Extra: dev
26
26
  Requires-Dist: isolate[test]; extra == "dev"
27
+ Requires-Dist: grpcio-tools==1.64.0; extra == "dev"
27
28
 
28
29
  # Isolate
29
30
 
@@ -18,7 +18,9 @@ description = "Managed isolated environments for Python"
18
18
  authors = [{ name = "Features & Labels", email = "hello@fal.ai"}]
19
19
  requires-python = ">=3.8"
20
20
  dependencies = [
21
- "grpcio>=1.49",
21
+ # NOTE: make sure you re-generate python bindings (see tools/regen_grpc.py)
22
+ # when updating grpcio version.
23
+ "grpcio==1.64.0",
22
24
  "protobuf",
23
25
  # These are non-intrusive packages with no transitive dependencies.
24
26
  # They are also used in the agents themselves.
@@ -49,6 +51,7 @@ test = [
49
51
  ]
50
52
  dev = [
51
53
  "isolate[test]",
54
+ "grpcio-tools==1.64.0",
52
55
  ]
53
56
 
54
57
 
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.12.15'
16
- __version_tuple__ = version_tuple = (0, 12, 15)
15
+ __version__ = version = '0.13.0'
16
+ __version_tuple__ = version_tuple = (0, 13, 0)
@@ -171,23 +171,26 @@ def _unblocked_pipe() -> tuple[int, int]:
171
171
  def logged_io(
172
172
  stdout_hook: HookT,
173
173
  stderr_hook: HookT | None = None,
174
- ) -> Iterator[tuple[int, int]]:
174
+ log_hook: HookT | None = None,
175
+ ) -> Iterator[tuple[int, int, int]]:
175
176
  """Open two new streams (for stdout and stderr, respectively) and start relaying all
176
177
  the output from them to the given hooks."""
177
178
 
178
179
  stdout_reader_fd, stdout_writer_fd = _unblocked_pipe()
179
180
  stderr_reader_fd, stderr_writer_fd = _unblocked_pipe()
181
+ log_reader_fd, log_writer_fd = _unblocked_pipe()
180
182
 
181
183
  termination_event = threading.Event()
182
184
  io_observer = _io_observer(
183
185
  hooks={
184
186
  stdout_reader_fd: stdout_hook,
185
187
  stderr_reader_fd: stderr_hook or stdout_hook,
188
+ log_reader_fd: log_hook or stdout_hook,
186
189
  },
187
190
  termination_event=termination_event,
188
191
  )
189
192
  try:
190
- yield stdout_writer_fd, stderr_writer_fd
193
+ yield stdout_writer_fd, stderr_writer_fd, log_writer_fd
191
194
  finally:
192
195
  termination_event.set()
193
196
  try:
@@ -171,7 +171,7 @@ class CondaEnvironment(BaseEnvironment[Path]):
171
171
 
172
172
  def _run_conda(self, *args: Any) -> None:
173
173
  conda_executable = get_executable(self._exec_command, self._exec_home)
174
- with logged_io(partial(self.log, level=LogLevel.INFO)) as (stdout, stderr):
174
+ with logged_io(partial(self.log, level=LogLevel.INFO)) as (stdout, stderr, _):
175
175
  subprocess.check_call(
176
176
  [conda_executable, *args],
177
177
  stdout=stdout,
@@ -80,7 +80,7 @@ class PyenvEnvironment(BaseEnvironment[Path]):
80
80
  return Path(prefix.strip())
81
81
 
82
82
  def _install_python(self, pyenv: Path, root_path: Path) -> None:
83
- with logged_io(partial(self.log, level=LogLevel.INFO)) as (stdout, stderr):
83
+ with logged_io(partial(self.log, level=LogLevel.INFO)) as (stdout, stderr, _):
84
84
  try:
85
85
  subprocess.check_call(
86
86
  [pyenv, "install", "--skip-existing", self.python_version],
@@ -102,7 +102,7 @@ class PyenvEnvironment(BaseEnvironment[Path]):
102
102
  return None
103
103
 
104
104
  pyenv_root = connection_key.parent.parent
105
- with logged_io(self.log) as (stdout, stderr):
105
+ with logged_io(self.log) as (stdout, stderr, _):
106
106
  subprocess.check_call(
107
107
  [pyenv, "uninstall", "-f", connection_key.name],
108
108
  env={**os.environ, "PYENV_ROOT": str(pyenv_root)},
@@ -110,7 +110,7 @@ class VirtualPythonEnvironment(BaseEnvironment[Path]):
110
110
  for extra_index_url in self.extra_index_urls:
111
111
  pip_cmd.extend(["--extra-index-url", extra_index_url])
112
112
 
113
- with logged_io(partial(self.log, level=LogLevel.INFO)) as (stdout, stderr):
113
+ with logged_io(partial(self.log, level=LogLevel.INFO)) as (stdout, stderr, _):
114
114
  try:
115
115
  subprocess.check_call(
116
116
  pip_cmd,
@@ -17,7 +17,7 @@ from typing import (
17
17
 
18
18
  from isolate.backends.common import get_executable_path, logged_io
19
19
  from isolate.connections.common import AGENT_SIGNATURE
20
- from isolate.logs import LogLevel
20
+ from isolate.logs import LogLevel, LogSource
21
21
 
22
22
  if TYPE_CHECKING:
23
23
  from isolate.backends import BaseEnvironment
@@ -113,14 +113,22 @@ class PythonExecutionBase(Generic[ConnectionType]):
113
113
 
114
114
  python_executable = get_executable_path(self.environment_path, "python")
115
115
  with logged_io(
116
- partial(self.handle_agent_log, level=LogLevel.STDOUT),
117
- partial(self.handle_agent_log, level=LogLevel.STDERR),
118
- ) as (stdout, stderr):
116
+ partial(
117
+ self.handle_agent_log, source=LogSource.USER, level=LogLevel.STDOUT
118
+ ),
119
+ partial(
120
+ self.handle_agent_log, source=LogSource.USER, level=LogLevel.STDERR
121
+ ),
122
+ partial(
123
+ self.handle_agent_log, source=LogSource.BRIDGE, level=LogLevel.TRACE
124
+ ),
125
+ ) as (stdout, stderr, log_fd):
119
126
  yield subprocess.Popen(
120
- self.get_python_cmd(python_executable, connection),
127
+ self.get_python_cmd(python_executable, connection, log_fd),
121
128
  env=self.get_env_vars(),
122
129
  stdout=stdout,
123
130
  stderr=stderr,
131
+ pass_fds=(log_fd,),
124
132
  text=True,
125
133
  )
126
134
 
@@ -158,11 +166,12 @@ class PythonExecutionBase(Generic[ConnectionType]):
158
166
  self,
159
167
  executable: Path,
160
168
  connection: ConnectionType,
169
+ log_fd: int,
161
170
  ) -> list[str | Path]:
162
171
  """Return the command to run the agent process with."""
163
172
  raise NotImplementedError
164
173
 
165
- def handle_agent_log(self, line: str, level: LogLevel) -> None:
174
+ def handle_agent_log(self, line: str, level: LogLevel, source: LogSource) -> None:
166
175
  """Handle a log line emitted by the agent process. The level will be either
167
176
  STDOUT or STDERR."""
168
177
  raise NotImplementedError
@@ -36,7 +36,7 @@ class GRPCExecutionBase(EnvironmentConnection):
36
36
  def _establish_bridge(
37
37
  self,
38
38
  *,
39
- max_wait_timeout: float = 10.0,
39
+ max_wait_timeout: float = 20.0,
40
40
  ) -> Iterator[definitions.AgentStub]:
41
41
  with self.start_agent() as (address, credentials):
42
42
  with grpc.secure_channel(
@@ -136,13 +136,17 @@ class LocalPythonGRPC(PythonExecutionBase[str], GRPCExecutionBase):
136
136
  self,
137
137
  executable: Path,
138
138
  connection: str,
139
+ log_fd: int,
139
140
  ) -> List[Union[str, Path]]:
140
141
  return [
141
142
  executable,
142
143
  agent_startup.__file__,
143
144
  agent.__file__,
144
145
  connection,
146
+ "--log-fd",
147
+ str(log_fd),
145
148
  ]
146
149
 
147
- def handle_agent_log(self, line: str, level: LogLevel) -> None:
148
- self.log(line, level=level, source=LogSource.USER)
150
+ def handle_agent_log(self, line: str, level: LogLevel, source: LogSource) -> None:
151
+ print(f"[{source}] [{level}] {line}")
152
+ self.log(line, level=level, source=source)
@@ -2,16 +2,16 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import os
6
+ import sys
5
7
  import traceback
6
8
  from argparse import ArgumentParser
7
9
  from concurrent import futures
8
- from dataclasses import dataclass, field
10
+ from dataclasses import dataclass
9
11
  from typing import (
10
12
  Any,
11
- Generator,
12
13
  Iterable,
13
14
  Iterator,
14
- cast,
15
15
  )
16
16
 
17
17
  import grpc
@@ -21,8 +21,7 @@ from isolate.backends.common import sha256_digest_of
21
21
  from isolate.connections.common import SerializationError, serialize_object
22
22
  from isolate.connections.grpc import definitions
23
23
  from isolate.connections.grpc.configuration import get_default_options
24
- from isolate.connections.grpc.interface import from_grpc, to_grpc
25
- from isolate.logs import Log, LogLevel, LogSource
24
+ from isolate.connections.grpc.interface import from_grpc
26
25
 
27
26
 
28
27
  @dataclass
@@ -30,16 +29,19 @@ class AbortException(Exception):
30
29
  message: str
31
30
 
32
31
 
33
- @dataclass
34
32
  class AgentServicer(definitions.AgentServicer):
35
- _run_cache: dict[str, Any] = field(default_factory=dict)
33
+ def __init__(self, log_fd: int | None = None):
34
+ super().__init__()
35
+
36
+ self._run_cache: dict[str, Any] = {}
37
+ self._log = sys.stdout if log_fd is None else os.fdopen(log_fd, "w")
36
38
 
37
39
  def Run(
38
40
  self,
39
41
  request: definitions.FunctionCall,
40
42
  context: ServicerContext,
41
43
  ) -> Iterator[definitions.PartialRunResult]:
42
- yield from self.log(f"A connection has been established: {context.peer()}!")
44
+ self.log(f"A connection has been established: {context.peer()}!")
43
45
 
44
46
  extra_args = []
45
47
  if request.HasField("setup_func"):
@@ -53,16 +55,16 @@ class AgentServicer(definitions.AgentServicer):
53
55
  result,
54
56
  was_it_raised,
55
57
  stringized_tb,
56
- ) = yield from self.execute_function(
58
+ ) = self.execute_function(
57
59
  request.setup_func,
58
60
  "setup",
59
61
  )
60
62
 
61
63
  if was_it_raised:
62
- yield from self.log(
64
+ self.log(
63
65
  "The setup function has thrown an error. Aborting the run."
64
66
  )
65
- yield from self.send_object(
67
+ yield self.send_object(
66
68
  request.setup_func.method,
67
69
  result,
68
70
  was_it_raised,
@@ -78,12 +80,12 @@ class AgentServicer(definitions.AgentServicer):
78
80
  extra_args.append(self._run_cache[cache_key])
79
81
 
80
82
  try:
81
- result, was_it_raised, stringized_tb = yield from self.execute_function(
83
+ result, was_it_raised, stringized_tb = self.execute_function(
82
84
  request.function,
83
85
  "function",
84
86
  extra_args=extra_args,
85
87
  )
86
- yield from self.send_object(
88
+ yield self.send_object(
87
89
  request.function.method,
88
90
  result,
89
91
  was_it_raised,
@@ -98,7 +100,7 @@ class AgentServicer(definitions.AgentServicer):
98
100
  function_kind: str,
99
101
  *,
100
102
  extra_args: Iterable[Any] = (),
101
- ) -> Generator[definitions.PartialRunResult, None, Any]:
103
+ ) -> tuple[Any, bool, str | None]:
102
104
  if function.was_it_raised:
103
105
  raise AbortException(
104
106
  f"The {function_kind} function must be callable, "
@@ -110,7 +112,7 @@ class AgentServicer(definitions.AgentServicer):
110
112
  # depickling is basically involves code execution from the *user*.
111
113
  function = from_grpc(function)
112
114
  except SerializationError:
113
- yield from self.log(traceback.format_exc(), level=LogLevel.ERROR)
115
+ self.log(traceback.format_exc())
114
116
  raise AbortException(
115
117
  f"The {function_kind} function could not be deserialized."
116
118
  )
@@ -121,7 +123,7 @@ class AgentServicer(definitions.AgentServicer):
121
123
  f"not {type(function).__name__}."
122
124
  )
123
125
 
124
- yield from self.log(f"Starting the execution of the {function_kind} function.")
126
+ self.log(f"Starting the execution of the {function_kind} function.")
125
127
 
126
128
  was_it_raised = False
127
129
  stringized_tb = None
@@ -133,7 +135,7 @@ class AgentServicer(definitions.AgentServicer):
133
135
  num_frames = len(traceback.extract_stack()[:-5])
134
136
  stringized_tb = "".join(traceback.format_exc(limit=-num_frames))
135
137
 
136
- yield from self.log(f"Completed the execution of the {function_kind} function.")
138
+ self.log(f"Completed the execution of the {function_kind} function.")
137
139
  return result, was_it_raised, stringized_tb
138
140
 
139
141
  def send_object(
@@ -142,46 +144,38 @@ class AgentServicer(definitions.AgentServicer):
142
144
  result: object,
143
145
  was_it_raised: bool,
144
146
  stringized_tb: str | None,
145
- ) -> Generator[definitions.PartialRunResult, None, Any]:
147
+ ) -> definitions.PartialRunResult:
146
148
  try:
147
149
  definition = serialize_object(serialization_method, result)
148
150
  except SerializationError:
149
151
  if stringized_tb:
150
- yield from self.log(
151
- stringized_tb, source=LogSource.USER, level=LogLevel.STDERR
152
- )
152
+ print(stringized_tb, file=sys.stderr)
153
153
  raise AbortException(
154
154
  "Error while serializing the execution result "
155
155
  f"(object of type {type(result)})."
156
156
  )
157
157
  except BaseException:
158
- yield from self.log(traceback.format_exc(), level=LogLevel.ERROR)
158
+ self.log(traceback.format_exc())
159
159
  raise AbortException(
160
160
  "An unexpected error occurred while serializing the result."
161
161
  )
162
162
 
163
- yield from self.log("Sending the result.")
163
+ self.log("Sending the result.")
164
164
  serialized_obj = definitions.SerializedObject(
165
165
  method=serialization_method,
166
166
  definition=definition,
167
167
  was_it_raised=was_it_raised,
168
168
  stringized_traceback=stringized_tb,
169
169
  )
170
- yield definitions.PartialRunResult(
170
+ return definitions.PartialRunResult(
171
171
  result=serialized_obj,
172
172
  is_complete=True,
173
173
  logs=[],
174
174
  )
175
175
 
176
- def log(
177
- self,
178
- message: str,
179
- level: LogLevel = LogLevel.TRACE,
180
- source: LogSource = LogSource.BRIDGE,
181
- ) -> Iterator[definitions.PartialRunResult]:
182
- log = to_grpc(Log(message, level=level, source=source))
183
- log = cast(definitions.Log, log)
184
- yield definitions.PartialRunResult(result=None, is_complete=False, logs=[log])
176
+ def log(self, message: str) -> None:
177
+ self._log.write(message)
178
+ self._log.flush()
185
179
 
186
180
  def abort_with_msg(
187
181
  self,
@@ -211,10 +205,10 @@ def create_server(address: str) -> grpc.Server:
211
205
  return server
212
206
 
213
207
 
214
- def run_agent(address: str) -> int:
208
+ def run_agent(address: str, log_fd: int | None = None) -> int:
215
209
  """Run the agent servicer on the given address."""
216
210
  server = create_server(address)
217
- servicer = AgentServicer()
211
+ servicer = AgentServicer(log_fd=log_fd)
218
212
 
219
213
  # This function just calls some methods on the server
220
214
  # and register a generic handler for the bridge. It does
@@ -229,9 +223,10 @@ def run_agent(address: str) -> int:
229
223
  def main() -> int:
230
224
  parser = ArgumentParser()
231
225
  parser.add_argument("address", type=str)
226
+ parser.add_argument("--log-fd", type=int)
232
227
 
233
228
  options = parser.parse_args()
234
- return run_agent(options.address)
229
+ return run_agent(options.address, log_fd=options.log_fd)
235
230
 
236
231
 
237
232
  if __name__ == "__main__":
@@ -0,0 +1,29 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: agent.proto
4
+ # Protobuf Python Version: 5.26.1
5
+ """Generated protocol buffer code."""
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ from google.protobuf.internal import builder as _builder
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+
15
+ from isolate.connections.grpc.definitions import common_pb2 as common__pb2
16
+
17
+
18
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0b\x61gent.proto\x1a\x0c\x63ommon.proto\"n\n\x0c\x46unctionCall\x12#\n\x08\x66unction\x18\x01 \x01(\x0b\x32\x11.SerializedObject\x12*\n\nsetup_func\x18\x02 \x01(\x0b\x32\x11.SerializedObjectH\x00\x88\x01\x01\x42\r\n\x0b_setup_func24\n\x05\x41gent\x12+\n\x03Run\x12\r.FunctionCall\x1a\x11.PartialRunResult\"\x00\x30\x01\x62\x06proto3')
19
+
20
+ _globals = globals()
21
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
22
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'agent_pb2', _globals)
23
+ if not _descriptor._USE_C_DESCRIPTORS:
24
+ DESCRIPTOR._loaded_options = None
25
+ _globals['_FUNCTIONCALL']._serialized_start=29
26
+ _globals['_FUNCTIONCALL']._serialized_end=139
27
+ _globals['_AGENT']._serialized_start=141
28
+ _globals['_AGENT']._serialized_end=193
29
+ # @@protoc_insertion_point(module_scope)
@@ -2,20 +2,16 @@
2
2
  @generated by mypy-protobuf. Do not edit manually!
3
3
  isort:skip_file
4
4
  """
5
+
5
6
  import builtins
6
7
  from isolate.connections.grpc.definitions import common_pb2
7
8
  import google.protobuf.descriptor
8
9
  import google.protobuf.message
9
- import sys
10
-
11
- if sys.version_info >= (3, 8):
12
- import typing as typing_extensions
13
- else:
14
- import typing_extensions
10
+ import typing
15
11
 
16
12
  DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
17
13
 
18
- @typing_extensions.final
14
+ @typing.final
19
15
  class FunctionCall(google.protobuf.message.Message):
20
16
  DESCRIPTOR: google.protobuf.descriptor.Descriptor
21
17
 
@@ -24,6 +20,7 @@ class FunctionCall(google.protobuf.message.Message):
24
20
  @property
25
21
  def function(self) -> common_pb2.SerializedObject:
26
22
  """The function to execute and return the results to."""
23
+
27
24
  @property
28
25
  def setup_func(self) -> common_pb2.SerializedObject:
29
26
  """Optionally the setup function which will be passed
@@ -31,36 +28,15 @@ class FunctionCall(google.protobuf.message.Message):
31
28
  has to be an idempotent step since the result for
32
29
  this executable will be cached.
33
30
  """
31
+
34
32
  def __init__(
35
33
  self,
36
34
  *,
37
35
  function: common_pb2.SerializedObject | None = ...,
38
36
  setup_func: common_pb2.SerializedObject | None = ...,
39
37
  ) -> None: ...
40
- def HasField(
41
- self,
42
- field_name: typing_extensions.Literal[
43
- "_setup_func",
44
- b"_setup_func",
45
- "function",
46
- b"function",
47
- "setup_func",
48
- b"setup_func",
49
- ],
50
- ) -> builtins.bool: ...
51
- def ClearField(
52
- self,
53
- field_name: typing_extensions.Literal[
54
- "_setup_func",
55
- b"_setup_func",
56
- "function",
57
- b"function",
58
- "setup_func",
59
- b"setup_func",
60
- ],
61
- ) -> None: ...
62
- def WhichOneof(
63
- self, oneof_group: typing_extensions.Literal["_setup_func", b"_setup_func"]
64
- ) -> typing_extensions.Literal["setup_func"] | None: ...
38
+ def HasField(self, field_name: typing.Literal["_setup_func", b"_setup_func", "function", b"function", "setup_func", b"setup_func"]) -> builtins.bool: ...
39
+ def ClearField(self, field_name: typing.Literal["_setup_func", b"_setup_func", "function", b"function", "setup_func", b"setup_func"]) -> None: ...
40
+ def WhichOneof(self, oneof_group: typing.Literal["_setup_func", b"_setup_func"]) -> typing.Literal["setup_func"] | None: ...
65
41
 
66
42
  global___FunctionCall = FunctionCall
@@ -0,0 +1,104 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+ import warnings
5
+
6
+ from isolate.connections.grpc.definitions import agent_pb2 as agent__pb2
7
+ from isolate.connections.grpc.definitions import common_pb2 as common__pb2
8
+
9
+ GRPC_GENERATED_VERSION = '1.64.0'
10
+ GRPC_VERSION = grpc.__version__
11
+ EXPECTED_ERROR_RELEASE = '1.65.0'
12
+ SCHEDULED_RELEASE_DATE = 'June 25, 2024'
13
+ _version_not_supported = False
14
+
15
+ try:
16
+ from grpc._utilities import first_version_is_lower
17
+ _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
18
+ except ImportError:
19
+ _version_not_supported = True
20
+
21
+ if _version_not_supported:
22
+ warnings.warn(
23
+ f'The grpc package installed is at version {GRPC_VERSION},'
24
+ + f' but the generated code in agent_pb2_grpc.py depends on'
25
+ + f' grpcio>={GRPC_GENERATED_VERSION}.'
26
+ + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
27
+ + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
28
+ + f' This warning will become an error in {EXPECTED_ERROR_RELEASE},'
29
+ + f' scheduled for release on {SCHEDULED_RELEASE_DATE}.',
30
+ RuntimeWarning
31
+ )
32
+
33
+
34
+ class AgentStub(object):
35
+ """Missing associated documentation comment in .proto file."""
36
+
37
+ def __init__(self, channel):
38
+ """Constructor.
39
+
40
+ Args:
41
+ channel: A grpc.Channel.
42
+ """
43
+ self.Run = channel.unary_stream(
44
+ '/Agent/Run',
45
+ request_serializer=agent__pb2.FunctionCall.SerializeToString,
46
+ response_deserializer=common__pb2.PartialRunResult.FromString,
47
+ _registered_method=True)
48
+
49
+
50
+ class AgentServicer(object):
51
+ """Missing associated documentation comment in .proto file."""
52
+
53
+ def Run(self, request, context):
54
+ """Start running the given function, and stream results back.
55
+ """
56
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
57
+ context.set_details('Method not implemented!')
58
+ raise NotImplementedError('Method not implemented!')
59
+
60
+
61
+ def add_AgentServicer_to_server(servicer, server):
62
+ rpc_method_handlers = {
63
+ 'Run': grpc.unary_stream_rpc_method_handler(
64
+ servicer.Run,
65
+ request_deserializer=agent__pb2.FunctionCall.FromString,
66
+ response_serializer=common__pb2.PartialRunResult.SerializeToString,
67
+ ),
68
+ }
69
+ generic_handler = grpc.method_handlers_generic_handler(
70
+ 'Agent', rpc_method_handlers)
71
+ server.add_generic_rpc_handlers((generic_handler,))
72
+ server.add_registered_method_handlers('Agent', rpc_method_handlers)
73
+
74
+
75
+ # This class is part of an EXPERIMENTAL API.
76
+ class Agent(object):
77
+ """Missing associated documentation comment in .proto file."""
78
+
79
+ @staticmethod
80
+ def Run(request,
81
+ target,
82
+ options=(),
83
+ channel_credentials=None,
84
+ call_credentials=None,
85
+ insecure=False,
86
+ compression=None,
87
+ wait_for_ready=None,
88
+ timeout=None,
89
+ metadata=None):
90
+ return grpc.experimental.unary_stream(
91
+ request,
92
+ target,
93
+ '/Agent/Run',
94
+ agent__pb2.FunctionCall.SerializeToString,
95
+ common__pb2.PartialRunResult.FromString,
96
+ options,
97
+ channel_credentials,
98
+ insecure,
99
+ call_credentials,
100
+ compression,
101
+ wait_for_ready,
102
+ timeout,
103
+ metadata,
104
+ _registered_method=True)
@@ -0,0 +1,35 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: common.proto
4
+ # Protobuf Python Version: 5.26.1
5
+ """Generated protocol buffer code."""
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ from google.protobuf.internal import builder as _builder
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+
15
+ from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
16
+
17
+
18
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x63ommon.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x89\x01\n\x10SerializedObject\x12\x0e\n\x06method\x18\x01 \x01(\t\x12\x12\n\ndefinition\x18\x02 \x01(\x0c\x12\x15\n\rwas_it_raised\x18\x03 \x01(\x08\x12!\n\x14stringized_traceback\x18\x04 \x01(\tH\x00\x88\x01\x01\x42\x17\n\x15_stringized_traceback\"n\n\x10PartialRunResult\x12\x13\n\x0bis_complete\x18\x01 \x01(\x08\x12\x12\n\x04logs\x18\x02 \x03(\x0b\x32\x04.Log\x12&\n\x06result\x18\x03 \x01(\x0b\x32\x11.SerializedObjectH\x00\x88\x01\x01\x42\t\n\x07_result\"{\n\x03Log\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x1a\n\x06source\x18\x02 \x01(\x0e\x32\n.LogSource\x12\x18\n\x05level\x18\x03 \x01(\x0e\x32\t.LogLevel\x12-\n\ttimestamp\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp*.\n\tLogSource\x12\x0b\n\x07\x42UILDER\x10\x00\x12\n\n\x06\x42RIDGE\x10\x01\x12\x08\n\x04USER\x10\x02*Z\n\x08LogLevel\x12\t\n\x05TRACE\x10\x00\x12\t\n\x05\x44\x45\x42UG\x10\x01\x12\x08\n\x04INFO\x10\x02\x12\x0b\n\x07WARNING\x10\x03\x12\t\n\x05\x45RROR\x10\x04\x12\n\n\x06STDOUT\x10\x05\x12\n\n\x06STDERR\x10\x06\x62\x06proto3')
19
+
20
+ _globals = globals()
21
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
22
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'common_pb2', _globals)
23
+ if not _descriptor._USE_C_DESCRIPTORS:
24
+ DESCRIPTOR._loaded_options = None
25
+ _globals['_LOGSOURCE']._serialized_start=426
26
+ _globals['_LOGSOURCE']._serialized_end=472
27
+ _globals['_LOGLEVEL']._serialized_start=474
28
+ _globals['_LOGLEVEL']._serialized_end=564
29
+ _globals['_SERIALIZEDOBJECT']._serialized_start=50
30
+ _globals['_SERIALIZEDOBJECT']._serialized_end=187
31
+ _globals['_PARTIALRUNRESULT']._serialized_start=189
32
+ _globals['_PARTIALRUNRESULT']._serialized_end=299
33
+ _globals['_LOG']._serialized_start=301
34
+ _globals['_LOG']._serialized_end=424
35
+ # @@protoc_insertion_point(module_scope)