modAL 1.6.1__tar.gz → 1.6.1.dev0__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.
- {modal-1.6.1 → modal-1.6.1.dev0}/PKG-INFO +3 -3
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_environments.py +1 -2
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_output/status.py +3 -1
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_server.py +9 -34
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_server.pyi +1 -18
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/grpc_utils.py +12 -11
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/task_command_router_client.py +8 -29
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/function.py +3 -5
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/server.py +4 -5
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/client.pyi +2 -2
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/config.py +6 -28
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/object.pyi +2 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/sandbox.py +46 -47
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/sandbox.pyi +0 -16
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/skills/modal/SKILL.md +24 -19
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/types.py +0 -4
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/volume.py +0 -4
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/volume.pyi +0 -12
- {modal-1.6.1 → modal-1.6.1.dev0}/modal.egg-info/PKG-INFO +3 -3
- {modal-1.6.1 → modal-1.6.1.dev0}/modal.egg-info/requires.txt +2 -2
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_proto/api_pb2.py +1373 -1383
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_proto/api_pb2.pyi +8 -64
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_proto/task_command_router_pb2.py +96 -96
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_proto/task_command_router_pb2.pyi +2 -12
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_version/__init__.py +1 -1
- {modal-1.6.1 → modal-1.6.1.dev0}/pyproject.toml +3 -3
- {modal-1.6.1 → modal-1.6.1.dev0}/LICENSE +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/README.md +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/__init__.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/__main__.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_billing.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_cluster.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_cluster.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_container_entrypoint.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_function_variants.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_functions.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_grpc_client.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_image.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_ipython.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_load_context.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_location.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_logs.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_logs_manager.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_logs_manager.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_object.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_outbound_policy.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_outbound_policy.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_output/__init__.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_output/manager.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_output/pty.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_output/rich.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_partial_function.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_resolver.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_resources.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_runtime/__init__.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_runtime/asgi.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_runtime/execution_context.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_runtime/task_lifecycle_manager.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_runtime/telemetry.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_serialization.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_supports_logs.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_traceback.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_tunnel.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_tunnel.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_type_manager.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/__init__.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/app_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/async_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/blob_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/browser_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/curl_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/deprecation.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/display_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/docker_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/function_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/git_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/hash_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/http_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/idle_countdown.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/logger.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/mount_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/name_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/package_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/proxy_support.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/shell_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_utils/time_utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_vendor/__init__.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_vendor/tblib.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_vendor/version.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_watcher.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/_workspace.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/app.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/app.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/billing.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/billing.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/builder/2023.12.txt +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/builder/2024.04.txt +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/builder/2024.10.txt +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/builder/2025.06.txt +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/builder/README.md +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/builder/base-images.json +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/call_graph.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/__init__.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/_download.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/_help.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/_logs.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/_stats.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/_traceback.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/app.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/billing.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/changelog.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/config.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/container.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/curl.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/dashboard.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/dict.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/endpoint.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/entry_point.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/environment.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/image.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/import_refs.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/logo.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/network_file_system.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/profile.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/queues.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/run.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/secret.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/selector.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/shell.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/skills.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/token.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/utils.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/volume.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cli/workspace.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/client.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cls.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cls.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cluster.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/cluster.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/container_process.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/container_process.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/dict.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/dict.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/environments.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/environments.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/exception.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/experimental/__init__.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/experimental/_flash_container_entry.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/experimental/flash.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/experimental/flash.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/experimental/flash_server.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/experimental/flash_server.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/experimental/ipython.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/file_pattern_matcher.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/functions.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/functions.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/image.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/image.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/io_streams.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/io_streams.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/mount.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/mount.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/network_file_system.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/network_file_system.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/object.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/output.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/parallel_map.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/parallel_map.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/partial_function.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/partial_function.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/proxy.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/proxy.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/py.typed +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/queue.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/queue.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/retries.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/runner.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/runner.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/running_app.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/sandbox_fs.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/sandbox_fs.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/schedule.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/scheduler_placement.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/secret.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/secret.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/server.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/server.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/serving.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/serving.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/snapshot.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/snapshot.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/stream_type.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/token_flow.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/token_flow.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/workspace.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal/workspace.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal.egg-info/top_level.txt +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_docs/__init__.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_docs/mdmd/types.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_docs/reference_intro.md +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_proto/__init__.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_proto/api_grpc.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_proto/py.typed +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/modal_version/__main__.py +0 -0
- {modal-1.6.1 → modal-1.6.1.dev0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: modal
|
|
3
|
-
Version: 1.6.1
|
|
3
|
+
Version: 1.6.1.dev0
|
|
4
4
|
Summary: Python client library for Modal
|
|
5
5
|
Author-email: Modal Labs <support@modal.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -21,9 +21,9 @@ Requires-Dist: certifi
|
|
|
21
21
|
Requires-Dist: click~=8.1
|
|
22
22
|
Requires-Dist: grpclib<0.4.10,>=0.4.7; python_version < "3.14"
|
|
23
23
|
Requires-Dist: grpclib<0.4.10,>=0.4.9; python_version >= "3.14"
|
|
24
|
-
Requires-Dist: protobuf!=4.24.0,<
|
|
24
|
+
Requires-Dist: protobuf!=4.24.0,<7.0,>=3.19
|
|
25
25
|
Requires-Dist: rich>=12.0.0
|
|
26
|
-
Requires-Dist: synchronicity~=0.12.
|
|
26
|
+
Requires-Dist: synchronicity~=0.12.5
|
|
27
27
|
Requires-Dist: toml
|
|
28
28
|
Requires-Dist: types-certifi
|
|
29
29
|
Requires-Dist: types-toml
|
|
@@ -22,7 +22,7 @@ from ._utils.time_utils import is_utc_month_aligned, parse_billing_cycle
|
|
|
22
22
|
from .client import _Client
|
|
23
23
|
from .config import config, logger
|
|
24
24
|
from .exception import InvalidError, WorkspaceManagementError
|
|
25
|
-
from .types import
|
|
25
|
+
from .types import BillingReportItem, EnvironmentBillingSummary
|
|
26
26
|
|
|
27
27
|
if TYPE_CHECKING:
|
|
28
28
|
import modal
|
|
@@ -346,7 +346,6 @@ class _EnvironmentAppsManager:
|
|
|
346
346
|
self._environment.name,
|
|
347
347
|
self._environment.client,
|
|
348
348
|
description=item.description or None,
|
|
349
|
-
info=AppInfo._from_proto(item.metadata, item.app_id),
|
|
350
349
|
)
|
|
351
350
|
for item in response.apps
|
|
352
351
|
if item.state not in stopped_app_states
|
|
@@ -13,7 +13,9 @@ from .manager import OutputManager
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def _get_annotation_for_web_url(url_info: api_pb2.WebUrlInfo) -> str:
|
|
16
|
-
if url_info.
|
|
16
|
+
if url_info.truncated:
|
|
17
|
+
suffix = " [grey70](label truncated)[/grey70]"
|
|
18
|
+
elif url_info.label_stolen:
|
|
17
19
|
suffix = " [grey70](label stolen)[/grey70]"
|
|
18
20
|
else:
|
|
19
21
|
suffix = ""
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
# Copyright Modal Labs 2025
|
|
2
|
-
import asyncio
|
|
3
2
|
import inspect
|
|
4
3
|
import json
|
|
5
|
-
import time
|
|
6
4
|
import typing
|
|
7
|
-
import uuid
|
|
8
5
|
from datetime import datetime, timedelta, timezone
|
|
9
6
|
|
|
10
7
|
from typing_extensions import Self
|
|
@@ -480,8 +477,9 @@ class _Server:
|
|
|
480
477
|
return ServerStats._from_proto(stats)
|
|
481
478
|
|
|
482
479
|
|
|
480
|
+
@retry(n_attempts=5, base_delay=0.5, attempt_timeout=65, total_timeout=200)
|
|
483
481
|
async def _post_session_control(url: str, headers: dict[str, str]) -> tuple[int, str, str]:
|
|
484
|
-
"""POST to a sticky session control endpoint,
|
|
482
|
+
"""POST to a sticky session control endpoint, retrying connection errors and 5xx. Returns (status, reason, body)."""
|
|
485
483
|
async with ClientSessionRegistry.get_session().post(url, headers=headers) as resp:
|
|
486
484
|
body = await resp.text()
|
|
487
485
|
if resp.status >= 400:
|
|
@@ -491,28 +489,6 @@ async def _post_session_control(url: str, headers: dict[str, str]) -> tuple[int,
|
|
|
491
489
|
return resp.status, resp.reason or "", body
|
|
492
490
|
|
|
493
491
|
|
|
494
|
-
async def _post_session_start(base_url: str, fn: _Function, idle_timeout: int) -> tuple[int, str, str]:
|
|
495
|
-
idempotency_key = str(uuid.uuid4())
|
|
496
|
-
start_timestamp = str(time.time())
|
|
497
|
-
|
|
498
|
-
@retry(n_attempts=5, base_delay=0.5, attempt_timeout=None, total_timeout=1515)
|
|
499
|
-
async def attempt() -> tuple[int, str, str]:
|
|
500
|
-
headers = {
|
|
501
|
-
"Modal-Authorization": f"Bearer {await fn._get_flash_auth_token()}",
|
|
502
|
-
"x-idempotency-key": idempotency_key,
|
|
503
|
-
"x-modal-timestamp": start_timestamp,
|
|
504
|
-
"x-modal-server-session-idle-timeout": str(idle_timeout),
|
|
505
|
-
}
|
|
506
|
-
return await _post_session_control(f"{base_url}/_modal/sessions/start", headers)
|
|
507
|
-
|
|
508
|
-
return await attempt()
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
@retry(n_attempts=3, base_delay=0.5, attempt_timeout=None, total_timeout=60)
|
|
512
|
-
async def _post_session_terminate(base_url: str, headers: dict[str, str]) -> tuple[int, str, str]:
|
|
513
|
-
return await _post_session_control(f"{base_url}/_modal/sessions/terminate", headers)
|
|
514
|
-
|
|
515
|
-
|
|
516
492
|
class _ServerSessionsManager:
|
|
517
493
|
"""mdmd:namespace"""
|
|
518
494
|
|
|
@@ -531,10 +507,6 @@ class _ServerSessionsManager:
|
|
|
531
507
|
session has had no connections for `idle_timeout` seconds or is terminated. A container won't be scaled down
|
|
532
508
|
for as long as it holds a live session.
|
|
533
509
|
|
|
534
|
-
If no container has room for the session, the call waits for additional capacity. It will block for
|
|
535
|
-
up to 25 minutes before giving up. To control the wait per call, use the HTTP API and apply your own retry
|
|
536
|
-
policy.
|
|
537
|
-
|
|
538
510
|
Args:
|
|
539
511
|
idle_timeout: Seconds without an in-flight request before the session ends.
|
|
540
512
|
|
|
@@ -559,10 +531,13 @@ class _ServerSessionsManager:
|
|
|
559
531
|
self._validate()
|
|
560
532
|
assert url is not None, "Server has no URL."
|
|
561
533
|
|
|
534
|
+
headers = {
|
|
535
|
+
"Modal-Authorization": f"Bearer {await fn._get_flash_auth_token()}",
|
|
536
|
+
"x-modal-server-session-idle-timeout": str(idle_timeout),
|
|
537
|
+
}
|
|
538
|
+
|
|
562
539
|
try:
|
|
563
|
-
status, reason, body = await
|
|
564
|
-
except asyncio.TimeoutError:
|
|
565
|
-
raise asyncio.TimeoutError("Failed to start session: timed out") from None
|
|
540
|
+
status, reason, body = await _post_session_control(f"{url}/_modal/sessions/start", headers)
|
|
566
541
|
except ServiceError as exc:
|
|
567
542
|
raise ExecutionError(f"Failed to start session: {exc}") from None
|
|
568
543
|
if status >= 400:
|
|
@@ -601,7 +576,7 @@ class _ServerSessionsManager:
|
|
|
601
576
|
"x-modal-server-session-token": token,
|
|
602
577
|
}
|
|
603
578
|
try:
|
|
604
|
-
status, reason, _body = await
|
|
579
|
+
status, reason, _body = await _post_session_control(f"{url}/_modal/sessions/terminate", headers)
|
|
605
580
|
except ServiceError as exc:
|
|
606
581
|
raise ExecutionError(f"Failed to terminate session: {exc}") from None
|
|
607
582
|
if status == 404:
|
|
@@ -272,14 +272,9 @@ class _Server:
|
|
|
272
272
|
...
|
|
273
273
|
|
|
274
274
|
async def _post_session_control(url: str, headers: dict[str, str]) -> tuple[int, str, str]:
|
|
275
|
-
"""POST to a sticky session control endpoint,
|
|
275
|
+
"""POST to a sticky session control endpoint, retrying connection errors and 5xx. Returns (status, reason, body)."""
|
|
276
276
|
...
|
|
277
277
|
|
|
278
|
-
async def _post_session_start(
|
|
279
|
-
base_url: str, fn: modal._functions._Function, idle_timeout: int
|
|
280
|
-
) -> tuple[int, str, str]: ...
|
|
281
|
-
async def _post_session_terminate(base_url: str, headers: dict[str, str]) -> tuple[int, str, str]: ...
|
|
282
|
-
|
|
283
278
|
class _ServerSessionsManager:
|
|
284
279
|
"""mdmd:namespace"""
|
|
285
280
|
def __init__(self, server: _Server):
|
|
@@ -294,10 +289,6 @@ class _ServerSessionsManager:
|
|
|
294
289
|
session has had no connections for `idle_timeout` seconds or is terminated. A container won't be scaled down
|
|
295
290
|
for as long as it holds a live session.
|
|
296
291
|
|
|
297
|
-
If no container has room for the session, the call waits for additional capacity. It will block for
|
|
298
|
-
up to 25 minutes before giving up. To control the wait per call, use the HTTP API and apply your own retry
|
|
299
|
-
policy.
|
|
300
|
-
|
|
301
292
|
Args:
|
|
302
293
|
idle_timeout: Seconds without an in-flight request before the session ends.
|
|
303
294
|
|
|
@@ -351,10 +342,6 @@ class ServerSessionsManager:
|
|
|
351
342
|
session has had no connections for `idle_timeout` seconds or is terminated. A container won't be scaled down
|
|
352
343
|
for as long as it holds a live session.
|
|
353
344
|
|
|
354
|
-
If no container has room for the session, the call waits for additional capacity. It will block for
|
|
355
|
-
up to 25 minutes before giving up. To control the wait per call, use the HTTP API and apply your own retry
|
|
356
|
-
policy.
|
|
357
|
-
|
|
358
345
|
Args:
|
|
359
346
|
idle_timeout: Seconds without an in-flight request before the session ends.
|
|
360
347
|
|
|
@@ -380,10 +367,6 @@ class ServerSessionsManager:
|
|
|
380
367
|
session has had no connections for `idle_timeout` seconds or is terminated. A container won't be scaled down
|
|
381
368
|
for as long as it holds a live session.
|
|
382
369
|
|
|
383
|
-
If no container has room for the session, the call waits for additional capacity. It will block for
|
|
384
|
-
up to 25 minutes before giving up. To control the wait per call, use the HTTP API and apply your own retry
|
|
385
|
-
policy.
|
|
386
|
-
|
|
387
370
|
Args:
|
|
388
371
|
idle_timeout: Seconds without an in-flight request before the session ends.
|
|
389
372
|
|
|
@@ -307,19 +307,20 @@ def create_channel_config(*, sustained_keepalive: bool = False) -> grpclib.confi
|
|
|
307
307
|
HTTP/2 keepalive probes keep idle transports warm through stateful
|
|
308
308
|
middleboxes and surface dead connections before retries reuse them.
|
|
309
309
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
310
|
+
`sustained_keepalive` clears the two grpclib defaults such that a probe
|
|
311
|
+
actually goes out every `_keepalive_time`, for as long as the connection is
|
|
312
|
+
open.
|
|
313
313
|
"""
|
|
314
|
-
ping_throttle_overrides: dict[str, Any] = {
|
|
315
|
-
# Default 300s floor between probes, applied regardless of data
|
|
316
|
-
# despite the name, so it has to stay under `_keepalive_time`.
|
|
317
|
-
"_http2_min_sent_ping_interval_without_data": GRPC_KEEPALIVE_TIME_SECS / 2,
|
|
318
|
-
}
|
|
314
|
+
ping_throttle_overrides: dict[str, Any] = {}
|
|
319
315
|
if sustained_keepalive:
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
316
|
+
ping_throttle_overrides = {
|
|
317
|
+
# Default 2: probing stops after two probes with no request sent in
|
|
318
|
+
# between. Requests reset the count, acks don't. 0 = no cap.
|
|
319
|
+
"_http2_max_pings_without_data": 0,
|
|
320
|
+
# Default 300s floor between probes, applied regardless of data
|
|
321
|
+
# despite the name, so it has to stay under `_keepalive_time`.
|
|
322
|
+
"_http2_min_sent_ping_interval_without_data": GRPC_KEEPALIVE_TIME_SECS / 2,
|
|
323
|
+
}
|
|
323
324
|
|
|
324
325
|
return grpclib.config.Configuration(
|
|
325
326
|
_keepalive_time=GRPC_KEEPALIVE_TIME_SECS,
|
|
@@ -226,7 +226,6 @@ async def fetch_command_router_access_v2(
|
|
|
226
226
|
*,
|
|
227
227
|
sandbox_id: str | None = None,
|
|
228
228
|
task_id: str | None = None,
|
|
229
|
-
sandbox_token: str | None = None,
|
|
230
229
|
) -> api_pb2.SandboxGetCommandRouterAccessResponse:
|
|
231
230
|
"""Fetch direct command router access info from Modal server for a V2 sandbox."""
|
|
232
231
|
if sandbox_id is not None:
|
|
@@ -237,10 +236,10 @@ async def fetch_command_router_access_v2(
|
|
|
237
236
|
raise ValueError("Either sandbox_id or task_id must be provided")
|
|
238
237
|
assert server_client._auth_token_manager
|
|
239
238
|
auth_token = await server_client._auth_token_manager.get_token()
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
metadata
|
|
243
|
-
|
|
239
|
+
return await server_client._stub.SandboxGetCommandRouterAccess(
|
|
240
|
+
request,
|
|
241
|
+
metadata=[("x-modal-auth-token", auth_token)],
|
|
242
|
+
)
|
|
244
243
|
|
|
245
244
|
|
|
246
245
|
def _finalize_channel(loop, channel):
|
|
@@ -268,7 +267,6 @@ class TaskCommandRouterClient:
|
|
|
268
267
|
jwt: str,
|
|
269
268
|
*,
|
|
270
269
|
sandbox_id: str | None = None,
|
|
271
|
-
sandbox_token: str | None = None,
|
|
272
270
|
) -> "TaskCommandRouterClient":
|
|
273
271
|
"""Build a connected client from a jwt and url."""
|
|
274
272
|
o = urllib.parse.urlparse(url)
|
|
@@ -317,17 +315,7 @@ class TaskCommandRouterClient:
|
|
|
317
315
|
loop = asyncio.get_running_loop()
|
|
318
316
|
jwt_refresh_lock = asyncio.Lock()
|
|
319
317
|
|
|
320
|
-
client = cls(
|
|
321
|
-
server_client,
|
|
322
|
-
task_id,
|
|
323
|
-
url,
|
|
324
|
-
jwt,
|
|
325
|
-
channel,
|
|
326
|
-
loop,
|
|
327
|
-
jwt_refresh_lock,
|
|
328
|
-
sandbox_id=sandbox_id,
|
|
329
|
-
sandbox_token=sandbox_token,
|
|
330
|
-
)
|
|
318
|
+
client = cls(server_client, task_id, url, jwt, channel, loop, jwt_refresh_lock, sandbox_id=sandbox_id)
|
|
331
319
|
# An unused client releases its connection too.
|
|
332
320
|
client._arm_idle_release()
|
|
333
321
|
return client
|
|
@@ -349,8 +337,6 @@ class TaskCommandRouterClient:
|
|
|
349
337
|
sandbox_id: str,
|
|
350
338
|
task_id: str,
|
|
351
339
|
access: api_pb2.CommandRouterAccess | None = None,
|
|
352
|
-
*,
|
|
353
|
-
sandbox_token: str | None = None,
|
|
354
340
|
) -> "TaskCommandRouterClient":
|
|
355
341
|
"""Initialize a TaskCommandRouterClient for a V2 sandbox.
|
|
356
342
|
|
|
@@ -362,12 +348,10 @@ class TaskCommandRouterClient:
|
|
|
362
348
|
if access is not None:
|
|
363
349
|
url, jwt = access.url, access.jwt
|
|
364
350
|
else:
|
|
365
|
-
resp = await fetch_command_router_access_v2(
|
|
366
|
-
server_client, sandbox_id=sandbox_id, sandbox_token=sandbox_token
|
|
367
|
-
)
|
|
351
|
+
resp = await fetch_command_router_access_v2(server_client, sandbox_id=sandbox_id)
|
|
368
352
|
url, jwt = resp.url, resp.jwt
|
|
369
353
|
logger.debug(f"Using command router access for sandbox {sandbox_id}")
|
|
370
|
-
return await cls._connect(server_client, task_id, url, jwt, sandbox_id=sandbox_id
|
|
354
|
+
return await cls._connect(server_client, task_id, url, jwt, sandbox_id=sandbox_id)
|
|
371
355
|
|
|
372
356
|
@classmethod
|
|
373
357
|
async def init_v2_by_task_id(
|
|
@@ -391,7 +375,6 @@ class TaskCommandRouterClient:
|
|
|
391
375
|
jwt_refresh_lock: asyncio.Lock,
|
|
392
376
|
*,
|
|
393
377
|
sandbox_id: str | None = None,
|
|
394
|
-
sandbox_token: str | None = None,
|
|
395
378
|
stream_stdio_retry_delay_secs: float = 0.01,
|
|
396
379
|
stream_stdio_retry_delay_factor: float = 2,
|
|
397
380
|
stream_stdio_max_retries: int = 10,
|
|
@@ -405,7 +388,6 @@ class TaskCommandRouterClient:
|
|
|
405
388
|
self._server_client = server_client
|
|
406
389
|
self._task_id = task_id
|
|
407
390
|
self._sandbox_id = sandbox_id
|
|
408
|
-
self._sandbox_token = sandbox_token
|
|
409
391
|
self._server_url = server_url
|
|
410
392
|
self._jwt = jwt
|
|
411
393
|
self._channel = channel
|
|
@@ -920,10 +902,7 @@ class TaskCommandRouterClient:
|
|
|
920
902
|
if self._is_v2_sandbox:
|
|
921
903
|
logger.debug(f"Refreshing JWT for V2 exec with task ID {self._task_id}")
|
|
922
904
|
v2_resp = await fetch_command_router_access_v2(
|
|
923
|
-
self._server_client,
|
|
924
|
-
sandbox_id=self._sandbox_id,
|
|
925
|
-
task_id=self._task_id,
|
|
926
|
-
sandbox_token=self._sandbox_token,
|
|
905
|
+
self._server_client, sandbox_id=self._sandbox_id, task_id=self._task_id
|
|
927
906
|
)
|
|
928
907
|
logger.debug(f"Finished refreshing JWT for V2 exec with task ID {self._task_id}")
|
|
929
908
|
jwt, url = v2_resp.jwt, v2_resp.url
|
|
@@ -112,7 +112,6 @@ def _time_range_stats_json(response: api_pb2.FunctionGetTimeRangeStatsResponse)
|
|
|
112
112
|
"input_percentile_stats": _distribution_map_json(
|
|
113
113
|
cast(dict[str, api_pb2.StatsPercentileDistribution], response.input_percentile_stats)
|
|
114
114
|
),
|
|
115
|
-
"container_total_count": response.container_total_count,
|
|
116
115
|
"container_started_count": response.container_started_count,
|
|
117
116
|
"container_error_count": response.container_error_count,
|
|
118
117
|
"container_creating_at_end_count": response.container_creating_at_end_count,
|
|
@@ -795,10 +794,9 @@ async def stats(
|
|
|
795
794
|
|
|
796
795
|
output.print("")
|
|
797
796
|
container_count = resp.container_started_count + resp.container_error_count
|
|
798
|
-
total_containers = resp.container_total_count
|
|
799
797
|
container_heading = Text("Containers", style=stats_style(STATS_SECTION_STYLE, use_color))
|
|
800
798
|
container_heading.append(" " * (46 - len("Containers")))
|
|
801
|
-
container_heading.append(f"{
|
|
799
|
+
container_heading.append(f"{container_count:,} total (")
|
|
802
800
|
container_heading.append(
|
|
803
801
|
f"{resp.container_creating_at_end_count:,} creating",
|
|
804
802
|
style=progress_style(resp.container_creating_at_end_count, use_color),
|
|
@@ -808,12 +806,12 @@ async def stats(
|
|
|
808
806
|
|
|
809
807
|
container_counts = Text(" ")
|
|
810
808
|
container_counts.append(
|
|
811
|
-
|
|
809
|
+
_count_with_percentage(resp.container_started_count, container_count, "started"),
|
|
812
810
|
style=success_style(resp.container_started_count, container_count, use_color),
|
|
813
811
|
)
|
|
814
812
|
container_counts.append(" · ")
|
|
815
813
|
container_counts.append(
|
|
816
|
-
|
|
814
|
+
_count_with_percentage(resp.container_error_count, container_count, "errored"),
|
|
817
815
|
style=problem_style(resp.container_error_count, container_count, use_color),
|
|
818
816
|
)
|
|
819
817
|
output.print(container_counts)
|
|
@@ -33,6 +33,7 @@ from ._stats import (
|
|
|
33
33
|
STATS_METADATA_STYLE,
|
|
34
34
|
STATS_PROBLEM_STYLE,
|
|
35
35
|
STATS_SECTION_STYLE,
|
|
36
|
+
_count_with_percentage,
|
|
36
37
|
_distribution_map_json,
|
|
37
38
|
_metric_rows,
|
|
38
39
|
_percentile_table,
|
|
@@ -559,7 +560,6 @@ def _stats_json(
|
|
|
559
560
|
"request_rate_per_second": history.request_rate_per_second,
|
|
560
561
|
"container_started_count": history.container_started_count,
|
|
561
562
|
"container_error_count": history.container_error_count,
|
|
562
|
-
"container_total_count": history.container_total_count,
|
|
563
563
|
"container_creating_at_end_count": history.container_creating_at_end_count,
|
|
564
564
|
"request_percentile_stats": _distribution_map_json(
|
|
565
565
|
cast(dict[str, api_pb2.StatsPercentileDistribution], history.request_percentile_stats)
|
|
@@ -754,10 +754,9 @@ async def _run_server_stats(
|
|
|
754
754
|
|
|
755
755
|
output.print("")
|
|
756
756
|
container_count = history.container_started_count + history.container_error_count
|
|
757
|
-
container_total_count = history.container_total_count
|
|
758
757
|
container_heading = Text("Containers", style=stats_style(STATS_SECTION_STYLE, use_color))
|
|
759
758
|
container_heading.append(" " * (46 - len("Containers")))
|
|
760
|
-
container_heading.append(f"{
|
|
759
|
+
container_heading.append(f"{container_count:,} total (")
|
|
761
760
|
container_heading.append(
|
|
762
761
|
f"{history.container_creating_at_end_count:,} creating",
|
|
763
762
|
style=progress_style(history.container_creating_at_end_count, use_color),
|
|
@@ -767,12 +766,12 @@ async def _run_server_stats(
|
|
|
767
766
|
|
|
768
767
|
container_counts = Text(" ")
|
|
769
768
|
container_counts.append(
|
|
770
|
-
|
|
769
|
+
_count_with_percentage(history.container_started_count, container_count, "started"),
|
|
771
770
|
style=success_style(history.container_started_count, container_count, use_color),
|
|
772
771
|
)
|
|
773
772
|
container_counts.append(" · ")
|
|
774
773
|
container_counts.append(
|
|
775
|
-
|
|
774
|
+
_count_with_percentage(history.container_error_count, container_count, "errored"),
|
|
776
775
|
style=problem_style(history.container_error_count, container_count, use_color),
|
|
777
776
|
)
|
|
778
777
|
output.print(container_counts)
|
|
@@ -80,7 +80,7 @@ class _Client:
|
|
|
80
80
|
server_url: str,
|
|
81
81
|
client_type: int,
|
|
82
82
|
credentials: typing.Optional[tuple[str, str]],
|
|
83
|
-
version: str = "1.6.1",
|
|
83
|
+
version: str = "1.6.1.dev0",
|
|
84
84
|
*,
|
|
85
85
|
oauth_credentials: typing.Optional[_OAuthCredentials] = None,
|
|
86
86
|
):
|
|
@@ -290,7 +290,7 @@ class Client:
|
|
|
290
290
|
server_url: str,
|
|
291
291
|
client_type: int,
|
|
292
292
|
credentials: typing.Optional[tuple[str, str]],
|
|
293
|
-
version: str = "1.6.1",
|
|
293
|
+
version: str = "1.6.1.dev0",
|
|
294
294
|
*,
|
|
295
295
|
oauth_credentials: typing.Optional[_OAuthCredentials] = None,
|
|
296
296
|
):
|
|
@@ -134,9 +134,13 @@ def _agent_environment() -> str | None:
|
|
|
134
134
|
|
|
135
135
|
Returns the agent name if detected, or None otherwise.
|
|
136
136
|
|
|
137
|
-
Checks
|
|
138
|
-
|
|
137
|
+
Checks the emerging `AGENT` standard variable first, then falls back to
|
|
138
|
+
tool-specific environment variables used by known agent harnesses.
|
|
139
139
|
"""
|
|
140
|
+
# Emerging standard: AGENT=<name>
|
|
141
|
+
if agent := os.environ.get("AGENT"):
|
|
142
|
+
return agent
|
|
143
|
+
|
|
140
144
|
# Tool-specific environment variables
|
|
141
145
|
_TOOL_SPECIFIC_ENV_VARS: list[tuple[str, str]] = [
|
|
142
146
|
("CLAUDECODE", "claude-code"),
|
|
@@ -148,23 +152,11 @@ def _agent_environment() -> str | None:
|
|
|
148
152
|
("OPENCODE_CLIENT", "opencode"),
|
|
149
153
|
("GOOSE_TERMINAL", "goose"), # honk
|
|
150
154
|
("TRAE_AI_SHELL_ID", "trae"),
|
|
151
|
-
("PI_CODING_AGENT", "pi"),
|
|
152
|
-
("COPILOT_AGENT_SESSION_ID", "copilot"),
|
|
153
|
-
("ANTIGRAVITY_AGENT", "antigravity"),
|
|
154
|
-
("JUNIE_SHIM_PATH", "junie"),
|
|
155
155
|
]
|
|
156
156
|
for env_var, agent_name in _TOOL_SPECIFIC_ENV_VARS:
|
|
157
157
|
if os.environ.get(env_var):
|
|
158
158
|
return agent_name
|
|
159
159
|
|
|
160
|
-
# Emerging standards, checked last because neither value is normalized.
|
|
161
|
-
# `AGENT` may be a bare `1` rather than a name (opencode), and `AI_AGENT`
|
|
162
|
-
# may embed a version or suffix (e.g. `claude-code_2-1-268_agent`).
|
|
163
|
-
if agent := os.environ.get("AGENT"):
|
|
164
|
-
return agent
|
|
165
|
-
if agent := os.environ.get("AI_AGENT"):
|
|
166
|
-
return agent
|
|
167
|
-
|
|
168
160
|
return None
|
|
169
161
|
|
|
170
162
|
|
|
@@ -430,9 +422,6 @@ class Config:
|
|
|
430
422
|
|
|
431
423
|
Returns:
|
|
432
424
|
The transformed configuration value (type depends on the setting).
|
|
433
|
-
|
|
434
|
-
Raises:
|
|
435
|
-
KeyError: If ``key`` is not the name of a setting.
|
|
436
425
|
"""
|
|
437
426
|
if profile is None:
|
|
438
427
|
profile = _profile
|
|
@@ -483,7 +472,6 @@ class Config:
|
|
|
483
472
|
return repr(self.to_dict())
|
|
484
473
|
|
|
485
474
|
def to_dict(self, *, include_internal: bool = False):
|
|
486
|
-
"""Return every public setting along with its current value."""
|
|
487
475
|
return {
|
|
488
476
|
key: self.get(key) for key, setting in sorted(_SETTINGS.items()) if include_internal or not setting.internal
|
|
489
477
|
}
|
|
@@ -491,16 +479,6 @@ class Config:
|
|
|
491
479
|
|
|
492
480
|
config = Config()
|
|
493
481
|
|
|
494
|
-
__doc__config = """The process-wide `Config` instance the Modal client reads its settings from.
|
|
495
|
-
|
|
496
|
-
```python
|
|
497
|
-
from modal.config import config
|
|
498
|
-
|
|
499
|
-
log_level = config.get("loglevel")
|
|
500
|
-
```
|
|
501
|
-
|
|
502
|
-
"""
|
|
503
|
-
|
|
504
482
|
# Logging
|
|
505
483
|
|
|
506
484
|
logger = logging.getLogger("modal-client")
|