isolate 0.26.6__tar.gz → 0.26.7__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 (95) hide show
  1. {isolate-0.26.6 → isolate-0.26.7}/.github/workflows/test.yml +2 -2
  2. {isolate-0.26.6/src/isolate.egg-info → isolate-0.26.7}/PKG-INFO +1 -1
  3. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/_isolate_version.py +3 -3
  4. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/common.py +32 -11
  5. {isolate-0.26.6 → isolate-0.26.7/src/isolate.egg-info}/PKG-INFO +1 -1
  6. {isolate-0.26.6 → isolate-0.26.7}/tests/test_backends.py +1 -0
  7. {isolate-0.26.6 → isolate-0.26.7}/tests/test_serialization.py +36 -0
  8. {isolate-0.26.6 → isolate-0.26.7}/.github/workflows/claude-code-review.yml +0 -0
  9. {isolate-0.26.6 → isolate-0.26.7}/.github/workflows/claude.yml +0 -0
  10. {isolate-0.26.6 → isolate-0.26.7}/.github/workflows/lint.yml +0 -0
  11. {isolate-0.26.6 → isolate-0.26.7}/.github/workflows/release.yml +0 -0
  12. {isolate-0.26.6 → isolate-0.26.7}/.gitignore +0 -0
  13. {isolate-0.26.6 → isolate-0.26.7}/.pre-commit-config.yaml +0 -0
  14. {isolate-0.26.6 → isolate-0.26.7}/LICENSE +0 -0
  15. {isolate-0.26.6 → isolate-0.26.7}/README.md +0 -0
  16. {isolate-0.26.6 → isolate-0.26.7}/pyproject.toml +0 -0
  17. {isolate-0.26.6 → isolate-0.26.7}/setup.cfg +0 -0
  18. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/__init__.py +0 -0
  19. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/_version.py +0 -0
  20. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/backends/__init__.py +0 -0
  21. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/backends/_base.py +0 -0
  22. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/backends/common.py +0 -0
  23. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/backends/conda.py +0 -0
  24. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/backends/container.py +0 -0
  25. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/backends/local.py +0 -0
  26. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/backends/pyenv.py +0 -0
  27. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/backends/remote.py +0 -0
  28. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/backends/settings.py +0 -0
  29. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/backends/virtualenv.py +0 -0
  30. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/common/__init__.py +0 -0
  31. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/common/timestamp.py +0 -0
  32. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/__init__.py +0 -0
  33. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/_local/__init__.py +0 -0
  34. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/_local/_base.py +0 -0
  35. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/_local/agent_startup.py +0 -0
  36. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/grpc/__init__.py +0 -0
  37. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/grpc/_base.py +0 -0
  38. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/grpc/agent.py +0 -0
  39. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/grpc/configuration.py +0 -0
  40. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/grpc/definitions/__init__.py +0 -0
  41. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/grpc/definitions/agent.proto +0 -0
  42. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/grpc/definitions/agent_pb2.py +0 -0
  43. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/grpc/definitions/agent_pb2.pyi +0 -0
  44. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/grpc/definitions/agent_pb2_grpc.py +0 -0
  45. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/grpc/definitions/common.proto +0 -0
  46. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/grpc/definitions/common_pb2.py +0 -0
  47. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/grpc/definitions/common_pb2.pyi +0 -0
  48. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/grpc/definitions/common_pb2_grpc.py +0 -0
  49. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/grpc/interface.py +0 -0
  50. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/ipc/__init__.py +0 -0
  51. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/ipc/_base.py +0 -0
  52. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/connections/ipc/agent.py +0 -0
  53. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/logger.py +0 -0
  54. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/logs.py +0 -0
  55. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/py.typed +0 -0
  56. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/registry.py +0 -0
  57. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/server/__init__.py +0 -0
  58. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/server/definitions/__init__.py +0 -0
  59. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/server/definitions/server.proto +0 -0
  60. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/server/definitions/server_pb2.py +0 -0
  61. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/server/definitions/server_pb2.pyi +0 -0
  62. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/server/definitions/server_pb2_grpc.py +0 -0
  63. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/server/health/__init__.py +0 -0
  64. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/server/health/health.proto +0 -0
  65. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/server/health/health_pb2.py +0 -0
  66. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/server/health/health_pb2.pyi +0 -0
  67. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/server/health/health_pb2_grpc.py +0 -0
  68. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/server/health_server.py +0 -0
  69. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/server/interface.py +0 -0
  70. {isolate-0.26.6 → isolate-0.26.7}/src/isolate/server/server.py +0 -0
  71. {isolate-0.26.6 → isolate-0.26.7}/src/isolate.egg-info/SOURCES.txt +0 -0
  72. {isolate-0.26.6 → isolate-0.26.7}/src/isolate.egg-info/dependency_links.txt +0 -0
  73. {isolate-0.26.6 → isolate-0.26.7}/src/isolate.egg-info/entry_points.txt +0 -0
  74. {isolate-0.26.6 → isolate-0.26.7}/src/isolate.egg-info/requires.txt +0 -0
  75. {isolate-0.26.6 → isolate-0.26.7}/src/isolate.egg-info/top_level.txt +0 -0
  76. {isolate-0.26.6 → isolate-0.26.7}/tests/__init__.py +0 -0
  77. {isolate-0.26.6 → isolate-0.26.7}/tests/conftest.py +0 -0
  78. {isolate-0.26.6 → isolate-0.26.7}/tests/test_agent_backward_compatibility.py +0 -0
  79. {isolate-0.26.6 → isolate-0.26.7}/tests/test_concurrency.py +0 -0
  80. {isolate-0.26.6 → isolate-0.26.7}/tests/test_connections.py +0 -0
  81. {isolate-0.26.6 → isolate-0.26.7}/tests/test_connections_grpc_base.py +0 -0
  82. {isolate-0.26.6 → isolate-0.26.7}/tests/test_isolate.py +0 -0
  83. {isolate-0.26.6 → isolate-0.26.7}/tests/test_log.py +0 -0
  84. {isolate-0.26.6 → isolate-0.26.7}/tests/test_log_masking.py +0 -0
  85. {isolate-0.26.6 → isolate-0.26.7}/tests/test_logged_io_pipe.py +0 -0
  86. {isolate-0.26.6 → isolate-0.26.7}/tests/test_logger.py +0 -0
  87. {isolate-0.26.6 → isolate-0.26.7}/tests/test_server.py +0 -0
  88. {isolate-0.26.6 → isolate-0.26.7}/tests/test_shutdown.py +0 -0
  89. {isolate-0.26.6 → isolate-0.26.7}/tools/Dockerfile +0 -0
  90. {isolate-0.26.6 → isolate-0.26.7}/tools/agent_requirements.txt +0 -0
  91. {isolate-0.26.6 → isolate-0.26.7}/tools/isolate_client.py +0 -0
  92. {isolate-0.26.6 → isolate-0.26.7}/tools/protobuf-requirements.txt +0 -0
  93. {isolate-0.26.6 → isolate-0.26.7}/tools/regen_grpc.py +0 -0
  94. {isolate-0.26.6 → isolate-0.26.7}/tools/requirements.txt +0 -0
  95. {isolate-0.26.6 → isolate-0.26.7}/tools/test_agent_requirements.txt +0 -0
