withruntime 0.8.3__tar.gz → 0.9.0__tar.gz
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.
- {withruntime-0.8.3/withruntime.egg-info → withruntime-0.9.0}/PKG-INFO +10 -5
- {withruntime-0.8.3 → withruntime-0.9.0}/README.md +7 -4
- {withruntime-0.8.3 → withruntime-0.9.0}/pyproject.toml +3 -1
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_client.py +43 -14
- withruntime-0.9.0/tests/test_compat_live.py +101 -0
- withruntime-0.9.0/tests/test_compat_new_providers.py +607 -0
- withruntime-0.9.0/tests/test_compat_python_disk_snapshots.py +159 -0
- withruntime-0.9.0/tests/test_compat_python_e2b_deadline.py +146 -0
- withruntime-0.9.0/tests/test_compat_python_e2b_pty.py +172 -0
- withruntime-0.9.0/tests/test_compat_python_e2b_stream.py +126 -0
- withruntime-0.9.0/tests/test_compat_python_e2b_watch.py +66 -0
- withruntime-0.9.0/tests/test_compat_python_interpreter_deadline.py +110 -0
- withruntime-0.9.0/tests/test_compat_python_modal.py +116 -0
- withruntime-0.9.0/tests/test_compat_python_official.py +668 -0
- withruntime-0.9.0/tests/test_compat_python_pins.py +63 -0
- withruntime-0.9.0/tests/test_compat_python_processes.py +274 -0
- withruntime-0.9.0/tests/test_compat_python_request_scope.py +179 -0
- withruntime-0.9.0/tests/test_compat_python_runloop.py +146 -0
- withruntime-0.9.0/tests/test_compat_python_shell.py +61 -0
- withruntime-0.9.0/tests/test_compat_python_snapshot_capture.py +86 -0
- withruntime-0.9.0/tests/test_compat_python_sprites.py +65 -0
- withruntime-0.9.0/tests/test_compat_router.py +133 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_e2b_code_interpreter.py +21 -13
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_e2b_sandbox.py +30 -8
- withruntime-0.9.0/tests/test_e2b_watch.py +103 -0
- withruntime-0.9.0/tests/test_embed_and_webhook_watch.py +57 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_files_upload_parallel.py +8 -0
- withruntime-0.9.0/tests/test_interface_contract.py +81 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_jobs.py +1 -1
- withruntime-0.9.0/tests/test_process_deadline.py +269 -0
- withruntime-0.9.0/tests/test_process_input.py +50 -0
- withruntime-0.9.0/tests/test_process_output.py +50 -0
- withruntime-0.9.0/tests/test_sandbox_origin.py +53 -0
- withruntime-0.9.0/tests/test_start_report_kept.py +43 -0
- withruntime-0.9.0/tests/test_switch_image.py +74 -0
- withruntime-0.9.0/tests/test_tailscale.py +80 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_unpack.py +37 -0
- withruntime-0.9.0/withruntime/_api_defaults.py +21 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_client.py +250 -80
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/__init__.py +2 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/interpreter.py +40 -23
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/jobs.py +5 -4
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/limits.py +6 -3
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/previews.py +10 -3
- withruntime-0.9.0/withruntime/_async_products/tailscale.py +37 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/watch.py +9 -2
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_clock.py +31 -2
- withruntime-0.9.0/withruntime/_compat.py +100 -0
- withruntime-0.9.0/withruntime/_compat_lifecycle.py +24 -0
- withruntime-0.9.0/withruntime/_compat_shell.py +166 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_errors.py +8 -3
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_eval_sandbox.py +3 -1
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_http.py +237 -15
- withruntime-0.9.0/withruntime/_request_scope.py +84 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_client.py +250 -80
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/__init__.py +2 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/interpreter.py +40 -23
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/jobs.py +5 -4
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/limits.py +6 -3
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/previews.py +10 -3
- withruntime-0.9.0/withruntime/_sync_products/tailscale.py +38 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/watch.py +9 -2
- withruntime-0.9.0/withruntime/_unpack.py +265 -0
- withruntime-0.9.0/withruntime/_version.py +1 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/_core.py +2 -1
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/deepagents.py +2 -1
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/e2b/__init__.py +10 -6
- withruntime-0.9.0/withruntime/e2b/_async_io.py +310 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/e2b/_async_sandbox.py +176 -74
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/e2b/_core.py +63 -13
- withruntime-0.9.0/withruntime/e2b/_sync_io.py +245 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/e2b/_sync_sandbox.py +164 -79
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/e2b/code_interpreter/_async_ci.py +18 -37
- withruntime-0.9.0/withruntime/e2b/code_interpreter/_models.py +156 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/e2b/code_interpreter/_sync_ci.py +18 -37
- withruntime-0.9.0/withruntime/e2b/code_interpreter/charts.py +120 -0
- withruntime-0.9.0/withruntime/e2b/sandbox/__init__.py +1 -0
- withruntime-0.9.0/withruntime/e2b/sandbox/commands/__init__.py +2 -0
- withruntime-0.9.0/withruntime/e2b/sandbox/commands/command_handle.py +5 -0
- withruntime-0.9.0/withruntime/e2b/sandbox/filesystem/__init__.py +2 -0
- withruntime-0.9.0/withruntime/e2b/sandbox/filesystem/filesystem.py +4 -0
- withruntime-0.9.0/withruntime/e2b/sandbox_async/__init__.py +2 -0
- withruntime-0.9.0/withruntime/e2b/sandbox_async/commands/__init__.py +4 -0
- withruntime-0.9.0/withruntime/e2b/sandbox_async/commands/command.py +2 -0
- withruntime-0.9.0/withruntime/e2b/sandbox_async/commands/command_handle.py +6 -0
- withruntime-0.9.0/withruntime/e2b/sandbox_async/commands/pty.py +3 -0
- withruntime-0.9.0/withruntime/e2b/sandbox_async/filesystem/__init__.py +2 -0
- withruntime-0.9.0/withruntime/e2b/sandbox_async/filesystem/filesystem.py +4 -0
- withruntime-0.9.0/withruntime/e2b/sandbox_sync/__init__.py +2 -0
- withruntime-0.9.0/withruntime/e2b/sandbox_sync/commands/__init__.py +4 -0
- withruntime-0.9.0/withruntime/e2b/sandbox_sync/commands/command.py +2 -0
- withruntime-0.9.0/withruntime/e2b/sandbox_sync/commands/command_handle.py +6 -0
- withruntime-0.9.0/withruntime/e2b/sandbox_sync/commands/pty.py +3 -0
- withruntime-0.9.0/withruntime/e2b/sandbox_sync/filesystem/__init__.py +2 -0
- withruntime-0.9.0/withruntime/e2b/sandbox_sync/filesystem/filesystem.py +4 -0
- withruntime-0.9.0/withruntime/modal/__init__.py +373 -0
- withruntime-0.9.0/withruntime/modal/_async.py +306 -0
- withruntime-0.9.0/withruntime/modal/_dual.py +25 -0
- withruntime-0.9.0/withruntime/modal/_fs_async.py +118 -0
- withruntime-0.9.0/withruntime/modal/_fs_common.py +39 -0
- withruntime-0.9.0/withruntime/modal/_fs_sync.py +118 -0
- withruntime-0.9.0/withruntime/modal/_lookup.py +23 -0
- withruntime-0.9.0/withruntime/modal/_snapshot.py +33 -0
- withruntime-0.9.0/withruntime/modal/exception.py +52 -0
- withruntime-0.9.0/withruntime/modal/sandbox_fs.py +46 -0
- withruntime-0.9.0/withruntime/modal/types.py +37 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/openai_agents.py +2 -1
- withruntime-0.9.0/withruntime/prime/__init__.py +67 -0
- withruntime-0.9.0/withruntime/prime/_async.py +298 -0
- withruntime-0.9.0/withruntime/prime/_sync.py +298 -0
- withruntime-0.9.0/withruntime/prime/core/__init__.py +4 -0
- withruntime-0.9.0/withruntime/prime/core/client.py +4 -0
- withruntime-0.9.0/withruntime/prime/exceptions.py +97 -0
- withruntime-0.9.0/withruntime/prime/models.py +269 -0
- withruntime-0.9.0/withruntime/prime/process.py +154 -0
- withruntime-0.9.0/withruntime/prime/sandbox.py +3 -0
- withruntime-0.9.0/withruntime/runloop/__init__.py +6 -0
- withruntime-0.9.0/withruntime/runloop/_async.py +643 -0
- withruntime-0.9.0/withruntime/runloop/_exceptions.py +2 -0
- withruntime-0.9.0/withruntime/runloop/_snapshots.py +48 -0
- withruntime-0.9.0/withruntime/runloop/_sync.py +643 -0
- withruntime-0.9.0/withruntime/runloop/lib/__init__.py +1 -0
- withruntime-0.9.0/withruntime/runloop/lib/polling.py +15 -0
- withruntime-0.9.0/withruntime/runloop/sdk/__init__.py +3 -0
- withruntime-0.9.0/withruntime/sprites/__init__.py +298 -0
- withruntime-0.9.0/withruntime/sprites/_capture.py +56 -0
- withruntime-0.9.0/withruntime/sprites/_capture_async.py +56 -0
- withruntime-0.9.0/withruntime/sprites/_metadata.py +64 -0
- withruntime-0.9.0/withruntime/sprites/_stream.py +68 -0
- withruntime-0.9.0/withruntime/sprites/_stream_async.py +67 -0
- withruntime-0.9.0/withruntime/sprites/async_client.py +217 -0
- withruntime-0.9.0/withruntime/sprites/async_exec.py +50 -0
- withruntime-0.9.0/withruntime/sprites/client.py +2 -0
- withruntime-0.9.0/withruntime/sprites/exceptions.py +25 -0
- withruntime-0.9.0/withruntime/sprites/exec.py +80 -0
- withruntime-0.9.0/withruntime/sprites/filesystem.py +2 -0
- withruntime-0.9.0/withruntime/sprites/sprite.py +2 -0
- withruntime-0.9.0/withruntime/sprites/types.py +36 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/tools.py +2 -1
- {withruntime-0.8.3 → withruntime-0.9.0/withruntime.egg-info}/PKG-INFO +10 -5
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime.egg-info/SOURCES.txt +97 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime.egg-info/requires.txt +3 -0
- withruntime-0.8.3/withruntime/_unpack.py +0 -99
- withruntime-0.8.3/withruntime/_version.py +0 -1
- withruntime-0.8.3/withruntime/e2b/_async_io.py +0 -68
- withruntime-0.8.3/withruntime/e2b/_sync_io.py +0 -46
- withruntime-0.8.3/withruntime/e2b/code_interpreter/_models.py +0 -101
- {withruntime-0.8.3 → withruntime-0.9.0}/LICENSE +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/setup.cfg +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_account_errors.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_async_stream_cleanup.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_audit.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_billing.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_blaxel.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_capacity_wait.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_daytona.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_deepagents.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_eval_sandbox.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_exec_stream.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_files_download.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_files_mode.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_harbor.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_http_tls_close.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_identity_token.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_images_v2.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_images_volumes_interpreter.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_inspect_ai.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_late_answer.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_lifecycle_settings.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_limits.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_mounts.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_network_funding.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_network_products.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_observability.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_openai_agents.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_previews_network_desktop.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_proxy.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_referrals.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_sandbox_sessions.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_secrets.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_snapshot_after_fork.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_sso.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_stream_exit_close.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_switching.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_tools.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_vercel.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_volume_backups.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_wake_awake.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_wallet.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/tests/test_watch.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/__init__.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/audit.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/billing.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/desktop.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/images.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/mcp.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/mounts.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/network.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/network_products.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/observability.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/referrals.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/secrets.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/sso.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/switching.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_async_products/volumes.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_connection.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_proxy.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/audit.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/billing.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/desktop.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/images.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/mcp.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/mounts.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/network.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/network_products.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/observability.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/referrals.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/secrets.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/sso.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/switching.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_sync_products/volumes.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_tunnel.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/_ws.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/__init__.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/_async_io.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/_async_sandbox.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/_sync_io.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/_sync_sandbox.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/__init__.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/agents.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/__init__.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/api/__init__.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/api/applications/__init__.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/api/applications/list_application_revisions.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/api/compute/__init__.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/api/compute/get_sandbox.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/api/compute/update_sandbox.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/api/functions/__init__.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/api/functions/create_function.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/api/images.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/api/workspaces.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/client.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/models/__init__.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/models/create_job_execution_request.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/models/create_job_execution_request_env.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/models/env.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/models/function.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/models/function_runtime.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/models/function_spec.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/models/metadata.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/models/workspace.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/client/types.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/common.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/drive.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/jobs.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/sandbox/__init__.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/core/sandbox/types.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/crewai.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/googleadk.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/langgraph.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/livekit.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/llamaindex.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/openai.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/pydantic.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/blaxel/telemetry.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/daytona/__init__.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/daytona/_async_daytona.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/daytona/_async_io.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/daytona/_core.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/daytona/_sync_daytona.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/daytona/_sync_io.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/e2b/code_interpreter/__init__.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/harbor.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/inspect_ai.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/vercel/__init__.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/vercel/_async_io.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/vercel/_async_sandbox.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/vercel/_core.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/vercel/_sync_io.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/vercel/_sync_sandbox.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/vercel/api.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/vercel/sandbox/__init__.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/vercel/sandbox/sync.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/wallet.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime/webhooks.py +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime.egg-info/dependency_links.txt +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime.egg-info/entry_points.txt +0 -0
- {withruntime-0.8.3 → withruntime-0.9.0}/withruntime.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: withruntime
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
4
4
|
Summary: Runtime Cloud: one client (sync and async) for every Runtime product. Sandboxes first.
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Project-URL: Homepage, https://withruntime.com
|
|
@@ -11,6 +11,8 @@ Keywords: sandbox,ai-agents,agents,microvm,firecracker,code-execution,code-inter
|
|
|
11
11
|
Requires-Python: >=3.10
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
+
Provides-Extra: e2b
|
|
15
|
+
Requires-Dist: httpx<1.0.0,>=0.27.0; extra == "e2b"
|
|
14
16
|
Provides-Extra: openai-agents
|
|
15
17
|
Requires-Dist: openai-agents>=0.22.3; extra == "openai-agents"
|
|
16
18
|
Provides-Extra: deepagents
|
|
@@ -70,15 +72,18 @@ asyncio.run(main())
|
|
|
70
72
|
A sandbox has `exec`, `exec_stream`, `spawn`, `terminal`, `forward_port` (any
|
|
71
73
|
TCP port in the sandbox on a local port), `files` (read, write,
|
|
72
74
|
list, glob, stat, move, remove, upload and download directories), `pause`,
|
|
73
|
-
`wake`, `extend`, `update
|
|
75
|
+
`wake`, `extend`, `update` (its name, environment and settings), `keep_alive`,
|
|
76
|
+
`fork`, `snapshot`, `switch_image` (move it to a new image keeping /workspace)
|
|
77
|
+
and `delete` (remove it for good), and the
|
|
74
78
|
`interpreter`, `network`, `previews`, `desktop`, `mounts` (your S3, R2 or Google
|
|
75
|
-
Cloud Storage bucket as a folder), `
|
|
76
|
-
|
|
79
|
+
Cloud Storage bucket as a folder), `tailscale` (a paid sandbox on your own
|
|
80
|
+
tailnet), `metrics` and `mcp` (servers from the MCP catalog, run in the
|
|
81
|
+
sandbox) products. A paused sandbox
|
|
77
82
|
also wakes by itself on the next call, and `Sandbox.get_or_create(name)` returns
|
|
78
83
|
the sandbox with that name or creates it. A sandbox pauses itself after 60 seconds
|
|
79
84
|
with nothing happening in it, keeping its memory and processes, so an
|
|
80
85
|
idle sandbox costs no compute; `idle_pause_seconds` sets 10 to 86,400, or 0 for
|
|
81
|
-
never. The client has `sandboxes`, `images`, `volumes`, `snapshots`,
|
|
86
|
+
never. The client has `sandboxes`, `images`, `volumes`, `snapshots`, `jobs`,
|
|
82
87
|
`secrets`, `limits`, `feedback` and `support`; `webhooks`, `events`, `otel` and
|
|
83
88
|
`audit` to watch the account; `domains`, `ports`, `addresses`, `tunnel` and
|
|
84
89
|
`network` to connect sandboxes to your own world (paid accounts); and `mcp`,
|
|
@@ -47,15 +47,18 @@ asyncio.run(main())
|
|
|
47
47
|
A sandbox has `exec`, `exec_stream`, `spawn`, `terminal`, `forward_port` (any
|
|
48
48
|
TCP port in the sandbox on a local port), `files` (read, write,
|
|
49
49
|
list, glob, stat, move, remove, upload and download directories), `pause`,
|
|
50
|
-
`wake`, `extend`, `update
|
|
50
|
+
`wake`, `extend`, `update` (its name, environment and settings), `keep_alive`,
|
|
51
|
+
`fork`, `snapshot`, `switch_image` (move it to a new image keeping /workspace)
|
|
52
|
+
and `delete` (remove it for good), and the
|
|
51
53
|
`interpreter`, `network`, `previews`, `desktop`, `mounts` (your S3, R2 or Google
|
|
52
|
-
Cloud Storage bucket as a folder), `
|
|
53
|
-
|
|
54
|
+
Cloud Storage bucket as a folder), `tailscale` (a paid sandbox on your own
|
|
55
|
+
tailnet), `metrics` and `mcp` (servers from the MCP catalog, run in the
|
|
56
|
+
sandbox) products. A paused sandbox
|
|
54
57
|
also wakes by itself on the next call, and `Sandbox.get_or_create(name)` returns
|
|
55
58
|
the sandbox with that name or creates it. A sandbox pauses itself after 60 seconds
|
|
56
59
|
with nothing happening in it, keeping its memory and processes, so an
|
|
57
60
|
idle sandbox costs no compute; `idle_pause_seconds` sets 10 to 86,400, or 0 for
|
|
58
|
-
never. The client has `sandboxes`, `images`, `volumes`, `snapshots`,
|
|
61
|
+
never. The client has `sandboxes`, `images`, `volumes`, `snapshots`, `jobs`,
|
|
59
62
|
`secrets`, `limits`, `feedback` and `support`; `webhooks`, `events`, `otel` and
|
|
60
63
|
`audit` to watch the account; `domains`, `ports`, `addresses`, `tunnel` and
|
|
61
64
|
`network` to connect sandboxes to your own world (paid accounts); and `mcp`,
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "withruntime"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.9.0"
|
|
8
8
|
description = "Runtime Cloud: one client (sync and async) for every Runtime product. Sandboxes first."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "Apache-2.0" }
|
|
@@ -19,6 +19,8 @@ Source = "https://github.com/withruntime/runtime/tree/main/sdks/python"
|
|
|
19
19
|
Issues = "https://github.com/withruntime/runtime/issues"
|
|
20
20
|
|
|
21
21
|
[project.optional-dependencies]
|
|
22
|
+
# Preserve E2B's HTTP file-transfer timeout exception types.
|
|
23
|
+
e2b = ["httpx>=0.27.0,<1.0.0"]
|
|
22
24
|
# withruntime.openai_agents: a sandbox client for the OpenAI Agents SDK's SandboxAgent.
|
|
23
25
|
openai-agents = ["openai-agents>=0.22.3"]
|
|
24
26
|
# withruntime.deepagents: a LangChain Deep Agents sandbox backend.
|
|
@@ -8,6 +8,7 @@ import asyncio
|
|
|
8
8
|
import inspect
|
|
9
9
|
import json
|
|
10
10
|
import os
|
|
11
|
+
import shutil
|
|
11
12
|
import subprocess
|
|
12
13
|
import sys
|
|
13
14
|
import tempfile
|
|
@@ -98,17 +99,19 @@ class Sync(unittest.TestCase):
|
|
|
98
99
|
self.assertEqual([s.id for s in page], [ID])
|
|
99
100
|
self.assertFalse(page.has_more)
|
|
100
101
|
|
|
101
|
-
def
|
|
102
|
-
# The
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
def test_a_folder_goes_in_and_comes_back_through_the_folder_routes(self):
|
|
103
|
+
# The fixture runs the real tar behind the API's folder routes: the
|
|
104
|
+
# upload is unpacked by the sandbox, the download packed by it.
|
|
105
|
+
sbx = client().sandboxes.get(ID)
|
|
106
|
+
noise = os.urandom(1_500_000) # past 1 MiB compressed: sent in parts
|
|
105
107
|
with tempfile.TemporaryDirectory() as root:
|
|
106
|
-
Path(root, "src").mkdir()
|
|
107
|
-
Path(root, "src", "a.py").write_text("print(1)\n")
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
self.
|
|
108
|
+
Path(root, "up", "src").mkdir(parents=True)
|
|
109
|
+
Path(root, "up", "src", "a.py").write_text("print(1)\n")
|
|
110
|
+
Path(root, "up", "noise.bin").write_bytes(noise)
|
|
111
|
+
sbx.files.upload(str(Path(root, "up")), "/workspace/roundtrip")
|
|
112
|
+
sbx.files.download("/workspace/roundtrip", str(Path(root, "down")))
|
|
113
|
+
self.assertEqual(Path(root, "down", "src", "a.py").read_text(), "print(1)\n")
|
|
114
|
+
self.assertEqual(Path(root, "down", "noise.bin").read_bytes(), noise)
|
|
112
115
|
|
|
113
116
|
def test_terminal_over_websocket(self):
|
|
114
117
|
sbx = client().sandboxes.get(ID)
|
|
@@ -329,13 +332,39 @@ class Parity(unittest.TestCase):
|
|
|
329
332
|
self.assertEqual(sync_methods, {m for m in async_methods if m in sync_methods | async_methods} & sync_methods | sync_methods)
|
|
330
333
|
self.assertEqual(sorted(m for m in async_methods if not m.startswith("_")), sorted(sync_methods), name)
|
|
331
334
|
|
|
335
|
+
def test_import_leaves_heavy_modules_unloaded(self):
|
|
336
|
+
# asyncio is a third of the import budget and dataclasses brings inspect and
|
|
337
|
+
# tokenize: only the call that needs one should pay for it.
|
|
338
|
+
root = Path(__file__).resolve().parent.parent
|
|
339
|
+
loaded = subprocess.run([sys.executable, "-c", "import sys, withruntime; print(sorted(m for m in ('asyncio', 'concurrent.futures', 'dataclasses', 'inspect') if m in sys.modules))"],
|
|
340
|
+
env={**os.environ, "PYTHONPATH": str(root)}, capture_output=True, text=True, check=True, timeout=10)
|
|
341
|
+
self.assertEqual(loaded.stdout.strip(), "[]")
|
|
342
|
+
|
|
343
|
+
@unittest.skipUnless(shutil.which("python3.10"), "python3.10 is not on PATH")
|
|
344
|
+
def test_the_oldest_supported_python_compiles_every_module(self):
|
|
345
|
+
# pyproject says 3.10; the suite runs on the newest python3, whose grammar
|
|
346
|
+
# accepts what 3.10 refuses (withruntime.blaxel did not import on 3.10 or 3.11).
|
|
347
|
+
package = Path(__file__).resolve().parent.parent / "withruntime"
|
|
348
|
+
code = ("import pathlib, sys\n"
|
|
349
|
+
"for path in sorted(pathlib.Path(sys.argv[1]).rglob('*.py')):\n"
|
|
350
|
+
" compile(path.read_text(encoding='utf-8'), str(path), 'exec')\n")
|
|
351
|
+
result = subprocess.run([shutil.which("python3.10"), "-c", code, str(package)],
|
|
352
|
+
capture_output=True, text=True, timeout=60)
|
|
353
|
+
self.assertEqual(result.returncode, 0, result.stderr)
|
|
354
|
+
|
|
355
|
+
@unittest.skipIf(os.environ.get("RUNTIME_IMPORT_AFTER") == "1", "run after all SDK language suites finish")
|
|
332
356
|
def test_import_is_cheap(self):
|
|
357
|
+
from statistics import median
|
|
333
358
|
code = "import time; t=time.perf_counter(); import withruntime; print((time.perf_counter()-t)*1000)"
|
|
334
359
|
root = Path(__file__).resolve().parent.parent
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
360
|
+
env = {**os.environ, "PYTHONPATH": str(root)}
|
|
361
|
+
subprocess.run([sys.executable, "-c", "import withruntime"], env=env, check=True, timeout=10)
|
|
362
|
+
# Fresh interpreters measure import work; the median prevents one scheduler
|
|
363
|
+
# interruption from deciding the budget without hiding sustained regressions.
|
|
364
|
+
samples = [float(subprocess.run([sys.executable, "-c", code], env=env,
|
|
365
|
+
capture_output=True, text=True, check=True, timeout=10).stdout)
|
|
366
|
+
for _ in range(5)]
|
|
367
|
+
self.assertLess(median(samples), 60, f"import samples (ms): {samples}")
|
|
339
368
|
|
|
340
369
|
|
|
341
370
|
@unittest.skipUnless(URL, "needs the fixture")
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Opt-in trial-only Python adapter acceptance, never part of routine CI.
|
|
2
|
+
|
|
3
|
+
RUNTIME_COMPAT_LIVE=1 PYTHONPATH=sdks/python python3 -m unittest discover \
|
|
4
|
+
-s sdks/python/tests -p test_compat_live.py
|
|
5
|
+
|
|
6
|
+
Creates exactly one explicitly trial-funded native sandbox for at most 120 seconds.
|
|
7
|
+
No image builds, persistent sandboxes, paid fallback, competitor calls, or existing
|
|
8
|
+
customer resources. This proves commands/files/streams/reconnection, not each
|
|
9
|
+
provider's create policy or image equivalence. Always stops the owned sandbox.
|
|
10
|
+
"""
|
|
11
|
+
import asyncio
|
|
12
|
+
import hashlib
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import unittest
|
|
16
|
+
import uuid
|
|
17
|
+
from withruntime import Runtime, AsyncRuntime
|
|
18
|
+
from withruntime._compat import ENV_PATH
|
|
19
|
+
from withruntime.runloop import RunloopSDK, Runloop, AsyncRunloop
|
|
20
|
+
from withruntime.prime import SandboxClient, AsyncSandboxClient
|
|
21
|
+
from withruntime.sprites import SpritesClient, AsyncSpritesClient
|
|
22
|
+
from withruntime.modal import Sandbox
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@unittest.skipUnless(os.environ.get("RUNTIME_COMPAT_LIVE") == "1", "Opt-in live trial acceptance only")
|
|
26
|
+
class LiveTrial(unittest.TestCase):
|
|
27
|
+
def test_existing_sandbox_consumers(self):
|
|
28
|
+
api_key = os.environ.get("RUNTIME_API_KEY", "")
|
|
29
|
+
if not api_key.startswith("rtcloud_"):
|
|
30
|
+
raise ValueError("An explicit Runtime test API key is required; login fallback is disabled")
|
|
31
|
+
runtime = Runtime(api_key=api_key, wait_for_capacity=0)
|
|
32
|
+
usage = runtime.usage()
|
|
33
|
+
if (usage.get("trial") or {}).get("availableMs", 0) < 3_600_000:
|
|
34
|
+
runtime.close()
|
|
35
|
+
raise ValueError("At least one trial hour is required; no paid fallback")
|
|
36
|
+
name = "compat-python-" + uuid.uuid4().hex[:12]
|
|
37
|
+
sb = runtime.sandboxes.create(name=name, funding="trial", timeout_seconds=120,
|
|
38
|
+
idle_pause_seconds=0, on_lease_end="stop", labels={"compat.provider": "sprites"})
|
|
39
|
+
owned_id = sb.id
|
|
40
|
+
try:
|
|
41
|
+
self.assertEqual(sb.info.get("funding"), "trial", "Created sandbox must be trial-funded")
|
|
42
|
+
sb.files.write(ENV_PATH, json.dumps({"COMPAT_ENV": "persisted"}), mode=0o600)
|
|
43
|
+
runloop = RunloopSDK(runtime=runtime).devbox.from_id(sb.id)
|
|
44
|
+
result = runloop.cmd.exec("printf '%s' \"$COMPAT_ENV\"")
|
|
45
|
+
self.assertEqual((result.exit_code, result.stdout()), (0, "persisted"))
|
|
46
|
+
shell = runloop.shell("live-session")
|
|
47
|
+
shell.exec("mkdir -p /workspace/named && cd /workspace/named && export HELLO=world")
|
|
48
|
+
self.assertEqual(shell.exec('printf "%s:%s" "$PWD" "$HELLO"').stdout(), "/workspace/named:world")
|
|
49
|
+
reconnected = RunloopSDK(runtime=runtime).devbox.from_id(sb.id).shell("live-session")
|
|
50
|
+
self.assertEqual(reconnected.exec('printf "%s" "$HELLO"').stdout(), "world")
|
|
51
|
+
low = Runloop(runtime=runtime)
|
|
52
|
+
self.assertEqual(low.devboxes.execute_sync(sb.id, command="exit 7").exit_status, 7)
|
|
53
|
+
data = bytes(range(256)) * 4097
|
|
54
|
+
runloop.file.upload(path="/workspace/roundtrip", file=data)
|
|
55
|
+
self.assertEqual(hashlib.sha256(runloop.file.download(path="/workspace/roundtrip")).digest(), hashlib.sha256(data).digest())
|
|
56
|
+
prime = SandboxClient(runtime)
|
|
57
|
+
self.assertEqual(prime.execute_command(sb.id, 'printf "%s" "$COMPAT_ENV"').stdout, "persisted")
|
|
58
|
+
self.assertEqual(prime.execute_command(sb.id, "python3 -c 'print(\"x\"*100000,end=\"\")'").stdout, "x" * 100000)
|
|
59
|
+
prime.upload_bytes(sb.id, "/workspace/prime-text", "こんにちは".encode(), "prime-text")
|
|
60
|
+
self.assertEqual(prime.read_file(sb.id, "/workspace/prime-text").content, "こんにちは")
|
|
61
|
+
sprite = SpritesClient(runtime=runtime).get_sprite(name)
|
|
62
|
+
self.assertEqual(sprite.id, owned_id, "Only the sandbox created by this test may be used")
|
|
63
|
+
self.assertEqual(sprite.run("printf", "%s", "literal; data", capture_output=True).stdout, b"literal; data")
|
|
64
|
+
self.assertEqual(sprite.command("printf", "hello").output(), b"hello")
|
|
65
|
+
binary = sprite.command("python3", "-c", "import sys; sys.stdout.buffer.write(bytes(range(256)))").output()
|
|
66
|
+
self.assertEqual(binary, bytes(range(256)))
|
|
67
|
+
path = sprite.filesystem("/workspace") / "sprites-binary"
|
|
68
|
+
path.write_bytes(data)
|
|
69
|
+
self.assertEqual(path.read_bytes(), data)
|
|
70
|
+
modal = Sandbox.from_id(sb.id, client=runtime)
|
|
71
|
+
process = modal.exec("bash", "-c", "printf 'out'; printf 'err' >&2; exit 3")
|
|
72
|
+
self.assertEqual((process.stdout.read(), process.stderr.read(), process.wait()), ("out", "err", 3))
|
|
73
|
+
self._async_consumers(sb.id, name)
|
|
74
|
+
finally:
|
|
75
|
+
self.assertEqual(sb.id, owned_id)
|
|
76
|
+
sb.stop()
|
|
77
|
+
runtime.close()
|
|
78
|
+
|
|
79
|
+
def _async_consumers(self, sandbox_id, name):
|
|
80
|
+
async def run():
|
|
81
|
+
runtime = AsyncRuntime(api_key=os.environ["RUNTIME_API_KEY"], wait_for_capacity=0)
|
|
82
|
+
try:
|
|
83
|
+
low = AsyncRunloop(runtime=runtime)
|
|
84
|
+
self.assertEqual((await low.devboxes.execute_sync(sandbox_id, command="printf async")).stdout, "async")
|
|
85
|
+
prime = AsyncSandboxClient(runtime=runtime)
|
|
86
|
+
self.assertEqual((await prime.execute_command(sandbox_id, "printf prime")).stdout, "prime")
|
|
87
|
+
sprite = await AsyncSpritesClient(runtime=runtime).get_sprite(name)
|
|
88
|
+
self.assertEqual(sprite.id, sandbox_id)
|
|
89
|
+
self.assertEqual(await sprite.command("printf", "sprite").output(), b"sprite")
|
|
90
|
+
binary = await sprite.command("python3", "-c", "import sys; sys.stdout.buffer.write(bytes(range(256)))").output()
|
|
91
|
+
self.assertEqual(binary, bytes(range(256)))
|
|
92
|
+
modal = await Sandbox.from_id.aio(sandbox_id, client=runtime)
|
|
93
|
+
process = await modal.exec.aio("bash", "-c", "read line; printf '%s' \"$line\"")
|
|
94
|
+
process.stdin.write(b"input\n")
|
|
95
|
+
process.stdin.write_eof()
|
|
96
|
+
await process.stdin.drain.aio()
|
|
97
|
+
self.assertEqual(await process.stdout.read.aio(), "input")
|
|
98
|
+
self.assertEqual(await process.wait.aio(), 0)
|
|
99
|
+
finally:
|
|
100
|
+
await runtime.close()
|
|
101
|
+
asyncio.run(run())
|