isolate 0.26.6__tar.gz → 0.26.8__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.
- {isolate-0.26.6 → isolate-0.26.8}/.github/workflows/test.yml +2 -2
- {isolate-0.26.6/src/isolate.egg-info → isolate-0.26.8}/PKG-INFO +1 -1
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/_isolate_version.py +3 -3
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/common.py +36 -11
- {isolate-0.26.6 → isolate-0.26.8/src/isolate.egg-info}/PKG-INFO +1 -1
- {isolate-0.26.6 → isolate-0.26.8}/tests/test_backends.py +1 -0
- {isolate-0.26.6 → isolate-0.26.8}/tests/test_serialization.py +37 -0
- {isolate-0.26.6 → isolate-0.26.8}/.github/workflows/claude-code-review.yml +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/.github/workflows/claude.yml +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/.github/workflows/lint.yml +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/.github/workflows/release.yml +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/.gitignore +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/.pre-commit-config.yaml +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/LICENSE +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/README.md +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/pyproject.toml +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/setup.cfg +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/__init__.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/_version.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/backends/__init__.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/backends/_base.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/backends/common.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/backends/conda.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/backends/container.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/backends/local.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/backends/pyenv.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/backends/remote.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/backends/settings.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/backends/virtualenv.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/common/__init__.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/common/timestamp.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/__init__.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/_local/__init__.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/_local/_base.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/_local/agent_startup.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/__init__.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/_base.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/agent.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/configuration.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/definitions/__init__.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/definitions/agent.proto +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/definitions/agent_pb2.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/definitions/agent_pb2.pyi +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/definitions/agent_pb2_grpc.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/definitions/common.proto +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/definitions/common_pb2.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/definitions/common_pb2.pyi +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/definitions/common_pb2_grpc.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/interface.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/ipc/__init__.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/ipc/_base.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/ipc/agent.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/logger.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/logs.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/py.typed +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/registry.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/server/__init__.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/server/definitions/__init__.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/server/definitions/server.proto +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/server/definitions/server_pb2.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/server/definitions/server_pb2.pyi +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/server/definitions/server_pb2_grpc.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/server/health/__init__.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/server/health/health.proto +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/server/health/health_pb2.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/server/health/health_pb2.pyi +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/server/health/health_pb2_grpc.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/server/health_server.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/server/interface.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate/server/server.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate.egg-info/SOURCES.txt +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate.egg-info/dependency_links.txt +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate.egg-info/entry_points.txt +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate.egg-info/requires.txt +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/src/isolate.egg-info/top_level.txt +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tests/__init__.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tests/conftest.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tests/test_agent_backward_compatibility.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tests/test_concurrency.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tests/test_connections.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tests/test_connections_grpc_base.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tests/test_isolate.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tests/test_log.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tests/test_log_masking.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tests/test_logged_io_pipe.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tests/test_logger.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tests/test_server.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tests/test_shutdown.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tools/Dockerfile +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tools/agent_requirements.txt +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tools/isolate_client.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tools/protobuf-requirements.txt +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tools/regen_grpc.py +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/tools/requirements.txt +0 -0
- {isolate-0.26.6 → isolate-0.26.8}/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.
|
|
30
|
+
python: "3.14"
|
|
31
31
|
steps:
|
|
32
32
|
- uses: actions/checkout@v3
|
|
33
33
|
|
|
@@ -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.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 26,
|
|
31
|
+
__version__ = version = '0.26.8'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 26, 8)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'ge1f994002'
|
|
@@ -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,15 @@ 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
|
+
original_stringized_traceback: str | None
|
|
39
|
+
|
|
40
|
+
|
|
31
41
|
# NOTE: tblib's install() will search for BaseException subclasses,
|
|
32
42
|
# so we have to call it after the SerializationError is defined.
|
|
33
43
|
tblib_install()
|
|
@@ -77,8 +87,22 @@ def load_serialized_object(
|
|
|
77
87
|
importlib.import_module(serialization_method)
|
|
78
88
|
)
|
|
79
89
|
|
|
80
|
-
|
|
81
|
-
|
|
90
|
+
try:
|
|
91
|
+
with _step("deserializing the given object"):
|
|
92
|
+
result = serialization_backend.loads(raw_object)
|
|
93
|
+
except SerializationError as exc:
|
|
94
|
+
if was_it_raised:
|
|
95
|
+
# We were trying to reconstruct a remote exception but its type
|
|
96
|
+
# isn't importable here, so loads() failed. Surface the genuine
|
|
97
|
+
# local cause along with the remote traceback.
|
|
98
|
+
# Keep both traceback forms: Traceback.from_string() preserves
|
|
99
|
+
# frames, while the string also includes the exception type/message.
|
|
100
|
+
raise ExceptionDeserializationError(
|
|
101
|
+
exc.message,
|
|
102
|
+
original_traceback=_prepare_traceback(stringized_traceback),
|
|
103
|
+
original_stringized_traceback=stringized_traceback,
|
|
104
|
+
) from exc.__cause__
|
|
105
|
+
raise
|
|
82
106
|
|
|
83
107
|
if was_it_raised:
|
|
84
108
|
raise prepare_exc(result, stringized_traceback=stringized_traceback)
|
|
@@ -111,18 +135,19 @@ def validate_entrypoint(entrypoint: str) -> None:
|
|
|
111
135
|
raise ValueError(f"Invalid entrypoint {entrypoint!r}: expected 'module:attr'.")
|
|
112
136
|
|
|
113
137
|
|
|
138
|
+
def _prepare_traceback(stringized_traceback: str | None) -> TracebackType | None:
|
|
139
|
+
if stringized_traceback:
|
|
140
|
+
try:
|
|
141
|
+
return Traceback.from_string(stringized_traceback).as_traceback()
|
|
142
|
+
except TracebackParseError:
|
|
143
|
+
pass
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
|
|
114
147
|
def prepare_exc(
|
|
115
148
|
exc: BaseException,
|
|
116
149
|
*,
|
|
117
150
|
stringized_traceback: str | None = None,
|
|
118
151
|
) -> BaseException:
|
|
119
|
-
|
|
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
|
|
152
|
+
exc.__traceback__ = _prepare_traceback(stringized_traceback)
|
|
128
153
|
return exc
|
|
@@ -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,39 @@ 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 exc_info.value.original_stringized_traceback == stringized_traceback
|
|
74
|
+
assert isinstance(exc_info.value.__cause__, ModuleNotFoundError)
|
|
75
|
+
|
|
76
|
+
|
|
40
77
|
def error_while_serializing():
|
|
41
78
|
anon = lambda: 2 + 2 # anonymous functions are not # noqa: E731
|
|
42
79
|
# 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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/definitions/agent_pb2_grpc.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{isolate-0.26.6 → isolate-0.26.8}/src/isolate/connections/grpc/definitions/common_pb2_grpc.py
RENAMED
|
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
|
|
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
|
|
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
|