blaxel 0.1.9rc37__py3-none-any.whl → 0.1.10rc38__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.
Files changed (49) hide show
  1. blaxel/authentication/__init__.py +11 -2
  2. blaxel/authentication/devicemode.py +1 -0
  3. blaxel/common/autoload.py +1 -0
  4. blaxel/common/internal.py +5 -5
  5. blaxel/sandbox/base.py +68 -0
  6. blaxel/sandbox/client/__init__.py +8 -0
  7. blaxel/sandbox/client/api/__init__.py +1 -0
  8. blaxel/sandbox/client/api/filesystem/__init__.py +0 -0
  9. blaxel/sandbox/client/api/filesystem/delete_filesystem_path.py +184 -0
  10. blaxel/sandbox/client/api/filesystem/get_filesystem_path.py +184 -0
  11. blaxel/sandbox/client/api/filesystem/put_filesystem_path.py +189 -0
  12. blaxel/sandbox/client/api/network/__init__.py +0 -0
  13. blaxel/sandbox/client/api/network/delete_network_process_pid_monitor.py +169 -0
  14. blaxel/sandbox/client/api/network/get_network_process_pid_ports.py +169 -0
  15. blaxel/sandbox/client/api/network/post_network_process_pid_monitor.py +195 -0
  16. blaxel/sandbox/client/api/process/__init__.py +0 -0
  17. blaxel/sandbox/client/api/process/delete_process_identifier.py +163 -0
  18. blaxel/sandbox/client/api/process/delete_process_identifier_kill.py +189 -0
  19. blaxel/sandbox/client/api/process/get_process.py +135 -0
  20. blaxel/sandbox/client/api/process/get_process_identifier.py +159 -0
  21. blaxel/sandbox/client/api/process/get_process_identifier_logs.py +167 -0
  22. blaxel/sandbox/client/api/process/post_process.py +176 -0
  23. blaxel/sandbox/client/client.py +162 -0
  24. blaxel/sandbox/client/errors.py +16 -0
  25. blaxel/sandbox/client/models/__init__.py +35 -0
  26. blaxel/sandbox/client/models/delete_network_process_pid_monitor_response_200.py +45 -0
  27. blaxel/sandbox/client/models/directory.py +110 -0
  28. blaxel/sandbox/client/models/error_response.py +60 -0
  29. blaxel/sandbox/client/models/file.py +105 -0
  30. blaxel/sandbox/client/models/file_request.py +78 -0
  31. blaxel/sandbox/client/models/file_with_content.py +114 -0
  32. blaxel/sandbox/client/models/get_network_process_pid_ports_response_200.py +45 -0
  33. blaxel/sandbox/client/models/get_process_identifier_logs_response_200.py +45 -0
  34. blaxel/sandbox/client/models/port_monitor_request.py +60 -0
  35. blaxel/sandbox/client/models/post_network_process_pid_monitor_response_200.py +45 -0
  36. blaxel/sandbox/client/models/process_kill_request.py +60 -0
  37. blaxel/sandbox/client/models/process_request.py +118 -0
  38. blaxel/sandbox/client/models/process_response.py +123 -0
  39. blaxel/sandbox/client/models/success_response.py +69 -0
  40. blaxel/sandbox/client/py.typed +1 -0
  41. blaxel/sandbox/client/types.py +46 -0
  42. blaxel/sandbox/filesystem.py +102 -0
  43. blaxel/sandbox/process.py +57 -0
  44. blaxel/sandbox/sandbox.py +92 -0
  45. blaxel/tools/__init__.py +1 -1
  46. {blaxel-0.1.9rc37.dist-info → blaxel-0.1.10rc38.dist-info}/METADATA +1 -1
  47. {blaxel-0.1.9rc37.dist-info → blaxel-0.1.10rc38.dist-info}/RECORD +49 -9
  48. {blaxel-0.1.9rc37.dist-info → blaxel-0.1.10rc38.dist-info}/WHEEL +0 -0
  49. {blaxel-0.1.9rc37.dist-info → blaxel-0.1.10rc38.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,45 @@
1
+ from typing import Any, TypeVar
2
+
3
+ from attrs import define as _attrs_define
4
+ from attrs import field as _attrs_field
5
+
6
+ T = TypeVar("T", bound="PostNetworkProcessPidMonitorResponse200")
7
+
8
+
9
+ @_attrs_define
10
+ class PostNetworkProcessPidMonitorResponse200:
11
+ """ """
12
+
13
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
14
+
15
+ def to_dict(self) -> dict[str, Any]:
16
+ field_dict: dict[str, Any] = {}
17
+ field_dict.update(self.additional_properties)
18
+
19
+ return field_dict
20
+
21
+ @classmethod
22
+ def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T:
23
+ if not src_dict:
24
+ return None
25
+ d = src_dict.copy()
26
+ post_network_process_pid_monitor_response_200 = cls()
27
+
28
+ post_network_process_pid_monitor_response_200.additional_properties = d
29
+ return post_network_process_pid_monitor_response_200
30
+
31
+ @property
32
+ def additional_keys(self) -> list[str]:
33
+ return list(self.additional_properties.keys())
34
+
35
+ def __getitem__(self, key: str) -> Any:
36
+ return self.additional_properties[key]
37
+
38
+ def __setitem__(self, key: str, value: Any) -> None:
39
+ self.additional_properties[key] = value
40
+
41
+ def __delitem__(self, key: str) -> None:
42
+ del self.additional_properties[key]
43
+
44
+ def __contains__(self, key: str) -> bool:
45
+ return key in self.additional_properties
@@ -0,0 +1,60 @@
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="ProcessKillRequest")
9
+
10
+
11
+ @_attrs_define
12
+ class ProcessKillRequest:
13
+ """
14
+ Attributes:
15
+ signal (Union[Unset, str]): Example: SIGTERM.
16
+ """
17
+
18
+ signal: Union[Unset, str] = UNSET
19
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
20
+
21
+ def to_dict(self) -> dict[str, Any]:
22
+ signal = self.signal
23
+
24
+ field_dict: dict[str, Any] = {}
25
+ field_dict.update(self.additional_properties)
26
+ field_dict.update({})
27
+ if signal is not UNSET:
28
+ field_dict["signal"] = signal
29
+
30
+ return field_dict
31
+
32
+ @classmethod
33
+ def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T:
34
+ if not src_dict:
35
+ return None
36
+ d = src_dict.copy()
37
+ signal = d.pop("signal", UNSET)
38
+
39
+ process_kill_request = cls(
40
+ signal=signal,
41
+ )
42
+
43
+ process_kill_request.additional_properties = d
44
+ return process_kill_request
45
+
46
+ @property
47
+ def additional_keys(self) -> list[str]:
48
+ return list(self.additional_properties.keys())
49
+
50
+ def __getitem__(self, key: str) -> Any:
51
+ return self.additional_properties[key]
52
+
53
+ def __setitem__(self, key: str, value: Any) -> None:
54
+ self.additional_properties[key] = value
55
+
56
+ def __delitem__(self, key: str) -> None:
57
+ del self.additional_properties[key]
58
+
59
+ def __contains__(self, key: str) -> bool:
60
+ return key in self.additional_properties
@@ -0,0 +1,118 @@
1
+ from typing import Any, TypeVar, Union, cast
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="ProcessRequest")
9
+
10
+
11
+ @_attrs_define
12
+ class ProcessRequest:
13
+ """
14
+ Attributes:
15
+ command (str): Example: ls -la.
16
+ name (Union[Unset, str]): Example: my-process.
17
+ stream_logs (Union[Unset, bool]): Example: True.
18
+ timeout (Union[Unset, int]): Example: 30.
19
+ wait_for_completion (Union[Unset, bool]):
20
+ wait_for_ports (Union[Unset, list[int]]): Example: [3000, 8080].
21
+ working_dir (Union[Unset, str]): Example: /home/user.
22
+ """
23
+
24
+ command: str
25
+ name: Union[Unset, str] = UNSET
26
+ stream_logs: Union[Unset, bool] = UNSET
27
+ timeout: Union[Unset, int] = UNSET
28
+ wait_for_completion: Union[Unset, bool] = UNSET
29
+ wait_for_ports: Union[Unset, list[int]] = UNSET
30
+ working_dir: Union[Unset, str] = UNSET
31
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
32
+
33
+ def to_dict(self) -> dict[str, Any]:
34
+ command = self.command
35
+
36
+ name = self.name
37
+
38
+ stream_logs = self.stream_logs
39
+
40
+ timeout = self.timeout
41
+
42
+ wait_for_completion = self.wait_for_completion
43
+
44
+ wait_for_ports: Union[Unset, list[int]] = UNSET
45
+ if not isinstance(self.wait_for_ports, Unset):
46
+ wait_for_ports = self.wait_for_ports
47
+
48
+ working_dir = self.working_dir
49
+
50
+ field_dict: dict[str, Any] = {}
51
+ field_dict.update(self.additional_properties)
52
+ field_dict.update(
53
+ {
54
+ "command": command,
55
+ }
56
+ )
57
+ if name is not UNSET:
58
+ field_dict["name"] = name
59
+ if stream_logs is not UNSET:
60
+ field_dict["streamLogs"] = stream_logs
61
+ if timeout is not UNSET:
62
+ field_dict["timeout"] = timeout
63
+ if wait_for_completion is not UNSET:
64
+ field_dict["waitForCompletion"] = wait_for_completion
65
+ if wait_for_ports is not UNSET:
66
+ field_dict["waitForPorts"] = wait_for_ports
67
+ if working_dir is not UNSET:
68
+ field_dict["workingDir"] = working_dir
69
+
70
+ return field_dict
71
+
72
+ @classmethod
73
+ def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T:
74
+ if not src_dict:
75
+ return None
76
+ d = src_dict.copy()
77
+ command = d.pop("command")
78
+
79
+ name = d.pop("name", UNSET)
80
+
81
+ stream_logs = d.pop("streamLogs", UNSET)
82
+
83
+ timeout = d.pop("timeout", UNSET)
84
+
85
+ wait_for_completion = d.pop("waitForCompletion", UNSET)
86
+
87
+ wait_for_ports = cast(list[int], d.pop("waitForPorts", UNSET))
88
+
89
+ working_dir = d.pop("workingDir", UNSET)
90
+
91
+ process_request = cls(
92
+ command=command,
93
+ name=name,
94
+ stream_logs=stream_logs,
95
+ timeout=timeout,
96
+ wait_for_completion=wait_for_completion,
97
+ wait_for_ports=wait_for_ports,
98
+ working_dir=working_dir,
99
+ )
100
+
101
+ process_request.additional_properties = d
102
+ return process_request
103
+
104
+ @property
105
+ def additional_keys(self) -> list[str]:
106
+ return list(self.additional_properties.keys())
107
+
108
+ def __getitem__(self, key: str) -> Any:
109
+ return self.additional_properties[key]
110
+
111
+ def __setitem__(self, key: str, value: Any) -> None:
112
+ self.additional_properties[key] = value
113
+
114
+ def __delitem__(self, key: str) -> None:
115
+ del self.additional_properties[key]
116
+
117
+ def __contains__(self, key: str) -> bool:
118
+ return key in self.additional_properties
@@ -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,102 @@
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.startswith("/"):
101
+ path = path[1:]
102
+ 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")