@@ -22,12 +22,12 @@ jobs:
22
22
 
23
23
  matrix:
24
24
  os: [ubuntu-latest]
25
- python: ["3.8", "3.9", "3.10", "3.11"]
25
+ python: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
26
26
  include:
27
27
  - os: macos-15-intel
28
28
  python: "3.8"
29
29
  - os: macos-15-intel
30
- python: "3.11"
30
+ python: "3.14"
31
31
  steps:
32
32
  - uses: actions/checkout@v3
33
33
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: isolate
3
- Version: 0.26.6
3
+ Version: 0.26.7
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.6'
32
- __version_tuple__ = version_tuple = (0, 26, 6)
31
+ __version__ = version = '0.26.7'
32
+ __version_tuple__ = version_tuple = (0, 26, 7)
33
33
 
34
- __commit_id__ = commit_id = 'g6d4ff5277'
34
+ __commit_id__ = commit_id = 'g9b3604b86'
@@ -4,6 +4,7 @@ import importlib
4
4
  import os
5
5
  from contextlib import contextmanager
6
6
  from dataclasses import dataclass
7
+ from types import TracebackType
7
8
  from typing import TYPE_CHECKING, Any, Iterator, cast
8
9
 
9
10
  from tblib import Traceback, TracebackParseError
@@ -28,6 +29,14 @@ class SerializationError(Exception):
28
29
  message: str
29
30
 
30
31
 
32
+ @dataclass
33
+ class ExceptionDeserializationError(SerializationError):
34
+ """Raised when a remote exception cannot be deserialized locally (e.g. the
35
+ module that defines its type isn't importable here)."""
36
+
37
+ original_traceback: TracebackType | None
38
+
39
+
31
40
  # NOTE: tblib's install() will search for BaseException subclasses,
32
41
  # so we have to call it after the SerializationError is defined.
