loopix-sdk 2.30.0__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 (238) hide show
  1. loopix/__init__.py +260 -0
  2. loopix/api/__init__.py +287 -0
  3. loopix/api/client/__init__.py +8 -0
  4. loopix/api/client/api/__init__.py +1 -0
  5. loopix/api/client/api/sandboxes/__init__.py +1 -0
  6. loopix/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py +161 -0
  7. loopix/api/client/api/sandboxes/get_sandboxes.py +176 -0
  8. loopix/api/client/api/sandboxes/get_sandboxes_metrics.py +173 -0
  9. loopix/api/client/api/sandboxes/get_sandboxes_sandbox_id.py +163 -0
  10. loopix/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py +199 -0
  11. loopix/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py +212 -0
  12. loopix/api/client/api/sandboxes/get_v2_sandboxes.py +230 -0
  13. loopix/api/client/api/sandboxes/get_v_2_sandboxes_sandbox_id_logs.py +254 -0
  14. loopix/api/client/api/sandboxes/post_sandboxes.py +172 -0
  15. loopix/api/client/api/sandboxes/post_sandboxes_sandbox_id_connect.py +193 -0
  16. loopix/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py +187 -0
  17. loopix/api/client/api/sandboxes/post_sandboxes_sandbox_id_refreshes.py +181 -0
  18. loopix/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py +189 -0
  19. loopix/api/client/api/sandboxes/post_sandboxes_sandbox_id_snapshots.py +195 -0
  20. loopix/api/client/api/sandboxes/post_sandboxes_sandbox_id_timeout.py +193 -0
  21. loopix/api/client/api/sandboxes/put_sandboxes_sandbox_id_network.py +199 -0
  22. loopix/api/client/api/snapshots/__init__.py +1 -0
  23. loopix/api/client/api/snapshots/get_snapshots.py +202 -0
  24. loopix/api/client/api/tags/__init__.py +1 -0
  25. loopix/api/client/api/tags/delete_templates_tags.py +174 -0
  26. loopix/api/client/api/tags/get_templates_template_id_tags.py +172 -0
  27. loopix/api/client/api/tags/post_templates_tags.py +176 -0
  28. loopix/api/client/api/templates/__init__.py +1 -0
  29. loopix/api/client/api/templates/delete_templates_template_id.py +157 -0
  30. loopix/api/client/api/templates/get_templates.py +172 -0
  31. loopix/api/client/api/templates/get_templates_aliases_alias.py +167 -0
  32. loopix/api/client/api/templates/get_templates_template_id.py +195 -0
  33. loopix/api/client/api/templates/get_templates_template_id_builds_build_id_logs.py +272 -0
  34. loopix/api/client/api/templates/get_templates_template_id_builds_build_id_status.py +232 -0
  35. loopix/api/client/api/templates/get_templates_template_id_files_hash.py +180 -0
  36. loopix/api/client/api/templates/patch_templates_template_id.py +183 -0
  37. loopix/api/client/api/templates/patch_v_2_templates_template_id.py +185 -0
  38. loopix/api/client/api/templates/post_templates.py +172 -0
  39. loopix/api/client/api/templates/post_templates_template_id.py +181 -0
  40. loopix/api/client/api/templates/post_templates_template_id_builds_build_id.py +170 -0
  41. loopix/api/client/api/templates/post_v2_templates.py +172 -0
  42. loopix/api/client/api/templates/post_v3_templates.py +176 -0
  43. loopix/api/client/api/templates/post_v_2_templates_template_id_builds_build_id.py +192 -0
  44. loopix/api/client/api/volumes/__init__.py +1 -0
  45. loopix/api/client/api/volumes/delete_volumes_volume_id.py +161 -0
  46. loopix/api/client/api/volumes/get_volumes.py +140 -0
  47. loopix/api/client/api/volumes/get_volumes_volume_id.py +163 -0
  48. loopix/api/client/api/volumes/post_volumes.py +172 -0
  49. loopix/api/client/client.py +286 -0
  50. loopix/api/client/errors.py +16 -0
  51. loopix/api/client/models/__init__.py +185 -0
  52. loopix/api/client/models/admin_build_cancel_result.py +67 -0
  53. loopix/api/client/models/admin_sandbox_kill_result.py +67 -0
  54. loopix/api/client/models/assign_template_tags_request.py +67 -0
  55. loopix/api/client/models/assigned_template_tags.py +68 -0
  56. loopix/api/client/models/aws_registry.py +85 -0
  57. loopix/api/client/models/aws_registry_type.py +8 -0
  58. loopix/api/client/models/build_log_entry.py +89 -0
  59. loopix/api/client/models/build_status_reason.py +95 -0
  60. loopix/api/client/models/connect_sandbox.py +59 -0
  61. loopix/api/client/models/created_access_token.py +100 -0
  62. loopix/api/client/models/created_team_api_key.py +166 -0
  63. loopix/api/client/models/delete_template_tags_request.py +67 -0
  64. loopix/api/client/models/disk_metrics.py +91 -0
  65. loopix/api/client/models/error.py +67 -0
  66. loopix/api/client/models/gcp_registry.py +69 -0
  67. loopix/api/client/models/gcp_registry_type.py +8 -0
  68. loopix/api/client/models/general_registry.py +77 -0
  69. loopix/api/client/models/general_registry_type.py +8 -0
  70. loopix/api/client/models/identifier_masking_details.py +83 -0
  71. loopix/api/client/models/listed_sandbox.py +179 -0
  72. loopix/api/client/models/log_level.py +11 -0
  73. loopix/api/client/models/logs_direction.py +9 -0
  74. loopix/api/client/models/logs_source.py +9 -0
  75. loopix/api/client/models/machine_info.py +83 -0
  76. loopix/api/client/models/max_team_metric.py +78 -0
  77. loopix/api/client/models/mcp_type_0.py +44 -0
  78. loopix/api/client/models/new_access_token.py +59 -0
  79. loopix/api/client/models/new_sandbox.py +224 -0
  80. loopix/api/client/models/new_team_api_key.py +59 -0
  81. loopix/api/client/models/new_volume.py +59 -0
  82. loopix/api/client/models/node.py +160 -0
  83. loopix/api/client/models/node_detail.py +160 -0
  84. loopix/api/client/models/node_metrics.py +122 -0
  85. loopix/api/client/models/node_status.py +12 -0
  86. loopix/api/client/models/node_status_change.py +82 -0
  87. loopix/api/client/models/post_sandboxes_sandbox_id_refreshes_body.py +59 -0
  88. loopix/api/client/models/post_sandboxes_sandbox_id_snapshots_body.py +60 -0
  89. loopix/api/client/models/post_sandboxes_sandbox_id_timeout_body.py +59 -0
  90. loopix/api/client/models/resumed_sandbox.py +68 -0
  91. loopix/api/client/models/sandbox.py +145 -0
  92. loopix/api/client/models/sandbox_auto_resume_config.py +60 -0
  93. loopix/api/client/models/sandbox_detail.py +267 -0
  94. loopix/api/client/models/sandbox_lifecycle.py +70 -0
  95. loopix/api/client/models/sandbox_log.py +70 -0
  96. loopix/api/client/models/sandbox_log_entry.py +93 -0
  97. loopix/api/client/models/sandbox_log_entry_fields.py +44 -0
  98. loopix/api/client/models/sandbox_logs.py +91 -0
  99. loopix/api/client/models/sandbox_logs_v2_response.py +73 -0
  100. loopix/api/client/models/sandbox_metric.py +126 -0
  101. loopix/api/client/models/sandbox_network_config.py +118 -0
  102. loopix/api/client/models/sandbox_network_config_rules.py +72 -0
  103. loopix/api/client/models/sandbox_network_rule.py +74 -0
  104. loopix/api/client/models/sandbox_network_transform.py +79 -0
  105. loopix/api/client/models/sandbox_network_transform_headers.py +47 -0
  106. loopix/api/client/models/sandbox_network_update_config.py +114 -0
  107. loopix/api/client/models/sandbox_network_update_config_rules.py +71 -0
  108. loopix/api/client/models/sandbox_on_timeout.py +9 -0
  109. loopix/api/client/models/sandbox_pause_request.py +62 -0
  110. loopix/api/client/models/sandbox_state.py +9 -0
  111. loopix/api/client/models/sandbox_volume_mount.py +67 -0
  112. loopix/api/client/models/sandboxes_with_metrics.py +59 -0
  113. loopix/api/client/models/snapshot_info.py +70 -0
  114. loopix/api/client/models/team.py +83 -0
  115. loopix/api/client/models/team_api_key.py +158 -0
  116. loopix/api/client/models/team_metric.py +86 -0
  117. loopix/api/client/models/team_user.py +75 -0
  118. loopix/api/client/models/template.py +225 -0
  119. loopix/api/client/models/template_alias_response.py +67 -0
  120. loopix/api/client/models/template_build.py +139 -0
  121. loopix/api/client/models/template_build_file_upload.py +70 -0
  122. loopix/api/client/models/template_build_info.py +126 -0
  123. loopix/api/client/models/template_build_logs_response.py +73 -0
  124. loopix/api/client/models/template_build_request.py +115 -0
  125. loopix/api/client/models/template_build_request_v2.py +88 -0
  126. loopix/api/client/models/template_build_request_v3.py +107 -0
  127. loopix/api/client/models/template_build_start_v2.py +184 -0
  128. loopix/api/client/models/template_build_status.py +11 -0
  129. loopix/api/client/models/template_legacy.py +207 -0
  130. loopix/api/client/models/template_request_response_v3.py +99 -0
  131. loopix/api/client/models/template_step.py +91 -0
  132. loopix/api/client/models/template_tag.py +78 -0
  133. loopix/api/client/models/template_update_request.py +59 -0
  134. loopix/api/client/models/template_update_response.py +59 -0
  135. loopix/api/client/models/template_with_builds.py +156 -0
  136. loopix/api/client/models/update_team_api_key.py +59 -0
  137. loopix/api/client/models/volume.py +67 -0
  138. loopix/api/client/models/volume_and_token.py +75 -0
  139. loopix/api/client/models/volume_token.py +59 -0
  140. loopix/api/client/py.typed +1 -0
  141. loopix/api/client/types.py +54 -0
  142. loopix/api/client_async/__init__.py +74 -0
  143. loopix/api/client_sync/__init__.py +73 -0
  144. loopix/api/metadata.py +14 -0
  145. loopix/connection_config.py +309 -0
  146. loopix/envd/api.py +170 -0
  147. loopix/envd/filesystem/filesystem_connect.py +193 -0
  148. loopix/envd/filesystem/filesystem_pb2.py +80 -0
  149. loopix/envd/filesystem/filesystem_pb2.pyi +272 -0
  150. loopix/envd/process/process_connect.py +174 -0
  151. loopix/envd/process/process_pb2.py +96 -0
  152. loopix/envd/process/process_pb2.pyi +316 -0
  153. loopix/envd/rpc.py +139 -0
  154. loopix/envd/versions.py +11 -0
  155. loopix/exceptions.py +133 -0
  156. loopix/io_utils.py +57 -0
  157. loopix/paginator.py +52 -0
  158. loopix/py.typed +0 -0
  159. loopix/sandbox/_git/__init__.py +85 -0
  160. loopix/sandbox/_git/args.py +363 -0
  161. loopix/sandbox/_git/auth.py +132 -0
  162. loopix/sandbox/_git/config.py +32 -0
  163. loopix/sandbox/_git/parse.py +222 -0
  164. loopix/sandbox/_git/types.py +149 -0
  165. loopix/sandbox/commands/command_handle.py +69 -0
  166. loopix/sandbox/commands/main.py +39 -0
  167. loopix/sandbox/filesystem/filesystem.py +337 -0
  168. loopix/sandbox/filesystem/watch_handle.py +70 -0
  169. loopix/sandbox/main.py +227 -0
  170. loopix/sandbox/mcp.py +1949 -0
  171. loopix/sandbox/network.py +8 -0
  172. loopix/sandbox/sandbox_api.py +624 -0
  173. loopix/sandbox/signature.py +47 -0
  174. loopix/sandbox/utils.py +34 -0
  175. loopix/sandbox_async/commands/command.py +396 -0
  176. loopix/sandbox_async/commands/command_handle.py +298 -0
  177. loopix/sandbox_async/commands/pty.py +257 -0
  178. loopix/sandbox_async/filesystem/filesystem.py +720 -0
  179. loopix/sandbox_async/filesystem/watch_handle.py +97 -0
  180. loopix/sandbox_async/git.py +1100 -0
  181. loopix/sandbox_async/main.py +987 -0
  182. loopix/sandbox_async/paginator.py +140 -0
  183. loopix/sandbox_async/sandbox_api.py +504 -0
  184. loopix/sandbox_async/utils.py +7 -0
  185. loopix/sandbox_domains.py +5 -0
  186. loopix/sandbox_sync/commands/command.py +420 -0
  187. loopix/sandbox_sync/commands/command_handle.py +239 -0
  188. loopix/sandbox_sync/commands/pty.py +279 -0
  189. loopix/sandbox_sync/filesystem/filesystem.py +710 -0
  190. loopix/sandbox_sync/filesystem/watch_handle.py +102 -0
  191. loopix/sandbox_sync/git.py +1077 -0
  192. loopix/sandbox_sync/main.py +975 -0
  193. loopix/sandbox_sync/paginator.py +140 -0
  194. loopix/sandbox_sync/sandbox_api.py +491 -0
  195. loopix/template/consts.py +45 -0
  196. loopix/template/dockerfile_parser.py +286 -0
  197. loopix/template/logger.py +232 -0
  198. loopix/template/main.py +1368 -0
  199. loopix/template/readycmd.py +144 -0
  200. loopix/template/types.py +194 -0
  201. loopix/template/utils.py +426 -0
  202. loopix/template_async/build_api.py +419 -0
  203. loopix/template_async/main.py +528 -0
  204. loopix/template_sync/build_api.py +409 -0
  205. loopix/template_sync/main.py +529 -0
  206. loopix/volume/client/__init__.py +8 -0
  207. loopix/volume/client/api/__init__.py +1 -0
  208. loopix/volume/client/api/volumes/__init__.py +1 -0
  209. loopix/volume/client/api/volumes/delete_volumecontent_volume_id_path.py +174 -0
  210. loopix/volume/client/api/volumes/get_volumecontent_volume_id_dir.py +204 -0
  211. loopix/volume/client/api/volumes/get_volumecontent_volume_id_file.py +179 -0
  212. loopix/volume/client/api/volumes/get_volumecontent_volume_id_path.py +176 -0
  213. loopix/volume/client/api/volumes/patch_volumecontent_volume_id_path.py +203 -0
  214. loopix/volume/client/api/volumes/post_volumecontent_volume_id_dir.py +239 -0
  215. loopix/volume/client/api/volumes/put_volumecontent_volume_id_file.py +259 -0
  216. loopix/volume/client/client.py +286 -0
  217. loopix/volume/client/errors.py +16 -0
  218. loopix/volume/client/models/__init__.py +13 -0
  219. loopix/volume/client/models/error.py +67 -0
  220. loopix/volume/client/models/patch_volumecontent_volume_id_path_body.py +77 -0
  221. loopix/volume/client/models/volume_entry_stat.py +145 -0
  222. loopix/volume/client/models/volume_entry_stat_type.py +11 -0
  223. loopix/volume/client/py.typed +1 -0
  224. loopix/volume/client/types.py +54 -0
  225. loopix/volume/client_async/__init__.py +88 -0
  226. loopix/volume/client_sync/__init__.py +80 -0
  227. loopix/volume/connection_config.py +145 -0
  228. loopix/volume/types.py +62 -0
  229. loopix/volume/utils.py +52 -0
  230. loopix/volume/volume_async.py +639 -0
  231. loopix/volume/volume_sync.py +639 -0
  232. loopix_connect/__init__.py +1 -0
  233. loopix_connect/client.py +534 -0
  234. loopix_connect/py.typed +0 -0
  235. loopix_sdk-2.30.0.dist-info/METADATA +98 -0
  236. loopix_sdk-2.30.0.dist-info/RECORD +238 -0
  237. loopix_sdk-2.30.0.dist-info/WHEEL +4 -0
  238. loopix_sdk-2.30.0.dist-info/licenses/LICENSE +9 -0
