blaxel 0.1.9rc37__py3-none-any.whl → 0.1.10rc39__py3-none-any.whl
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.
- blaxel/authentication/__init__.py +11 -2
- blaxel/common/autoload.py +1 -0
- blaxel/common/internal.py +5 -5
- blaxel/sandbox/base.py +68 -0
- blaxel/sandbox/client/__init__.py +8 -0
- blaxel/sandbox/client/api/__init__.py +1 -0
- blaxel/sandbox/client/api/filesystem/__init__.py +0 -0
- blaxel/sandbox/client/api/filesystem/delete_filesystem_path.py +184 -0
- blaxel/sandbox/client/api/filesystem/get_filesystem_path.py +184 -0
- blaxel/sandbox/client/api/filesystem/put_filesystem_path.py +189 -0
- blaxel/sandbox/client/api/network/__init__.py +0 -0
- blaxel/sandbox/client/api/network/delete_network_process_pid_monitor.py +169 -0
- blaxel/sandbox/client/api/network/get_network_process_pid_ports.py +169 -0
- blaxel/sandbox/client/api/network/post_network_process_pid_monitor.py +195 -0
- blaxel/sandbox/client/api/process/__init__.py +0 -0
- blaxel/sandbox/client/api/process/delete_process_identifier.py +163 -0
- blaxel/sandbox/client/api/process/delete_process_identifier_kill.py +189 -0
- blaxel/sandbox/client/api/process/get_process.py +135 -0
- blaxel/sandbox/client/api/process/get_process_identifier.py +159 -0
- blaxel/sandbox/client/api/process/get_process_identifier_logs.py +167 -0
- blaxel/sandbox/client/api/process/post_process.py +176 -0
- blaxel/sandbox/client/client.py +162 -0
- blaxel/sandbox/client/errors.py +16 -0
- blaxel/sandbox/client/models/__init__.py +35 -0
- blaxel/sandbox/client/models/delete_network_process_pid_monitor_response_200.py +45 -0
- blaxel/sandbox/client/models/directory.py +110 -0
- blaxel/sandbox/client/models/error_response.py +60 -0
- blaxel/sandbox/client/models/file.py +105 -0
- blaxel/sandbox/client/models/file_request.py +78 -0
- blaxel/sandbox/client/models/file_with_content.py +114 -0
- blaxel/sandbox/client/models/get_network_process_pid_ports_response_200.py +45 -0
- blaxel/sandbox/client/models/get_process_identifier_logs_response_200.py +45 -0
- blaxel/sandbox/client/models/port_monitor_request.py +60 -0
- blaxel/sandbox/client/models/post_network_process_pid_monitor_response_200.py +45 -0
- blaxel/sandbox/client/models/process_kill_request.py +60 -0
- blaxel/sandbox/client/models/process_request.py +118 -0
- blaxel/sandbox/client/models/process_response.py +123 -0
- blaxel/sandbox/client/models/success_response.py +69 -0
- blaxel/sandbox/client/py.typed +1 -0
- blaxel/sandbox/client/types.py +46 -0
- blaxel/sandbox/filesystem.py +104 -0
- blaxel/sandbox/process.py +57 -0
- blaxel/sandbox/sandbox.py +92 -0
- blaxel/tools/__init__.py +1 -1
- {blaxel-0.1.9rc37.dist-info → blaxel-0.1.10rc39.dist-info}/METADATA +1 -1
- {blaxel-0.1.9rc37.dist-info → blaxel-0.1.10rc39.dist-info}/RECORD +48 -8
- {blaxel-0.1.9rc37.dist-info → blaxel-0.1.10rc39.dist-info}/WHEEL +0 -0
- {blaxel-0.1.9rc37.dist-info → blaxel-0.1.10rc39.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,123 @@
|
|
1
|
+
from typing import Any, TypeVar, Union
|
2
|
+
|
3
|
+
from attrs import define as _attrs_define
|
4
|
+
from attrs import field as _attrs_field
|
5
|
+
|
6
|
+
from ..types import UNSET, Unset
|
7
|
+
|
8
|
+
T = TypeVar("T", bound="ProcessResponse")
|
9
|
+
|
10
|
+
|
11
|
+
@_attrs_define
|
12
|
+
class ProcessResponse:
|
13
|
+
"""
|
14
|
+
Attributes:
|
15
|
+
command (Union[Unset, str]): Example: ls -la.
|
16
|
+
completed_at (Union[Unset, str]): Example: Wed, 01 Jan 2023 12:01:00 GMT.
|
17
|
+
exit_code (Union[Unset, int]):
|
18
|
+
name (Union[Unset, str]): Example: my-process.
|
19
|
+
pid (Union[Unset, str]): Example: 1234.
|
20
|
+
started_at (Union[Unset, str]): Example: Wed, 01 Jan 2023 12:00:00 GMT.
|
21
|
+
status (Union[Unset, str]): Example: running.
|
22
|
+
working_dir (Union[Unset, str]): Example: /home/user.
|
23
|
+
"""
|
24
|
+
|
25
|
+
command: Union[Unset, str] = UNSET
|
26
|
+
completed_at: Union[Unset, str] = UNSET
|
27
|
+
exit_code: Union[Unset, int] = UNSET
|
28
|
+
name: Union[Unset, str] = UNSET
|
29
|
+
pid: Union[Unset, str] = UNSET
|
30
|
+
started_at: Union[Unset, str] = UNSET
|
31
|
+
status: Union[Unset, str] = UNSET
|
32
|
+
working_dir: Union[Unset, str] = UNSET
|
33
|
+
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
|
34
|
+
|
35
|
+
def to_dict(self) -> dict[str, Any]:
|
36
|
+
command = self.command
|
37
|
+
|
38
|
+
completed_at = self.completed_at
|
39
|
+
|
40
|
+
exit_code = self.exit_code
|
41
|
+
|
42
|
+
name = self.name
|
43
|
+
|
44
|
+
pid = self.pid
|
45
|
+
|
46
|
+
started_at = self.started_at
|
47
|
+
|
48
|
+
status = self.status
|
49
|
+
|
50
|
+
working_dir = self.working_dir
|
51
|
+
|
52
|
+
field_dict: dict[str, Any] = {}
|
53
|
+
field_dict.update(self.additional_properties)
|
54
|
+
field_dict.update({})
|
55
|
+
if command is not UNSET:
|
56
|
+
field_dict["command"] = command
|
57
|
+
if completed_at is not UNSET:
|
58
|
+
field_dict["completedAt"] = completed_at
|
59
|
+
if exit_code is not UNSET:
|
60
|
+
field_dict["exitCode"] = exit_code
|
61
|
+
if name is not UNSET:
|
62
|
+
field_dict["name"] = name
|
63
|
+
if pid is not UNSET:
|
64
|
+
field_dict["pid"] = pid
|
65
|
+
if started_at is not UNSET:
|
66
|
+
field_dict["startedAt"] = started_at
|
67
|
+
if status is not UNSET:
|
68
|
+
field_dict["status"] = status
|
69
|
+
if working_dir is not UNSET:
|
70
|
+
field_dict["workingDir"] = working_dir
|
71
|
+
|
72
|
+
return field_dict
|
73
|
+
|
74
|
+
@classmethod
|
75
|
+
def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T:
|
76
|
+
if not src_dict:
|
77
|
+
return None
|
78
|
+
d = src_dict.copy()
|
79
|
+
command = d.pop("command", UNSET)
|
80
|
+
|
81
|
+
completed_at = d.pop("completedAt", UNSET)
|
82
|
+
|
83
|
+
exit_code = d.pop("exitCode", UNSET)
|
84
|
+
|
85
|
+
name = d.pop("name", UNSET)
|
86
|
+
|
87
|
+
pid = d.pop("pid", UNSET)
|
88
|
+
|
89
|
+
started_at = d.pop("startedAt", UNSET)
|
90
|
+
|
91
|
+
status = d.pop("status", UNSET)
|
92
|
+
|
93
|
+
working_dir = d.pop("workingDir", UNSET)
|
94
|
+
|
95
|
+
process_response = cls(
|
96
|
+
command=command,
|
97
|
+
completed_at=completed_at,
|
98
|
+
exit_code=exit_code,
|
99
|
+
name=name,
|
100
|
+
pid=pid,
|
101
|
+
started_at=started_at,
|
102
|
+
status=status,
|
103
|
+
working_dir=working_dir,
|
104
|
+
)
|
105
|
+
|
106
|
+
process_response.additional_properties = d
|
107
|
+
return process_response
|
108
|
+
|
109
|
+
@property
|
110
|
+
def additional_keys(self) -> list[str]:
|
111
|
+
return list(self.additional_properties.keys())
|
112
|
+
|
113
|
+
def __getitem__(self, key: str) -> Any:
|
114
|
+
return self.additional_properties[key]
|
115
|
+
|
116
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
117
|
+
self.additional_properties[key] = value
|
118
|
+
|
119
|
+
def __delitem__(self, key: str) -> None:
|
120
|
+
del self.additional_properties[key]
|
121
|
+
|
122
|
+
def __contains__(self, key: str) -> bool:
|
123
|
+
return key in self.additional_properties
|
@@ -0,0 +1,69 @@
|
|
1
|
+
from typing import Any, TypeVar, Union
|
2
|
+
|
3
|
+
from attrs import define as _attrs_define
|
4
|
+
from attrs import field as _attrs_field
|
5
|
+
|
6
|
+
from ..types import UNSET, Unset
|
7
|
+
|
8
|
+
T = TypeVar("T", bound="SuccessResponse")
|
9
|
+
|
10
|
+
|
11
|
+
@_attrs_define
|
12
|
+
class SuccessResponse:
|
13
|
+
"""
|
14
|
+
Attributes:
|
15
|
+
message (Union[Unset, str]): Example: File created successfully.
|
16
|
+
path (Union[Unset, str]): Example: /path/to/file.
|
17
|
+
"""
|
18
|
+
|
19
|
+
message: Union[Unset, str] = UNSET
|
20
|
+
path: Union[Unset, str] = UNSET
|
21
|
+
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
|
22
|
+
|
23
|
+
def to_dict(self) -> dict[str, Any]:
|
24
|
+
message = self.message
|
25
|
+
|
26
|
+
path = self.path
|
27
|
+
|
28
|
+
field_dict: dict[str, Any] = {}
|
29
|
+
field_dict.update(self.additional_properties)
|
30
|
+
field_dict.update({})
|
31
|
+
if message is not UNSET:
|
32
|
+
field_dict["message"] = message
|
33
|
+
if path is not UNSET:
|
34
|
+
field_dict["path"] = path
|
35
|
+
|
36
|
+
return field_dict
|
37
|
+
|
38
|
+
@classmethod
|
39
|
+
def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T:
|
40
|
+
if not src_dict:
|
41
|
+
return None
|
42
|
+
d = src_dict.copy()
|
43
|
+
message = d.pop("message", UNSET)
|
44
|
+
|
45
|
+
path = d.pop("path", UNSET)
|
46
|
+
|
47
|
+
success_response = cls(
|
48
|
+
message=message,
|
49
|
+
path=path,
|
50
|
+
)
|
51
|
+
|
52
|
+
success_response.additional_properties = d
|
53
|
+
return success_response
|
54
|
+
|
55
|
+
@property
|
56
|
+
def additional_keys(self) -> list[str]:
|
57
|
+
return list(self.additional_properties.keys())
|
58
|
+
|
59
|
+
def __getitem__(self, key: str) -> Any:
|
60
|
+
return self.additional_properties[key]
|
61
|
+
|
62
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
63
|
+
self.additional_properties[key] = value
|
64
|
+
|
65
|
+
def __delitem__(self, key: str) -> None:
|
66
|
+
del self.additional_properties[key]
|
67
|
+
|
68
|
+
def __contains__(self, key: str) -> bool:
|
69
|
+
return key in self.additional_properties
|
@@ -0,0 +1 @@
|
|
1
|
+
# Marker file for PEP 561
|
@@ -0,0 +1,46 @@
|
|
1
|
+
"""Contains some shared types for properties"""
|
2
|
+
|
3
|
+
from collections.abc import MutableMapping
|
4
|
+
from http import HTTPStatus
|
5
|
+
from typing import BinaryIO, Generic, Literal, Optional, TypeVar
|
6
|
+
|
7
|
+
from attrs import define
|
8
|
+
|
9
|
+
|
10
|
+
class Unset:
|
11
|
+
def __bool__(self) -> Literal[False]:
|
12
|
+
return False
|
13
|
+
|
14
|
+
|
15
|
+
UNSET: Unset = Unset()
|
16
|
+
|
17
|
+
FileJsonType = tuple[Optional[str], BinaryIO, Optional[str]]
|
18
|
+
|
19
|
+
|
20
|
+
@define
|
21
|
+
class File:
|
22
|
+
"""Contains information for file uploads"""
|
23
|
+
|
24
|
+
payload: BinaryIO
|
25
|
+
file_name: Optional[str] = None
|
26
|
+
mime_type: Optional[str] = None
|
27
|
+
|
28
|
+
def to_tuple(self) -> FileJsonType:
|
29
|
+
"""Return a tuple representation that httpx will accept for multipart/form-data"""
|
30
|
+
return self.file_name, self.payload, self.mime_type
|
31
|
+
|
32
|
+
|
33
|
+
T = TypeVar("T")
|
34
|
+
|
35
|
+
|
36
|
+
@define
|
37
|
+
class Response(Generic[T]):
|
38
|
+
"""A response from an endpoint"""
|
39
|
+
|
40
|
+
status_code: HTTPStatus
|
41
|
+
content: bytes
|
42
|
+
headers: MutableMapping[str, str]
|
43
|
+
parsed: Optional[T]
|
44
|
+
|
45
|
+
|
46
|
+
__all__ = ["UNSET", "File", "FileJsonType", "Response", "Unset"]
|
@@ -0,0 +1,104 @@
|
|
1
|
+
import asyncio
|
2
|
+
from typing import Dict
|
3
|
+
|
4
|
+
from ..common.settings import settings
|
5
|
+
from .base import SandboxHandleBase
|
6
|
+
from .client.api.filesystem.delete_filesystem_path import (
|
7
|
+
asyncio_detailed as delete_filesystem_by_path,
|
8
|
+
)
|
9
|
+
from .client.api.filesystem.get_filesystem_path import asyncio_detailed as get_filesystem_by_path
|
10
|
+
from .client.api.filesystem.put_filesystem_path import asyncio_detailed as put_filesystem_by_path
|
11
|
+
from .client.client import client
|
12
|
+
from .client.models import Directory, FileRequest, SuccessResponse
|
13
|
+
|
14
|
+
|
15
|
+
class SandboxFileSystem(SandboxHandleBase):
|
16
|
+
def __init__(self, sandbox):
|
17
|
+
super().__init__(sandbox)
|
18
|
+
self.client = client.with_base_url(self.url).with_headers(settings.headers)
|
19
|
+
|
20
|
+
async def mkdir(self, path: str, permissions: str = "0755") -> SuccessResponse:
|
21
|
+
path = self.format_path(path)
|
22
|
+
body = FileRequest(is_directory=True, permissions=permissions)
|
23
|
+
response = await put_filesystem_by_path(path=path, client=self.client, body=body)
|
24
|
+
self.handle_response(response)
|
25
|
+
return response.parsed
|
26
|
+
|
27
|
+
async def write(self, path: str, content: str) -> SuccessResponse:
|
28
|
+
path = self.format_path(path)
|
29
|
+
body = FileRequest(content=content)
|
30
|
+
response = await put_filesystem_by_path(path=path, client=self.client, body=body)
|
31
|
+
self.handle_response(response)
|
32
|
+
return response.parsed
|
33
|
+
|
34
|
+
async def read(self, path: str) -> str:
|
35
|
+
path = self.format_path(path)
|
36
|
+
response = await get_filesystem_by_path(path=path, client=self.client)
|
37
|
+
self.handle_response(response)
|
38
|
+
if "content" not in response.parsed.additional_properties:
|
39
|
+
raise Exception('{"error": "File not found"}')
|
40
|
+
return response.parsed.additional_properties["content"]
|
41
|
+
|
42
|
+
async def rm(self, path: str, recursive: bool = False) -> SuccessResponse:
|
43
|
+
path = self.format_path(path)
|
44
|
+
response = await delete_filesystem_by_path(path=path, client=self.client, recursive=recursive)
|
45
|
+
self.handle_response(response)
|
46
|
+
return response.parsed
|
47
|
+
|
48
|
+
async def ls(self, path: str) -> Directory:
|
49
|
+
path = self.format_path(path)
|
50
|
+
response = await get_filesystem_by_path(path=path, client=self.client)
|
51
|
+
self.handle_response(response)
|
52
|
+
if not hasattr(response.parsed, "files") and not hasattr(response.parsed, "subdirectories"):
|
53
|
+
raise Exception('{"error": "Directory not found"}')
|
54
|
+
return response.parsed
|
55
|
+
|
56
|
+
async def cp(self, source: str, destination: str) -> Dict[str, str]:
|
57
|
+
source = self.format_path(source)
|
58
|
+
destination = self.format_path(destination)
|
59
|
+
response = await get_filesystem_by_path(path=source, client=self.client)
|
60
|
+
self.handle_response(response)
|
61
|
+
data = response.parsed
|
62
|
+
if "content" in data.additional_properties:
|
63
|
+
await self.write(destination, data.additional_properties["content"])
|
64
|
+
return {
|
65
|
+
"message": "File copied successfully",
|
66
|
+
"source": source,
|
67
|
+
"destination": destination,
|
68
|
+
}
|
69
|
+
elif hasattr(data, "subdirectories") or hasattr(data, "files"):
|
70
|
+
# Create destination directory
|
71
|
+
await self.mkdir(destination)
|
72
|
+
# Process subdirectories in batches of 5
|
73
|
+
subdirectories = getattr(data, "subdirectories", []) or []
|
74
|
+
for i in range(0, len(subdirectories), 5):
|
75
|
+
batch = subdirectories[i:i+5]
|
76
|
+
await asyncio.gather(*[
|
77
|
+
self.cp(
|
78
|
+
getattr(subdir, "path", f"{source}/{getattr(subdir, 'path', '')}"),
|
79
|
+
f"{destination}/{getattr(subdir, 'path', '')}"
|
80
|
+
) for subdir in batch
|
81
|
+
])
|
82
|
+
# Process files in batches of 10
|
83
|
+
files = getattr(data, "files", []) or []
|
84
|
+
for i in range(0, len(files), 10):
|
85
|
+
batch = files[i:i+10]
|
86
|
+
await asyncio.gather(*[
|
87
|
+
self.write(
|
88
|
+
f"{destination}/{getattr(file, 'path', '')}",
|
89
|
+
await self.read(getattr(file, "path", f"{source}/{getattr(file, 'path', '')}"))
|
90
|
+
) for file in batch
|
91
|
+
])
|
92
|
+
return {
|
93
|
+
"message": "Directory copied successfully",
|
94
|
+
"source": source,
|
95
|
+
"destination": destination,
|
96
|
+
}
|
97
|
+
raise Exception("Unsupported file type")
|
98
|
+
|
99
|
+
def format_path(self, path: str) -> str:
|
100
|
+
if path == "/":
|
101
|
+
return "%2F"
|
102
|
+
if path.startswith("/"):
|
103
|
+
path = path[1:]
|
104
|
+
return path
|
@@ -0,0 +1,57 @@
|
|
1
|
+
from blaxel.sandbox.client.models.process_request import ProcessRequest
|
2
|
+
|
3
|
+
from .base import SandboxHandleBase
|
4
|
+
from .client.api.process.delete_process_identifier import (
|
5
|
+
asyncio_detailed as delete_process_by_identifier,
|
6
|
+
)
|
7
|
+
from .client.api.process.delete_process_identifier_kill import (
|
8
|
+
asyncio_detailed as delete_process_by_identifier_kill,
|
9
|
+
)
|
10
|
+
from .client.api.process.get_process import asyncio_detailed as get_process
|
11
|
+
from .client.api.process.get_process_identifier import asyncio_detailed as get_process_by_identifier
|
12
|
+
from .client.api.process.get_process_identifier_logs import (
|
13
|
+
asyncio_detailed as get_process_by_identifier_logs,
|
14
|
+
)
|
15
|
+
from .client.api.process.post_process import asyncio_detailed as post_process
|
16
|
+
from .client.models import (
|
17
|
+
GetProcessIdentifierLogsResponse200,
|
18
|
+
ProcessKillRequest,
|
19
|
+
ProcessResponse,
|
20
|
+
SuccessResponse,
|
21
|
+
)
|
22
|
+
|
23
|
+
|
24
|
+
class SandboxProcess(SandboxHandleBase):
|
25
|
+
async def exec(self, process: ProcessRequest) -> ProcessResponse:
|
26
|
+
response = await post_process(client=self.client, body=process)
|
27
|
+
self.handle_response(response)
|
28
|
+
return response.parsed
|
29
|
+
|
30
|
+
async def get(self, identifier: str) -> ProcessResponse:
|
31
|
+
response = await get_process_by_identifier(identifier=identifier, client=self.client)
|
32
|
+
self.handle_response(response)
|
33
|
+
return response.parsed
|
34
|
+
|
35
|
+
async def list(self) -> list[ProcessResponse]:
|
36
|
+
response = await get_process(client=self.client)
|
37
|
+
self.handle_response(response)
|
38
|
+
return response.parsed
|
39
|
+
|
40
|
+
async def stop(self, identifier: str) -> SuccessResponse:
|
41
|
+
response = await delete_process_by_identifier(identifier=identifier, client=self.client)
|
42
|
+
self.handle_response(response)
|
43
|
+
return response.parsed
|
44
|
+
|
45
|
+
async def kill(self, identifier: str, signal: str = "SIGKILL") -> SuccessResponse:
|
46
|
+
kill_request = ProcessKillRequest(signal=signal)
|
47
|
+
response = await delete_process_by_identifier_kill(identifier=identifier, client=self.client, body=kill_request)
|
48
|
+
self.handle_response(response)
|
49
|
+
return response.parsed
|
50
|
+
|
51
|
+
async def logs(self, identifier: str, type_: str = "stdout") -> str:
|
52
|
+
response = await get_process_by_identifier_logs(identifier=identifier, client=self.client)
|
53
|
+
self.handle_response(response)
|
54
|
+
data: GetProcessIdentifierLogsResponse200 = response.parsed
|
55
|
+
if type_ in data.additional_properties:
|
56
|
+
return data.additional_properties[type_]
|
57
|
+
raise Exception("Unsupported log type")
|
@@ -0,0 +1,92 @@
|
|
1
|
+
import asyncio
|
2
|
+
import logging
|
3
|
+
import time
|
4
|
+
from typing import List
|
5
|
+
|
6
|
+
from ..client.api.compute.create_sandbox import asyncio as create_sandbox
|
7
|
+
from ..client.api.compute.delete_sandbox import asyncio as delete_sandbox
|
8
|
+
from ..client.api.compute.get_sandbox import asyncio as get_sandbox
|
9
|
+
from ..client.api.compute.list_sandboxes import asyncio as list_sandboxes
|
10
|
+
from ..client.client import client
|
11
|
+
from ..client.models import Sandbox
|
12
|
+
from .filesystem import SandboxFileSystem
|
13
|
+
from .process import SandboxProcess
|
14
|
+
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
class SandboxInstance:
|
18
|
+
def __init__(self, sandbox: Sandbox):
|
19
|
+
self.sandbox = sandbox
|
20
|
+
self.fs = SandboxFileSystem(sandbox)
|
21
|
+
self.process = SandboxProcess(sandbox)
|
22
|
+
|
23
|
+
@property
|
24
|
+
def metadata(self):
|
25
|
+
return self.sandbox.metadata
|
26
|
+
|
27
|
+
@property
|
28
|
+
def status(self):
|
29
|
+
return self.sandbox.status
|
30
|
+
|
31
|
+
@property
|
32
|
+
def events(self):
|
33
|
+
return self.sandbox.events
|
34
|
+
|
35
|
+
@property
|
36
|
+
def spec(self):
|
37
|
+
return self.sandbox.spec
|
38
|
+
|
39
|
+
async def wait(self, max_wait: int = 60000, interval: int = 1000) -> None:
|
40
|
+
start_time = time.time() * 1000 # Convert to milliseconds
|
41
|
+
while self.sandbox.status != "DEPLOYED":
|
42
|
+
await asyncio.sleep(interval / 1000) # Convert to seconds
|
43
|
+
try:
|
44
|
+
response = await get_sandbox(
|
45
|
+
self.sandbox.metadata.name,
|
46
|
+
client=client,
|
47
|
+
)
|
48
|
+
logger.info(f"Waiting for sandbox to be deployed, status: {response.status}")
|
49
|
+
self.sandbox = response
|
50
|
+
except Exception as e:
|
51
|
+
logger.error("Could not retrieve sandbox", exc_info=e)
|
52
|
+
|
53
|
+
if self.sandbox.status == "FAILED":
|
54
|
+
raise Exception("Sandbox failed to deploy")
|
55
|
+
|
56
|
+
if (time.time() * 1000) - start_time > max_wait:
|
57
|
+
raise Exception("Sandbox did not deploy in time")
|
58
|
+
|
59
|
+
@classmethod
|
60
|
+
async def create(cls, sandbox: Sandbox) -> "SandboxInstance":
|
61
|
+
if not sandbox.spec:
|
62
|
+
raise Exception("Sandbox spec is required")
|
63
|
+
if not sandbox.spec.runtime:
|
64
|
+
raise Exception("Sandbox runtime is required")
|
65
|
+
sandbox.spec.runtime.generation = sandbox.spec.runtime.generation or "mk3"
|
66
|
+
|
67
|
+
response = await create_sandbox(
|
68
|
+
client=client,
|
69
|
+
body=sandbox,
|
70
|
+
)
|
71
|
+
return cls(response)
|
72
|
+
|
73
|
+
@classmethod
|
74
|
+
async def get(cls, sandbox_name: str) -> "SandboxInstance":
|
75
|
+
response = await get_sandbox(
|
76
|
+
sandbox_name,
|
77
|
+
client=client,
|
78
|
+
)
|
79
|
+
return cls(response)
|
80
|
+
|
81
|
+
@classmethod
|
82
|
+
async def list(cls) -> List["SandboxInstance"]:
|
83
|
+
response = await list_sandboxes()
|
84
|
+
return [cls(sandbox) for sandbox in response]
|
85
|
+
|
86
|
+
@classmethod
|
87
|
+
async def delete(cls, sandbox_name: str) -> Sandbox:
|
88
|
+
response = await delete_sandbox(
|
89
|
+
sandbox_name,
|
90
|
+
client=client,
|
91
|
+
)
|
92
|
+
return response
|
blaxel/tools/__init__.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
blaxel/__init__.py,sha256=qmuJKjl5oGnjj4TbqHcJqUkKoxk4PvCsMb6-8rp67pE,159
|
2
2
|
blaxel/agents/__init__.py,sha256=RDWkvfICIXXaQxJuuSu63jsFj_F8NBAL4U752hfN4AE,5262
|
3
|
-
blaxel/authentication/__init__.py,sha256=
|
3
|
+
blaxel/authentication/__init__.py,sha256=tL9XKNCek5ixszTqjlKRBvidXMg4Nj6ODlBKlxxA9uk,3283
|
4
4
|
blaxel/authentication/apikey.py,sha256=nOgLVba7EfVk3V-qm7cj-30LAL-BT7NOMIlGL9Ni1jY,1249
|
5
5
|
blaxel/authentication/clientcredentials.py,sha256=SfWNuZVHZw6jjMqoBMMB4ZawmpyKbVPbOpv-JDFqzw8,3080
|
6
6
|
blaxel/authentication/devicemode.py,sha256=kWbArs4okIIDqW-ql5oV2eQRE_LpRwfadCB6LG83irw,5986
|
@@ -236,9 +236,9 @@ blaxel/client/models/workspace.py,sha256=K_xs5Z6qFVgw6ShzaSBtTLIdltcpfu1Op422IA2
|
|
236
236
|
blaxel/client/models/workspace_labels.py,sha256=WbnUY6eCTkUNdY7hhhSF-KQCl8fWFfkCf7hzCTiNp4A,1246
|
237
237
|
blaxel/client/models/workspace_runtime.py,sha256=dxEpmwCFPOCRKHRKhY-iW7j6TbtL5qUsbjzSn00uTXU,1665
|
238
238
|
blaxel/client/models/workspace_user.py,sha256=70CcifQWYbeWG7TDui4pblTzUe5sVK0AS19vNCzKE8g,3423
|
239
|
-
blaxel/common/autoload.py,sha256=
|
239
|
+
blaxel/common/autoload.py,sha256=NFuK71-IHOY2JQyEBSjDCVfUaQ8D8PJsEUEryIdG4AU,263
|
240
240
|
blaxel/common/env.py,sha256=wTbzPDdNgz4HMJiS2NCZmQlN0qpxy1PQEYBaZgtvhoc,1247
|
241
|
-
blaxel/common/internal.py,sha256=
|
241
|
+
blaxel/common/internal.py,sha256=J-etgnBzelb-ln8uBR9WIWzrEUyDds8rdT9FImjes9g,2390
|
242
242
|
blaxel/common/logger.py,sha256=emqgonfZMBIaQPowpngWOOZxWQieKP-yj_OzGZT8Oe8,1918
|
243
243
|
blaxel/common/settings.py,sha256=X0g0_hIR19qfjSeWNf8qraxb_UTSbYukVHJeRHKLTn8,2138
|
244
244
|
blaxel/instrumentation/exporters.py,sha256=EoX3uaBVku1Rg49pSNXKFyHhgY5OV3Ih6UlqgjF5epw,1670
|
@@ -260,7 +260,47 @@ blaxel/models/pydantic.py,sha256=4_z2KtaeEiRMt_Zz6Ghy6il-QiaXzE3yizDJnCBcWO8,332
|
|
260
260
|
blaxel/models/custom/langchain/gemini.py,sha256=AkhpuVMXnh1CyJ0zR2NMTtxQFPPHtAdHf_cyNzV3EsA,55421
|
261
261
|
blaxel/models/custom/llamaindex/cohere.py,sha256=Igj5Y1ozf1V4feIXfBHDdaTFU7od_wuOhm0yChZNxMY,19109
|
262
262
|
blaxel/models/custom/pydantic/gemini.py,sha256=rbsunh-M7EEKlD5ir3GlA-8a12JzPFcvsf6NISjzE5I,1052
|
263
|
-
blaxel/
|
263
|
+
blaxel/sandbox/base.py,sha256=Ps1RvasF1MB8h0-XRz3Sxz7UGjpAPaI6pvrfonUckHo,2106
|
264
|
+
blaxel/sandbox/filesystem.py,sha256=3dvg92owjHypv0aFmBdx6i9QfMSfp6z9Z0D93yKfeiQ,4653
|
265
|
+
blaxel/sandbox/process.py,sha256=EWI6UctxdWo4Vd4VUSilABJME3g3x3ceuSuBN2mDfhM,2519
|
266
|
+
blaxel/sandbox/sandbox.py,sha256=meRE_iUx1dvlav-RIBdzQLrrHE_efBTtcbq-u9_mId4,2992
|
267
|
+
blaxel/sandbox/client/__init__.py,sha256=N26bD5o1jsTb48oExow6Rgivd8ylaU9jaWZfZsVilP8,128
|
268
|
+
blaxel/sandbox/client/client.py,sha256=tcP8cJ4Q3dV9aB3yQ01dDXO-ekfsa3WGGFz4DQAEf8I,7079
|
269
|
+
blaxel/sandbox/client/errors.py,sha256=gO8GBmKqmSNgAg-E5oT-oOyxztvp7V_6XG7OUTT15q0,546
|
270
|
+
blaxel/sandbox/client/py.typed,sha256=8ZJUsxZiuOy1oJeVhsTWQhTG_6pTVHVXk5hJL79ebTk,25
|
271
|
+
blaxel/sandbox/client/types.py,sha256=E1hhDh_zXfsSQ0NCt9-uw90_Mr5iIlsdfnfvxv5HarU,1005
|
272
|
+
blaxel/sandbox/client/api/__init__.py,sha256=zTSiG_ujSjAqWPyc435YXaX9XTlpMjiJWBbV-f-YtdA,45
|
273
|
+
blaxel/sandbox/client/api/filesystem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
274
|
+
blaxel/sandbox/client/api/filesystem/delete_filesystem_path.py,sha256=PVm-a_nacy6QQb6mh_HIDx-JkiFYeUOypHZq0AtE6dA,4782
|
275
|
+
blaxel/sandbox/client/api/filesystem/get_filesystem_path.py,sha256=Hp8pM8xvi5zAjO5xujAbKxALUBJHH-JdyvWIEJ8dHo0,5010
|
276
|
+
blaxel/sandbox/client/api/filesystem/put_filesystem_path.py,sha256=GIqwjevow7sRw5Po9iraYY1Yl5UXqgv2pjUw9nle97E,4759
|
277
|
+
blaxel/sandbox/client/api/network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
278
|
+
blaxel/sandbox/client/api/network/delete_network_process_pid_monitor.py,sha256=nhQe7a4PqBhFQ6pZxSPilcvg-tt3jP0tmuX3Po8bd9g,4581
|
279
|
+
blaxel/sandbox/client/api/network/get_network_process_pid_ports.py,sha256=2lsDR78DMqJChOHe84JCy2iTHGIEDnzDArm4SMnt3JY,4455
|
280
|
+
blaxel/sandbox/client/api/network/post_network_process_pid_monitor.py,sha256=3sUYnFyMwpypQfLBZvIcFB9v8RrhNIMOKGb1uM15pzU,5235
|
281
|
+
blaxel/sandbox/client/api/process/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
282
|
+
blaxel/sandbox/client/api/process/delete_process_identifier.py,sha256=7ihlG9_R7p-sbw_4h93cnOyBGYhiWfFtpsjY6z9P7iQ,4179
|
283
|
+
blaxel/sandbox/client/api/process/delete_process_identifier_kill.py,sha256=1x_KMc7uJD_fap8uoTmZkWIDTgLJKmCTGcOP1Mr6X1E,4858
|
284
|
+
blaxel/sandbox/client/api/process/get_process.py,sha256=XWf_hNFZLkS14eWjBjir22QwdtV313_llrQGExJ7lZo,3588
|
285
|
+
blaxel/sandbox/client/api/process/get_process_identifier.py,sha256=OqmxuKKHDGX6rwS0Mavn6nnL0X_7AasPUdS5RS04URc,4159
|
286
|
+
blaxel/sandbox/client/api/process/get_process_identifier_logs.py,sha256=m34pQjMLpEUJsqkjEh0OafdNaMbDhR0NhzaJ1jWLJVk,4513
|
287
|
+
blaxel/sandbox/client/api/process/post_process.py,sha256=cemvWEtrZ24RBx3QHusE9Al_yrgQip9nBSkaQhSGUkI,4527
|
288
|
+
blaxel/sandbox/client/models/__init__.py,sha256=KiSEopbp_UpGTz_3kcRG_XDd7Vfcn3LbOAmj8Ex-PFs,1288
|
289
|
+
blaxel/sandbox/client/models/delete_network_process_pid_monitor_response_200.py,sha256=9cQgKDjG98sMridjXKgeR2oZzFKcQ0G9QIojhwYFosI,1376
|
290
|
+
blaxel/sandbox/client/models/directory.py,sha256=pHJ2lX4IjuMIdZSkb7plmzPsmALP3EwUymfH0Ra4YgA,3482
|
291
|
+
blaxel/sandbox/client/models/error_response.py,sha256=lI15zKBoD2X9yHzSiEaYGUn5TPTxWM7j1Tu5crtd23M,1581
|
292
|
+
blaxel/sandbox/client/models/file.py,sha256=-SwKgrzbXfPQfxhAp2S_P8On-vT5Ac4Q-ODKRdwdsts,2835
|
293
|
+
blaxel/sandbox/client/models/file_request.py,sha256=xOZSru-fae-En-_2YBgkHa_6iGbqbJsG3RLqBuajVY0,2227
|
294
|
+
blaxel/sandbox/client/models/file_with_content.py,sha256=CGRXhUrrYtLAxQIsJi01kFUVAt1Bkj2tFUalULLA77Q,3153
|
295
|
+
blaxel/sandbox/client/models/get_network_process_pid_ports_response_200.py,sha256=x4uv80kK0GVroWO98l5sE84a6uwZ8pnUKTpGg81ipWA,1351
|
296
|
+
blaxel/sandbox/client/models/get_process_identifier_logs_response_200.py,sha256=pEs9vxD29oxrojOgeyppXXmFVvem7beWzm5_i4TkgDc,1343
|
297
|
+
blaxel/sandbox/client/models/port_monitor_request.py,sha256=LK7sjAK1TF1ojgG4vGytaKLVtV6-SNXxfZ3sxew1cRE,1698
|
298
|
+
blaxel/sandbox/client/models/post_network_process_pid_monitor_response_200.py,sha256=Y8BvNGKU8SlzTGqhaQZk_WWIrmFpNU0LVcmLFjNvqhA,1366
|
299
|
+
blaxel/sandbox/client/models/process_kill_request.py,sha256=TqhuOmVPm_yKZj52YFv3yyu2UA8eVgXEio4sgCVAR-0,1614
|
300
|
+
blaxel/sandbox/client/models/process_request.py,sha256=FGWl2SnuHdBY-8t_YatpKwYCUfA3LMHt8RnU0hjPcLc,3598
|
301
|
+
blaxel/sandbox/client/models/process_response.py,sha256=WMfxuNTrL5wo5QT7HOR4_CTyf9XztO5cPvmtlHMdNd8,3624
|
302
|
+
blaxel/sandbox/client/models/success_response.py,sha256=JQbCUIdVJy_TJ3mp8IuvCGbKgCm_iZQMMrqn8uZkxCk,1874
|
303
|
+
blaxel/tools/__init__.py,sha256=4lzqDt0FNWcO8L0DkFzY1KTHLNtgEux66id4Psq7sXY,11520
|
264
304
|
blaxel/tools/common.py,sha256=JGK052v_fvwWBFYnIArlBnFFViYyFrqdDn3gdVf53EU,1332
|
265
305
|
blaxel/tools/crewai.py,sha256=rPrRGwkXejunJQ6In1IsYAxJPNbr6d9EckXrSIHQods,638
|
266
306
|
blaxel/tools/googleadk.py,sha256=65qJysecgAMujxsyGxuCEVL0fWoR5I489DMiSA3ZaGs,2265
|
@@ -270,7 +310,7 @@ blaxel/tools/llamaindex.py,sha256=-gQ-C9V_h9a11J4ItsbWjXrCJOg0lRKsb98v9rVsNak,71
|
|
270
310
|
blaxel/tools/openai.py,sha256=GuFXkj6bXEwldyVr89jEsRAi5ihZUVEVe327QuWiGNs,653
|
271
311
|
blaxel/tools/pydantic.py,sha256=CvnNbAG_J4yBtA-XFI4lQrq3FYKjNd39hu841vZT004,1801
|
272
312
|
blaxel/tools/types.py,sha256=YPCGJ4vZDhqR0X2H_TWtc5chQScsC32nGTQdRKJlO8Y,707
|
273
|
-
blaxel-0.1.
|
274
|
-
blaxel-0.1.
|
275
|
-
blaxel-0.1.
|
276
|
-
blaxel-0.1.
|
313
|
+
blaxel-0.1.10rc39.dist-info/METADATA,sha256=EQelat7hNQYQqQRoDE2dpk5HDKDb2JgLRUMAd3lpO5Q,11607
|
314
|
+
blaxel-0.1.10rc39.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
315
|
+
blaxel-0.1.10rc39.dist-info/licenses/LICENSE,sha256=p5PNQvpvyDT_0aYBDgmV1fFI_vAD2aSV0wWG7VTgRis,1069
|
316
|
+
blaxel-0.1.10rc39.dist-info/RECORD,,
|
File without changes
|
File without changes
|