33
42
  tblib_install()
@@ -77,8 +86,19 @@ def load_serialized_object(
77
86
  importlib.import_module(serialization_method)
78
87
  )
79
88
 
80
- with _step("deserializing the given object"):
81
- result = serialization_backend.loads(raw_object)
89
+ try:
90
+ with _step("deserializing the given object"):
91
+ result = serialization_backend.loads(raw_object)
92
+ except SerializationError as exc:
93
+ if was_it_raised:
94
+ # We were trying to reconstruct a remote exception but its type
95
+ # isn't importable here, so loads() failed. Surface the genuine
96
+ # local cause along with the remote traceback.
97
+ raise ExceptionDeserializationError(
98
+ exc.message,
99
+ original_traceback=_prepare_traceback(stringized_traceback),
100
+ ) from exc.__cause__
101
+ raise
82
102
 
83
103
  if was_it_raised:
84
104
  raise prepare_exc(result, stringized_traceback=stringized_traceback)
@@ -111,18 +131,19 @@ def validate_entrypoint(entrypoint: str) -> None:
111
131
  raise ValueError(f"Invalid entrypoint {entrypoint!r}: expected 'module:attr'.")
112
132
 
113
133
 
134
+ def _prepare_traceback(stringized_traceback: str | None) -> TracebackType | None:
135
+ if stringized_traceback:
136
+ try:
137
+ return Traceback.from_string(stringized_traceback).as_traceback()
138
+ except TracebackParseError:
139
+ pass
140
+ return None
141
+
142
+
114
143
  def prepare_exc(
115
144
  exc: BaseException,
116
145
  *,
117
146
  stringized_traceback: str | None = None,
118
147
  ) -> BaseException:
119
- if stringized_traceback:
120
- try:
121
- traceback = Traceback.from_string(stringized_traceback).as_traceback()
122
- except TracebackParseError:
123
- traceback = None
124
- else:
125
- traceback = None
126
-
127
- exc.__traceback__ = traceback
148
+ exc.__traceback__ = _prepare_traceback(stringized_traceback)
128
149
  return exc
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: isolate
3
- Version: 0.26.6
3
+ Version: 0.26.7
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
@@ -555,6 +555,7 @@ class TestConda(GenericEnvironmentTests):
555
555
  "packages": [],
556
556
  },
557
557
  "black": {
558
+ "python_version": "3.11",
558
559
  "packages": ["black=22.12.0"],
559
560
  },
560
561
  "old-python": {
@@ -1,7 +1,11 @@
1
+ import importlib
2
+ import sys
3
+ import traceback
1
4
  from functools import partial
2
5
 
3
6
  import pytest
4
7
  from isolate.connections.common import (
8
+ ExceptionDeserializationError,
5
9
  SerializationError,
6
10
  load_serialized_object,
7
11
  serialize_object,
@@ -37,6 +41,38 @@ def test_deserialize_raised_exception():
37
41
  assert exc_info.value.args == ("some error",)
38
42
 
39
43
 
44
+ def test_deserialize_raised_exception_with_unimportable_type_preserves_traceback(
45
+ tmp_path,
46
+ monkeypatch,
47
+ ):
48
+ module_name = "remote_only_exc_for_isolate_test"
49
+ module_path = tmp_path / f"{module_name}.py"
50
+ module_path.write_text("class RemoteOnlyError(Exception):\n pass\n")
51
+ monkeypatch.syspath_prepend(str(tmp_path))
52
+ remote_module = importlib.import_module(module_name)
53
+
54
+ try:
55
+ raise remote_module.RemoteOnlyError("remote boom")
56
+ except remote_module.RemoteOnlyError as exc:
57
+ serialized = serialize_object("pickle", exc)
58
+ stringized_traceback = traceback.format_exc()
59
+
60
+ sys.modules.pop(module_name, None)
61
+ sys.path.remove(str(tmp_path))
62
+
63
+ with pytest.raises(ExceptionDeserializationError) as exc_info:
64
+ load_serialized_object(
65
+ "pickle",
66
+ serialized,
67
+ was_it_raised=True,
68
+ stringized_traceback=stringized_traceback,
69
+ )
70
+
71
+ assert exc_info.value.message == "Error while deserializing the given object"
72
+ assert exc_info.value.original_traceback is not None
73
+ assert isinstance(exc_info.value.__cause__, ModuleNotFoundError)
74
+
75
+
40
76
  def error_while_serializing():
41
77
  anon = lambda: 2 + 2 # anonymous functions are not # noqa: E731
42
78
  # serializable by pickle
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes