isolate 0.26.0__tar.gz → 0.26.2__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.
Files changed (96) hide show
  1. isolate-0.26.2/.github/workflows/test.yml +91 -0
  2. {isolate-0.26.0 → isolate-0.26.2}/PKG-INFO +1 -1
  3. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/_isolate_version.py +3 -3
  4. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/backends/_base.py +5 -10
  5. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/backends/remote.py +4 -3
  6. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/grpc/_base.py +6 -8
  7. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/grpc/agent.py +64 -16
  8. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/grpc/definitions/agent.proto +1 -1
  9. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/grpc/definitions/agent_pb2.py +7 -7
  10. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/grpc/definitions/agent_pb2.pyi +5 -3
  11. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/grpc/definitions/agent_pb2_grpc.py +0 -1
  12. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/server/definitions/server.proto +1 -1
  13. isolate-0.26.2/src/isolate/server/definitions/server_pb2.py +56 -0
  14. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/server/definitions/server_pb2.pyi +5 -3
  15. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/server/definitions/server_pb2_grpc.py +0 -1
  16. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/server/server.py +2 -2
  17. {isolate-0.26.0 → isolate-0.26.2}/src/isolate.egg-info/PKG-INFO +1 -1
  18. {isolate-0.26.0 → isolate-0.26.2}/src/isolate.egg-info/SOURCES.txt +1 -0
  19. isolate-0.26.2/tests/test_agent_backward_compatibility.py +228 -0
  20. {isolate-0.26.0 → isolate-0.26.2}/tests/test_server.py +189 -2
  21. isolate-0.26.0/.github/workflows/test.yml +0 -67
  22. isolate-0.26.0/src/isolate/server/definitions/server_pb2.py +0 -56
  23. {isolate-0.26.0 → isolate-0.26.2}/.github/workflows/claude-code-review.yml +0 -0
  24. {isolate-0.26.0 → isolate-0.26.2}/.github/workflows/claude.yml +0 -0
  25. {isolate-0.26.0 → isolate-0.26.2}/.github/workflows/lint.yml +0 -0
  26. {isolate-0.26.0 → isolate-0.26.2}/.github/workflows/release.yml +0 -0
  27. {isolate-0.26.0 → isolate-0.26.2}/.gitignore +0 -0
  28. {isolate-0.26.0 → isolate-0.26.2}/.pre-commit-config.yaml +0 -0
  29. {isolate-0.26.0 → isolate-0.26.2}/LICENSE +0 -0
  30. {isolate-0.26.0 → isolate-0.26.2}/README.md +0 -0
  31. {isolate-0.26.0 → isolate-0.26.2}/pyproject.toml +0 -0
  32. {isolate-0.26.0 → isolate-0.26.2}/setup.cfg +0 -0
  33. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/__init__.py +0 -0
  34. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/_version.py +0 -0
  35. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/backends/__init__.py +0 -0
  36. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/backends/common.py +0 -0
  37. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/backends/conda.py +0 -0
  38. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/backends/container.py +0 -0
  39. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/backends/local.py +0 -0
  40. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/backends/pyenv.py +0 -0
  41. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/backends/settings.py +0 -0
  42. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/backends/virtualenv.py +0 -0
  43. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/common/__init__.py +0 -0
  44. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/common/timestamp.py +0 -0
  45. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/__init__.py +0 -0
  46. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/_local/__init__.py +0 -0
  47. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/_local/_base.py +0 -0
  48. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/_local/agent_startup.py +0 -0
  49. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/common.py +0 -0
  50. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/grpc/__init__.py +0 -0
  51. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/grpc/configuration.py +0 -0
  52. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/grpc/definitions/__init__.py +0 -0
  53. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/grpc/definitions/common.proto +0 -0
  54. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/grpc/definitions/common_pb2.py +0 -0
  55. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/grpc/definitions/common_pb2.pyi +0 -0
  56. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/grpc/definitions/common_pb2_grpc.py +0 -0
  57. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/grpc/interface.py +0 -0
  58. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/ipc/__init__.py +0 -0
  59. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/ipc/_base.py +0 -0
  60. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/connections/ipc/agent.py +0 -0
  61. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/logger.py +0 -0
  62. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/logs.py +0 -0
  63. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/py.typed +0 -0
  64. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/registry.py +0 -0
  65. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/server/__init__.py +0 -0
  66. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/server/definitions/__init__.py +0 -0
  67. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/server/health/__init__.py +0 -0
  68. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/server/health/health.proto +0 -0
  69. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/server/health/health_pb2.py +0 -0
  70. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/server/health/health_pb2.pyi +0 -0
  71. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/server/health/health_pb2_grpc.py +0 -0
  72. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/server/health_server.py +0 -0
  73. {isolate-0.26.0 → isolate-0.26.2}/src/isolate/server/interface.py +0 -0
  74. {isolate-0.26.0 → isolate-0.26.2}/src/isolate.egg-info/dependency_links.txt +0 -0
  75. {isolate-0.26.0 → isolate-0.26.2}/src/isolate.egg-info/entry_points.txt +0 -0
  76. {isolate-0.26.0 → isolate-0.26.2}/src/isolate.egg-info/requires.txt +0 -0
  77. {isolate-0.26.0 → isolate-0.26.2}/src/isolate.egg-info/top_level.txt +0 -0
  78. {isolate-0.26.0 → isolate-0.26.2}/tests/__init__.py +0 -0
  79. {isolate-0.26.0 → isolate-0.26.2}/tests/conftest.py +0 -0
  80. {isolate-0.26.0 → isolate-0.26.2}/tests/test_backends.py +0 -0
  81. {isolate-0.26.0 → isolate-0.26.2}/tests/test_concurrency.py +0 -0
  82. {isolate-0.26.0 → isolate-0.26.2}/tests/test_connections.py +0 -0
  83. {isolate-0.26.0 → isolate-0.26.2}/tests/test_connections_grpc_base.py +0 -0
  84. {isolate-0.26.0 → isolate-0.26.2}/tests/test_isolate.py +0 -0
  85. {isolate-0.26.0 → isolate-0.26.2}/tests/test_log.py +0 -0
  86. {isolate-0.26.0 → isolate-0.26.2}/tests/test_log_masking.py +0 -0
  87. {isolate-0.26.0 → isolate-0.26.2}/tests/test_logger.py +0 -0
  88. {isolate-0.26.0 → isolate-0.26.2}/tests/test_serialization.py +0 -0
  89. {isolate-0.26.0 → isolate-0.26.2}/tests/test_shutdown.py +0 -0
  90. {isolate-0.26.0 → isolate-0.26.2}/tools/Dockerfile +0 -0
  91. {isolate-0.26.0 → isolate-0.26.2}/tools/agent_requirements.txt +0 -0
  92. {isolate-0.26.0 → isolate-0.26.2}/tools/isolate_client.py +0 -0
  93. {isolate-0.26.0 → isolate-0.26.2}/tools/protobuf-requirements.txt +0 -0
  94. {isolate-0.26.0 → isolate-0.26.2}/tools/regen_grpc.py +0 -0
  95. {isolate-0.26.0 → isolate-0.26.2}/tools/requirements.txt +0 -0
  96. {isolate-0.26.0 → isolate-0.26.2}/tools/test_agent_requirements.txt +0 -0
