blaxel 0.2.36__py3-none-any.whl → 0.2.37__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/client/models/create_job_execution_request_env.py +3 -3
- blaxel/core/client/models/preview.py +48 -1
- blaxel/core/client/models/sandbox.py +10 -0
- blaxel/core/jobs/__init__.py +2 -2
- blaxel/core/sandbox/__init__.py +12 -0
- blaxel/core/sandbox/client/api/system/__init__.py +0 -0
- blaxel/core/sandbox/client/api/system/get_health.py +134 -0
- blaxel/core/sandbox/client/api/system/post_upgrade.py +196 -0
- blaxel/core/sandbox/client/models/__init__.py +8 -0
- blaxel/core/sandbox/client/models/content_search_match.py +24 -25
- blaxel/core/sandbox/client/models/content_search_response.py +25 -29
- blaxel/core/sandbox/client/models/find_match.py +13 -14
- blaxel/core/sandbox/client/models/find_response.py +21 -24
- blaxel/core/sandbox/client/models/fuzzy_search_match.py +17 -19
- blaxel/core/sandbox/client/models/fuzzy_search_response.py +21 -24
- blaxel/core/sandbox/client/models/health_response.py +159 -0
- blaxel/core/sandbox/client/models/process_upgrade_state.py +20 -0
- blaxel/core/sandbox/client/models/upgrade_request.py +71 -0
- blaxel/core/sandbox/client/models/upgrade_status.py +125 -0
- blaxel/core/sandbox/default/__init__.py +2 -0
- blaxel/core/sandbox/default/filesystem.py +20 -6
- blaxel/core/sandbox/default/preview.py +48 -1
- blaxel/core/sandbox/default/process.py +66 -21
- blaxel/core/sandbox/default/sandbox.py +36 -5
- blaxel/core/sandbox/default/system.py +71 -0
- blaxel/core/sandbox/sync/__init__.py +2 -0
- blaxel/core/sandbox/sync/filesystem.py +19 -2
- blaxel/core/sandbox/sync/preview.py +50 -3
- blaxel/core/sandbox/sync/process.py +38 -15
- blaxel/core/sandbox/sync/sandbox.py +29 -4
- blaxel/core/sandbox/sync/system.py +71 -0
- blaxel/core/sandbox/types.py +212 -5
- blaxel/core/volume/volume.py +6 -0
- blaxel/langgraph/tools.py +0 -1
- blaxel-0.2.37.dist-info/METADATA +569 -0
- {blaxel-0.2.36.dist-info → blaxel-0.2.37.dist-info}/RECORD +39 -30
- blaxel-0.2.36.dist-info/METADATA +0 -228
- {blaxel-0.2.36.dist-info → blaxel-0.2.37.dist-info}/WHEEL +0 -0
- {blaxel-0.2.36.dist-info → blaxel-0.2.37.dist-info}/licenses/LICENSE +0 -0
blaxel/core/sandbox/types.py
CHANGED
|
@@ -4,7 +4,14 @@ from typing import Any, Callable, Dict, List, TypeVar, Union
|
|
|
4
4
|
import httpx
|
|
5
5
|
from attrs import define as _attrs_define
|
|
6
6
|
|
|
7
|
-
from ..client.models import
|
|
7
|
+
from ..client.models import (
|
|
8
|
+
Env,
|
|
9
|
+
Port,
|
|
10
|
+
PortProtocol,
|
|
11
|
+
Sandbox,
|
|
12
|
+
SandboxLifecycle,
|
|
13
|
+
VolumeAttachment,
|
|
14
|
+
)
|
|
8
15
|
from ..client.types import UNSET
|
|
9
16
|
from .client.models.process_request import ProcessRequest
|
|
10
17
|
from .client.models.process_response import ProcessResponse
|
|
@@ -205,7 +212,7 @@ class SandboxCreateConfiguration:
|
|
|
205
212
|
if isinstance(port, Port):
|
|
206
213
|
# If it's already a Port object, ensure protocol defaults to HTTP
|
|
207
214
|
if port.protocol is UNSET or not port.protocol:
|
|
208
|
-
port.protocol =
|
|
215
|
+
port.protocol = PortProtocol.HTTP
|
|
209
216
|
port_objects.append(port)
|
|
210
217
|
elif isinstance(port, dict):
|
|
211
218
|
# Convert dict to Port object with HTTP as default protocol
|
|
@@ -218,20 +225,22 @@ class SandboxCreateConfiguration:
|
|
|
218
225
|
|
|
219
226
|
return port_objects
|
|
220
227
|
|
|
221
|
-
def _normalize_envs(self) -> List[
|
|
228
|
+
def _normalize_envs(self) -> List[Env] | None:
|
|
222
229
|
"""Convert envs to list of dicts with name and value keys."""
|
|
223
230
|
if not self.envs:
|
|
224
231
|
return None
|
|
225
232
|
|
|
226
233
|
env_objects = []
|
|
227
234
|
for env in self.envs:
|
|
228
|
-
if isinstance(env,
|
|
235
|
+
if isinstance(env, Env):
|
|
236
|
+
env_objects.append(env)
|
|
237
|
+
elif isinstance(env, dict):
|
|
229
238
|
# Validate that the dict has the required keys
|
|
230
239
|
if "name" not in env or "value" not in env:
|
|
231
240
|
raise ValueError(
|
|
232
241
|
f"Environment variable dict must have 'name' and 'value' keys: {env}"
|
|
233
242
|
)
|
|
234
|
-
env_objects.append(
|
|
243
|
+
env_objects.append(Env(name=env["name"], value=env["value"]))
|
|
235
244
|
else:
|
|
236
245
|
raise ValueError(
|
|
237
246
|
f"Invalid env type: {type(env)}. Expected dict with 'name' and 'value' keys."
|
|
@@ -385,3 +394,201 @@ class Context:
|
|
|
385
394
|
@classmethod
|
|
386
395
|
def from_json(cls, data: Dict[str, Any]) -> "Context":
|
|
387
396
|
return cls(id=str(data.get("id") or data.get("context_id") or ""))
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
class StreamHandle:
|
|
400
|
+
"""Handle for managing a streaming operation (sync version).
|
|
401
|
+
|
|
402
|
+
Can be used as a context manager for automatic cleanup:
|
|
403
|
+
|
|
404
|
+
with sandbox.process.stream_logs(name, options) as handle:
|
|
405
|
+
# do something
|
|
406
|
+
# handle is automatically closed
|
|
407
|
+
|
|
408
|
+
Or used manually:
|
|
409
|
+
|
|
410
|
+
handle = sandbox.process.stream_logs(name, options)
|
|
411
|
+
try:
|
|
412
|
+
# do something
|
|
413
|
+
finally:
|
|
414
|
+
handle.close()
|
|
415
|
+
"""
|
|
416
|
+
|
|
417
|
+
def __init__(self, close_func: Callable[[], None]):
|
|
418
|
+
self._close_func = close_func
|
|
419
|
+
self._closed = False
|
|
420
|
+
|
|
421
|
+
def close(self) -> None:
|
|
422
|
+
"""Close the stream and stop receiving data."""
|
|
423
|
+
if not self._closed:
|
|
424
|
+
self._close_func()
|
|
425
|
+
self._closed = True
|
|
426
|
+
|
|
427
|
+
@property
|
|
428
|
+
def closed(self) -> bool:
|
|
429
|
+
"""Returns True if the stream handle has been closed."""
|
|
430
|
+
return self._closed
|
|
431
|
+
|
|
432
|
+
def __enter__(self) -> "StreamHandle":
|
|
433
|
+
return self
|
|
434
|
+
|
|
435
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
436
|
+
self.close()
|
|
437
|
+
|
|
438
|
+
# Backward compatibility: support dict-like access
|
|
439
|
+
def __getitem__(self, key: str) -> Callable[[], None]:
|
|
440
|
+
if key == "close":
|
|
441
|
+
return self.close
|
|
442
|
+
raise KeyError(key)
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
class AsyncStreamHandle:
|
|
446
|
+
"""Handle for managing a streaming operation (async version).
|
|
447
|
+
|
|
448
|
+
Can be used as an async context manager for automatic cleanup:
|
|
449
|
+
|
|
450
|
+
async with sandbox.process.stream_logs(name, options) as handle:
|
|
451
|
+
# do something
|
|
452
|
+
# handle is automatically closed
|
|
453
|
+
|
|
454
|
+
Or used manually:
|
|
455
|
+
|
|
456
|
+
handle = sandbox.process.stream_logs(name, options)
|
|
457
|
+
try:
|
|
458
|
+
# do something
|
|
459
|
+
finally:
|
|
460
|
+
handle.close()
|
|
461
|
+
"""
|
|
462
|
+
|
|
463
|
+
def __init__(self, close_func: Callable[[], None]):
|
|
464
|
+
self._close_func = close_func
|
|
465
|
+
self._closed = False
|
|
466
|
+
|
|
467
|
+
def close(self) -> None:
|
|
468
|
+
"""Close the stream and stop receiving data."""
|
|
469
|
+
if not self._closed:
|
|
470
|
+
self._close_func()
|
|
471
|
+
self._closed = True
|
|
472
|
+
|
|
473
|
+
@property
|
|
474
|
+
def closed(self) -> bool:
|
|
475
|
+
"""Returns True if the stream handle has been closed."""
|
|
476
|
+
return self._closed
|
|
477
|
+
|
|
478
|
+
async def __aenter__(self) -> "AsyncStreamHandle":
|
|
479
|
+
return self
|
|
480
|
+
|
|
481
|
+
async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
482
|
+
self.close()
|
|
483
|
+
|
|
484
|
+
# Also support sync context manager for convenience
|
|
485
|
+
def __enter__(self) -> "AsyncStreamHandle":
|
|
486
|
+
return self
|
|
487
|
+
|
|
488
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
489
|
+
self.close()
|
|
490
|
+
|
|
491
|
+
# Backward compatibility: support dict-like access
|
|
492
|
+
def __getitem__(self, key: str) -> Callable[[], None]:
|
|
493
|
+
if key == "close":
|
|
494
|
+
return self.close
|
|
495
|
+
raise KeyError(key)
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
class WatchHandle:
|
|
499
|
+
"""Handle for managing a file system watch operation (sync version).
|
|
500
|
+
|
|
501
|
+
Can be used as a context manager for automatic cleanup:
|
|
502
|
+
|
|
503
|
+
with sandbox.fs.watch(path, callback) as handle:
|
|
504
|
+
# do something
|
|
505
|
+
# handle is automatically closed
|
|
506
|
+
|
|
507
|
+
Or used manually:
|
|
508
|
+
|
|
509
|
+
handle = sandbox.fs.watch(path, callback)
|
|
510
|
+
try:
|
|
511
|
+
# do something
|
|
512
|
+
finally:
|
|
513
|
+
handle.close()
|
|
514
|
+
"""
|
|
515
|
+
|
|
516
|
+
def __init__(self, close_func: Callable[[], None]):
|
|
517
|
+
self._close_func = close_func
|
|
518
|
+
self._closed = False
|
|
519
|
+
|
|
520
|
+
def close(self) -> None:
|
|
521
|
+
"""Close the watch and stop receiving events."""
|
|
522
|
+
if not self._closed:
|
|
523
|
+
self._close_func()
|
|
524
|
+
self._closed = True
|
|
525
|
+
|
|
526
|
+
@property
|
|
527
|
+
def closed(self) -> bool:
|
|
528
|
+
"""Returns True if the watch handle has been closed."""
|
|
529
|
+
return self._closed
|
|
530
|
+
|
|
531
|
+
def __enter__(self) -> "WatchHandle":
|
|
532
|
+
return self
|
|
533
|
+
|
|
534
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
535
|
+
self.close()
|
|
536
|
+
|
|
537
|
+
# Backward compatibility: support dict-like access
|
|
538
|
+
def __getitem__(self, key: str) -> Callable[[], None]:
|
|
539
|
+
if key == "close":
|
|
540
|
+
return self.close
|
|
541
|
+
raise KeyError(key)
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
class AsyncWatchHandle:
|
|
545
|
+
"""Handle for managing a file system watch operation (async version).
|
|
546
|
+
|
|
547
|
+
Can be used as an async context manager for automatic cleanup:
|
|
548
|
+
|
|
549
|
+
async with sandbox.fs.watch(path, callback) as handle:
|
|
550
|
+
# do something
|
|
551
|
+
# handle is automatically closed
|
|
552
|
+
|
|
553
|
+
Or used manually:
|
|
554
|
+
|
|
555
|
+
handle = sandbox.fs.watch(path, callback)
|
|
556
|
+
try:
|
|
557
|
+
# do something
|
|
558
|
+
finally:
|
|
559
|
+
handle.close()
|
|
560
|
+
"""
|
|
561
|
+
|
|
562
|
+
def __init__(self, close_func: Callable[[], None]):
|
|
563
|
+
self._close_func = close_func
|
|
564
|
+
self._closed = False
|
|
565
|
+
|
|
566
|
+
def close(self) -> None:
|
|
567
|
+
"""Close the watch and stop receiving events."""
|
|
568
|
+
if not self._closed:
|
|
569
|
+
self._close_func()
|
|
570
|
+
self._closed = True
|
|
571
|
+
|
|
572
|
+
@property
|
|
573
|
+
def closed(self) -> bool:
|
|
574
|
+
"""Returns True if the watch handle has been closed."""
|
|
575
|
+
return self._closed
|
|
576
|
+
|
|
577
|
+
async def __aenter__(self) -> "AsyncWatchHandle":
|
|
578
|
+
return self
|
|
579
|
+
|
|
580
|
+
async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
581
|
+
self.close()
|
|
582
|
+
|
|
583
|
+
# Also support sync context manager for convenience
|
|
584
|
+
def __enter__(self) -> "AsyncWatchHandle":
|
|
585
|
+
return self
|
|
586
|
+
|
|
587
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
588
|
+
self.close()
|
|
589
|
+
|
|
590
|
+
# Backward compatibility: support dict-like access
|
|
591
|
+
def __getitem__(self, key: str) -> Callable[[], None]:
|
|
592
|
+
if key == "close":
|
|
593
|
+
return self.close
|
|
594
|
+
raise KeyError(key)
|
blaxel/core/volume/volume.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import time
|
|
1
3
|
import uuid
|
|
2
4
|
from typing import Callable, Dict, List, Union
|
|
3
5
|
|
|
@@ -500,6 +502,8 @@ async def _update_volume_by_name(
|
|
|
500
502
|
status_code = int(response.code) if response.code is not UNSET else None
|
|
501
503
|
message = response.message if response.message is not UNSET else response.error
|
|
502
504
|
raise VolumeAPIError(message, status_code=status_code, code=response.error)
|
|
505
|
+
# This is for safe update
|
|
506
|
+
await asyncio.sleep(0.5)
|
|
503
507
|
return VolumeInstance(response)
|
|
504
508
|
|
|
505
509
|
|
|
@@ -576,6 +580,8 @@ def _update_volume_by_name_sync(
|
|
|
576
580
|
status_code = int(response.code) if response.code is not UNSET else None
|
|
577
581
|
message = response.message if response.message is not UNSET else response.error
|
|
578
582
|
raise VolumeAPIError(message, status_code=status_code, code=response.error)
|
|
583
|
+
# This is for safe update
|
|
584
|
+
time.sleep(0.5)
|
|
579
585
|
return SyncVolumeInstance(response)
|
|
580
586
|
|
|
581
587
|
|
blaxel/langgraph/tools.py
CHANGED