@@ -0,0 +1,279 @@
1
+ import loopix_connect
2
+ import httpx
3
+ import threading
4
+
5
+ from typing import Dict, Optional
6
+
7
+ from packaging.version import Version
8
+ from loopix.api import make_logging_event_hooks
9
+ from loopix.api.client_sync import get_envd_transport
10
+ from loopix.envd.process import process_connect, process_pb2
11
+ from loopix.connection_config import (
12
+ Username,
13
+ ConnectionConfig,
14
+ KEEPALIVE_PING_HEADER,
15
+ KEEPALIVE_PING_INTERVAL_SEC,
16
+ )
17
+ from loopix.exceptions import SandboxException
18
+ from loopix.envd.api import check_sandbox_health
19
+ from loopix.envd.rpc import authentication_header, handle_rpc_exception_with_health
20
+ from loopix.sandbox.commands.command_handle import PtySize
21
+ from loopix.sandbox_sync.commands.command_handle import CommandHandle
22
+
23
+
24
+ class Pty:
25
+ """
26
+ Module for interacting with PTYs (pseudo-terminals) in the sandbox.
27
+ """
28
+
29
+ def __init__(
30
+ self,
31
+ envd_api_url: str,
32
+ connection_config: ConnectionConfig,
33
+ envd_version: Version,
34
+ ) -> None:
35
+ self._envd_api_url = envd_api_url
36
+ self._connection_config = connection_config
37
+ self._envd_version = envd_version
38
+ self._thread_local = threading.local()
39
+
40
+ def _create_envd_api(self) -> httpx.Client:
41
+ transport = get_envd_transport(self._connection_config)
42
+ return httpx.Client(
43
+ base_url=self._envd_api_url,
44
+ transport=transport,
45
+ headers=self._connection_config.sandbox_headers,
46
+ event_hooks=make_logging_event_hooks(self._connection_config.logger),
47
+ )
48
+
49
+ def _create_rpc(self) -> process_connect.ProcessClient:
50
+ transport = get_envd_transport(self._connection_config)
51
+ return process_connect.ProcessClient(
52
+ self._envd_api_url,
53
+ # TODO: Fix and enable compression again — the headers compression is not solved for streaming.
54
+ # compressor=loopix_connect.GzipCompressor,
55
+ pool=transport.pool,
56
+ json=True,
57
+ headers=self._connection_config.sandbox_headers,
58
+ logger=self._connection_config.logger,
59
+ )
60
+
61
+ @property
62
+ def _envd_api(self) -> httpx.Client:
63
+ envd_api = getattr(self._thread_local, "envd_api", None)
64
+ if envd_api is None:
65
+ envd_api = self._create_envd_api()
66
+ self._thread_local.envd_api = envd_api
67
+ return envd_api
68
+
69
+ @property
70
+ def _rpc(self) -> process_connect.ProcessClient:
71
+ rpc = getattr(self._thread_local, "rpc", None)
72
+ if rpc is None:
73
+ rpc = self._create_rpc()
74
+ self._thread_local.rpc = rpc
75
+ return rpc
76
+
77
+ def _check_health(self) -> Optional[bool]:
78
+ return check_sandbox_health(self._envd_api)
79
+
80
+ def kill(
81
+ self,
82
+ pid: int,
83
+ request_timeout: Optional[float] = None,
84
+ ) -> bool:
85
+ """
86
+ Kill PTY.
87
+
88
+ :param pid: Process ID of the PTY
89
+ :param request_timeout: Timeout for the request in **seconds**
90
+
91
+ :return: `true` if the PTY was killed, `false` if the PTY was not found
92
+ """
93
+ try:
94
+ self._rpc.send_signal(
95
+ process_pb2.SendSignalRequest(
96
+ process=process_pb2.ProcessSelector(pid=pid),
97
+ signal=process_pb2.Signal.SIGNAL_SIGKILL,
98
+ ),
99
+ request_timeout=self._connection_config.get_request_timeout(
100
+ request_timeout
101
+ ),
102
+ )
103
+ return True
104
+ except Exception as e:
105
+ if isinstance(e, loopix_connect.ConnectException):
106
+ if e.status == loopix_connect.Code.not_found:
107
+ return False
108
+ raise handle_rpc_exception_with_health(e, self._check_health)
109
+
110
+ def send_stdin(
111
+ self,
112
+ pid: int,
113
+ data: bytes,
114
+ request_timeout: Optional[float] = None,
115
+ ) -> None:
116
+ """
117
+ Send input to a PTY.
118
+
119
+ :param pid: Process ID of the PTY
120
+ :param data: Input data to send
121
+ :param request_timeout: Timeout for the request in **seconds**
122
+ """
123
+ try:
124
+ self._rpc.send_input(
125
+ process_pb2.SendInputRequest(
126
+ process=process_pb2.ProcessSelector(pid=pid),
127
+ input=process_pb2.ProcessInput(
128
+ pty=data,
129
+ ),
130
+ ),
131
+ request_timeout=self._connection_config.get_request_timeout(
132
+ request_timeout
133
+ ),
134
+ )
135
+ except Exception as e:
136
+ raise handle_rpc_exception_with_health(e, self._check_health)
137
+
138
+ def create(
139
+ self,
140
+ size: PtySize,
141
+ user: Optional[Username] = None,
142
+ cwd: Optional[str] = None,
143
+ envs: Optional[Dict[str, str]] = None,
144
+ timeout: Optional[float] = 60,
145
+ request_timeout: Optional[float] = None,
146
+ ) -> CommandHandle:
147
+ """
148
+ Start a new PTY (pseudo-terminal).
149
+
150
+ :param size: Size of the PTY
151
+ :param user: User to use for the PTY
152
+ :param cwd: Working directory for the PTY
153
+ :param envs: Environment variables for the PTY
154
+ :param timeout: Timeout for the PTY in **seconds**
155
+ :param request_timeout: Timeout for the request in **seconds**
156
+
157
+ :return: Handle to interact with the PTY
158
+ """
159
+ envs = dict(envs) if envs else {}
160
+ envs.setdefault("TERM", "xterm-256color")
161
+ envs.setdefault("LANG", "C.UTF-8")
162
+ envs.setdefault("LC_ALL", "C.UTF-8")
163
+ events = self._rpc.start(
164
+ process_pb2.StartRequest(
165
+ process=process_pb2.ProcessConfig(
166
+ cmd="/bin/bash",
167
+ envs=envs,
168
+ args=["-i", "-l"],
169
+ cwd=cwd,
170
+ ),
171
+ pty=process_pb2.PTY(
172
+ size=process_pb2.PTY.Size(rows=size.rows, cols=size.cols)
173
+ ),
174
+ ),
175
+ headers={
176
+ **authentication_header(self._envd_version, user),
177
+ KEEPALIVE_PING_HEADER: str(KEEPALIVE_PING_INTERVAL_SEC),
178
+ },
179
+ timeout=timeout,
180
+ request_timeout=self._connection_config.get_request_timeout(
181
+ request_timeout
182
+ ),
183
+ )
184
+
185
+ try:
186
+ start_event = events.__next__()
187
+
188
+ if not start_event.HasField("event"):
189
+ raise SandboxException(
190
+ f"Failed to start process: expected start event, got {start_event}"
191
+ )
192
+
193
+ return CommandHandle(
194
+ pid=start_event.event.start.pid,
195
+ handle_kill=lambda: self.kill(start_event.event.start.pid),
196
+ events=events,
197
+ check_health=self._check_health,
198
+ )
199
+ except Exception as e:
200
+ try:
201
+ events.close()
202
+ except Exception:
203
+ pass
204
+ raise handle_rpc_exception_with_health(e, self._check_health)
205
+
206
+ def connect(
207
+ self,
208
+ pid: int,
209
+ timeout: Optional[float] = 60,
210
+ request_timeout: Optional[float] = None,
211
+ ) -> CommandHandle:
212
+ """
213
+ Connect to a running PTY.
214
+
215
+ :param pid: Process ID of the PTY to connect to. You can get the list of running PTYs using `sandbox.pty.list()`.
216
+ :param timeout: Timeout for the PTY connection in **seconds**. Using `0` will not limit the connection time
217
+ :param request_timeout: Timeout for the request in **seconds**
218
+
219
+ :return: Handle to interact with the PTY
220
+ """
221
+ events = self._rpc.connect(
222
+ process_pb2.ConnectRequest(
223
+ process=process_pb2.ProcessSelector(pid=pid),
224
+ ),
225
+ headers={
226
+ KEEPALIVE_PING_HEADER: str(KEEPALIVE_PING_INTERVAL_SEC),
227
+ },
228
+ timeout=timeout,
229
+ request_timeout=self._connection_config.get_request_timeout(
230
+ request_timeout
231
+ ),
232
+ )
233
+
234
+ try:
235
+ start_event = events.__next__()
236
+
237
+ if not start_event.HasField("event"):
238
+ raise SandboxException(
239
+ f"Failed to connect to process: expected start event, got {start_event}"
240
+ )
241
+
242
+ return CommandHandle(
243
+ pid=start_event.event.start.pid,
244
+ handle_kill=lambda: self.kill(start_event.event.start.pid),
245
+ events=events,
246
+ check_health=self._check_health,
247
+ )
248
+ except Exception as e:
249
+ try:
250
+ events.close()
251
+ except Exception:
252
+ pass
253
+ raise handle_rpc_exception_with_health(e, self._check_health)
254
+
255
+ def resize(
256
+ self,
257
+ pid: int,
258
+ size: PtySize,
259
+ request_timeout: Optional[float] = None,
260
+ ) -> None:
261
+ """
262
+ Resize PTY.
263
+ Call this when the terminal window is resized and the number of columns and rows has changed.
264
+
265
+ :param pid: Process ID of the PTY
266
+ :param size: New size of the PTY
267
+ :param request_timeout: Timeout for the request in **seconds**
268
+ """
269
+ self._rpc.update(
270
+ process_pb2.UpdateRequest(
271
+ process=process_pb2.ProcessSelector(pid=pid),
272
+ pty=process_pb2.PTY(
273
+ size=process_pb2.PTY.Size(rows=size.rows, cols=size.cols),
274
+ ),
275
+ ),
276
+ request_timeout=self._connection_config.get_request_timeout(
277
+ request_timeout
278
+ ),
279
+ )