@@ -0,0 +1,91 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ schedule:
10
+ - cron: "30 5 * * *" # every day at 5:30 UTC
11
+
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ test:
18
+ runs-on: ${{ matrix.os }}
19
+ timeout-minutes: 45
20
+ strategy:
21
+ fail-fast: false
22
+
23
+ matrix:
24
+ os: [ubuntu-latest]
25
+ python: ["3.8", "3.9", "3.10", "3.11"]
26
+ include:
27
+ - os: macos-15-intel
28
+ python: "3.8"
29
+ - os: macos-15-intel
30
+ python: "3.11"
31
+ steps:
32
+ - uses: actions/checkout@v3
33
+
34
+ - uses: actions/setup-python@v3
35
+ with:
36
+ python-version: ${{ matrix.python }}
37
+
38
+ - name: Install mamba
39
+ uses: mamba-org/setup-micromamba@v1
40
+ with:
41
+ environment-name: ci
42
+ create-args: >-
43
+ python=${{ matrix.python }}
44
+ condarc: |
45
+ channels:
46
+ - anaconda
47
+ - conda-forge
48
+ - pytorch
49
+
50
+ - uses: actions/checkout@v3
51
+ with:
52
+ repository: pyenv/pyenv
53
+ ref: v2.3.6
54
+ path: pyenv
55
+
56
+ - name: Install dependencies
57
+ run: |
58
+ python -m pip install -e ".[test]"
59
+
60
+ - name: Install uv
61
+ run: |
62
+ python -m pip install uv
63
+
64
+ - name: Test
65
+ run: |
66
+ export ISOLATE_PYENV_EXECUTABLE=pyenv/bin/pyenv
67
+ python -m pytest -vvv --ignore=tests/test_agent_backward_compatibility.py
68
+
69
+ backward-compat:
70
+ runs-on: ubuntu-latest
71
+ timeout-minutes: 30
72
+ steps:
73
+ - uses: actions/checkout@v3
74
+ with:
75
+ fetch-depth: 0
76
+
77
+ - uses: actions/setup-python@v3
78
+ with:
79
+ python-version: "3.11"
80
+
81
+ - name: Install dependencies
82
+ run: |
83
+ python -m pip install -e ".[test]"
84
+
85
+ - name: Install uv
86
+ run: |
87
+ python -m pip install uv
88
+
89
+ - name: Test backward compatibility
90
+ run: |
91
+ python -m pytest -vvv tests/test_agent_backward_compatibility.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: isolate
3
- Version: 0.26.0
3
+ Version: 0.26.2
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
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.26.0'
32
- __version_tuple__ = version_tuple = (0, 26, 0)
31
+ __version__ = version = '0.26.2'
32
+ __version_tuple__ = version_tuple = (0, 26, 2)
33
33
 
