blaxel 0.2.33__py3-none-any.whl → 0.2.34__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/__init__.py +2 -2
- blaxel/core/__init__.py +2 -1
- blaxel/core/sandbox/default/sandbox.py +34 -10
- blaxel/core/sandbox/sync/sandbox.py +34 -10
- blaxel/core/sandbox/types.py +3 -0
- blaxel/core/volume/__init__.py +2 -2
- blaxel/core/volume/volume.py +200 -6
- {blaxel-0.2.33.dist-info → blaxel-0.2.34.dist-info}/METADATA +1 -1
- {blaxel-0.2.33.dist-info → blaxel-0.2.34.dist-info}/RECORD +11 -11
- {blaxel-0.2.33.dist-info → blaxel-0.2.34.dist-info}/WHEEL +0 -0
- {blaxel-0.2.33.dist-info → blaxel-0.2.34.dist-info}/licenses/LICENSE +0 -0
blaxel/__init__.py
CHANGED
|
@@ -4,8 +4,8 @@ from .core.common.autoload import autoload
|
|
|
4
4
|
from .core.common.env import env
|
|
5
5
|
from .core.common.settings import settings
|
|
6
6
|
|
|
7
|
-
__version__ = "0.2.
|
|
8
|
-
__commit__ = "
|
|
7
|
+
__version__ = "0.2.34"
|
|
8
|
+
__commit__ = "84fc1c14e48dec727c7de1966c51022e09f7c80f"
|
|
9
9
|
__sentry_dsn__ = "https://9711de13cd02b285ca4378c01de8dc30@o4508714045276160.ingest.us.sentry.io/4510461121462272"
|
|
10
10
|
__all__ = ["autoload", "settings", "env"]
|
|
11
11
|
|
blaxel/core/__init__.py
CHANGED
|
@@ -30,7 +30,7 @@ from .sandbox import (
|
|
|
30
30
|
)
|
|
31
31
|
from .sandbox.types import Sandbox
|
|
32
32
|
from .tools import BlTools, bl_tools, convert_mcp_tool_to_blaxel_tool
|
|
33
|
-
from .volume import VolumeCreateConfiguration, VolumeInstance
|
|
33
|
+
from .volume import SyncVolumeInstance, VolumeCreateConfiguration, VolumeInstance
|
|
34
34
|
|
|
35
35
|
__all__ = [
|
|
36
36
|
"BlAgent",
|
|
@@ -65,6 +65,7 @@ __all__ = [
|
|
|
65
65
|
"convert_mcp_tool_to_blaxel_tool",
|
|
66
66
|
"websocket_client",
|
|
67
67
|
"VolumeInstance",
|
|
68
|
+
"SyncVolumeInstance",
|
|
68
69
|
"VolumeCreateConfiguration",
|
|
69
70
|
"verify_webhook_signature",
|
|
70
71
|
"verify_webhook_from_request",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import uuid
|
|
3
|
-
from typing import Any, Dict, List, Union
|
|
3
|
+
from typing import Any, Callable, Dict, List, Union
|
|
4
4
|
|
|
5
5
|
from ...client.api.compute.create_sandbox import asyncio as create_sandbox
|
|
6
6
|
from ...client.api.compute.delete_sandbox import asyncio as delete_sandbox
|
|
@@ -26,6 +26,24 @@ from .session import SandboxSessions
|
|
|
26
26
|
logger = logging.getLogger(__name__)
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
class _AsyncDeleteDescriptor:
|
|
30
|
+
"""Descriptor that provides both class-level and instance-level delete functionality."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, delete_func: Callable):
|
|
33
|
+
self._delete_func = delete_func
|
|
34
|
+
|
|
35
|
+
def __get__(self, instance, owner):
|
|
36
|
+
if instance is None:
|
|
37
|
+
# Called on the class: SandboxInstance.delete("name")
|
|
38
|
+
return self._delete_func
|
|
39
|
+
else:
|
|
40
|
+
# Called on an instance: instance.delete()
|
|
41
|
+
async def instance_delete() -> Sandbox:
|
|
42
|
+
return await self._delete_func(instance.metadata.name)
|
|
43
|
+
|
|
44
|
+
return instance_delete
|
|
45
|
+
|
|
46
|
+
|
|
29
47
|
class SandboxInstance:
|
|
30
48
|
def __init__(
|
|
31
49
|
self,
|
|
@@ -107,6 +125,7 @@ class SandboxInstance:
|
|
|
107
125
|
or "lifecycle" in (sandbox if isinstance(sandbox, dict) else sandbox.__dict__)
|
|
108
126
|
or "snapshot_enabled"
|
|
109
127
|
in (sandbox if isinstance(sandbox, dict) else sandbox.__dict__)
|
|
128
|
+
or "labels" in (sandbox if isinstance(sandbox, dict) else sandbox.__dict__)
|
|
110
129
|
)
|
|
111
130
|
)
|
|
112
131
|
):
|
|
@@ -135,7 +154,7 @@ class SandboxInstance:
|
|
|
135
154
|
|
|
136
155
|
# Create full Sandbox object
|
|
137
156
|
sandbox = Sandbox(
|
|
138
|
-
metadata=Metadata(name=name),
|
|
157
|
+
metadata=Metadata(name=name, labels=config.labels),
|
|
139
158
|
spec=SandboxSpec(
|
|
140
159
|
runtime=Runtime(
|
|
141
160
|
image=image,
|
|
@@ -202,14 +221,6 @@ class SandboxInstance:
|
|
|
202
221
|
response = await list_sandboxes()
|
|
203
222
|
return [cls(sandbox) for sandbox in response]
|
|
204
223
|
|
|
205
|
-
@classmethod
|
|
206
|
-
async def delete(cls, sandbox_name: str) -> Sandbox:
|
|
207
|
-
response = await delete_sandbox(
|
|
208
|
-
sandbox_name,
|
|
209
|
-
client=client,
|
|
210
|
-
)
|
|
211
|
-
return response
|
|
212
|
-
|
|
213
224
|
@classmethod
|
|
214
225
|
async def update_metadata(
|
|
215
226
|
cls, sandbox_name: str, metadata: SandboxUpdateMetadata
|
|
@@ -319,3 +330,16 @@ class SandboxInstance:
|
|
|
319
330
|
headers={"X-Blaxel-Preview-Token": session.token},
|
|
320
331
|
params={"bl_preview_token": session.token},
|
|
321
332
|
)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
async def _delete_sandbox_by_name(sandbox_name: str) -> Sandbox:
|
|
336
|
+
"""Delete a sandbox by name."""
|
|
337
|
+
response = await delete_sandbox(
|
|
338
|
+
sandbox_name,
|
|
339
|
+
client=client,
|
|
340
|
+
)
|
|
341
|
+
return response
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
# Assign the delete descriptor to support both class-level and instance-level calls
|
|
345
|
+
SandboxInstance.delete = _AsyncDeleteDescriptor(_delete_sandbox_by_name)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import uuid
|
|
3
|
-
from typing import Any, Dict, List, Union
|
|
3
|
+
from typing import Any, Callable, Dict, List, Union
|
|
4
4
|
|
|
5
5
|
from ...client.api.compute.create_sandbox import sync as create_sandbox
|
|
6
6
|
from ...client.api.compute.delete_sandbox import sync as delete_sandbox
|
|
@@ -26,6 +26,24 @@ from .session import SyncSandboxSessions
|
|
|
26
26
|
logger = logging.getLogger(__name__)
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
class _SyncDeleteDescriptor:
|
|
30
|
+
"""Descriptor that provides both class-level and instance-level delete functionality."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, delete_func: Callable):
|
|
33
|
+
self._delete_func = delete_func
|
|
34
|
+
|
|
35
|
+
def __get__(self, instance, owner):
|
|
36
|
+
if instance is None:
|
|
37
|
+
# Called on the class: SyncSandboxInstance.delete("name")
|
|
38
|
+
return self._delete_func
|
|
39
|
+
else:
|
|
40
|
+
# Called on an instance: instance.delete()
|
|
41
|
+
def instance_delete() -> Sandbox:
|
|
42
|
+
return self._delete_func(instance.metadata.name)
|
|
43
|
+
|
|
44
|
+
return instance_delete
|
|
45
|
+
|
|
46
|
+
|
|
29
47
|
class SyncSandboxInstance:
|
|
30
48
|
def __init__(
|
|
31
49
|
self,
|
|
@@ -102,6 +120,7 @@ class SyncSandboxInstance:
|
|
|
102
120
|
or "lifecycle" in (sandbox if isinstance(sandbox, dict) else sandbox.__dict__)
|
|
103
121
|
or "snapshot_enabled"
|
|
104
122
|
in (sandbox if isinstance(sandbox, dict) else sandbox.__dict__)
|
|
123
|
+
or "labels" in (sandbox if isinstance(sandbox, dict) else sandbox.__dict__)
|
|
105
124
|
)
|
|
106
125
|
)
|
|
107
126
|
):
|
|
@@ -125,7 +144,7 @@ class SyncSandboxInstance:
|
|
|
125
144
|
region = config.region
|
|
126
145
|
lifecycle = config.lifecycle
|
|
127
146
|
sandbox = Sandbox(
|
|
128
|
-
metadata=Metadata(name=name),
|
|
147
|
+
metadata=Metadata(name=name, labels=config.labels),
|
|
129
148
|
spec=SandboxSpec(
|
|
130
149
|
runtime=Runtime(
|
|
131
150
|
image=image,
|
|
@@ -184,14 +203,6 @@ class SyncSandboxInstance:
|
|
|
184
203
|
response = list_sandboxes(client=client)
|
|
185
204
|
return [cls(sandbox) for sandbox in response]
|
|
186
205
|
|
|
187
|
-
@classmethod
|
|
188
|
-
def delete(cls, sandbox_name: str) -> Sandbox:
|
|
189
|
-
response = delete_sandbox(
|
|
190
|
-
sandbox_name,
|
|
191
|
-
client=client,
|
|
192
|
-
)
|
|
193
|
-
return response
|
|
194
|
-
|
|
195
206
|
@classmethod
|
|
196
207
|
def update_metadata(
|
|
197
208
|
cls, sandbox_name: str, metadata: SandboxUpdateMetadata
|
|
@@ -261,3 +272,16 @@ class SyncSandboxInstance:
|
|
|
261
272
|
headers={"X-Blaxel-Preview-Token": session.token},
|
|
262
273
|
params={"bl_preview_token": session.token},
|
|
263
274
|
)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def _delete_sandbox_by_name(sandbox_name: str) -> Sandbox:
|
|
278
|
+
"""Delete a sandbox by name."""
|
|
279
|
+
response = delete_sandbox(
|
|
280
|
+
sandbox_name,
|
|
281
|
+
client=client,
|
|
282
|
+
)
|
|
283
|
+
return response
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
# Assign the delete descriptor to support both class-level and instance-level calls
|
|
287
|
+
SyncSandboxInstance.delete = _SyncDeleteDescriptor(_delete_sandbox_by_name)
|
blaxel/core/sandbox/types.py
CHANGED
|
@@ -155,6 +155,7 @@ class SandboxCreateConfiguration:
|
|
|
155
155
|
region: str | None = None,
|
|
156
156
|
lifecycle: Union[SandboxLifecycle, Dict[str, Any]] | None = None,
|
|
157
157
|
snapshot_enabled: bool | None = None,
|
|
158
|
+
labels: Dict[str, str] | None = None,
|
|
158
159
|
):
|
|
159
160
|
self.name = name
|
|
160
161
|
self.image = image
|
|
@@ -167,6 +168,7 @@ class SandboxCreateConfiguration:
|
|
|
167
168
|
self.region = region
|
|
168
169
|
self.lifecycle = lifecycle
|
|
169
170
|
self.snapshot_enabled = snapshot_enabled
|
|
171
|
+
self.labels = labels
|
|
170
172
|
|
|
171
173
|
@classmethod
|
|
172
174
|
def from_dict(cls, data: Dict[str, Any]) -> "SandboxCreateConfiguration":
|
|
@@ -190,6 +192,7 @@ class SandboxCreateConfiguration:
|
|
|
190
192
|
region=data.get("region"),
|
|
191
193
|
lifecycle=lifecycle,
|
|
192
194
|
snapshot_enabled=data.get("snapshot_enabled"),
|
|
195
|
+
labels=data.get("labels"),
|
|
193
196
|
)
|
|
194
197
|
|
|
195
198
|
def _normalize_ports(self) -> List[Port] | None:
|
blaxel/core/volume/__init__.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""Volume module for persistent storage management."""
|
|
2
2
|
|
|
3
|
-
from .volume import VolumeCreateConfiguration, VolumeInstance
|
|
3
|
+
from .volume import SyncVolumeInstance, VolumeCreateConfiguration, VolumeInstance
|
|
4
4
|
|
|
5
|
-
__all__ = ["VolumeInstance", "VolumeCreateConfiguration"]
|
|
5
|
+
__all__ = ["VolumeInstance", "SyncVolumeInstance", "VolumeCreateConfiguration"]
|
blaxel/core/volume/volume.py
CHANGED
|
@@ -1,15 +1,55 @@
|
|
|
1
1
|
import uuid
|
|
2
|
-
from typing import Dict, Union
|
|
2
|
+
from typing import Callable, Dict, List, Union
|
|
3
3
|
|
|
4
4
|
from ..client.api.volumes.create_volume import asyncio as create_volume
|
|
5
|
+
from ..client.api.volumes.create_volume import sync as create_volume_sync
|
|
5
6
|
from ..client.api.volumes.delete_volume import asyncio as delete_volume
|
|
7
|
+
from ..client.api.volumes.delete_volume import sync as delete_volume_sync
|
|
6
8
|
from ..client.api.volumes.get_volume import asyncio as get_volume
|
|
9
|
+
from ..client.api.volumes.get_volume import sync as get_volume_sync
|
|
7
10
|
from ..client.api.volumes.list_volumes import asyncio as list_volumes
|
|
11
|
+
from ..client.api.volumes.list_volumes import sync as list_volumes_sync
|
|
8
12
|
from ..client.client import client
|
|
9
13
|
from ..client.models import Metadata, Volume, VolumeSpec
|
|
10
14
|
from ..client.types import UNSET
|
|
11
15
|
|
|
12
16
|
|
|
17
|
+
class _AsyncDeleteDescriptor:
|
|
18
|
+
"""Descriptor that provides both class-level and instance-level delete functionality."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, delete_func: Callable):
|
|
21
|
+
self._delete_func = delete_func
|
|
22
|
+
|
|
23
|
+
def __get__(self, instance, owner):
|
|
24
|
+
if instance is None:
|
|
25
|
+
# Called on the class: VolumeInstance.delete("name")
|
|
26
|
+
return self._delete_func
|
|
27
|
+
else:
|
|
28
|
+
# Called on an instance: instance.delete()
|
|
29
|
+
async def instance_delete() -> Volume:
|
|
30
|
+
return await self._delete_func(instance.metadata.name or "")
|
|
31
|
+
|
|
32
|
+
return instance_delete
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class _SyncDeleteDescriptor:
|
|
36
|
+
"""Descriptor that provides both class-level and instance-level delete functionality (sync)."""
|
|
37
|
+
|
|
38
|
+
def __init__(self, delete_func: Callable):
|
|
39
|
+
self._delete_func = delete_func
|
|
40
|
+
|
|
41
|
+
def __get__(self, instance, owner):
|
|
42
|
+
if instance is None:
|
|
43
|
+
# Called on the class: SyncVolumeInstance.delete("name")
|
|
44
|
+
return self._delete_func
|
|
45
|
+
else:
|
|
46
|
+
# Called on an instance: instance.delete()
|
|
47
|
+
def instance_delete() -> Volume:
|
|
48
|
+
return self._delete_func(instance.metadata.name or "")
|
|
49
|
+
|
|
50
|
+
return instance_delete
|
|
51
|
+
|
|
52
|
+
|
|
13
53
|
class VolumeCreateConfiguration:
|
|
14
54
|
"""Simplified configuration for creating volumes with default values."""
|
|
15
55
|
|
|
@@ -17,12 +57,14 @@ class VolumeCreateConfiguration:
|
|
|
17
57
|
self,
|
|
18
58
|
name: str | None = None,
|
|
19
59
|
display_name: str | None = None,
|
|
60
|
+
labels: Dict[str, str] | None = None,
|
|
20
61
|
size: int | None = None, # Size in MB
|
|
21
62
|
region: str | None = None, # AWS region
|
|
22
63
|
template: str | None = None, # Template
|
|
23
64
|
):
|
|
24
65
|
self.name = name
|
|
25
66
|
self.display_name = display_name
|
|
67
|
+
self.labels = labels
|
|
26
68
|
self.size = size
|
|
27
69
|
self.region = region
|
|
28
70
|
self.template = template
|
|
@@ -32,6 +74,7 @@ class VolumeCreateConfiguration:
|
|
|
32
74
|
return cls(
|
|
33
75
|
name=data.get("name"),
|
|
34
76
|
display_name=data.get("display_name"),
|
|
77
|
+
labels=data.get("labels"),
|
|
35
78
|
size=data.get("size"),
|
|
36
79
|
region=data.get("region"),
|
|
37
80
|
template=data.get("template"),
|
|
@@ -90,6 +133,7 @@ class VolumeInstance:
|
|
|
90
133
|
metadata=Metadata(
|
|
91
134
|
name=config.name or default_name,
|
|
92
135
|
display_name=config.display_name or config.name or default_name,
|
|
136
|
+
labels=config.labels,
|
|
93
137
|
),
|
|
94
138
|
spec=VolumeSpec(
|
|
95
139
|
size=config.size or default_size,
|
|
@@ -103,6 +147,7 @@ class VolumeInstance:
|
|
|
103
147
|
metadata=Metadata(
|
|
104
148
|
name=volume_config.name or default_name,
|
|
105
149
|
display_name=volume_config.display_name or volume_config.name or default_name,
|
|
150
|
+
labels=volume_config.labels,
|
|
106
151
|
),
|
|
107
152
|
spec=VolumeSpec(
|
|
108
153
|
size=volume_config.size or default_size,
|
|
@@ -138,11 +183,6 @@ class VolumeInstance:
|
|
|
138
183
|
response = await list_volumes(client=client)
|
|
139
184
|
return [cls(volume) for volume in response or []]
|
|
140
185
|
|
|
141
|
-
@classmethod
|
|
142
|
-
async def delete(cls, volume_name: str) -> Volume:
|
|
143
|
-
response = await delete_volume(volume_name=volume_name, client=client)
|
|
144
|
-
return response
|
|
145
|
-
|
|
146
186
|
@classmethod
|
|
147
187
|
async def create_if_not_exists(
|
|
148
188
|
cls, config: Union[VolumeCreateConfiguration, Volume, Dict[str, any]]
|
|
@@ -171,3 +211,157 @@ class VolumeInstance:
|
|
|
171
211
|
volume_instance = await cls.get(name)
|
|
172
212
|
return volume_instance
|
|
173
213
|
raise e
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class SyncVolumeInstance:
|
|
217
|
+
"""Synchronous volume instance for managing persistent storage."""
|
|
218
|
+
|
|
219
|
+
def __init__(self, volume: Volume):
|
|
220
|
+
self.volume = volume
|
|
221
|
+
|
|
222
|
+
@property
|
|
223
|
+
def metadata(self):
|
|
224
|
+
return self.volume.metadata
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def spec(self):
|
|
228
|
+
return self.volume.spec
|
|
229
|
+
|
|
230
|
+
@property
|
|
231
|
+
def status(self):
|
|
232
|
+
return self.volume.status
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
def name(self):
|
|
236
|
+
return self.volume.metadata.name if self.volume.metadata else None
|
|
237
|
+
|
|
238
|
+
@property
|
|
239
|
+
def display_name(self):
|
|
240
|
+
return self.volume.metadata.display_name if self.volume.metadata else None
|
|
241
|
+
|
|
242
|
+
@property
|
|
243
|
+
def size(self):
|
|
244
|
+
return self.volume.spec.size if self.volume.spec else None
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def region(self):
|
|
248
|
+
return self.volume.spec.region if self.volume.spec else None
|
|
249
|
+
|
|
250
|
+
@property
|
|
251
|
+
def template(self):
|
|
252
|
+
return self.volume.spec.template if self.volume.spec else None
|
|
253
|
+
|
|
254
|
+
@classmethod
|
|
255
|
+
def create(
|
|
256
|
+
cls, config: Union[VolumeCreateConfiguration, Volume, Dict[str, any]]
|
|
257
|
+
) -> "SyncVolumeInstance":
|
|
258
|
+
"""Create a new volume synchronously."""
|
|
259
|
+
# Generate default values
|
|
260
|
+
default_name = f"volume-{uuid.uuid4().hex[:8]}"
|
|
261
|
+
default_size = 1024 # 1GB in MB
|
|
262
|
+
|
|
263
|
+
# Handle different configuration types
|
|
264
|
+
if isinstance(config, Volume):
|
|
265
|
+
volume = config
|
|
266
|
+
elif isinstance(config, VolumeCreateConfiguration):
|
|
267
|
+
volume = Volume(
|
|
268
|
+
metadata=Metadata(
|
|
269
|
+
name=config.name or default_name,
|
|
270
|
+
display_name=config.display_name or config.name or default_name,
|
|
271
|
+
labels=config.labels,
|
|
272
|
+
),
|
|
273
|
+
spec=VolumeSpec(
|
|
274
|
+
size=config.size or default_size,
|
|
275
|
+
region=config.region or UNSET,
|
|
276
|
+
template=config.template or UNSET,
|
|
277
|
+
),
|
|
278
|
+
)
|
|
279
|
+
elif isinstance(config, dict):
|
|
280
|
+
volume_config = VolumeCreateConfiguration.from_dict(config)
|
|
281
|
+
volume = Volume(
|
|
282
|
+
metadata=Metadata(
|
|
283
|
+
name=volume_config.name or default_name,
|
|
284
|
+
display_name=volume_config.display_name or volume_config.name or default_name,
|
|
285
|
+
labels=volume_config.labels,
|
|
286
|
+
),
|
|
287
|
+
spec=VolumeSpec(
|
|
288
|
+
size=volume_config.size or default_size,
|
|
289
|
+
region=volume_config.region or UNSET,
|
|
290
|
+
template=volume_config.template or UNSET,
|
|
291
|
+
),
|
|
292
|
+
)
|
|
293
|
+
else:
|
|
294
|
+
raise ValueError(
|
|
295
|
+
f"Invalid config type: {type(config)}. Expected VolumeCreateConfiguration, Volume, or dict."
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
# Ensure required fields have defaults
|
|
299
|
+
if not volume.metadata:
|
|
300
|
+
volume.metadata = Metadata(name=default_name)
|
|
301
|
+
if not volume.metadata.name:
|
|
302
|
+
volume.metadata.name = default_name
|
|
303
|
+
if not volume.spec:
|
|
304
|
+
volume.spec = VolumeSpec(size=default_size)
|
|
305
|
+
if not volume.spec.size:
|
|
306
|
+
volume.spec.size = default_size
|
|
307
|
+
|
|
308
|
+
response = create_volume_sync(client=client, body=volume)
|
|
309
|
+
return cls(response)
|
|
310
|
+
|
|
311
|
+
@classmethod
|
|
312
|
+
def get(cls, volume_name: str) -> "SyncVolumeInstance":
|
|
313
|
+
"""Get a volume by name synchronously."""
|
|
314
|
+
response = get_volume_sync(volume_name=volume_name, client=client)
|
|
315
|
+
return cls(response)
|
|
316
|
+
|
|
317
|
+
@classmethod
|
|
318
|
+
def list(cls) -> List["SyncVolumeInstance"]:
|
|
319
|
+
"""List all volumes synchronously."""
|
|
320
|
+
response = list_volumes_sync(client=client)
|
|
321
|
+
return [cls(volume) for volume in response or []]
|
|
322
|
+
|
|
323
|
+
@classmethod
|
|
324
|
+
def create_if_not_exists(
|
|
325
|
+
cls, config: Union[VolumeCreateConfiguration, Volume, Dict[str, any]]
|
|
326
|
+
) -> "SyncVolumeInstance":
|
|
327
|
+
"""Create a volume if it doesn't exist, otherwise return existing."""
|
|
328
|
+
try:
|
|
329
|
+
return cls.create(config)
|
|
330
|
+
except Exception as e:
|
|
331
|
+
# Check if it's a 409 conflict error (volume already exists)
|
|
332
|
+
if (hasattr(e, "status_code") and e.status_code == 409) or (
|
|
333
|
+
hasattr(e, "code") and e.code in [409, "VOLUME_ALREADY_EXISTS"]
|
|
334
|
+
):
|
|
335
|
+
# Extract name from different configuration types
|
|
336
|
+
if isinstance(config, VolumeCreateConfiguration):
|
|
337
|
+
name = config.name
|
|
338
|
+
elif isinstance(config, dict):
|
|
339
|
+
name = config.get("name")
|
|
340
|
+
elif isinstance(config, Volume):
|
|
341
|
+
name = config.metadata.name if config.metadata else None
|
|
342
|
+
else:
|
|
343
|
+
name = None
|
|
344
|
+
|
|
345
|
+
if not name:
|
|
346
|
+
raise ValueError("Volume name is required")
|
|
347
|
+
|
|
348
|
+
volume_instance = cls.get(name)
|
|
349
|
+
return volume_instance
|
|
350
|
+
raise e
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
async def _delete_volume_by_name(volume_name: str) -> Volume:
|
|
354
|
+
"""Delete a volume by name (async)."""
|
|
355
|
+
response = await delete_volume(volume_name=volume_name, client=client)
|
|
356
|
+
return response
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def _delete_volume_by_name_sync(volume_name: str) -> Volume:
|
|
360
|
+
"""Delete a volume by name (sync)."""
|
|
361
|
+
response = delete_volume_sync(volume_name=volume_name, client=client)
|
|
362
|
+
return response
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
# Assign the delete descriptors to support both class-level and instance-level calls
|
|
366
|
+
VolumeInstance.delete = _AsyncDeleteDescriptor(_delete_volume_by_name)
|
|
367
|
+
SyncVolumeInstance.delete = _SyncDeleteDescriptor(_delete_volume_by_name_sync)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
blaxel/__init__.py,sha256=
|
|
2
|
-
blaxel/core/__init__.py,sha256=
|
|
1
|
+
blaxel/__init__.py,sha256=JFHDlTbbIPz2qG5ETm0mcQ1NX7AXph_tw6L5PVKLXzg,413
|
|
2
|
+
blaxel/core/__init__.py,sha256=CU0gXpVRbuQZNWoCJuuhZS0ZhXPEu0cg-3XzoYMrBm4,1756
|
|
3
3
|
blaxel/core/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
blaxel/core/agents/__init__.py,sha256=MJZga99lU8JWUUPHd4rmUfdo7ALwWgF7CQq95SfT2OI,4456
|
|
5
5
|
blaxel/core/authentication/__init__.py,sha256=5uHv73xZ2aZRXzGHc1sP-XWqZUryfXxfC9dMX7-gd6o,3241
|
|
@@ -344,7 +344,7 @@ blaxel/core/mcp/client.py,sha256=EZ7l5w3bTXaD41nalHzM-byxfQK-JdcmQqxg3zGpVO4,550
|
|
|
344
344
|
blaxel/core/mcp/server.py,sha256=edAztWBlukERw9-dzS2Sk96TP8R3-CSofY1CZDu19ZA,5967
|
|
345
345
|
blaxel/core/models/__init__.py,sha256=ydz1txqIVyOhehItut-AOnLMnGp7AtCD2zku9gkvAsE,1722
|
|
346
346
|
blaxel/core/sandbox/__init__.py,sha256=SQ9YH0I9ruAYscY_W75jqIhNbejbY_92xL7VqM083Mc,1345
|
|
347
|
-
blaxel/core/sandbox/types.py,sha256=
|
|
347
|
+
blaxel/core/sandbox/types.py,sha256=mi2fbD5vvPzgyDbmN1YA-LkFS6Iaq0dLtI4OxQDb16s,12817
|
|
348
348
|
blaxel/core/sandbox/client/__init__.py,sha256=N26bD5o1jsTb48oExow6Rgivd8ylaU9jaWZfZsVilP8,128
|
|
349
349
|
blaxel/core/sandbox/client/client.py,sha256=EGCYliUHCk4RyIBlydEZyVpc_VUiIIGPuu2E-xYeKFY,7074
|
|
350
350
|
blaxel/core/sandbox/client/errors.py,sha256=gO8GBmKqmSNgAg-E5oT-oOyxztvp7V_6XG7OUTT15q0,546
|
|
@@ -440,7 +440,7 @@ blaxel/core/sandbox/default/interpreter.py,sha256=TJSryQvq2rWedyhMU69tOlXVOF1iIp
|
|
|
440
440
|
blaxel/core/sandbox/default/network.py,sha256=3ZvrJB_9JdZrclNkwifZOIciz2OqzV0LQfbebjZXLIY,358
|
|
441
441
|
blaxel/core/sandbox/default/preview.py,sha256=dV_xuu9Efop5TnzuFJPeLUZ7CEepuYkJedx01fDVMX4,6132
|
|
442
442
|
blaxel/core/sandbox/default/process.py,sha256=7nI1wJXeZWoveBesC13wur-ghIjP5POZ38G8wqCdJTw,16983
|
|
443
|
-
blaxel/core/sandbox/default/sandbox.py,sha256=
|
|
443
|
+
blaxel/core/sandbox/default/sandbox.py,sha256=B7MGnVnelV4iOh1PSBWbMwO6Vq6KNNxpQQ42mMNgShU,13485
|
|
444
444
|
blaxel/core/sandbox/default/session.py,sha256=XzVpPOH_az6T38Opp4Hmj3RIg7QCzA1l5wh1YDh7czc,5313
|
|
445
445
|
blaxel/core/sandbox/sync/__init__.py,sha256=iqTRxQYbJyHTXoA4MHaigeXFxi9wtJ3o9XygZuFe3bM,372
|
|
446
446
|
blaxel/core/sandbox/sync/action.py,sha256=9t8nCS9KX6SBflJmzK8dsen_bDim3zElBTebY6N6JQc,2136
|
|
@@ -450,13 +450,13 @@ blaxel/core/sandbox/sync/interpreter.py,sha256=5cAzwnt5BgnByGimagMBotjGW2vMAz4vu
|
|
|
450
450
|
blaxel/core/sandbox/sync/network.py,sha256=QkCFKfFayvwL1J4JYwOuXPGlYQuX4J9Jj55Kf_kD-ig,283
|
|
451
451
|
blaxel/core/sandbox/sync/preview.py,sha256=w3bC8iA3QecHiLkRvITmQ6LTT9Co_93G24QpZFgEQSE,6379
|
|
452
452
|
blaxel/core/sandbox/sync/process.py,sha256=W-ZUM6VyFDxTmexHTQn9PI6iRc0QiB9JMOEq__r2bBA,14913
|
|
453
|
-
blaxel/core/sandbox/sync/sandbox.py,sha256=
|
|
453
|
+
blaxel/core/sandbox/sync/sandbox.py,sha256=mz1_AJkoIBIgrAtX5pGn5h3lhmKI1jtKB75fMmoJ3UM,11418
|
|
454
454
|
blaxel/core/sandbox/sync/session.py,sha256=e0CVbW2LBRYTwm4RL52S0UdNvhNfuFLo6AYE5hk9DH0,4931
|
|
455
455
|
blaxel/core/tools/__init__.py,sha256=OK2TFqeXAIi6CC7xtL8fFl-4DvCB7jjihkhx6RTld_c,13147
|
|
456
456
|
blaxel/core/tools/common.py,sha256=fjapOcJwFCS1Do9FCwqmdDTXpo1pZ-9vbfSjadJ9l8g,1321
|
|
457
457
|
blaxel/core/tools/types.py,sha256=EXa-10iOOXvd8zB2IsTS0gWrgoC2hqbIv6iK5m6E5t8,693
|
|
458
|
-
blaxel/core/volume/__init__.py,sha256=
|
|
459
|
-
blaxel/core/volume/volume.py,sha256=
|
|
458
|
+
blaxel/core/volume/__init__.py,sha256=YgEquO_GVxtcymSZoIJTEPvL8KeXtHIobNjGecEKtwM,219
|
|
459
|
+
blaxel/core/volume/volume.py,sha256=24ihurOCGfvadeWNvJCEI3OAK1UpLUWpYacALS8u0MI,13153
|
|
460
460
|
blaxel/crewai/__init__.py,sha256=HdAZxRDgC2zW-O5xYzb_Xuysb66_fMykNJVPxlTmFnY,123
|
|
461
461
|
blaxel/crewai/model.py,sha256=iR-40o8pGBFrktYNKcTaMdqbF_F1SFVavNOhhi2fW3w,1957
|
|
462
462
|
blaxel/crewai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -501,7 +501,7 @@ blaxel/telemetry/instrumentation/map.py,sha256=PCzZJj39yiYVYJrxLBNP-NW-tjjYyTijw
|
|
|
501
501
|
blaxel/telemetry/instrumentation/utils.py,sha256=FGyMY5ZE4f-0JdZpm_R_BCoKLJ18hftz8vsh7ftDwMk,1889
|
|
502
502
|
blaxel/telemetry/log/log.py,sha256=vtzUIFIIj4MTTKUigILDYXN8NHHPOo44OaKukpyIjQg,2407
|
|
503
503
|
blaxel/telemetry/log/logger.py,sha256=IcFWCd1yyWWGAjAd2i0pDYqpZHQ61pmcaQ7Kf4bC8lg,4150
|
|
504
|
-
blaxel-0.2.
|
|
505
|
-
blaxel-0.2.
|
|
506
|
-
blaxel-0.2.
|
|
507
|
-
blaxel-0.2.
|
|
504
|
+
blaxel-0.2.34.dist-info/METADATA,sha256=L6AhAF7TXWMZCy4FRqjnkHYUEOl-WBxbDO09pVzZdv0,10074
|
|
505
|
+
blaxel-0.2.34.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
506
|
+
blaxel-0.2.34.dist-info/licenses/LICENSE,sha256=p5PNQvpvyDT_0aYBDgmV1fFI_vAD2aSV0wWG7VTgRis,1069
|
|
507
|
+
blaxel-0.2.34.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|