render 1.0.1__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.
- render/__init__.py +98 -0
- render/client/__init__.py +119 -0
- render/client/client.py +110 -0
- render/client/errors.py +39 -0
- render/client/sse.py +90 -0
- render/client/sse_sync.py +20 -0
- render/client/tests/__init__.py +0 -0
- render/client/tests/test_client.py +379 -0
- render/client/tests/test_method_parity.py +118 -0
- render/client/tests/test_render.py +52 -0
- render/client/tests/test_sse.py +67 -0
- render/client/tests/test_util.py +303 -0
- render/client/tests/test_util_sync.py +73 -0
- render/client/tests/test_workflows_sync.py +313 -0
- render/client/types.py +52 -0
- render/client/util.py +285 -0
- render/client/util_sync.py +83 -0
- render/client/workflows.py +363 -0
- render/client/workflows_sync.py +298 -0
- render/experimental/__init__.py +37 -0
- render/experimental/experimental.py +93 -0
- render/experimental/experimental_sync.py +78 -0
- render/experimental/key_value/__init__.py +33 -0
- render/experimental/key_value/api.py +243 -0
- render/experimental/key_value/compare.py +83 -0
- render/experimental/key_value/provider.py +285 -0
- render/experimental/key_value/tests/__init__.py +0 -0
- render/experimental/key_value/tests/test_api.py +371 -0
- render/experimental/key_value/tests/test_compare.py +136 -0
- render/experimental/key_value/tests/test_provider.py +1016 -0
- render/experimental/key_value/types.py +130 -0
- render/experimental/key_value/utils.py +11 -0
- render/experimental/object/__init__.py +38 -0
- render/experimental/object/api.py +250 -0
- render/experimental/object/api_sync.py +250 -0
- render/experimental/object/client.py +545 -0
- render/experimental/object/client_sync.py +547 -0
- render/experimental/object/e2e_helpers.py +78 -0
- render/experimental/object/tests/__init__.py +0 -0
- render/experimental/object/tests/test_client.py +228 -0
- render/experimental/object/tests/test_e2e.py +125 -0
- render/experimental/object/types.py +87 -0
- render/experimental/sandbox/__init__.py +31 -0
- render/experimental/sandbox/_tar.py +278 -0
- render/experimental/sandbox/api.py +518 -0
- render/experimental/sandbox/api_sync.py +514 -0
- render/experimental/sandbox/client.py +168 -0
- render/experimental/sandbox/client_sync.py +170 -0
- render/experimental/sandbox/errors.py +37 -0
- render/experimental/sandbox/files.py +378 -0
- render/experimental/sandbox/tests/__init__.py +0 -0
- render/experimental/sandbox/tests/test_client.py +802 -0
- render/experimental/sandbox/tests/test_download.py +728 -0
- render/experimental/sandbox/tests/test_e2e.py +252 -0
- render/experimental/sandbox/tests/test_tar.py +153 -0
- render/experimental/sandbox/tests/test_types.py +57 -0
- render/experimental/sandbox/types.py +46 -0
- render/public_api/__init__.py +8 -0
- render/public_api/api/__init__.py +1 -0
- render/public_api/api/artifact_sources/__init__.py +1 -0
- render/public_api/api/artifact_sources/add_or_update_artifact_source_secret_file.py +252 -0
- render/public_api/api/artifact_sources/create_artifact_source.py +243 -0
- render/public_api/api/artifact_sources/delete_artifact_source.py +188 -0
- render/public_api/api/artifact_sources/delete_artifact_source_env_var.py +223 -0
- render/public_api/api/artifact_sources/delete_artifact_source_secret_file.py +223 -0
- render/public_api/api/artifact_sources/get_artifact_source.py +185 -0
- render/public_api/api/artifact_sources/get_env_vars_for_artifact_source.py +241 -0
- render/public_api/api/artifact_sources/link_artifact_source_to_env_group.py +215 -0
- render/public_api/api/artifact_sources/list_artifact_sources.py +338 -0
- render/public_api/api/artifact_sources/list_artifacts_in_artifact_source.py +241 -0
- render/public_api/api/artifact_sources/list_secret_files_for_artifact_source.py +241 -0
- render/public_api/api/artifact_sources/retrieve_artifact_source_env_var.py +225 -0
- render/public_api/api/artifact_sources/retrieve_artifact_source_secret_file.py +225 -0
- render/public_api/api/artifact_sources/unlink_artifact_source_from_env_group.py +209 -0
- render/public_api/api/artifact_sources/update_artifact_source.py +244 -0
- render/public_api/api/artifact_sources/update_artifact_source_env_var.py +257 -0
- render/public_api/api/artifact_sources/update_env_vars_for_artifact_source.py +245 -0
- render/public_api/api/artifact_sources/update_secret_files_for_artifact_source.py +255 -0
- render/public_api/api/audit_logs/__init__.py +1 -0
- render/public_api/api/audit_logs/list_organization_audit_logs.py +303 -0
- render/public_api/api/audit_logs/list_owner_audit_logs.py +303 -0
- render/public_api/api/blueprints/__init__.py +1 -0
- render/public_api/api/blueprints/disconnect_blueprint.py +210 -0
- render/public_api/api/blueprints/list_blueprint_syncs.py +241 -0
- render/public_api/api/blueprints/list_blueprints.py +251 -0
- render/public_api/api/blueprints/retrieve_blueprint.py +200 -0
- render/public_api/api/blueprints/update_blueprint.py +222 -0
- render/public_api/api/blueprints/validate_blueprint.py +217 -0
- render/public_api/api/custom_domains/__init__.py +1 -0
- render/public_api/api/custom_domains/create_custom_domain.py +242 -0
- render/public_api/api/custom_domains/delete_custom_domain.py +216 -0
- render/public_api/api/custom_domains/list_custom_domains.py +346 -0
- render/public_api/api/custom_domains/refresh_custom_domain.py +216 -0
- render/public_api/api/custom_domains/retrieve_custom_domain.py +218 -0
- render/public_api/api/dedicated_i_ps/__init__.py +1 -0
- render/public_api/api/dedicated_i_ps/create_dedicated_ip.py +234 -0
- render/public_api/api/dedicated_i_ps/delete_dedicated_ip.py +198 -0
- render/public_api/api/dedicated_i_ps/list_dedicated_ips.py +223 -0
- render/public_api/api/dedicated_i_ps/retrieve_dedicated_ip.py +200 -0
- render/public_api/api/dedicated_i_ps/update_dedicated_ip.py +244 -0
- render/public_api/api/deploys/__init__.py +1 -0
- render/public_api/api/deploys/cancel_deploy.py +216 -0
- render/public_api/api/deploys/create_deploy.py +231 -0
- render/public_api/api/deploys/list_deploys.py +377 -0
- render/public_api/api/deploys/retrieve_deploy.py +213 -0
- render/public_api/api/deploys/rollback_deploy.py +241 -0
- render/public_api/api/disks/__init__.py +1 -0
- render/public_api/api/disks/add_disk.py +222 -0
- render/public_api/api/disks/delete_disk.py +210 -0
- render/public_api/api/disks/list_disks.py +381 -0
- render/public_api/api/disks/list_snapshots.py +214 -0
- render/public_api/api/disks/restore_snapshot.py +255 -0
- render/public_api/api/disks/retrieve_disk.py +200 -0
- render/public_api/api/disks/update_disk.py +243 -0
- render/public_api/api/environment_groups/__init__.py +1 -0
- render/public_api/api/environment_groups/create_env_group.py +199 -0
- render/public_api/api/environment_groups/delete_env_group.py +192 -0
- render/public_api/api/environment_groups/delete_env_group_env_var.py +201 -0
- render/public_api/api/environment_groups/delete_env_group_secret_file.py +201 -0
- render/public_api/api/environment_groups/link_service_to_env_group.py +211 -0
- render/public_api/api/environment_groups/list_env_groups.py +352 -0
- render/public_api/api/environment_groups/retrieve_env_group.py +190 -0
- render/public_api/api/environment_groups/retrieve_env_group_env_var.py +203 -0
- render/public_api/api/environment_groups/retrieve_env_group_secret_file.py +203 -0
- render/public_api/api/environment_groups/unlink_service_from_env_group.py +209 -0
- render/public_api/api/environment_groups/update_env_group.py +212 -0
- render/public_api/api/environment_groups/update_env_group_env_var.py +230 -0
- render/public_api/api/environment_groups/update_env_group_secret_file.py +225 -0
- render/public_api/api/events/__init__.py +1 -0
- render/public_api/api/events/retrieve_event.py +205 -0
- render/public_api/api/key_value/__init__.py +1 -0
- render/public_api/api/key_value/create_key_value.py +199 -0
- render/public_api/api/key_value/delete_key_value.py +188 -0
- render/public_api/api/key_value/list_key_value.py +380 -0
- render/public_api/api/key_value/resume_key_value.py +203 -0
- render/public_api/api/key_value/retrieve_key_value.py +190 -0
- render/public_api/api/key_value/retrieve_key_value_connection_info.py +194 -0
- render/public_api/api/key_value/suspend_key_value.py +203 -0
- render/public_api/api/key_value/update_key_value.py +221 -0
- render/public_api/api/logs/__init__.py +1 -0
- render/public_api/api/logs/delete_owner_log_stream.py +188 -0
- render/public_api/api/logs/delete_resource_log_stream.py +192 -0
- render/public_api/api/logs/get_owner_log_stream.py +205 -0
- render/public_api/api/logs/get_resource_log_stream.py +209 -0
- render/public_api/api/logs/list_logs.py +535 -0
- render/public_api/api/logs/list_logs_values.py +527 -0
- render/public_api/api/logs/list_resource_log_streams.py +317 -0
- render/public_api/api/logs/subscribe_logs.py +527 -0
- render/public_api/api/logs/update_owner_log_stream.py +231 -0
- render/public_api/api/logs/update_resource_log_stream.py +231 -0
- render/public_api/api/maintenance/__init__.py +1 -0
- render/public_api/api/maintenance/list_maintenance.py +249 -0
- render/public_api/api/maintenance/retrieve_maintenance.py +190 -0
- render/public_api/api/maintenance/trigger_maintenance.py +212 -0
- render/public_api/api/maintenance/update_maintenance.py +222 -0
- render/public_api/api/metrics/__init__.py +1 -0
- render/public_api/api/metrics/delete_owner_metrics_stream.py +172 -0
- render/public_api/api/metrics/get_active_connections.py +237 -0
- render/public_api/api/metrics/get_bandwidth.py +237 -0
- render/public_api/api/metrics/get_bandwidth_sources.py +250 -0
- render/public_api/api/metrics/get_cpu.py +287 -0
- render/public_api/api/metrics/get_cpu_limit.py +267 -0
- render/public_api/api/metrics/get_cpu_target.py +267 -0
- render/public_api/api/metrics/get_disk_capacity.py +252 -0
- render/public_api/api/metrics/get_disk_usage.py +252 -0
- render/public_api/api/metrics/get_http_latency.py +297 -0
- render/public_api/api/metrics/get_http_requests.py +302 -0
- render/public_api/api/metrics/get_instance_count.py +252 -0
- render/public_api/api/metrics/get_memory.py +267 -0
- render/public_api/api/metrics/get_memory_limit.py +267 -0
- render/public_api/api/metrics/get_memory_target.py +267 -0
- render/public_api/api/metrics/get_owner_metrics_stream.py +174 -0
- render/public_api/api/metrics/get_replication_lag.py +237 -0
- render/public_api/api/metrics/get_task_runs_completed.py +281 -0
- render/public_api/api/metrics/get_task_runs_queued.py +237 -0
- render/public_api/api/metrics/list_application_filter_values.py +254 -0
- render/public_api/api/metrics/list_http_filter_values.py +282 -0
- render/public_api/api/metrics/list_path_filter_values.py +289 -0
- render/public_api/api/metrics/upsert_owner_metrics_stream.py +192 -0
- render/public_api/api/notification_settings/__init__.py +1 -0
- render/public_api/api/notification_settings/list_notification_overrides.py +255 -0
- render/public_api/api/notification_settings/patch_owner_notification_settings.py +207 -0
- render/public_api/api/notification_settings/patch_service_notification_overrides.py +207 -0
- render/public_api/api/notification_settings/retrieve_owner_notification_settings.py +193 -0
- render/public_api/api/notification_settings/retrieve_service_notification_overrides.py +193 -0
- render/public_api/api/object_storage/__init__.py +1 -0
- render/public_api/api/object_storage/delete_object.py +215 -0
- render/public_api/api/object_storage/get_object.py +221 -0
- render/public_api/api/object_storage/list_objects.py +240 -0
- render/public_api/api/object_storage/put_object.py +248 -0
- render/public_api/api/one_off_jobs/__init__.py +1 -0
- render/public_api/api/one_off_jobs/cancel_job.py +203 -0
- render/public_api/api/one_off_jobs/list_job.py +367 -0
- render/public_api/api/one_off_jobs/post_job.py +216 -0
- render/public_api/api/one_off_jobs/retrieve_job.py +203 -0
- render/public_api/api/postgres/__init__.py +1 -0
- render/public_api/api/postgres/create_postgres.py +199 -0
- render/public_api/api/postgres/create_postgres_export.py +207 -0
- render/public_api/api/postgres/create_postgres_user.py +229 -0
- render/public_api/api/postgres/delete_postgres.py +192 -0
- render/public_api/api/postgres/delete_postgres_user.py +201 -0
- render/public_api/api/postgres/failover_postgres.py +207 -0
- render/public_api/api/postgres/list_available_postgres_parameter_overrides.py +190 -0
- render/public_api/api/postgres/list_postgres.py +418 -0
- render/public_api/api/postgres/list_postgres_export.py +199 -0
- render/public_api/api/postgres/list_postgres_parameter_overrides.py +190 -0
- render/public_api/api/postgres/list_postgres_processes.py +190 -0
- render/public_api/api/postgres/list_postgres_sizes.py +190 -0
- render/public_api/api/postgres/list_postgres_table_scans.py +190 -0
- render/public_api/api/postgres/list_postgres_top_queries.py +194 -0
- render/public_api/api/postgres/list_postgres_users.py +195 -0
- render/public_api/api/postgres/promote_postgres.py +203 -0
- render/public_api/api/postgres/recover_postgres.py +231 -0
- render/public_api/api/postgres/restart_postgres.py +203 -0
- render/public_api/api/postgres/resume_postgres.py +203 -0
- render/public_api/api/postgres/retrieve_postgres.py +190 -0
- render/public_api/api/postgres/retrieve_postgres_connection_info.py +194 -0
- render/public_api/api/postgres/retrieve_postgres_recovery_info.py +194 -0
- render/public_api/api/postgres/setup_postgres_replication.py +231 -0
- render/public_api/api/postgres/suspend_postgres.py +203 -0
- render/public_api/api/postgres/update_postgres.py +217 -0
- render/public_api/api/postgres/update_postgres_parameter_overrides.py +217 -0
- render/public_api/api/projects_environments/__init__.py +1 -0
- render/public_api/api/projects_environments/add_resources_to_environment.py +212 -0
- render/public_api/api/projects_environments/create_environment.py +199 -0
- render/public_api/api/projects_environments/create_project.py +199 -0
- render/public_api/api/projects_environments/delete_environment.py +216 -0
- render/public_api/api/projects_environments/delete_project.py +216 -0
- render/public_api/api/projects_environments/list_environments.py +369 -0
- render/public_api/api/projects_environments/list_projects.py +329 -0
- render/public_api/api/projects_environments/remove_resources_from_environment.py +211 -0
- render/public_api/api/projects_environments/retrieve_environment.py +190 -0
- render/public_api/api/projects_environments/retrieve_project.py +190 -0
- render/public_api/api/projects_environments/update_environment.py +212 -0
- render/public_api/api/projects_environments/update_project.py +224 -0
- render/public_api/api/redis_deprecated/__init__.py +1 -0
- render/public_api/api/redis_deprecated/create_redis.py +199 -0
- render/public_api/api/redis_deprecated/delete_redis.py +188 -0
- render/public_api/api/redis_deprecated/list_redis.py +384 -0
- render/public_api/api/redis_deprecated/resume_redis.py +203 -0
- render/public_api/api/redis_deprecated/retrieve_redis.py +190 -0
- render/public_api/api/redis_deprecated/retrieve_redis_connection_info.py +194 -0
- render/public_api/api/redis_deprecated/suspend_redis.py +203 -0
- render/public_api/api/redis_deprecated/update_redis.py +217 -0
- render/public_api/api/registry_credentials/__init__.py +1 -0
- render/public_api/api/registry_credentials/create_registry_credential.py +209 -0
- render/public_api/api/registry_credentials/delete_registry_credential.py +198 -0
- render/public_api/api/registry_credentials/list_registry_credentials.py +370 -0
- render/public_api/api/registry_credentials/retrieve_registry_credential.py +200 -0
- render/public_api/api/registry_credentials/update_registry_credential.py +241 -0
- render/public_api/api/sandboxes/__init__.py +1 -0
- render/public_api/api/sandboxes/connect_sandbox_files.py +281 -0
- render/public_api/api/sandboxes/connect_sandbox_run.py +271 -0
- render/public_api/api/sandboxes/create_sandbox.py +199 -0
- render/public_api/api/sandboxes/list_sandbox_files.py +244 -0
- render/public_api/api/sandboxes/list_sandbox_groups.py +216 -0
- render/public_api/api/sandboxes/list_sandboxes.py +269 -0
- render/public_api/api/sandboxes/retrieve_sandbox.py +211 -0
- render/public_api/api/sandboxes/retrieve_sandbox_execution.py +224 -0
- render/public_api/api/sandboxes/stream_sandbox_logs.py +274 -0
- render/public_api/api/sandboxes/terminate_sandbox.py +217 -0
- render/public_api/api/sandboxes/update_sandbox_exec.py +258 -0
- render/public_api/api/services/__init__.py +1 -0
- render/public_api/api/services/add_or_update_secret_file.py +252 -0
- render/public_api/api/services/autoscale_service.py +230 -0
- render/public_api/api/services/create_ephemeral_shell.py +217 -0
- render/public_api/api/services/create_service.py +204 -0
- render/public_api/api/services/delete_autoscaling_config.py +198 -0
- render/public_api/api/services/delete_env_var.py +223 -0
- render/public_api/api/services/delete_secret_file.py +223 -0
- render/public_api/api/services/delete_service.py +198 -0
- render/public_api/api/services/get_env_vars_for_service.py +241 -0
- render/public_api/api/services/list_events.py +288 -0
- render/public_api/api/services/list_instances.py +190 -0
- render/public_api/api/services/list_secret_files_for_service.py +241 -0
- render/public_api/api/services/list_services.py +439 -0
- render/public_api/api/services/preview_service.py +227 -0
- render/public_api/api/services/purge_cache.py +203 -0
- render/public_api/api/services/restart_service.py +211 -0
- render/public_api/api/services/resume_service.py +203 -0
- render/public_api/api/services/retrieve_env_var.py +225 -0
- render/public_api/api/services/retrieve_secret_file.py +225 -0
- render/public_api/api/services/retrieve_service.py +190 -0
- render/public_api/api/services/retrieve_service_outbound_ips.py +207 -0
- render/public_api/api/services/scale_service.py +237 -0
- render/public_api/api/services/suspend_service.py +203 -0
- render/public_api/api/services/update_env_var.py +257 -0
- render/public_api/api/services/update_env_vars_for_service.py +241 -0
- render/public_api/api/services/update_secret_files_for_service.py +255 -0
- render/public_api/api/services/update_service.py +227 -0
- render/public_api/api/services_cron_jobs/__init__.py +1 -0
- render/public_api/api/services_cron_jobs/cancel_cron_job_run.py +183 -0
- render/public_api/api/services_cron_jobs/run_cron_job.py +185 -0
- render/public_api/api/services_headers/__init__.py +1 -0
- render/public_api/api/services_headers/add_headers.py +222 -0
- render/public_api/api/services_headers/delete_header.py +211 -0
- render/public_api/api/services_headers/list_headers.py +302 -0
- render/public_api/api/services_headers/update_headers.py +243 -0
- render/public_api/api/services_routes/__init__.py +1 -0
- render/public_api/api/services_routes/add_route.py +227 -0
- render/public_api/api/services_routes/delete_route.py +211 -0
- render/public_api/api/services_routes/list_routes.py +306 -0
- render/public_api/api/services_routes/patch_route.py +259 -0
- render/public_api/api/services_routes/put_routes.py +259 -0
- render/public_api/api/users/__init__.py +1 -0
- render/public_api/api/users/get_user.py +161 -0
- render/public_api/api/webhooks/__init__.py +1 -0
- render/public_api/api/webhooks/create_webhook.py +199 -0
- render/public_api/api/webhooks/delete_webhook.py +183 -0
- render/public_api/api/webhooks/list_webhook_events.py +268 -0
- render/public_api/api/webhooks/list_webhooks.py +237 -0
- render/public_api/api/webhooks/retrieve_webhook.py +185 -0
- render/public_api/api/webhooks/update_webhook.py +212 -0
- render/public_api/api/workflow_tasks_beta/__init__.py +1 -0
- render/public_api/api/workflow_tasks_beta/cancel_task_run.py +188 -0
- render/public_api/api/workflow_tasks_beta/create_task.py +204 -0
- render/public_api/api/workflow_tasks_beta/get_task.py +190 -0
- render/public_api/api/workflow_tasks_beta/get_task_run.py +190 -0
- render/public_api/api/workflow_tasks_beta/list_task_runs.py +317 -0
- render/public_api/api/workflow_tasks_beta/list_tasks.py +298 -0
- render/public_api/api/workflow_tasks_beta/stream_task_runs_events.py +230 -0
- render/public_api/api/workflows_beta/__init__.py +1 -0
- render/public_api/api/workflows_beta/create_workflow.py +199 -0
- render/public_api/api/workflows_beta/create_workflow_version.py +197 -0
- render/public_api/api/workflows_beta/delete_workflow.py +188 -0
- render/public_api/api/workflows_beta/get_workflow.py +190 -0
- render/public_api/api/workflows_beta/get_workflow_version.py +190 -0
- render/public_api/api/workflows_beta/list_workflow_versions.py +275 -0
- render/public_api/api/workflows_beta/list_workflows.py +298 -0
- render/public_api/api/workflows_beta/update_workflow.py +212 -0
- render/public_api/api/workspaces/__init__.py +1 -0
- render/public_api/api/workspaces/list_owners.py +255 -0
- render/public_api/api/workspaces/remove_workspace_member.py +206 -0
- render/public_api/api/workspaces/retrieve_owner.py +207 -0
- render/public_api/api/workspaces/retrieve_owner_members.py +200 -0
- render/public_api/api/workspaces/update_workspace_member.py +235 -0
- render/public_api/client.py +268 -0
- render/public_api/errors.py +16 -0
- render/public_api/models/__init__.py +861 -0
- render/public_api/models/add_headers_response_201.py +72 -0
- render/public_api/models/add_or_update_artifact_source_secret_file_body.py +59 -0
- render/public_api/models/add_or_update_secret_file_body.py +59 -0
- render/public_api/models/artifact.py +145 -0
- render/public_api/models/artifact_fetch_failed.py +67 -0
- render/public_api/models/artifact_source.py +162 -0
- render/public_api/models/artifact_source_changed.py +70 -0
- render/public_api/models/artifact_source_git.py +167 -0
- render/public_api/models/artifact_source_git_region.py +12 -0
- render/public_api/models/artifact_source_git_runtime.py +14 -0
- render/public_api/models/artifact_source_image.py +78 -0
- render/public_api/models/artifact_source_patch_git.py +175 -0
- render/public_api/models/artifact_source_patch_git_region.py +12 -0
- render/public_api/models/artifact_source_patch_git_runtime.py +14 -0
- render/public_api/models/artifact_source_patch_image.py +71 -0
- render/public_api/models/artifact_source_patch_input.py +101 -0
- render/public_api/models/artifact_source_post_input.py +213 -0
- render/public_api/models/artifact_source_service_link.py +67 -0
- render/public_api/models/artifact_source_with_cursor.py +73 -0
- render/public_api/models/audit_log.py +113 -0
- render/public_api/models/audit_log_actor.py +80 -0
- render/public_api/models/audit_log_actor_type.py +10 -0
- render/public_api/models/audit_log_event.py +87 -0
- render/public_api/models/audit_log_metadata.py +49 -0
- render/public_api/models/audit_log_status.py +9 -0
- render/public_api/models/audit_log_with_cursor.py +73 -0
- render/public_api/models/auto_deploy.py +9 -0
- render/public_api/models/auto_deploy_disabled.py +79 -0
- render/public_api/models/auto_deploy_enabled.py +68 -0
- render/public_api/models/auto_deploy_trigger.py +10 -0
- render/public_api/models/autoscaling_config.py +89 -0
- render/public_api/models/autoscaling_config_changed.py +83 -0
- render/public_api/models/autoscaling_criteria.py +73 -0
- render/public_api/models/autoscaling_criteria_percentage.py +68 -0
- render/public_api/models/autoscaling_ended.py +67 -0
- render/public_api/models/autoscaling_started.py +105 -0
- render/public_api/models/background_worker_details.py +256 -0
- render/public_api/models/background_worker_details_patch.py +184 -0
- render/public_api/models/background_worker_details_post.py +266 -0
- render/public_api/models/blueprint.py +128 -0
- render/public_api/models/blueprint_detail.py +150 -0
- render/public_api/models/blueprint_patch.py +77 -0
- render/public_api/models/blueprint_with_cursor.py +74 -0
- render/public_api/models/branch_deleted.py +67 -0
- render/public_api/models/build.py +148 -0
- render/public_api/models/build_config.py +96 -0
- render/public_api/models/build_deploy_end_reason.py +122 -0
- render/public_api/models/build_deploy_end_reason_id.py +59 -0
- render/public_api/models/build_deploy_trigger.py +150 -0
- render/public_api/models/build_ended.py +91 -0
- render/public_api/models/build_filter.py +67 -0
- render/public_api/models/build_plan.py +9 -0
- render/public_api/models/build_runtime.py +14 -0
- render/public_api/models/build_started.py +73 -0
- render/public_api/models/build_status.py +13 -0
- render/public_api/models/cache.py +61 -0
- render/public_api/models/cache_profile.py +10 -0
- render/public_api/models/cidr_block_and_description.py +67 -0
- render/public_api/models/commit_ignored.py +67 -0
- render/public_api/models/commit_ref.py +59 -0
- render/public_api/models/connect_sandbox_files_operation.py +9 -0
- render/public_api/models/connect_sandbox_run_operation.py +9 -0
- render/public_api/models/create_custom_domain_body.py +59 -0
- render/public_api/models/create_deploy_body.py +130 -0
- render/public_api/models/create_deploy_body_clear_cache.py +9 -0
- render/public_api/models/create_ephemeral_shell_body.py +69 -0
- render/public_api/models/create_ephemeral_shell_response_201.py +59 -0
- render/public_api/models/create_registry_credential_body.py +93 -0
- render/public_api/models/create_version.py +70 -0
- render/public_api/models/credential_create_input.py +59 -0
- render/public_api/models/cron_job_details.py +163 -0
- render/public_api/models/cron_job_details_patch.py +138 -0
- render/public_api/models/cron_job_details_post.py +172 -0
- render/public_api/models/cron_job_run.py +123 -0
- render/public_api/models/cron_job_run_ended.py +110 -0
- render/public_api/models/cron_job_run_started.py +59 -0
- render/public_api/models/cron_job_run_status.py +11 -0
- render/public_api/models/custom_domain.py +135 -0
- render/public_api/models/custom_domain_domain_type.py +9 -0
- render/public_api/models/custom_domain_server.py +68 -0
- render/public_api/models/custom_domain_verification_status.py +9 -0
- render/public_api/models/custom_domain_with_cursor.py +73 -0
- render/public_api/models/database_role.py +9 -0
- render/public_api/models/database_status.py +18 -0
- render/public_api/models/dedicated_ip.py +146 -0
- render/public_api/models/dedicated_ip_status.py +14 -0
- render/public_api/models/dedicated_ippatch.py +81 -0
- render/public_api/models/dedicated_ippost.py +100 -0
- render/public_api/models/deploy.py +211 -0
- render/public_api/models/deploy_commit.py +86 -0
- render/public_api/models/deploy_ended.py +102 -0
- render/public_api/models/deploy_image.py +78 -0
- render/public_api/models/deploy_mode.py +9 -0
- render/public_api/models/deploy_started.py +85 -0
- render/public_api/models/deploy_status.py +18 -0
- render/public_api/models/deploy_trigger.py +17 -0
- render/public_api/models/deploy_with_cursor.py +81 -0
- render/public_api/models/disk.py +83 -0
- render/public_api/models/disk_created.py +67 -0
- render/public_api/models/disk_deleted.py +59 -0
- render/public_api/models/disk_details.py +112 -0
- render/public_api/models/disk_patch.py +77 -0
- render/public_api/models/disk_post.py +83 -0
- render/public_api/models/disk_snapshot.py +88 -0
- render/public_api/models/disk_updated.py +75 -0
- render/public_api/models/disk_with_cursor.py +73 -0
- render/public_api/models/docker_details.py +108 -0
- render/public_api/models/docker_details_patch.py +86 -0
- render/public_api/models/docker_details_post.py +86 -0
- render/public_api/models/edge_cache_disabled.py +65 -0
- render/public_api/models/edge_cache_enabled.py +65 -0
- render/public_api/models/edge_cache_purged.py +65 -0
- render/public_api/models/edge_cache_trigger.py +91 -0
- render/public_api/models/env_group.py +162 -0
- render/public_api/models/env_group_link.py +77 -0
- render/public_api/models/env_group_meta.py +126 -0
- render/public_api/models/env_group_patch_input.py +59 -0
- render/public_api/models/env_group_post_input.py +161 -0
- render/public_api/models/env_var.py +67 -0
- render/public_api/models/env_var_generate_value.py +59 -0
- render/public_api/models/env_var_key_generate_value.py +68 -0
- render/public_api/models/env_var_key_value.py +67 -0
- render/public_api/models/env_var_value.py +59 -0
- render/public_api/models/env_var_with_cursor.py +73 -0
- render/public_api/models/environment.py +152 -0
- render/public_api/models/environment_patch_input.py +112 -0
- render/public_api/models/environment_post_input.py +122 -0
- render/public_api/models/environment_resources_post_input.py +59 -0
- render/public_api/models/environment_with_cursor.py +74 -0
- render/public_api/models/error.py +79 -0
- render/public_api/models/error_code.py +10 -0
- render/public_api/models/event.py +1122 -0
- render/public_api/models/event_status.py +10 -0
- render/public_api/models/event_type.py +74 -0
- render/public_api/models/execution.py +144 -0
- render/public_api/models/execution_operation.py +11 -0
- render/public_api/models/execution_type.py +9 -0
- render/public_api/models/failure_reason.py +138 -0
- render/public_api/models/filter_application_values_collection_item.py +78 -0
- render/public_api/models/filter_application_values_collection_item_filter.py +8 -0
- render/public_api/models/filter_http_values_collection_item.py +78 -0
- render/public_api/models/filter_http_values_collection_item_filter.py +9 -0
- render/public_api/models/get_bandwidth_sources_response_200.py +75 -0
- render/public_api/models/get_bandwidth_sources_response_200_data_item.py +101 -0
- render/public_api/models/get_bandwidth_sources_response_200_data_item_labels.py +78 -0
- render/public_api/models/get_bandwidth_sources_response_200_data_item_labels_traffic_source.py +12 -0
- render/public_api/models/get_bandwidth_sources_response_200_data_item_values_item.py +68 -0
- render/public_api/models/get_cpu_aggregation_method.py +10 -0
- render/public_api/models/get_http_requests_aggregate_by.py +9 -0
- render/public_api/models/get_object_output.py +71 -0
- render/public_api/models/get_task_runs_completed_aggregate_by.py +8 -0
- render/public_api/models/get_task_runs_completed_state.py +9 -0
- render/public_api/models/header.py +83 -0
- render/public_api/models/header_input.py +76 -0
- render/public_api/models/header_with_cursor.py +73 -0
- render/public_api/models/image.py +80 -0
- render/public_api/models/image_pull_failed.py +67 -0
- render/public_api/models/initial_deploy_hook_ended.py +59 -0
- render/public_api/models/initial_deploy_hook_started.py +59 -0
- render/public_api/models/instance_count_changed.py +67 -0
- render/public_api/models/instance_type_changed.py +67 -0
- render/public_api/models/internal_routing.py +8 -0
- render/public_api/models/job.py +144 -0
- render/public_api/models/job_run_ended.py +92 -0
- render/public_api/models/job_status.py +12 -0
- render/public_api/models/job_with_cursor.py +73 -0
- render/public_api/models/key_value.py +182 -0
- render/public_api/models/key_value_available.py +44 -0
- render/public_api/models/key_value_config_restart.py +67 -0
- render/public_api/models/key_value_connection_info.py +76 -0
- render/public_api/models/key_value_detail.py +192 -0
- render/public_api/models/key_value_options.py +79 -0
- render/public_api/models/key_value_patch_input.py +138 -0
- render/public_api/models/key_value_plan.py +13 -0
- render/public_api/models/key_value_post_input.py +166 -0
- render/public_api/models/key_value_unhealthy.py +44 -0
- render/public_api/models/key_value_with_cursor.py +73 -0
- render/public_api/models/label.py +68 -0
- render/public_api/models/list_custom_domains_domain_type.py +9 -0
- render/public_api/models/list_custom_domains_verification_status.py +9 -0
- render/public_api/models/list_logs_response_200.py +102 -0
- render/public_api/models/list_logs_values_label.py +13 -0
- render/public_api/models/list_objects_response.py +92 -0
- render/public_api/models/list_postgres_suspended_item.py +9 -0
- render/public_api/models/list_postgres_users_response_200_item.py +86 -0
- render/public_api/models/list_routes_type_item.py +9 -0
- render/public_api/models/list_services_suspended_item.py +9 -0
- render/public_api/models/log.py +100 -0
- render/public_api/models/log_direction.py +9 -0
- render/public_api/models/log_label.py +70 -0
- render/public_api/models/log_label_name.py +22 -0
- render/public_api/models/log_stream_owner_update.py +80 -0
- render/public_api/models/log_stream_preview_setting.py +9 -0
- render/public_api/models/log_stream_resource_update.py +80 -0
- render/public_api/models/log_stream_setting.py +9 -0
- render/public_api/models/maintenance_ended.py +44 -0
- render/public_api/models/maintenance_mode.py +68 -0
- render/public_api/models/maintenance_mode_enabled.py +59 -0
- render/public_api/models/maintenance_mode_uri_updated.py +67 -0
- render/public_api/models/maintenance_run.py +105 -0
- render/public_api/models/maintenance_run_patch.py +69 -0
- render/public_api/models/maintenance_run_with_resource.py +114 -0
- render/public_api/models/maintenance_started.py +65 -0
- render/public_api/models/maintenance_state.py +13 -0
- render/public_api/models/maintenance_trigger.py +91 -0
- render/public_api/models/maxmemory_policy.py +15 -0
- render/public_api/models/metrics_stream.py +77 -0
- render/public_api/models/metrics_stream_input.py +86 -0
- render/public_api/models/native_environment_details.py +78 -0
- render/public_api/models/native_environment_details_patch.py +68 -0
- render/public_api/models/native_environment_details_post.py +68 -0
- render/public_api/models/notification_override.py +78 -0
- render/public_api/models/notification_override_with_cursor.py +73 -0
- render/public_api/models/notification_service_override.py +78 -0
- render/public_api/models/notification_service_override_patch.py +84 -0
- render/public_api/models/notification_setting.py +93 -0
- render/public_api/models/notification_setting_patch.py +85 -0
- render/public_api/models/notify_override.py +11 -0
- render/public_api/models/notify_preview_override.py +10 -0
- render/public_api/models/notify_setting.py +10 -0
- render/public_api/models/notify_setting_v2.py +10 -0
- render/public_api/models/object_metadata.py +77 -0
- render/public_api/models/object_with_cursor.py +73 -0
- render/public_api/models/oom_killed.py +59 -0
- render/public_api/models/otel_provider_type.py +16 -0
- render/public_api/models/outbound_ips.py +81 -0
- render/public_api/models/outbound_ips_type.py +9 -0
- render/public_api/models/owner.py +121 -0
- render/public_api/models/owner_log_stream_setting.py +86 -0
- render/public_api/models/owner_type.py +9 -0
- render/public_api/models/owner_with_cursor.py +81 -0
- render/public_api/models/paid_plan.py +13 -0
- render/public_api/models/patch_route_response_200.py +72 -0
- render/public_api/models/persistence_mode.py +10 -0
- render/public_api/models/pipeline_minutes_exhausted.py +73 -0
- render/public_api/models/plan.py +22 -0
- render/public_api/models/post_job_body.py +70 -0
- render/public_api/models/postgres.py +300 -0
- render/public_api/models/postgres_available.py +44 -0
- render/public_api/models/postgres_available_parameter_override.py +106 -0
- render/public_api/models/postgres_available_parameter_overrides_result.py +75 -0
- render/public_api/models/postgres_backup_completed.py +44 -0
- render/public_api/models/postgres_backup_failed.py +44 -0
- render/public_api/models/postgres_backup_started.py +44 -0
- render/public_api/models/postgres_cluster_leader_changed.py +59 -0
- render/public_api/models/postgres_connection_info.py +103 -0
- render/public_api/models/postgres_connection_pool_changed.py +91 -0
- render/public_api/models/postgres_connection_pool_enabled_changed.py +83 -0
- render/public_api/models/postgres_created.py +72 -0
- render/public_api/models/postgres_detail.py +336 -0
- render/public_api/models/postgres_detail_suspended.py +9 -0
- render/public_api/models/postgres_disk_size_changed.py +91 -0
- render/public_api/models/postgres_export.py +80 -0
- render/public_api/models/postgres_ha_status_changed.py +67 -0
- render/public_api/models/postgres_parameter_overrides.py +44 -0
- render/public_api/models/postgres_parameter_overrides_wrapper.py +65 -0
- render/public_api/models/postgres_patch_input.py +199 -0
- render/public_api/models/postgres_pitr_checkpoint_completed.py +44 -0
- render/public_api/models/postgres_pitr_checkpoint_failed.py +44 -0
- render/public_api/models/postgres_pitr_checkpoint_started.py +44 -0
- render/public_api/models/postgres_plans.py +35 -0
- render/public_api/models/postgres_post_input.py +254 -0
- render/public_api/models/postgres_process.py +185 -0
- render/public_api/models/postgres_processes_result.py +73 -0
- render/public_api/models/postgres_put_parameter_overrides_result.py +82 -0
- render/public_api/models/postgres_query_statistic.py +222 -0
- render/public_api/models/postgres_read_replica_stale.py +44 -0
- render/public_api/models/postgres_read_replicas_changed.py +67 -0
- render/public_api/models/postgres_replication_setup_input.py +96 -0
- render/public_api/models/postgres_restarted.py +72 -0
- render/public_api/models/postgres_size.py +96 -0
- render/public_api/models/postgres_sizes_result.py +73 -0
- render/public_api/models/postgres_suspended.py +9 -0
- render/public_api/models/postgres_table_scan.py +87 -0
- render/public_api/models/postgres_table_scans_result.py +73 -0
- render/public_api/models/postgres_top_queries_result.py +73 -0
- render/public_api/models/postgres_unavailable.py +44 -0
- render/public_api/models/postgres_upgrade_failed.py +67 -0
- render/public_api/models/postgres_upgrade_started.py +91 -0
- render/public_api/models/postgres_upgrade_succeeded.py +67 -0
- render/public_api/models/postgres_version.py +15 -0
- render/public_api/models/postgres_with_cursor.py +73 -0
- render/public_api/models/pre_deploy_ended.py +99 -0
- render/public_api/models/pre_deploy_started.py +67 -0
- render/public_api/models/preview_input.py +94 -0
- render/public_api/models/previews.py +67 -0
- render/public_api/models/previews_generation.py +10 -0
- render/public_api/models/private_service_details.py +282 -0
- render/public_api/models/private_service_details_patch.py +184 -0
- render/public_api/models/private_service_details_post.py +266 -0
- render/public_api/models/project.py +108 -0
- render/public_api/models/project_patch_input.py +60 -0
- render/public_api/models/project_post_environment_input.py +114 -0
- render/public_api/models/project_post_input.py +89 -0
- render/public_api/models/project_with_cursor.py +73 -0
- render/public_api/models/protected_status.py +9 -0
- render/public_api/models/pull_request_previews_enabled.py +9 -0
- render/public_api/models/put_object_input.py +59 -0
- render/public_api/models/put_object_output.py +79 -0
- render/public_api/models/read_replica.py +91 -0
- render/public_api/models/read_replica_input.py +83 -0
- render/public_api/models/recovery_info.py +80 -0
- render/public_api/models/recovery_info_recovery_status.py +10 -0
- render/public_api/models/recovery_input.py +114 -0
- render/public_api/models/redis.py +182 -0
- render/public_api/models/redis_connection_info.py +76 -0
- render/public_api/models/redis_detail.py +192 -0
- render/public_api/models/redis_options.py +79 -0
- render/public_api/models/redis_patch_input.py +138 -0
- render/public_api/models/redis_plan.py +13 -0
- render/public_api/models/redis_post_input.py +166 -0
- render/public_api/models/redis_with_cursor.py +73 -0
- render/public_api/models/region.py +12 -0
- render/public_api/models/registry_credential.py +95 -0
- render/public_api/models/registry_credential_registry.py +12 -0
- render/public_api/models/registry_credential_summary.py +67 -0
- render/public_api/models/render_subdomain_policy.py +9 -0
- render/public_api/models/resource.py +67 -0
- render/public_api/models/resource_log_stream_setting.py +87 -0
- render/public_api/models/resource_ref.py +77 -0
- render/public_api/models/resource_ref_type.py +17 -0
- render/public_api/models/rollback_deploy_body.py +59 -0
- render/public_api/models/route.py +93 -0
- render/public_api/models/route_patch.py +60 -0
- render/public_api/models/route_post.py +88 -0
- render/public_api/models/route_put.py +77 -0
- render/public_api/models/route_type.py +9 -0
- render/public_api/models/route_with_cursor.py +73 -0
- render/public_api/models/run_task.py +96 -0
- render/public_api/models/runtime.py +12 -0
- render/public_api/models/sandbox.py +149 -0
- render/public_api/models/sandbox_connect_request.py +62 -0
- render/public_api/models/sandbox_connect_response.py +98 -0
- render/public_api/models/sandbox_directory_listing.py +82 -0
- render/public_api/models/sandbox_exec_update_request.py +60 -0
- render/public_api/models/sandbox_exec_update_response.py +130 -0
- render/public_api/models/sandbox_file_entry.py +98 -0
- render/public_api/models/sandbox_file_entry_type.py +10 -0
- render/public_api/models/sandbox_group.py +141 -0
- render/public_api/models/sandbox_group_with_cursor.py +74 -0
- render/public_api/models/sandbox_network_policy.py +61 -0
- render/public_api/models/sandbox_network_policy_default.py +9 -0
- render/public_api/models/sandbox_plan.py +10 -0
- render/public_api/models/sandbox_post.py +138 -0
- render/public_api/models/sandbox_post_env.py +44 -0
- render/public_api/models/sandbox_status.py +13 -0
- render/public_api/models/sandbox_with_cursor.py +74 -0
- render/public_api/models/scale_service_body.py +59 -0
- render/public_api/models/schemas_build_filter.py +70 -0
- render/public_api/models/schemas_image.py +96 -0
- render/public_api/models/schemas_user.py +68 -0
- render/public_api/models/secret_file.py +67 -0
- render/public_api/models/secret_file_input.py +67 -0
- render/public_api/models/secret_file_with_cursor.py +73 -0
- render/public_api/models/server_available.py +44 -0
- render/public_api/models/server_failed.py +81 -0
- render/public_api/models/server_hardware_failure.py +44 -0
- render/public_api/models/server_port.py +69 -0
- render/public_api/models/server_port_protocol.py +9 -0
- render/public_api/models/server_restarted.py +66 -0
- render/public_api/models/service_disk.py +78 -0
- render/public_api/models/service_env.py +15 -0
- render/public_api/models/service_event.py +770 -0
- render/public_api/models/service_event_type.py +48 -0
- render/public_api/models/service_event_with_cursor.py +66 -0
- render/public_api/models/service_instance.py +69 -0
- render/public_api/models/service_patch.py +273 -0
- render/public_api/models/service_post.py +357 -0
- render/public_api/models/service_resumed.py +44 -0
- render/public_api/models/service_runtime.py +15 -0
- render/public_api/models/service_suspended.py +44 -0
- render/public_api/models/service_type.py +12 -0
- render/public_api/models/service_type_short.py +12 -0
- render/public_api/models/setup_postgres_replication_response_201.py +44 -0
- render/public_api/models/snapshot_restore_post.py +72 -0
- render/public_api/models/static_site_details.py +183 -0
- render/public_api/models/static_site_details_patch.py +147 -0
- render/public_api/models/static_site_details_post.py +189 -0
- render/public_api/models/status.py +12 -0
- render/public_api/models/stream_sandbox_logs_accept.py +8 -0
- render/public_api/models/stream_task_runs_events_accept.py +8 -0
- render/public_api/models/suspender_added.py +83 -0
- render/public_api/models/suspender_removed.py +83 -0
- render/public_api/models/suspender_type.py +14 -0
- render/public_api/models/sync.py +118 -0
- render/public_api/models/sync_state.py +12 -0
- render/public_api/models/sync_with_cursor.py +74 -0
- render/public_api/models/task.py +97 -0
- render/public_api/models/task_attempt.py +121 -0
- render/public_api/models/task_attempt_details.py +141 -0
- render/public_api/models/task_data_type_1.py +44 -0
- render/public_api/models/task_run.py +168 -0
- render/public_api/models/task_run_details.py +216 -0
- render/public_api/models/task_run_status.py +14 -0
- render/public_api/models/task_run_with_cursor.py +73 -0
- render/public_api/models/task_with_cursor.py +73 -0
- render/public_api/models/team_member.py +102 -0
- render/public_api/models/team_member_role.py +12 -0
- render/public_api/models/team_member_status.py +9 -0
- render/public_api/models/time_series.py +100 -0
- render/public_api/models/time_series_value.py +70 -0
- render/public_api/models/update_env_group_secret_file_body.py +59 -0
- render/public_api/models/update_registry_credential_body.py +85 -0
- render/public_api/models/update_workspace_member_body.py +61 -0
- render/public_api/models/user.py +67 -0
- render/public_api/models/validate_blueprint_request.py +84 -0
- render/public_api/models/validate_blueprint_response.py +105 -0
- render/public_api/models/validation_error.py +88 -0
- render/public_api/models/validation_plan_summary.py +107 -0
- render/public_api/models/web_service_details.py +385 -0
- render/public_api/models/web_service_details_patch.py +270 -0
- render/public_api/models/web_service_details_post.py +354 -0
- render/public_api/models/webhook.py +110 -0
- render/public_api/models/webhook_event.py +115 -0
- render/public_api/models/webhook_event_with_cursor.py +73 -0
- render/public_api/models/webhook_patch_input.py +98 -0
- render/public_api/models/webhook_post_input.py +102 -0
- render/public_api/models/webhook_with_cursor.py +73 -0
- render/public_api/models/workflow.py +163 -0
- render/public_api/models/workflow_create.py +169 -0
- render/public_api/models/workflow_update.py +109 -0
- render/public_api/models/workflow_version.py +95 -0
- render/public_api/models/workflow_version_status.py +13 -0
- render/public_api/models/workflow_version_with_cursor.py +73 -0
- render/public_api/models/workflow_with_cursor.py +73 -0
- render/public_api/models/zero_downtime_redeploy_ended.py +44 -0
- render/public_api/models/zero_downtime_redeploy_started.py +59 -0
- render/public_api/py.typed +1 -0
- render/public_api/types.py +54 -0
- render/py.typed +0 -0
- render/render.py +81 -0
- render/render_async.py +80 -0
- render/version.py +27 -0
- render/workflows/__init__.py +25 -0
- render/workflows/_callback_models.py +194 -0
- render/workflows/_uds_http.py +128 -0
- render/workflows/app.py +263 -0
- render/workflows/cli.py +62 -0
- render/workflows/client.py +354 -0
- render/workflows/context.py +75 -0
- render/workflows/executor.py +86 -0
- render/workflows/runner.py +174 -0
- render/workflows/task.py +348 -0
- render/workflows/tests/__init__.py +0 -0
- render/workflows/tests/test_app.py +343 -0
- render/workflows/tests/test_cli.py +134 -0
- render/workflows/tests/test_client.py +59 -0
- render/workflows/tests/test_context.py +118 -0
- render/workflows/tests/test_end_to_end.py +307 -0
- render/workflows/tests/test_executor.py +221 -0
- render/workflows/tests/test_lazy_imports.py +100 -0
- render/workflows/tests/test_registration.py +293 -0
- render/workflows/tests/test_translate_errors.py +126 -0
- render/workflows/tests/test_uds_http.py +199 -0
- render/workflows/tests/test_version.py +15 -0
- render-1.0.1.dist-info/METADATA +382 -0
- render-1.0.1.dist-info/RECORD +799 -0
- render-1.0.1.dist-info/WHEEL +4 -0
- render-1.0.1.dist-info/entry_points.txt +2 -0
- render-1.0.1.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
"""Typed wrapper over the generated public_api sandbox endpoints."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import posixpath
|
|
8
|
+
import stat
|
|
9
|
+
from collections.abc import AsyncIterator, Sequence
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import TYPE_CHECKING, Any, NoReturn
|
|
13
|
+
|
|
14
|
+
import httpx
|
|
15
|
+
|
|
16
|
+
from render.client.errors import (
|
|
17
|
+
ClientError,
|
|
18
|
+
RateLimitError,
|
|
19
|
+
RenderError,
|
|
20
|
+
ServerError,
|
|
21
|
+
)
|
|
22
|
+
from render.client.util import (
|
|
23
|
+
handle_api_error,
|
|
24
|
+
handle_http_errors,
|
|
25
|
+
handle_httpx_exception,
|
|
26
|
+
)
|
|
27
|
+
from render.experimental.sandbox._tar import (
|
|
28
|
+
aclose_content,
|
|
29
|
+
aiter_file,
|
|
30
|
+
aiter_tar_gzip,
|
|
31
|
+
astat_path,
|
|
32
|
+
)
|
|
33
|
+
from render.experimental.sandbox.errors import (
|
|
34
|
+
SandboxDownloadError,
|
|
35
|
+
SandboxExecError,
|
|
36
|
+
SandboxExecStreamError,
|
|
37
|
+
SandboxFileNotFoundError,
|
|
38
|
+
SandboxNotFoundError,
|
|
39
|
+
)
|
|
40
|
+
from render.experimental.sandbox.files import (
|
|
41
|
+
PartialDownload,
|
|
42
|
+
arun_blocking,
|
|
43
|
+
check_content_encoding,
|
|
44
|
+
disposition_filename,
|
|
45
|
+
media_type,
|
|
46
|
+
parent_dir,
|
|
47
|
+
prepare_extract_dir,
|
|
48
|
+
resolve_file_dest,
|
|
49
|
+
)
|
|
50
|
+
from render.experimental.sandbox.types import (
|
|
51
|
+
Sandbox,
|
|
52
|
+
SandboxExecEvent,
|
|
53
|
+
SandboxExecExit,
|
|
54
|
+
SandboxExecOutput,
|
|
55
|
+
SandboxList,
|
|
56
|
+
)
|
|
57
|
+
from render.public_api.api.sandboxes import (
|
|
58
|
+
create_sandbox,
|
|
59
|
+
list_sandboxes,
|
|
60
|
+
retrieve_sandbox,
|
|
61
|
+
terminate_sandbox,
|
|
62
|
+
)
|
|
63
|
+
from render.public_api.models.error import Error
|
|
64
|
+
from render.public_api.models.sandbox import Sandbox as GeneratedSandbox
|
|
65
|
+
from render.public_api.models.sandbox_network_policy import SandboxNetworkPolicy
|
|
66
|
+
from render.public_api.models.sandbox_network_policy_default import (
|
|
67
|
+
SandboxNetworkPolicyDefault,
|
|
68
|
+
)
|
|
69
|
+
from render.public_api.models.sandbox_plan import SandboxPlan
|
|
70
|
+
from render.public_api.models.sandbox_post import SandboxPOST
|
|
71
|
+
from render.public_api.models.sandbox_post_env import SandboxPOSTEnv
|
|
72
|
+
from render.public_api.models.sandbox_status import SandboxStatus
|
|
73
|
+
from render.public_api.models.sandbox_with_cursor import SandboxWithCursor
|
|
74
|
+
from render.public_api.types import UNSET, Response
|
|
75
|
+
|
|
76
|
+
if TYPE_CHECKING:
|
|
77
|
+
from render.public_api.client import AuthenticatedClient, Client
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# The code the sandbox agent sends in a 404 body when the remote path is missing.
|
|
81
|
+
_FILE_NOT_FOUND_CODE = "file_not_found"
|
|
82
|
+
|
|
83
|
+
# Aliased at module scope so the annotations on _list_api_call resolve the
|
|
84
|
+
# builtin list, not the SandboxApi.list method that shadows it in the class body.
|
|
85
|
+
_SandboxWithCursorList = list[SandboxWithCursor]
|
|
86
|
+
_SandboxStatusList = list[SandboxStatus]
|
|
87
|
+
|
|
88
|
+
# File transfer content types. The content type states intent and nothing else:
|
|
89
|
+
# a single file travels as octet-stream and a directory as an x-tar archive the
|
|
90
|
+
# server extracts, with Content-Encoding carrying wire compression separately.
|
|
91
|
+
_CONTENT_TYPE_OCTET_STREAM = "application/octet-stream"
|
|
92
|
+
_CONTENT_TYPE_TAR = "application/x-tar"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _to_sandbox(model: GeneratedSandbox) -> Sandbox:
|
|
96
|
+
terminated = model.terminated_at
|
|
97
|
+
return Sandbox(
|
|
98
|
+
id=model.id,
|
|
99
|
+
status=model.status.value,
|
|
100
|
+
plan=model.plan.value,
|
|
101
|
+
network_policy=model.network_policy.default.value,
|
|
102
|
+
region=model.region,
|
|
103
|
+
timeout_seconds=model.timeout_seconds,
|
|
104
|
+
created_at=model.created_at,
|
|
105
|
+
terminated_at=terminated if isinstance(terminated, datetime) else None,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _normalize_statuses(status: str | Sequence[str] | None) -> list[SandboxStatus]:
|
|
110
|
+
if status is None:
|
|
111
|
+
return []
|
|
112
|
+
values = [status] if isinstance(status, str) else list(status)
|
|
113
|
+
return [SandboxStatus(value) for value in values]
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class SandboxApi:
|
|
117
|
+
"""Typed wrapper over the generated sandbox endpoints."""
|
|
118
|
+
|
|
119
|
+
def __init__(self, client: AuthenticatedClient | Client):
|
|
120
|
+
self.client = client
|
|
121
|
+
|
|
122
|
+
async def create(
|
|
123
|
+
self,
|
|
124
|
+
owner_id: str,
|
|
125
|
+
plan: str | None,
|
|
126
|
+
timeout_seconds: int | None,
|
|
127
|
+
network_policy: str | None,
|
|
128
|
+
region: str | None,
|
|
129
|
+
env: dict[str, str] | None,
|
|
130
|
+
) -> Sandbox:
|
|
131
|
+
body = SandboxPOST(owner_id=owner_id)
|
|
132
|
+
if plan is not None:
|
|
133
|
+
body.plan = SandboxPlan(plan)
|
|
134
|
+
if timeout_seconds is not None:
|
|
135
|
+
body.timeout_seconds = timeout_seconds
|
|
136
|
+
if region is not None:
|
|
137
|
+
body.region = region
|
|
138
|
+
if network_policy is not None:
|
|
139
|
+
body.network_policy = SandboxNetworkPolicy(
|
|
140
|
+
default=SandboxNetworkPolicyDefault(network_policy)
|
|
141
|
+
)
|
|
142
|
+
if env is not None:
|
|
143
|
+
body.env = SandboxPOSTEnv.from_dict(env)
|
|
144
|
+
|
|
145
|
+
response = await self._create_api_call(body)
|
|
146
|
+
if not isinstance(response.parsed, GeneratedSandbox):
|
|
147
|
+
raise RenderError("Failed to create sandbox: unexpected response type")
|
|
148
|
+
return _to_sandbox(response.parsed)
|
|
149
|
+
|
|
150
|
+
async def get(self, sandbox_id: str, owner_id: str) -> Sandbox:
|
|
151
|
+
try:
|
|
152
|
+
response = await retrieve_sandbox.asyncio_detailed(
|
|
153
|
+
sandbox_id, client=self.client, owner_id=owner_id
|
|
154
|
+
)
|
|
155
|
+
except httpx.RequestError as exc:
|
|
156
|
+
handle_httpx_exception(exc, "retrieve sandbox")
|
|
157
|
+
except json.JSONDecodeError as exc:
|
|
158
|
+
body = exc.doc.strip() if exc.doc else "empty response"
|
|
159
|
+
raise RenderError(
|
|
160
|
+
f"retrieve sandbox failed: server returned a non-JSON response: {body}"
|
|
161
|
+
) from exc
|
|
162
|
+
if response.status_code == 404:
|
|
163
|
+
raise SandboxNotFoundError(f"sandbox {sandbox_id} not found")
|
|
164
|
+
handle_api_error(response, "retrieve sandbox")
|
|
165
|
+
if not isinstance(response.parsed, GeneratedSandbox):
|
|
166
|
+
raise RenderError("Failed to retrieve sandbox: unexpected response type")
|
|
167
|
+
return _to_sandbox(response.parsed)
|
|
168
|
+
|
|
169
|
+
async def list(
|
|
170
|
+
self,
|
|
171
|
+
owner_id: str,
|
|
172
|
+
status: str | Sequence[str] | None,
|
|
173
|
+
cursor: str | None,
|
|
174
|
+
limit: int | None,
|
|
175
|
+
) -> SandboxList:
|
|
176
|
+
statuses = _normalize_statuses(status)
|
|
177
|
+
response = await self._list_api_call(owner_id, statuses, cursor, limit)
|
|
178
|
+
parsed = response.parsed
|
|
179
|
+
if not isinstance(parsed, list):
|
|
180
|
+
raise RenderError("Failed to list sandboxes: unexpected response type")
|
|
181
|
+
sandboxes = [_to_sandbox(item.sandbox) for item in parsed]
|
|
182
|
+
next_cursor = parsed[-1].cursor if parsed else None
|
|
183
|
+
return SandboxList(sandboxes=sandboxes, next_cursor=next_cursor)
|
|
184
|
+
|
|
185
|
+
@handle_http_errors("list sandboxes")
|
|
186
|
+
async def _list_api_call(
|
|
187
|
+
self,
|
|
188
|
+
owner_id: str,
|
|
189
|
+
statuses: _SandboxStatusList,
|
|
190
|
+
cursor: str | None,
|
|
191
|
+
limit: int | None,
|
|
192
|
+
) -> Response[Error | _SandboxWithCursorList]:
|
|
193
|
+
return await list_sandboxes.asyncio_detailed(
|
|
194
|
+
client=self.client,
|
|
195
|
+
owner_id=[owner_id],
|
|
196
|
+
status=statuses or UNSET,
|
|
197
|
+
cursor=cursor if cursor is not None else UNSET,
|
|
198
|
+
limit=limit if limit is not None else UNSET,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
async def terminate(self, sandbox_id: str, owner_id: str) -> None:
|
|
202
|
+
try:
|
|
203
|
+
response = await terminate_sandbox.asyncio_detailed(
|
|
204
|
+
sandbox_id, client=self.client, owner_id=owner_id
|
|
205
|
+
)
|
|
206
|
+
except httpx.RequestError as exc:
|
|
207
|
+
handle_httpx_exception(exc, "terminate sandbox")
|
|
208
|
+
except json.JSONDecodeError as exc:
|
|
209
|
+
body = exc.doc.strip() if exc.doc else "empty response"
|
|
210
|
+
raise RenderError(
|
|
211
|
+
f"terminate sandbox failed: server returned a non-JSON response: {body}"
|
|
212
|
+
) from exc
|
|
213
|
+
if response.status_code == 404:
|
|
214
|
+
raise SandboxNotFoundError(f"sandbox {sandbox_id} not found")
|
|
215
|
+
handle_api_error(response, "terminate sandbox")
|
|
216
|
+
|
|
217
|
+
async def _mint_run_token(
|
|
218
|
+
self, sandbox_id: str, owner_id: str, operation: str, command: str
|
|
219
|
+
) -> dict[str, Any]:
|
|
220
|
+
# Command rides along so the API keeps a sanitized copy for the audit trail.
|
|
221
|
+
api_client = self.client.get_async_httpx_client()
|
|
222
|
+
try:
|
|
223
|
+
response = await api_client.post(
|
|
224
|
+
f"/sandboxes/{sandbox_id}/runs/{operation}/token",
|
|
225
|
+
params={"ownerId": owner_id},
|
|
226
|
+
json={"command": command},
|
|
227
|
+
)
|
|
228
|
+
except httpx.RequestError as exc:
|
|
229
|
+
handle_httpx_exception(exc, "connect sandbox run")
|
|
230
|
+
if response.status_code >= 400:
|
|
231
|
+
_raise_sandbox_http_error(
|
|
232
|
+
sandbox_id, response.status_code, response.text, "exec"
|
|
233
|
+
)
|
|
234
|
+
return response.json()
|
|
235
|
+
|
|
236
|
+
async def _mint_file_token(
|
|
237
|
+
self, sandbox_id: str, owner_id: str, operation: str, path: str
|
|
238
|
+
) -> dict[str, Any]:
|
|
239
|
+
api_client = self.client.get_async_httpx_client()
|
|
240
|
+
try:
|
|
241
|
+
response = await api_client.post(
|
|
242
|
+
f"/sandboxes/{sandbox_id}/files/{operation}/token",
|
|
243
|
+
params={"ownerId": owner_id, "path": path},
|
|
244
|
+
)
|
|
245
|
+
except httpx.RequestError as exc:
|
|
246
|
+
handle_httpx_exception(exc, "connect sandbox files")
|
|
247
|
+
if response.status_code >= 400:
|
|
248
|
+
_raise_sandbox_http_error(
|
|
249
|
+
sandbox_id, response.status_code, response.text, operation
|
|
250
|
+
)
|
|
251
|
+
return response.json()
|
|
252
|
+
|
|
253
|
+
async def upload(
|
|
254
|
+
self,
|
|
255
|
+
sandbox_id: str,
|
|
256
|
+
local_path: str | os.PathLike[str],
|
|
257
|
+
remote_path: str,
|
|
258
|
+
owner_id: str,
|
|
259
|
+
) -> None:
|
|
260
|
+
source = Path(local_path)
|
|
261
|
+
# The server rejects any path it would have to clean, so clean it here
|
|
262
|
+
# instead of turning a trailing slash into a 400. The CLI does the same
|
|
263
|
+
# before minting, which keeps the two clients in step. Guard the empty
|
|
264
|
+
# path first: normpath turns it into ".", which would quietly copy to
|
|
265
|
+
# the home directory instead of failing.
|
|
266
|
+
if not remote_path:
|
|
267
|
+
raise ValueError("remote_path is required")
|
|
268
|
+
remote_path = posixpath.normpath(remote_path)
|
|
269
|
+
# stat, not lstat: a symlinked directory uploads as the directory it
|
|
270
|
+
# points at. Statting before the mint also keeps a missing local path
|
|
271
|
+
# from spending a token.
|
|
272
|
+
info = await astat_path(source)
|
|
273
|
+
if not (stat.S_ISDIR(info.st_mode) or stat.S_ISREG(info.st_mode)):
|
|
274
|
+
# Opening a fifo blocks until a writer appears, which may be never,
|
|
275
|
+
# and that open would block the event loop rather than time out.
|
|
276
|
+
# Refuse before the mint so a bad path does not spend a token.
|
|
277
|
+
raise ValueError(
|
|
278
|
+
f"{source} is not a file or directory; "
|
|
279
|
+
"sockets, fifos and devices cannot be copied to a sandbox"
|
|
280
|
+
)
|
|
281
|
+
connection = await self._mint_file_token(
|
|
282
|
+
sandbox_id, owner_id, "upload", remote_path
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
headers = {"Authorization": f"Bearer {connection['token']}"}
|
|
286
|
+
content: AsyncIterator[bytes]
|
|
287
|
+
if stat.S_ISDIR(info.st_mode):
|
|
288
|
+
headers["Content-Type"] = _CONTENT_TYPE_TAR
|
|
289
|
+
# The archive's length is not known until it has been produced, so
|
|
290
|
+
# the body goes out chunked. gzip is the wire encoding only: the
|
|
291
|
+
# server gunzips it and extracts the tar underneath.
|
|
292
|
+
headers["Content-Encoding"] = "gzip"
|
|
293
|
+
content = aiter_tar_gzip(source)
|
|
294
|
+
else:
|
|
295
|
+
headers["Content-Type"] = _CONTENT_TYPE_OCTET_STREAM
|
|
296
|
+
# An explicit length keeps httpx from sending an iterator body
|
|
297
|
+
# chunked, and lets the sandbox size the write up front.
|
|
298
|
+
headers["Content-Length"] = str(info.st_size)
|
|
299
|
+
content = aiter_file(source)
|
|
300
|
+
|
|
301
|
+
# Keep the connect timeout, but let a large upload take as long as it
|
|
302
|
+
# takes, as the object client does.
|
|
303
|
+
timeout = httpx.Timeout(5.0, read=None, write=None)
|
|
304
|
+
try:
|
|
305
|
+
async with httpx.AsyncClient(timeout=timeout) as proxy_client:
|
|
306
|
+
response = await proxy_client.request(
|
|
307
|
+
connection["method"],
|
|
308
|
+
connection["uri"],
|
|
309
|
+
headers=headers,
|
|
310
|
+
content=content,
|
|
311
|
+
)
|
|
312
|
+
except httpx.RequestError as exc:
|
|
313
|
+
handle_httpx_exception(exc, "upload to sandbox")
|
|
314
|
+
finally:
|
|
315
|
+
# httpx closes the body on today's failure paths, but that is its
|
|
316
|
+
# internals, not a contract. Closing here is what actually
|
|
317
|
+
# guarantees the archive producer stops when a request dies early.
|
|
318
|
+
await aclose_content(content)
|
|
319
|
+
# Any 2xx, not just the 204 the sandbox sends today: the API deploys
|
|
320
|
+
# ahead of the SDK, so pinning the exact code would break on a benign
|
|
321
|
+
# change.
|
|
322
|
+
if not 200 <= response.status_code < 300:
|
|
323
|
+
_raise_sandbox_http_error(
|
|
324
|
+
sandbox_id, response.status_code, response.text, "upload"
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
async def download_file(
|
|
328
|
+
self, sandbox_id: str, remote_path: str, local_path: str, owner_id: str
|
|
329
|
+
) -> str:
|
|
330
|
+
"""Copy remote_path out of the sandbox and return the local path written.
|
|
331
|
+
|
|
332
|
+
A directory arrives as an x-tar archive and is extracted under
|
|
333
|
+
local_path; anything else is written as a single file.
|
|
334
|
+
"""
|
|
335
|
+
connection = await self._mint_file_token(
|
|
336
|
+
sandbox_id, owner_id, "download", remote_path
|
|
337
|
+
)
|
|
338
|
+
headers = {
|
|
339
|
+
"Authorization": f"Bearer {connection['token']}",
|
|
340
|
+
# Ask only for the coding httpx undoes for us. Left to itself it
|
|
341
|
+
# also advertises deflate, and br/zstd when those are installed,
|
|
342
|
+
# any of which would arrive as a body we refuse to write.
|
|
343
|
+
"Accept-Encoding": "gzip",
|
|
344
|
+
}
|
|
345
|
+
# read bounds the wait for the next chunk, not the transfer, so a large
|
|
346
|
+
# download still has as long as it needs while a body that stops
|
|
347
|
+
# arriving fails instead of hanging. Same budget as exec_stream.
|
|
348
|
+
timeout = httpx.Timeout(5.0, read=45.0, write=None)
|
|
349
|
+
try:
|
|
350
|
+
async with (
|
|
351
|
+
httpx.AsyncClient(timeout=timeout) as proxy_client,
|
|
352
|
+
proxy_client.stream(
|
|
353
|
+
connection["method"], connection["uri"], headers=headers
|
|
354
|
+
) as response,
|
|
355
|
+
):
|
|
356
|
+
if response.status_code >= 400:
|
|
357
|
+
body = (await response.aread()).decode("utf-8", errors="replace")
|
|
358
|
+
_raise_sandbox_http_error(
|
|
359
|
+
sandbox_id, response.status_code, body, "download"
|
|
360
|
+
)
|
|
361
|
+
check_content_encoding(response.headers.get("content-encoding", ""))
|
|
362
|
+
|
|
363
|
+
if media_type(response.headers.get("content-type", "")) == (
|
|
364
|
+
_CONTENT_TYPE_TAR
|
|
365
|
+
):
|
|
366
|
+
# The archive is spooled next to the destination rather than
|
|
367
|
+
# extracted as it arrives: feeding tarfile from an async
|
|
368
|
+
# stream would take a thread to bridge, and the memory
|
|
369
|
+
# footprint is the same either way.
|
|
370
|
+
with PartialDownload(prepare_extract_dir(local_path)) as partial:
|
|
371
|
+
async for chunk in response.aiter_bytes():
|
|
372
|
+
partial.write(chunk)
|
|
373
|
+
await arun_blocking(partial.extract, local_path)
|
|
374
|
+
return local_path
|
|
375
|
+
|
|
376
|
+
dest = resolve_file_dest(
|
|
377
|
+
local_path,
|
|
378
|
+
disposition_filename(
|
|
379
|
+
response.headers.get("content-disposition", "")
|
|
380
|
+
),
|
|
381
|
+
remote_path,
|
|
382
|
+
)
|
|
383
|
+
with PartialDownload(parent_dir(dest)) as partial:
|
|
384
|
+
async for chunk in response.aiter_bytes():
|
|
385
|
+
partial.write(chunk)
|
|
386
|
+
return await arun_blocking(partial.commit, dest)
|
|
387
|
+
except httpx.RequestError as exc:
|
|
388
|
+
handle_httpx_exception(exc, "download sandbox file")
|
|
389
|
+
except OSError as exc:
|
|
390
|
+
# Spooling, extracting and renaming all touch the local disk, and a
|
|
391
|
+
# bare OSError from any of them tells a caller nothing about which
|
|
392
|
+
# download failed.
|
|
393
|
+
raise SandboxDownloadError(
|
|
394
|
+
f"could not write the download to {local_path}: {exc}"
|
|
395
|
+
) from exc
|
|
396
|
+
|
|
397
|
+
async def exec_stream(
|
|
398
|
+
self, sandbox_id: str, command: str, owner_id: str, operation: str = "stream"
|
|
399
|
+
) -> AsyncIterator[SandboxExecEvent]:
|
|
400
|
+
connection = await self._mint_run_token(
|
|
401
|
+
sandbox_id, owner_id, operation, command
|
|
402
|
+
)
|
|
403
|
+
token = connection["token"]
|
|
404
|
+
uri = connection["uri"]
|
|
405
|
+
method = connection["method"]
|
|
406
|
+
headers = {
|
|
407
|
+
"Authorization": f"Bearer {token}",
|
|
408
|
+
"Accept": "text/event-stream",
|
|
409
|
+
"Content-Type": "application/json",
|
|
410
|
+
}
|
|
411
|
+
# Read timeout at 3x the server's 15s SSE keep-alive interval, so a dead
|
|
412
|
+
# connection is detected without cutting off a live but idle stream.
|
|
413
|
+
timeout = httpx.Timeout(5.0, read=45.0, write=None)
|
|
414
|
+
try:
|
|
415
|
+
async with (
|
|
416
|
+
httpx.AsyncClient(timeout=timeout) as proxy_client,
|
|
417
|
+
proxy_client.stream(
|
|
418
|
+
method, uri, headers=headers, json={"command": command}
|
|
419
|
+
) as response,
|
|
420
|
+
):
|
|
421
|
+
if response.status_code >= 400:
|
|
422
|
+
body = (await response.aread()).decode("utf-8", errors="replace")
|
|
423
|
+
_raise_sandbox_http_error(
|
|
424
|
+
sandbox_id, response.status_code, body, "exec"
|
|
425
|
+
)
|
|
426
|
+
async for name, data in _iter_sse_events(response.aiter_lines()):
|
|
427
|
+
if name == "output":
|
|
428
|
+
payload = _load_event(data)
|
|
429
|
+
yield SandboxExecOutput(
|
|
430
|
+
stream=payload["stream"], data=payload["data"]
|
|
431
|
+
)
|
|
432
|
+
elif name == "exit":
|
|
433
|
+
payload = _load_event(data)
|
|
434
|
+
yield SandboxExecExit(exit_code=payload["exit_code"])
|
|
435
|
+
return
|
|
436
|
+
elif name == "error":
|
|
437
|
+
payload = _load_event(data)
|
|
438
|
+
raise SandboxExecStreamError(
|
|
439
|
+
payload.get("status", 0), payload.get("message", "")
|
|
440
|
+
)
|
|
441
|
+
else:
|
|
442
|
+
raise SandboxExecError(f"unknown sandbox exec event {name!r}")
|
|
443
|
+
raise SandboxExecError(
|
|
444
|
+
"sandbox exec stream ended without an exit event"
|
|
445
|
+
)
|
|
446
|
+
except httpx.RequestError as exc:
|
|
447
|
+
handle_httpx_exception(exc, "exec sandbox")
|
|
448
|
+
|
|
449
|
+
@handle_http_errors("create sandbox")
|
|
450
|
+
async def _create_api_call(
|
|
451
|
+
self, body: SandboxPOST
|
|
452
|
+
) -> Response[Error | GeneratedSandbox]:
|
|
453
|
+
return await create_sandbox.asyncio_detailed(client=self.client, body=body)
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
def _load_event(data: str) -> dict[str, Any]:
|
|
457
|
+
try:
|
|
458
|
+
return json.loads(data)
|
|
459
|
+
except json.JSONDecodeError as exc:
|
|
460
|
+
raise SandboxExecError(
|
|
461
|
+
f"failed to parse sandbox exec event data: {data}"
|
|
462
|
+
) from exc
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
def _file_error_code(body: str) -> str:
|
|
466
|
+
"""The ``code`` of a sandbox agent error body, or "" if it has none."""
|
|
467
|
+
try:
|
|
468
|
+
payload = json.loads(body)
|
|
469
|
+
except ValueError:
|
|
470
|
+
return ""
|
|
471
|
+
code = payload.get("code") if isinstance(payload, dict) else None
|
|
472
|
+
return code if isinstance(code, str) else ""
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def _raise_sandbox_http_error(
|
|
476
|
+
sandbox_id: str, status_code: int, body: str, action: str
|
|
477
|
+
) -> NoReturn:
|
|
478
|
+
message = f"{action} failed with status {status_code}"
|
|
479
|
+
if body:
|
|
480
|
+
message = f"{message}: {body}"
|
|
481
|
+
if status_code == 404:
|
|
482
|
+
# The agent 404s a missing remote path with this code, and the sandbox
|
|
483
|
+
# is alive when it does. Any other 404 is the sandbox itself being gone,
|
|
484
|
+
# including the one the mint endpoint returns.
|
|
485
|
+
if _file_error_code(body) == _FILE_NOT_FOUND_CODE:
|
|
486
|
+
raise SandboxFileNotFoundError(message)
|
|
487
|
+
raise SandboxNotFoundError(f"sandbox {sandbox_id} not found")
|
|
488
|
+
if status_code == 429:
|
|
489
|
+
raise RateLimitError(message)
|
|
490
|
+
if 400 <= status_code < 500:
|
|
491
|
+
raise ClientError(message)
|
|
492
|
+
raise ServerError(message)
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
async def _iter_sse_events(
|
|
496
|
+
lines: AsyncIterator[str],
|
|
497
|
+
) -> AsyncIterator[tuple[str, str]]:
|
|
498
|
+
event_name = ""
|
|
499
|
+
data_parts: list[str] = []
|
|
500
|
+
async for raw in lines:
|
|
501
|
+
line = raw.rstrip("\r")
|
|
502
|
+
if line == "":
|
|
503
|
+
if event_name or data_parts:
|
|
504
|
+
yield event_name, "\n".join(data_parts)
|
|
505
|
+
event_name = ""
|
|
506
|
+
data_parts = []
|
|
507
|
+
continue
|
|
508
|
+
if line.startswith(":"):
|
|
509
|
+
continue
|
|
510
|
+
if line.startswith("event:"):
|
|
511
|
+
event_name = line[len("event:") :].strip()
|
|
512
|
+
elif line.startswith("data:"):
|
|
513
|
+
chunk = line[len("data:") :]
|
|
514
|
+
if chunk.startswith(" "):
|
|
515
|
+
chunk = chunk[1:]
|
|
516
|
+
data_parts.append(chunk)
|
|
517
|
+
if event_name or data_parts:
|
|
518
|
+
yield event_name, "\n".join(data_parts)
|