34
- __commit_id__ = commit_id = 'g5f5f04791'
34
+ __commit_id__ = commit_id = 'g7e1de0bc2'
@@ -2,14 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from contextlib import contextmanager
4
4
  from dataclasses import dataclass
5
- from typing import (
6
- Any,
7
- Callable,
8
- ClassVar,
9
- Generic,
10
- Iterator,
11
- TypeVar,
12
- )
5
+ from typing import Any, Callable, ClassVar, Generic, Iterator, Optional, TypeVar
13
6
 
14
7
  from isolate.backends.settings import DEFAULT_SETTINGS, IsolateSettings
15
8
  from isolate.logs import Log, LogLevel, LogSource
@@ -131,7 +124,7 @@ class EnvironmentConnection:
131
124
  self,
132
125
  entrypoint: str,
133
126
  *,
134
- run_on_main_thread: bool = False,
127
+ run_on_main_thread: Optional[bool] = None,
135
128
  ) -> CallResultType: # type: ignore[type-var]
136
129
  """Run a ``"module:attr"`` Python entrypoint inside the environment,
137
130
  and return the result. If the entrypoint raises an exception, then it
@@ -139,7 +132,9 @@ class EnvironmentConnection:
139
132
 
140
133
  If ``run_on_main_thread`` is True, the resolved callable is invoked on
141
134
  the agent's main thread (and coroutines it returns are awaited on that
142
- loop); otherwise it runs on a thread pool."""
135
+ loop). If False, it runs on a thread pool. If None, the backend may
136
+ fall back to legacy callable-level hints such as
137
+ ``_run_on_main_thread``."""
143
138
  raise NotImplementedError
144
139
 
145
140
  def log(
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import copy
4
4
  import json
5
5
  from dataclasses import dataclass
6
- from typing import Any, ClassVar, List
6
+ from typing import Any, ClassVar, List, Optional
7
7
 
8
8
  import grpc
9
9
 
@@ -120,15 +120,16 @@ class IsolateServerConnection(EnvironmentConnection):
120
120
  self,
121
121
  entrypoint: str,
122
122
  *,
123
- run_on_main_thread: bool = False,
123
+ run_on_main_thread: Optional[bool] = None,
124
124
  ) -> CallResultType: # type: ignore[type-var]
125
125
  validate_entrypoint(entrypoint)
126
126
  request = BoundFunction(
127
127
  entrypoint=entrypoint,
128
128
  environments=self.definitions,
129
129
  stream_logs=True,
130
- run_on_main_thread=run_on_main_thread,
131
130
  )
131
+ if run_on_main_thread is not None:
132
+ request.run_on_main_thread = run_on_main_thread
132
133
  return self._run_request(request)
133
134
 
134
135
  def _run_request(self, request: BoundFunction) -> CallResultType: # type: ignore[type-var]
@@ -6,7 +6,7 @@ import time
6
6
  from contextlib import contextmanager
7
7
  from dataclasses import dataclass
8
8
  from pathlib import Path
9
- from typing import Any, ContextManager, Iterator, List, Tuple, Union, cast
9
+ from typing import Any, ContextManager, Iterator, List, Optional, Tuple, Union, cast
10
10
 
11
11
  import grpc
12
12
 
@@ -125,15 +125,13 @@ class GRPCExecutionBase(EnvironmentConnection):
125
125
  self,
126
126
  entrypoint: str,
127
127
  *,
128
- run_on_main_thread: bool = False,
128
+ run_on_main_thread: Optional[bool] = None,
129
129
  ) -> CallResultType: # type: ignore[type-var]
130
130
  validate_entrypoint(entrypoint)
131
- return self._run_function_call(
132
- definitions.FunctionCall(
133
- entrypoint=entrypoint,
134
- run_on_main_thread=run_on_main_thread,
135
- ),
136
- )
131
+ function_call = definitions.FunctionCall(entrypoint=entrypoint)
132
+ if run_on_main_thread is not None:
133
+ function_call.run_on_main_thread = run_on_main_thread
134
+ return self._run_function_call(function_call)
137
135
 
138
136
  def _run_function_call(
139
137
  self, function_call: definitions.FunctionCall
@@ -26,6 +26,7 @@ from typing import (
26
26
  Any,
27
27
  AsyncIterator,
28
28
  Iterable,
29
+ Optional,
29
30
  TextIO,
30
31
  )
31
32
 
@@ -39,12 +40,30 @@ except ImportError:
39
40
  agent_version = "UNKNOWN"
40
41
 
41
42
  from isolate.backends.common import sha256_digest_of
42
- from isolate.backends.settings import DEFAULT_SERIALIZATION_METHOD
43
- from isolate.connections.common import (
44
- SerializationError,
45
- serialize_object,
46
- validate_entrypoint,
47
- )
43
+
44
+ try:
45
+ from isolate.backends.settings import DEFAULT_SERIALIZATION_METHOD
46
+ except ImportError:
47
+ # Newer server code can run inside an older frozen agent environment
48
+ # that predates this exported constant. Keep the legacy default inline
49
+ # so version-skewed agent/server pairs remain compatible.
50
+ DEFAULT_SERIALIZATION_METHOD = "pickle"
51
+ from isolate.connections.common import SerializationError, serialize_object
52
+
53
+ try:
54
+ from isolate.connections.common import validate_entrypoint
55
+ except ImportError:
56
+ # Older installed isolate builds predate the shared helper. Keep the
57
+ # legacy syntax check inline so current agent scripts still start up
58
+ # under those versions.
59
+ def validate_entrypoint(entrypoint: str) -> None:
60
+ module, sep, attr = entrypoint.partition(":")
61
+ if not sep or not module or not attr or ":" in attr:
62
+ raise ValueError(
63
+ f"Invalid entrypoint {entrypoint!r}: expected 'module:attr'."
64
+ )
65
+
66
+
48
67
  from isolate.connections.grpc import definitions
49
68
  from isolate.connections.grpc.configuration import get_default_options
50
69
  from isolate.connections.grpc.interface import from_grpc
@@ -310,18 +329,23 @@ class AgentServicer(definitions.AgentServicer):
310
329
  extra_args.append(self._run_cache[cache_key])
311
330
 
312
331
  try:
332
+ run_on_main_thread = (
333
+ request.run_on_main_thread
334
+ if request.HasField("run_on_main_thread")
335
+ else None
336
+ )
313
337
  if has_entrypoint:
314
338
  invocation = await self.execute_entrypoint(
315
339
  request.entrypoint,
316
340
  "function",
317
- run_on_main_thread=request.run_on_main_thread,
341
+ run_on_main_thread=run_on_main_thread,
318
342
  )
319
343
  else:
320
344
  invocation = await self.execute_function(
321
345
  request.function,
322
346
  "function",
323
347
  extra_args=extra_args,
324
- run_on_main_thread=request.run_on_main_thread,
348
+ run_on_main_thread=run_on_main_thread,
325
349
  )
326
350
  result, was_it_raised, stringized_tb = invocation
327
351
  yield self.send_object(
@@ -340,7 +364,7 @@ class AgentServicer(definitions.AgentServicer):
340
364
  function_kind: str,
341
365
  *,
342
366
  extra_args: Iterable[Any] = (),
343
- run_on_main_thread: bool = False,
367
+ run_on_main_thread: Optional[bool] = None,
344
368
  ) -> tuple[Any, bool, str | None]:
345
369
  if function.was_it_raised:
346
370
  raise AbortException(
@@ -370,16 +394,37 @@ class AgentServicer(definitions.AgentServicer):
370
394
  entrypoint: str,
371
395
  function_kind: str,
372
396
  *,
373
- run_on_main_thread: bool = False,
397
+ run_on_main_thread: Optional[bool] = None,
374
398
  ) -> tuple[Any, bool, str | None]:
375
399
  # Resolve lazily so import / attribute errors surface through the
376
400
  # regular exception capture in _invoke_callable and reach the client
377
- # as a raised result, matching the pickle error path.
378
- def function() -> Any:
379
- return _resolve_entrypoint(entrypoint)()
401
+ # as a raised result, matching the pickle error path. The wrapper also
402
+ # mirrors the resolved callable's legacy `_run_on_main_thread` flag so
403
+ # absent RPC fields keep the old fallback behavior for entrypoints.
404
+ unresolved = object()
405
+
406
+ class ResolvedEntrypoint:
407
+ def __init__(self, value: str):
408
+ self._entrypoint = value
409
+ self._resolved: Any = unresolved
410
+
411
+ def _resolve(self) -> Any:
412
+ if self._resolved is unresolved:
413
+ self._resolved = _resolve_entrypoint(self._entrypoint)
414
+ return self._resolved
415
+
416
+ @property
417
+ def _run_on_main_thread(self) -> bool:
418
+ try:
419
+ return getattr(self._resolve(), "_run_on_main_thread", False)
420
+ except Exception:
421
+ return False
422
+
423
+ def __call__(self) -> Any:
424
+ return self._resolve()()
380
425
 
381
426
  return await self._invoke_callable(
382
- function,
427
+ ResolvedEntrypoint(entrypoint),
383
428
  function_kind,
384
429
  run_on_main_thread=run_on_main_thread,
385
430
  )
@@ -390,7 +435,7 @@ class AgentServicer(definitions.AgentServicer):
390
435
  function_kind: str,
391
436
  extra_args: Iterable[Any] = (),
392
437
  *,
393
- run_on_main_thread: bool = False,
438
+ run_on_main_thread: Optional[bool] = None,
394
439
  ) -> tuple[Any, bool, str | None]:
395
440
  if not callable(function):
396
441
  raise AbortException(
@@ -411,7 +456,10 @@ class AgentServicer(definitions.AgentServicer):
411
456
  # called from a running event loop" error and stay backward
412
457
  # compatible, we offload those unflagged functions to a thread pool.
413
458
 
414
- if run_on_main_thread or getattr(function, "_run_on_main_thread", False):
459
+ if run_on_main_thread is None:
460
+ run_on_main_thread = getattr(function, "_run_on_main_thread", False)
461
+
462
+ if run_on_main_thread:
415
463
  result = function(*extra_args)
416
464
  else:
417
465
  result = self._thread_pool.submit(function, *extra_args).result()
@@ -17,7 +17,7 @@ message FunctionCall {
17
17
  // event loop, useful for async callables) instead of a thread pool. The
18
18
  // agent also honors `_run_on_main_thread` set on the callable itself,
19
19
  // for backward compatibility with older clients.
20
- bool run_on_main_thread = 4;
20
+ optional bool run_on_main_thread = 4;
21
21
  // Exactly one of the following must be set.
22
22
  oneof callable {
23
23
  // A serialized callable to execute.
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
3
  # source: agent.proto
4
- # Protobuf Python Version: 4.25.1
4
+ # Protobuf Python Version: 5.26.1
5
5
  """Generated protocol buffer code."""
6
6
  from google.protobuf import descriptor as _descriptor
7
7
  from google.protobuf import descriptor_pool as _descriptor_pool
@@ -15,15 +15,15 @@ _sym_db = _symbol_database.Default()
15
15
  from isolate.connections.grpc.definitions import common_pb2 as common__pb2
16
16
 
17
17
 
18
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0b\x61gent.proto\x1a\x0c\x63ommon.proto\"\xae\x01\n\x0c\x46unctionCall\x12*\n\nsetup_func\x18\x02 \x01(\x0b\x32\x11.SerializedObjectH\x01\x88\x01\x01\x12\x1a\n\x12run_on_main_thread\x18\x04 \x01(\x08\x12%\n\x08\x66unction\x18\x01 \x01(\x0b\x32\x11.SerializedObjectH\x00\x12\x14\n\nentrypoint\x18\x03 \x01(\tH\x00\x42\n\n\x08\x63\x61llableB\r\n\x0b_setup_func24\n\x05\x41gent\x12+\n\x03Run\x12\r.FunctionCall\x1a\x11.PartialRunResult\"\x00\x30\x01\x62\x06proto3')
18
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0b\x61gent.proto\x1a\x0c\x63ommon.proto\"\xca\x01\n\x0c\x46unctionCall\x12*\n\nsetup_func\x18\x02 \x01(\x0b\x32\x11.SerializedObjectH\x01\x88\x01\x01\x12\x1f\n\x12run_on_main_thread\x18\x04 \x01(\x08H\x02\x88\x01\x01\x12%\n\x08\x66unction\x18\x01 \x01(\x0b\x32\x11.SerializedObjectH\x00\x12\x14\n\nentrypoint\x18\x03 \x01(\tH\x00\x42\n\n\x08\x63\x61llableB\r\n\x0b_setup_funcB\x15\n\x13_run_on_main_thread24\n\x05\x41gent\x12+\n\x03Run\x12\r.FunctionCall\x1a\x11.PartialRunResult\"\x00\x30\x01\x62\x06proto3')
19
19
 
20
20
  _globals = globals()
21
21
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
22
22
  _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'agent_pb2', _globals)
23
- if _descriptor._USE_C_DESCRIPTORS == False:
24
- DESCRIPTOR._options = None
23
+ if not _descriptor._USE_C_DESCRIPTORS:
24
+ DESCRIPTOR._loaded_options = None
25
25
  _globals['_FUNCTIONCALL']._serialized_start=30
26
- _globals['_FUNCTIONCALL']._serialized_end=204
27
- _globals['_AGENT']._serialized_start=206
28
- _globals['_AGENT']._serialized_end=258
26
+ _globals['_FUNCTIONCALL']._serialized_end=232
27
+ _globals['_AGENT']._serialized_start=234
28
+ _globals['_AGENT']._serialized_end=286
29
29
  # @@protoc_insertion_point(module_scope)
@@ -49,12 +49,14 @@ class FunctionCall(google.protobuf.message.Message):
49
49
  self,
50
50
  *,
51
51
  setup_func: common_pb2.SerializedObject | None = ...,
52
- run_on_main_thread: builtins.bool = ...,
52
+ run_on_main_thread: builtins.bool | None = ...,
53
53
  function: common_pb2.SerializedObject | None = ...,
54
54
  entrypoint: builtins.str = ...,
55
55
  ) -> None: ...
56
- def HasField(self, field_name: typing_extensions.Literal["_setup_func", b"_setup_func", "callable", b"callable", "entrypoint", b"entrypoint", "function", b"function", "setup_func", b"setup_func"]) -> builtins.bool: ...
57
- def ClearField(self, field_name: typing_extensions.Literal["_setup_func", b"_setup_func", "callable", b"callable", "entrypoint", b"entrypoint", "function", b"function", "run_on_main_thread", b"run_on_main_thread", "setup_func", b"setup_func"]) -> None: ...
56
+ def HasField(self, field_name: typing_extensions.Literal["_run_on_main_thread", b"_run_on_main_thread", "_setup_func", b"_setup_func", "callable", b"callable", "entrypoint", b"entrypoint", "function", b"function", "run_on_main_thread", b"run_on_main_thread", "setup_func", b"setup_func"]) -> builtins.bool: ...
57
+ def ClearField(self, field_name: typing_extensions.Literal["_run_on_main_thread", b"_run_on_main_thread", "_setup_func", b"_setup_func", "callable", b"callable", "entrypoint", b"entrypoint", "function", b"function", "run_on_main_thread", b"run_on_main_thread", "setup_func", b"setup_func"]) -> None: ...
58
+ @typing.overload
59
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_run_on_main_thread", b"_run_on_main_thread"]) -> typing_extensions.Literal["run_on_main_thread"] | None: ...
58
60
  @typing.overload
59
61
  def WhichOneof(self, oneof_group: typing_extensions.Literal["_setup_func", b"_setup_func"]) -> typing_extensions.Literal["setup_func"] | None: ...
60
62
  @typing.overload
@@ -5,7 +5,6 @@ import grpc
5
5
  from isolate.connections.grpc.definitions import agent_pb2 as agent__pb2
6
6
  from isolate.connections.grpc.definitions import common_pb2 as common__pb2
7
7
 
8
-
9
8
  class AgentStub(object):
10
9
  """Missing associated documentation comment in .proto file."""
11
10
 
@@ -29,7 +29,7 @@ message BoundFunction {
29
29
  // event loop, useful for async callables) instead of a thread pool. The
30
30
  // agent also honors `_run_on_main_thread` set on the callable itself,
31
31
  // for backward compatibility with older clients.
32
- bool run_on_main_thread = 6;
32
+ optional bool run_on_main_thread = 6;
33
33
  // Exactly one of the following must be set.
34
34
  oneof callable {
35
35
  // A serialized callable to run.
@@ -0,0 +1,56 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: server.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
+ from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2
17
+
18
+
19
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cserver.proto\x1a\x0c\x63ommon.proto\x1a\x1cgoogle/protobuf/struct.proto\"\x8e\x02\n\rBoundFunction\x12,\n\x0c\x65nvironments\x18\x01 \x03(\x0b\x32\x16.EnvironmentDefinition\x12*\n\nsetup_func\x18\x03 \x01(\x0b\x32\x11.SerializedObjectH\x01\x88\x01\x01\x12\x13\n\x0bstream_logs\x18\x04 \x01(\x08\x12\x1f\n\x12run_on_main_thread\x18\x06 \x01(\x08H\x02\x88\x01\x01\x12%\n\x08\x66unction\x18\x02 \x01(\x0b\x32\x11.SerializedObjectH\x00\x12\x14\n\nentrypoint\x18\x05 \x01(\tH\x00\x42\n\n\x08\x63\x61llableB\r\n\x0b_setup_funcB\x15\n\x13_run_on_main_thread\"d\n\x15\x45nvironmentDefinition\x12\x0c\n\x04kind\x18\x01 \x01(\t\x12.\n\rconfiguration\x18\x02 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\r\n\x05\x66orce\x18\x03 \x01(\x08\"R\n\rSubmitRequest\x12 \n\x08\x66unction\x18\x01 \x01(\x0b\x32\x0e.BoundFunction\x12\x1f\n\x08metadata\x18\x02 \x01(\x0b\x32\r.TaskMetadata\"{\n\x0cTaskMetadata\x12\x36\n\rlogger_labels\x18\x01 \x03(\x0b\x32\x1f.TaskMetadata.LoggerLabelsEntry\x1a\x33\n\x11LoggerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"!\n\x0eSubmitResponse\x12\x0f\n\x07task_id\x18\x01 \x01(\t\"F\n\x12SetMetadataRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x1f\n\x08metadata\x18\x02 \x01(\x0b\x32\r.TaskMetadata\"\x15\n\x13SetMetadataResponse\"\r\n\x0bListRequest\"\x1b\n\x08TaskInfo\x12\x0f\n\x07task_id\x18\x01 \x01(\t\"(\n\x0cListResponse\x12\x18\n\x05tasks\x18\x01 \x03(\x0b\x32\t.TaskInfo\" \n\rCancelRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\"\x10\n\x0e\x43\x61ncelResponse2\xf4\x01\n\x07Isolate\x12,\n\x03Run\x12\x0e.BoundFunction\x1a\x11.PartialRunResult\"\x00\x30\x01\x12+\n\x06Submit\x12\x0e.SubmitRequest\x1a\x0f.SubmitResponse\"\x00\x12:\n\x0bSetMetadata\x12\x13.SetMetadataRequest\x1a\x14.SetMetadataResponse\"\x00\x12%\n\x04List\x12\x0c.ListRequest\x1a\r.ListResponse\"\x00\x12+\n\x06\x43\x61ncel\x12\x0e.CancelRequest\x1a\x0f.CancelResponse\"\x00\x62\x06proto3')
20
+
21
+ _globals = globals()
22
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
23
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'server_pb2', _globals)
24
+ if not _descriptor._USE_C_DESCRIPTORS:
25
+ DESCRIPTOR._loaded_options = None
26
+ _globals['_TASKMETADATA_LOGGERLABELSENTRY']._loaded_options = None
27
+ _globals['_TASKMETADATA_LOGGERLABELSENTRY']._serialized_options = b'8\001'
28
+ _globals['_BOUNDFUNCTION']._serialized_start=61
29
+ _globals['_BOUNDFUNCTION']._serialized_end=331
30
+ _globals['_ENVIRONMENTDEFINITION']._serialized_start=333
31
+ _globals['_ENVIRONMENTDEFINITION']._serialized_end=433
32
+ _globals['_SUBMITREQUEST']._serialized_start=435
33
+ _globals['_SUBMITREQUEST']._serialized_end=517
34
+ _globals['_TASKMETADATA']._serialized_start=519
35
+ _globals['_TASKMETADATA']._serialized_end=642
36
+ _globals['_TASKMETADATA_LOGGERLABELSENTRY']._serialized_start=591
37
+ _globals['_TASKMETADATA_LOGGERLABELSENTRY']._serialized_end=642
38
+ _globals['_SUBMITRESPONSE']._serialized_start=644
39
+ _globals['_SUBMITRESPONSE']._serialized_end=677
40
+ _globals['_SETMETADATAREQUEST']._serialized_start=679
41
+ _globals['_SETMETADATAREQUEST']._serialized_end=749
42
+ _globals['_SETMETADATARESPONSE']._serialized_start=751
43
+ _globals['_SETMETADATARESPONSE']._serialized_end=772
44
+ _globals['_LISTREQUEST']._serialized_start=774
45
+ _globals['_LISTREQUEST']._serialized_end=787
46
+ _globals['_TASKINFO']._serialized_start=789
47
+ _globals['_TASKINFO']._serialized_end=816
48
+ _globals['_LISTRESPONSE']._serialized_start=818
49
+ _globals['_LISTRESPONSE']._serialized_end=858
50
+ _globals['_CANCELREQUEST']._serialized_start=860
51
+ _globals['_CANCELREQUEST']._serialized_end=892
52
+ _globals['_CANCELRESPONSE']._serialized_start=894
53
+ _globals['_CANCELRESPONSE']._serialized_end=910
54
+ _globals['_ISOLATE']._serialized_start=913
55
+ _globals['_ISOLATE']._serialized_end=1157
56
+ # @@protoc_insertion_point(module_scope)
@@ -54,12 +54,14 @@ class BoundFunction(google.protobuf.message.Message):
54
54
  environments: collections.abc.Iterable[global___EnvironmentDefinition] | None = ...,
55
55
  setup_func: common_pb2.SerializedObject | None = ...,
56
56
  stream_logs: builtins.bool = ...,
57
- run_on_main_thread: builtins.bool = ...,
57
+ run_on_main_thread: builtins.bool | None = ...,
58
58
  function: common_pb2.SerializedObject | None = ...,
59
59
  entrypoint: builtins.str = ...,
60
60
  ) -> None: ...
61
- def HasField(self, field_name: typing_extensions.Literal["_setup_func", b"_setup_func", "callable", b"callable", "entrypoint", b"entrypoint", "function", b"function", "setup_func", b"setup_func"]) -> builtins.bool: ...
62
- def ClearField(self, field_name: typing_extensions.Literal["_setup_func", b"_setup_func", "callable", b"callable", "entrypoint", b"entrypoint", "environments", b"environments", "function", b"function", "run_on_main_thread", b"run_on_main_thread", "setup_func", b"setup_func", "stream_logs", b"stream_logs"]) -> None: ...
61
+ def HasField(self, field_name: typing_extensions.Literal["_run_on_main_thread", b"_run_on_main_thread", "_setup_func", b"_setup_func", "callable", b"callable", "entrypoint", b"entrypoint", "function", b"function", "run_on_main_thread", b"run_on_main_thread", "setup_func", b"setup_func"]) -> builtins.bool: ...
62
+ def ClearField(self, field_name: typing_extensions.Literal["_run_on_main_thread", b"_run_on_main_thread", "_setup_func", b"_setup_func", "callable", b"callable", "entrypoint", b"entrypoint", "environments", b"environments", "function", b"function", "run_on_main_thread", b"run_on_main_thread", "setup_func", b"setup_func", "stream_logs", b"stream_logs"]) -> None: ...
63
+ @typing.overload
64
+ def WhichOneof(self, oneof_group: typing_extensions.Literal["_run_on_main_thread", b"_run_on_main_thread"]) -> typing_extensions.Literal["run_on_main_thread"] | None: ...
63
65
  @typing.overload
64
66
  def WhichOneof(self, oneof_group: typing_extensions.Literal["_setup_func", b"_setup_func"]) -> typing_extensions.Literal["setup_func"] | None: ...
65
67
  @typing.overload
@@ -5,7 +5,6 @@ import grpc
5
5
  from isolate.connections.grpc.definitions import common_pb2 as common__pb2
6
6
  from isolate.server.definitions import server_pb2 as server__pb2
7
7
 
8
-
9
8
  class IsolateStub(object):
10
9
  """Missing associated documentation comment in .proto file."""
11
10
 
@@ -330,16 +330,16 @@ class IsolateServicer(definitions.IsolateServicer):
330
330
  if has_entrypoint:
331
331
  function_call = definitions.FunctionCall(
332
332
  entrypoint=task.request.entrypoint,
333
- run_on_main_thread=task.request.run_on_main_thread,
334
333
  )
335
334
  else:
336
335
  function_call = definitions.FunctionCall(
337
336
  function=task.request.function,
338
337
  setup_func=task.request.setup_func,
339
- run_on_main_thread=task.request.run_on_main_thread,
340
338
  )
341
339
  if not task.request.HasField("setup_func"):
342
340
  function_call.ClearField("setup_func")
341
+ if task.request.HasField("run_on_main_thread"):
342
+ function_call.run_on_main_thread = task.request.run_on_main_thread
343
343
 
344
344
  future = local_pool.submit(
345
345
  _proxy_to_queue,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: isolate
3
- Version: 0.26.0
3
+ Version: 0.26.2
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
@@ -71,6 +71,7 @@ src/isolate/server/health/health_pb2.pyi
71
71
  src/isolate/server/health/health_pb2_grpc.py
72
72
  tests/__init__.py
73
73
  tests/conftest.py
74
+ tests/test_agent_backward_compatibility.py
74
75
  tests/test_backends.py
75
76
  tests/test_concurrency.py
76
77
  tests/test_connections.py