modal 1.5.6.dev27__tar.gz → 1.5.6.dev28__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.5.6.dev27 → modal-1.5.6.dev28}/PKG-INFO +1 -1
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_partial_function.py +2 -58
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_server.py +20 -5
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_server.pyi +12 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/app.py +5 -21
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/app.pyi +12 -12
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/app.py +51 -16
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/function.py +343 -8
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/server.py +315 -6
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/utils.py +4 -10
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/client.pyi +2 -2
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/partial_function.pyi +7 -19
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/sandbox.py +64 -7
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/sandbox.pyi +24 -3
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/secret.py +5 -2
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/secret.pyi +13 -2
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/server.pyi +12 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/types.py +28 -1
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_docs/gen_reference_docs.py +10 -2
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_docs/mdmd/mdmd.py +82 -8
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_proto/api_pb2.py +1216 -1218
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_proto/api_pb2.pyi +6 -29
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_proto/task_command_router_pb2.py +96 -96
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_proto/task_command_router_pb2.pyi +11 -2
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_version/__init__.py +1 -1
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/LICENSE +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/README.md +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/__init__.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/__main__.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_billing.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_cluster.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_cluster.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_container_entrypoint.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_environments.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_function_variants.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_functions.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_grpc_client.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_image.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_ipython.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_load_context.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_location.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_logs.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_logs_manager.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_logs_manager.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_object.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_outbound_policy.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_outbound_policy.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_output/__init__.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_output/manager.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_output/pty.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_output/rich.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_output/status.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_resolver.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_resources.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_runtime/__init__.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_runtime/asgi.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_runtime/execution_context.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_runtime/task_lifecycle_manager.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_runtime/telemetry.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_serialization.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_supports_logs.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_traceback.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_tunnel.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_tunnel.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_type_manager.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/__init__.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/app_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/async_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/blob_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/browser_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/curl_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/deprecation.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/display_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/docker_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/function_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/git_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/hash_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/http_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/idle_countdown.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/logger.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/mount_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/name_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/package_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/proxy_support.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/shell_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_utils/time_utils.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_vendor/__init__.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_vendor/tblib.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_vendor/version.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_watcher.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/_workspace.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/billing.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/billing.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/builder/2023.12.txt +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/builder/2024.04.txt +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/builder/2024.10.txt +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/builder/2025.06.txt +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/builder/README.md +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/builder/base-images.json +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/call_graph.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/__init__.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/_download.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/_help.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/_logs.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/_stats.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/_traceback.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/billing.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/changelog.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/config.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/container.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/curl.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/dashboard.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/dict.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/endpoint.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/entry_point.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/environment.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/image.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/import_refs.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/logo.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/network_file_system.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/profile.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/queues.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/run.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/secret.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/selector.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/shell.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/skills.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/token.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/volume.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cli/workspace.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/client.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cls.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cls.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cluster.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/cluster.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/config.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/container_process.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/container_process.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/dict.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/dict.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/environments.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/environments.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/exception.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/experimental/__init__.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/experimental/_flash_container_entry.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/experimental/flash.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/experimental/flash.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/experimental/flash_server.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/experimental/flash_server.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/experimental/ipython.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/file_pattern_matcher.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/functions.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/functions.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/image.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/image.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/io_streams.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/io_streams.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/mount.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/mount.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/network_file_system.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/network_file_system.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/object.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/object.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/output.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/parallel_map.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/parallel_map.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/partial_function.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/proxy.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/proxy.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/py.typed +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/queue.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/queue.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/retries.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/runner.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/runner.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/running_app.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/sandbox_fs.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/sandbox_fs.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/schedule.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/scheduler_placement.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/server.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/serving.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/serving.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/skills/modal/SKILL.md +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/snapshot.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/snapshot.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/stream_type.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/token_flow.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/token_flow.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/volume.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/volume.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/workspace.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal/workspace.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal.egg-info/requires.txt +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal.egg-info/top_level.txt +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_docs/__init__.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_docs/mdmd/types.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_docs/reference_intro.md +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_proto/__init__.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_proto/api_grpc.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_proto/py.typed +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/modal_version/__main__.py +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/pyproject.toml +0 -0
- {modal-1.5.6.dev27 → modal-1.5.6.dev28}/setup.cfg +0 -0
|
@@ -282,7 +282,6 @@ class _MethodDecoratorType:
|
|
|
282
282
|
|
|
283
283
|
# TODO(elias): fix support for coroutine type unwrapping for methods (static typing)
|
|
284
284
|
def _method(
|
|
285
|
-
_warn_parentheses_missing=None, # mdmd:line-hidden
|
|
286
285
|
*,
|
|
287
286
|
# Set this to True if it's a non-generator function returning
|
|
288
287
|
# a [sync/async] generator object
|
|
@@ -300,10 +299,6 @@ def _method(
|
|
|
300
299
|
...
|
|
301
300
|
```
|
|
302
301
|
"""
|
|
303
|
-
if _warn_parentheses_missing is not None:
|
|
304
|
-
raise InvalidError(
|
|
305
|
-
"Positional arguments are not allowed. Did you forget parentheses? Suggestion: `@modal.method()`."
|
|
306
|
-
)
|
|
307
302
|
|
|
308
303
|
def wrapper(obj: Callable[..., Any] | _PartialFunction) -> _PartialFunction:
|
|
309
304
|
flags = _PartialFunctionFlags.CALLABLE_INTERFACE
|
|
@@ -336,7 +331,6 @@ def _parse_custom_domains(custom_domains: Iterable[str] | None = None) -> list[a
|
|
|
336
331
|
|
|
337
332
|
|
|
338
333
|
def _fastapi_endpoint(
|
|
339
|
-
_warn_parentheses_missing=None, # mdmd:line-hidden
|
|
340
334
|
*,
|
|
341
335
|
method: str = "GET", # REST method for the created endpoint.
|
|
342
336
|
label: str | None = None, # Label for created endpoint. Final subdomain will be <workspace>--<label>.modal.run.
|
|
@@ -362,15 +356,6 @@ def _fastapi_endpoint(
|
|
|
362
356
|
|
|
363
357
|
*Added in v0.73.82*: This function replaces the deprecated `@web_endpoint` decorator.
|
|
364
358
|
"""
|
|
365
|
-
if isinstance(_warn_parentheses_missing, str):
|
|
366
|
-
# Probably passing the method string as a positional argument.
|
|
367
|
-
raise InvalidError(
|
|
368
|
-
f'Positional arguments are not allowed. Suggestion: `@modal.fastapi_endpoint(method="{method}")`.'
|
|
369
|
-
)
|
|
370
|
-
elif _warn_parentheses_missing is not None:
|
|
371
|
-
raise InvalidError(
|
|
372
|
-
"Positional arguments are not allowed. Did you forget parentheses? Suggestion: `@modal.fastapi_endpoint()`."
|
|
373
|
-
)
|
|
374
359
|
|
|
375
360
|
webhook_config = api_pb2.WebhookConfig(
|
|
376
361
|
type=api_pb2.WEBHOOK_TYPE_FUNCTION,
|
|
@@ -400,7 +385,6 @@ def _fastapi_endpoint(
|
|
|
400
385
|
|
|
401
386
|
|
|
402
387
|
def _web_endpoint(
|
|
403
|
-
_warn_parentheses_missing=None, # mdmd:line-hidden
|
|
404
388
|
*args,
|
|
405
389
|
**kwargs,
|
|
406
390
|
) -> None:
|
|
@@ -413,7 +397,6 @@ def _web_endpoint(
|
|
|
413
397
|
|
|
414
398
|
|
|
415
399
|
def _asgi_app(
|
|
416
|
-
_warn_parentheses_missing=None, # mdmd:line-hidden
|
|
417
400
|
*,
|
|
418
401
|
label: str | None = None, # Label for created endpoint. Final subdomain will be <workspace>--<label>.modal.run.
|
|
419
402
|
custom_domains: Iterable[str] | None = None, # Deploy this endpoint on a custom domain.
|
|
@@ -437,12 +420,6 @@ def _asgi_app(
|
|
|
437
420
|
To learn how to use Modal with popular web frameworks, see the
|
|
438
421
|
[guide on Web Functions](https://modal.com/docs/guide/webhooks).
|
|
439
422
|
"""
|
|
440
|
-
if isinstance(_warn_parentheses_missing, str):
|
|
441
|
-
raise InvalidError(f'Positional arguments are not allowed. Suggestion: `@modal.asgi_app(label="{label}")`.')
|
|
442
|
-
elif _warn_parentheses_missing is not None:
|
|
443
|
-
raise InvalidError(
|
|
444
|
-
"Positional arguments are not allowed. Did you forget parentheses? Suggestion: `@modal.asgi_app()`."
|
|
445
|
-
)
|
|
446
423
|
|
|
447
424
|
webhook_config = api_pb2.WebhookConfig(
|
|
448
425
|
type=api_pb2.WEBHOOK_TYPE_ASGI_APP,
|
|
@@ -468,7 +445,6 @@ def _asgi_app(
|
|
|
468
445
|
|
|
469
446
|
|
|
470
447
|
def _wsgi_app(
|
|
471
|
-
_warn_parentheses_missing=None, # mdmd:line-hidden
|
|
472
448
|
*,
|
|
473
449
|
label: str | None = None, # Label for created endpoint. Final subdomain will be <workspace>--<label>.modal.run.
|
|
474
450
|
custom_domains: Iterable[str] | None = None, # Deploy this endpoint on a custom domain.
|
|
@@ -494,12 +470,6 @@ def _wsgi_app(
|
|
|
494
470
|
To learn how to use this decorator with popular web frameworks, see the
|
|
495
471
|
[guide on Web Functions](https://modal.com/docs/guide/webhooks).
|
|
496
472
|
"""
|
|
497
|
-
if isinstance(_warn_parentheses_missing, str):
|
|
498
|
-
raise InvalidError(f'Positional arguments are not allowed. Suggestion: `@modal.wsgi_app(label="{label}")`.')
|
|
499
|
-
elif _warn_parentheses_missing is not None:
|
|
500
|
-
raise InvalidError(
|
|
501
|
-
"Positional arguments are not allowed. Did you forget parentheses? Suggestion: `@modal.wsgi_app()`."
|
|
502
|
-
)
|
|
503
473
|
|
|
504
474
|
webhook_config = api_pb2.WebhookConfig(
|
|
505
475
|
type=api_pb2.WEBHOOK_TYPE_WSGI_APP,
|
|
@@ -588,17 +558,12 @@ def _web_server(
|
|
|
588
558
|
|
|
589
559
|
|
|
590
560
|
def _enter(
|
|
591
|
-
_warn_parentheses_missing=None, # mdmd:line-hidden
|
|
592
561
|
*,
|
|
593
562
|
snap: bool = False,
|
|
594
563
|
) -> Callable[[_PartialFunction | NullaryMethod], _PartialFunction]:
|
|
595
564
|
"""Decorator for methods which should be executed when a new container is started.
|
|
596
565
|
|
|
597
566
|
See the [lifeycle function guide](https://modal.com/docs/guide/lifecycle-functions#enter) for more information."""
|
|
598
|
-
if _warn_parentheses_missing is not None:
|
|
599
|
-
raise InvalidError(
|
|
600
|
-
"Positional arguments are not allowed. Did you forget parentheses? Suggestion: `@modal.enter()`."
|
|
601
|
-
)
|
|
602
567
|
|
|
603
568
|
flags = _PartialFunctionFlags.ENTER_PRE_SNAPSHOT if snap else _PartialFunctionFlags.ENTER_POST_SNAPSHOT
|
|
604
569
|
params = _PartialFunctionParams()
|
|
@@ -615,14 +580,10 @@ def _enter(
|
|
|
615
580
|
return wrapper
|
|
616
581
|
|
|
617
582
|
|
|
618
|
-
def _exit(
|
|
583
|
+
def _exit() -> Callable[[NullaryMethod], _PartialFunction]:
|
|
619
584
|
"""Decorator for methods which should be executed when a container is about to exit.
|
|
620
585
|
|
|
621
586
|
See the [lifeycle function guide](https://modal.com/docs/guide/lifecycle-functions#exit) for more information."""
|
|
622
|
-
if _warn_parentheses_missing is not None:
|
|
623
|
-
raise InvalidError(
|
|
624
|
-
"Positional arguments are not allowed. Did you forget parentheses? Suggestion: `@modal.exit()`."
|
|
625
|
-
)
|
|
626
587
|
|
|
627
588
|
flags = _PartialFunctionFlags.EXIT
|
|
628
589
|
params = _PartialFunctionParams()
|
|
@@ -639,7 +600,6 @@ def _exit(_warn_parentheses_missing=None) -> Callable[[NullaryMethod], _PartialF
|
|
|
639
600
|
|
|
640
601
|
|
|
641
602
|
def _batched(
|
|
642
|
-
_warn_parentheses_missing=None, # mdmd:line-hidden
|
|
643
603
|
*,
|
|
644
604
|
max_batch_size: int,
|
|
645
605
|
wait_ms: int,
|
|
@@ -670,10 +630,6 @@ def _batched(
|
|
|
670
630
|
|
|
671
631
|
See the [dynamic batching guide](https://modal.com/docs/guide/dynamic-batching) for more information.
|
|
672
632
|
"""
|
|
673
|
-
if _warn_parentheses_missing is not None:
|
|
674
|
-
raise InvalidError(
|
|
675
|
-
"Positional arguments are not allowed. Did you forget parentheses? Suggestion: `@modal.batched()`."
|
|
676
|
-
)
|
|
677
633
|
if max_batch_size < 1:
|
|
678
634
|
raise InvalidError("max_batch_size must be a positive integer.")
|
|
679
635
|
if max_batch_size > MAX_MAX_BATCH_SIZE:
|
|
@@ -700,7 +656,6 @@ def _batched(
|
|
|
700
656
|
|
|
701
657
|
|
|
702
658
|
def _concurrent(
|
|
703
|
-
_warn_parentheses_missing=None, # mdmd:line-hidden
|
|
704
659
|
*,
|
|
705
660
|
max_inputs: int | None = None, # Hard limit on each container's input concurrency
|
|
706
661
|
target_inputs: int | None = None, # Input concurrency that Modal's autoscaler should target
|
|
@@ -749,10 +704,6 @@ def _concurrent(
|
|
|
749
704
|
in `@app.function()` and `@app.cls()`.
|
|
750
705
|
|
|
751
706
|
"""
|
|
752
|
-
if _warn_parentheses_missing is not None:
|
|
753
|
-
raise InvalidError(
|
|
754
|
-
"Positional arguments are not allowed. Did you forget parentheses? Suggestion: `@modal.concurrent()`."
|
|
755
|
-
)
|
|
756
707
|
|
|
757
708
|
if max_inputs is not None and target_inputs is not None and target_inputs > max_inputs:
|
|
758
709
|
raise InvalidError("`target_inputs` parameter cannot be greater than `max_inputs`.")
|
|
@@ -777,9 +728,7 @@ def _concurrent(
|
|
|
777
728
|
return wrapper
|
|
778
729
|
|
|
779
730
|
|
|
780
|
-
def _sessioned(
|
|
781
|
-
_warn_parentheses_missing=None, # mdmd:line-hidden
|
|
782
|
-
) -> Callable[
|
|
731
|
+
def _sessioned() -> Callable[
|
|
783
732
|
[Callable[P, ReturnType] | _PartialFunction[P, ReturnType, ReturnType]],
|
|
784
733
|
_PartialFunction[P, ReturnType, ReturnType],
|
|
785
734
|
]:
|
|
@@ -822,11 +771,6 @@ def _sessioned(
|
|
|
822
771
|
server.sessions.terminate(session.token)
|
|
823
772
|
```
|
|
824
773
|
"""
|
|
825
|
-
if _warn_parentheses_missing is not None:
|
|
826
|
-
raise InvalidError(
|
|
827
|
-
"Positional arguments are not allowed. Did you forget parentheses? Suggestion: `@modal.sessioned()`."
|
|
828
|
-
)
|
|
829
|
-
|
|
830
774
|
flags = _PartialFunctionFlags.SESSIONED
|
|
831
775
|
params = _PartialFunctionParams()
|
|
832
776
|
|
|
@@ -4,6 +4,8 @@ import json
|
|
|
4
4
|
import typing
|
|
5
5
|
from datetime import datetime, timedelta, timezone
|
|
6
6
|
|
|
7
|
+
from typing_extensions import Self
|
|
8
|
+
|
|
7
9
|
from modal_proto import api_pb2
|
|
8
10
|
|
|
9
11
|
from ._functions import _Function
|
|
@@ -73,7 +75,7 @@ class _Server:
|
|
|
73
75
|
_user_cls: type | None = None # None if remote
|
|
74
76
|
_service_function: _Function
|
|
75
77
|
_app: "modal.app._App | None" = None # None if remote
|
|
76
|
-
_is_sessioned: bool | None = None # None
|
|
78
|
+
_is_sessioned: bool | None = None # None until known (via local set or remote hydration)
|
|
77
79
|
|
|
78
80
|
def _get_user_cls(self) -> type:
|
|
79
81
|
assert self._user_cls is not None
|
|
@@ -248,8 +250,22 @@ class _Server:
|
|
|
248
250
|
# This is required since we want to support @livemethod() decorated methods
|
|
249
251
|
service_function = self._get_service_function()
|
|
250
252
|
await service_function.hydrate(client)
|
|
253
|
+
if service_function._function_info is not None:
|
|
254
|
+
self._is_sessioned = service_function._function_info._sessioned
|
|
251
255
|
return self
|
|
252
256
|
|
|
257
|
+
@classmethod
|
|
258
|
+
def _new_from_function(cls, object_id: str, client: _Client, metadata: api_pb2.FunctionHandleMetadata) -> Self:
|
|
259
|
+
"""mdmd:hidden
|
|
260
|
+
|
|
261
|
+
Callers which already have handle metadata for a Server service function can use this method to
|
|
262
|
+
create a hydrated handle without having to do an unnecessary RPC.
|
|
263
|
+
"""
|
|
264
|
+
|
|
265
|
+
obj = cls()
|
|
266
|
+
obj._service_function = _Function._new_hydrated(object_id, client, metadata)
|
|
267
|
+
return obj
|
|
268
|
+
|
|
253
269
|
# ============ Construction ============
|
|
254
270
|
@staticmethod
|
|
255
271
|
def _from_local(
|
|
@@ -478,7 +494,7 @@ class _ServerSessionsManager:
|
|
|
478
494
|
self._server = server
|
|
479
495
|
|
|
480
496
|
def _validate(self) -> None:
|
|
481
|
-
if self._server.
|
|
497
|
+
if self._server._is_sessioned is False:
|
|
482
498
|
raise InvalidError("`sessions` requires `@modal.sessioned()` on the Server.")
|
|
483
499
|
|
|
484
500
|
async def start(self, idle_timeout: int = 600) -> ServerSessionCredentials:
|
|
@@ -504,12 +520,12 @@ class _ServerSessionsManager:
|
|
|
504
520
|
server.sessions.terminate(session.token)
|
|
505
521
|
```
|
|
506
522
|
"""
|
|
507
|
-
self._validate()
|
|
508
523
|
if not isinstance(idle_timeout, int) or idle_timeout <= 0:
|
|
509
524
|
raise InvalidError("`idle_timeout` must be a positive integer.")
|
|
510
525
|
|
|
511
526
|
fn = self._server._get_service_function()
|
|
512
527
|
url = await self._server.get_url()
|
|
528
|
+
self._validate()
|
|
513
529
|
assert url is not None, "Server has no URL."
|
|
514
530
|
|
|
515
531
|
headers = {
|
|
@@ -545,10 +561,9 @@ class _ServerSessionsManager:
|
|
|
545
561
|
server.sessions.terminate(session.token)
|
|
546
562
|
```
|
|
547
563
|
"""
|
|
548
|
-
self._validate()
|
|
549
|
-
|
|
550
564
|
fn = self._server._get_service_function()
|
|
551
565
|
url = await self._server.get_url()
|
|
566
|
+
self._validate()
|
|
552
567
|
assert url is not None, "Server has no URL."
|
|
553
568
|
|
|
554
569
|
headers = {
|
|
@@ -7,6 +7,7 @@ import modal.app
|
|
|
7
7
|
import modal.client
|
|
8
8
|
import modal.server
|
|
9
9
|
import modal.types
|
|
10
|
+
import modal_proto.api_pb2
|
|
10
11
|
import typing
|
|
11
12
|
import typing_extensions
|
|
12
13
|
|
|
@@ -165,6 +166,17 @@ class _Server:
|
|
|
165
166
|
"""
|
|
166
167
|
...
|
|
167
168
|
|
|
169
|
+
@classmethod
|
|
170
|
+
def _new_from_function(
|
|
171
|
+
cls, object_id: str, client: modal.client._Client, metadata: modal_proto.api_pb2.FunctionHandleMetadata
|
|
172
|
+
) -> typing_extensions.Self:
|
|
173
|
+
"""mdmd:hidden
|
|
174
|
+
|
|
175
|
+
Callers which already have handle metadata for a Server service function can use this method to
|
|
176
|
+
create a hydrated handle without having to do an unnecessary RPC.
|
|
177
|
+
"""
|
|
178
|
+
...
|
|
179
|
+
|
|
168
180
|
@staticmethod
|
|
169
181
|
def _from_local(
|
|
170
182
|
wrapped_user_cls: typing.Union[type, modal._partial_function._PartialFunction],
|
|
@@ -727,9 +727,7 @@ class _App:
|
|
|
727
727
|
"""
|
|
728
728
|
return self._local_state.web_endpoints
|
|
729
729
|
|
|
730
|
-
def local_entrypoint(
|
|
731
|
-
self, _warn_parentheses_missing: Any = None, *, name: str | None = None
|
|
732
|
-
) -> Callable[[Callable[..., Any]], _LocalEntrypoint]:
|
|
730
|
+
def local_entrypoint(self, *, name: str | None = None) -> Callable[[Callable[..., Any]], _LocalEntrypoint]:
|
|
733
731
|
"""Decorate a function to be used as a CLI entrypoint for a Modal App.
|
|
734
732
|
|
|
735
733
|
These functions can be used to define code that runs locally to set up the app,
|
|
@@ -784,8 +782,6 @@ class _App:
|
|
|
784
782
|
Currently, `str`, `int`, `float`, `bool`, and `datetime.datetime` are supported.
|
|
785
783
|
Use `modal run app_module.py --help` for more information on usage.
|
|
786
784
|
"""
|
|
787
|
-
if _warn_parentheses_missing:
|
|
788
|
-
raise InvalidError("Did you forget parentheses? Suggestion: `@app.local_entrypoint()`.")
|
|
789
785
|
if name is not None and not isinstance(name, str):
|
|
790
786
|
raise InvalidError("Invalid value for `name`: Must be string.")
|
|
791
787
|
|
|
@@ -804,7 +800,6 @@ class _App:
|
|
|
804
800
|
@handle_deprecated_parameters
|
|
805
801
|
def function(
|
|
806
802
|
self,
|
|
807
|
-
_warn_parentheses_missing=None, # mdmd:line-hidden
|
|
808
803
|
*,
|
|
809
804
|
image: _Image | None = None,
|
|
810
805
|
schedule: Schedule | None = None,
|
|
@@ -890,11 +885,6 @@ class _App:
|
|
|
890
885
|
Returns:
|
|
891
886
|
A decorator that registers the wrapped callable or partial as a Modal `Function`.
|
|
892
887
|
"""
|
|
893
|
-
if isinstance(_warn_parentheses_missing, _Image):
|
|
894
|
-
# Handle edge case where maybe (?) some users passed image as a positional arg
|
|
895
|
-
raise InvalidError("`image` needs to be a keyword argument: `@app.function(image=image)`.")
|
|
896
|
-
if _warn_parentheses_missing:
|
|
897
|
-
raise InvalidError("Did you forget parentheses? Suggestion: `@app.function()`.")
|
|
898
888
|
|
|
899
889
|
if image is None:
|
|
900
890
|
image = self._get_default_image()
|
|
@@ -1063,7 +1053,6 @@ class _App:
|
|
|
1063
1053
|
@handle_deprecated_parameters
|
|
1064
1054
|
def cls(
|
|
1065
1055
|
self,
|
|
1066
|
-
_warn_parentheses_missing=None, # mdmd:line-hidden
|
|
1067
1056
|
*,
|
|
1068
1057
|
image: _Image | None = None,
|
|
1069
1058
|
env: dict[str, str | None] | None = None,
|
|
@@ -1096,7 +1085,7 @@ class _App:
|
|
|
1096
1085
|
experimental_options: dict[str, Any] | None = None,
|
|
1097
1086
|
_experimental_restrict_output: bool = False,
|
|
1098
1087
|
max_inputs: int | None = None,
|
|
1099
|
-
) -> Callable[[CLS_T | _PartialFunction], CLS_T]:
|
|
1088
|
+
) -> Callable[[CLS_T | _PartialFunction[..., Any, Any]], CLS_T]:
|
|
1100
1089
|
"""
|
|
1101
1090
|
Decorator to register a new Modal [Cls](https://modal.com/docs/sdk/py/latest/Cls) with this App.
|
|
1102
1091
|
|
|
@@ -1141,8 +1130,6 @@ class _App:
|
|
|
1141
1130
|
Returns:
|
|
1142
1131
|
A decorator that registers the wrapped class or partial as a Modal `Cls`.
|
|
1143
1132
|
"""
|
|
1144
|
-
if _warn_parentheses_missing:
|
|
1145
|
-
raise InvalidError("Did you forget parentheses? Suggestion: `@app.cls()`.")
|
|
1146
1133
|
|
|
1147
1134
|
if max_inputs is not None:
|
|
1148
1135
|
if not isinstance(max_inputs, int):
|
|
@@ -1161,7 +1148,7 @@ class _App:
|
|
|
1161
1148
|
if env:
|
|
1162
1149
|
secrets = [*secrets, _Secret.from_dict(env)]
|
|
1163
1150
|
|
|
1164
|
-
def wrapper(wrapped_cls: CLS_T | _PartialFunction) -> CLS_T:
|
|
1151
|
+
def wrapper(wrapped_cls: CLS_T | _PartialFunction[..., Any, Any]) -> CLS_T:
|
|
1165
1152
|
local_state = self._local_state
|
|
1166
1153
|
# Check if the decorated object is a class
|
|
1167
1154
|
http_config = None
|
|
@@ -1306,7 +1293,6 @@ class _App:
|
|
|
1306
1293
|
|
|
1307
1294
|
def server(
|
|
1308
1295
|
self,
|
|
1309
|
-
_warn_parentheses_missing=None, # mdmd:line-hidden
|
|
1310
1296
|
*,
|
|
1311
1297
|
image: _Image | None = None, # The image to run as the container for the server
|
|
1312
1298
|
env: dict[str, str | None] | None = None, # Environment variables to set in the container
|
|
@@ -1342,7 +1328,7 @@ class _App:
|
|
|
1342
1328
|
include_source: bool | None = None, # Whether to add source to container
|
|
1343
1329
|
# Experimental options
|
|
1344
1330
|
experimental_options: dict[str, Any] | None = None,
|
|
1345
|
-
) -> Callable[[type[Any] | _PartialFunction], _Server]:
|
|
1331
|
+
) -> Callable[[type[Any] | _PartialFunction[..., Any, Any]], _Server]:
|
|
1346
1332
|
"""
|
|
1347
1333
|
Decorator to register a new Modal Server with this App.
|
|
1348
1334
|
|
|
@@ -1407,8 +1393,6 @@ class _App:
|
|
|
1407
1393
|
self.proc.terminate()
|
|
1408
1394
|
```
|
|
1409
1395
|
"""
|
|
1410
|
-
if _warn_parentheses_missing:
|
|
1411
|
-
raise InvalidError("Did you forget parentheses? Suggestion: `@app.server()`.")
|
|
1412
1396
|
|
|
1413
1397
|
# Validate HTTP server config
|
|
1414
1398
|
validate_http_server_config(
|
|
@@ -1455,7 +1439,7 @@ class _App:
|
|
|
1455
1439
|
if env:
|
|
1456
1440
|
secrets_list.append(_Secret.from_dict(env))
|
|
1457
1441
|
|
|
1458
|
-
def wrapper(wrapped_user_cls: type[Any] | _PartialFunction | Callable) -> _Server:
|
|
1442
|
+
def wrapper(wrapped_user_cls: type[Any] | _PartialFunction[..., Any, Any] | Callable[..., Any]) -> _Server:
|
|
1459
1443
|
_Server._validate_wrapped_user_cls_decorators(wrapped_user_cls, enable_memory_snapshot)
|
|
1460
1444
|
|
|
1461
1445
|
# Validate the server class
|
|
@@ -487,7 +487,7 @@ class _App:
|
|
|
487
487
|
...
|
|
488
488
|
|
|
489
489
|
def local_entrypoint(
|
|
490
|
-
self,
|
|
490
|
+
self, *, name: typing.Optional[str] = None
|
|
491
491
|
) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], _LocalEntrypoint]:
|
|
492
492
|
"""Decorate a function to be used as a CLI entrypoint for a Modal App.
|
|
493
493
|
|
|
@@ -547,7 +547,6 @@ class _App:
|
|
|
547
547
|
|
|
548
548
|
def function(
|
|
549
549
|
self,
|
|
550
|
-
_warn_parentheses_missing=None,
|
|
551
550
|
*,
|
|
552
551
|
image: typing.Optional[modal._image._Image] = None,
|
|
553
552
|
schedule: typing.Optional[modal.schedule.Schedule] = None,
|
|
@@ -646,7 +645,6 @@ class _App:
|
|
|
646
645
|
)
|
|
647
646
|
def cls(
|
|
648
647
|
self,
|
|
649
|
-
_warn_parentheses_missing=None,
|
|
650
648
|
*,
|
|
651
649
|
image: typing.Optional[modal._image._Image] = None,
|
|
652
650
|
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
@@ -684,7 +682,9 @@ class _App:
|
|
|
684
682
|
experimental_options: typing.Optional[dict[str, typing.Any]] = None,
|
|
685
683
|
_experimental_restrict_output: bool = False,
|
|
686
684
|
max_inputs: typing.Optional[int] = None,
|
|
687
|
-
) -> collections.abc.Callable[
|
|
685
|
+
) -> collections.abc.Callable[
|
|
686
|
+
[typing.Union[CLS_T, modal._partial_function._PartialFunction[..., typing.Any, typing.Any]]], CLS_T
|
|
687
|
+
]:
|
|
688
688
|
"""Decorator to register a new Modal [Cls](https://modal.com/docs/sdk/py/latest/Cls) with this App.
|
|
689
689
|
|
|
690
690
|
Args:
|
|
@@ -732,7 +732,6 @@ class _App:
|
|
|
732
732
|
|
|
733
733
|
def server(
|
|
734
734
|
self,
|
|
735
|
-
_warn_parentheses_missing=None,
|
|
736
735
|
*,
|
|
737
736
|
image: typing.Optional[modal._image._Image] = None,
|
|
738
737
|
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
@@ -769,7 +768,8 @@ class _App:
|
|
|
769
768
|
include_source: typing.Optional[bool] = None,
|
|
770
769
|
experimental_options: typing.Optional[dict[str, typing.Any]] = None,
|
|
771
770
|
) -> collections.abc.Callable[
|
|
772
|
-
[typing.Union[type[typing.Any], modal._partial_function._PartialFunction]],
|
|
771
|
+
[typing.Union[type[typing.Any], modal._partial_function._PartialFunction[..., typing.Any, typing.Any]]],
|
|
772
|
+
modal._server._Server,
|
|
773
773
|
]:
|
|
774
774
|
"""Decorator to register a new Modal Server with this App.
|
|
775
775
|
|
|
@@ -1525,7 +1525,7 @@ class App:
|
|
|
1525
1525
|
...
|
|
1526
1526
|
|
|
1527
1527
|
def local_entrypoint(
|
|
1528
|
-
self,
|
|
1528
|
+
self, *, name: typing.Optional[str] = None
|
|
1529
1529
|
) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], LocalEntrypoint]:
|
|
1530
1530
|
"""Decorate a function to be used as a CLI entrypoint for a Modal App.
|
|
1531
1531
|
|
|
@@ -1585,7 +1585,6 @@ class App:
|
|
|
1585
1585
|
|
|
1586
1586
|
def function(
|
|
1587
1587
|
self,
|
|
1588
|
-
_warn_parentheses_missing=None,
|
|
1589
1588
|
*,
|
|
1590
1589
|
image: typing.Optional[modal.image.Image] = None,
|
|
1591
1590
|
schedule: typing.Optional[modal.schedule.Schedule] = None,
|
|
@@ -1684,7 +1683,6 @@ class App:
|
|
|
1684
1683
|
)
|
|
1685
1684
|
def cls(
|
|
1686
1685
|
self,
|
|
1687
|
-
_warn_parentheses_missing=None,
|
|
1688
1686
|
*,
|
|
1689
1687
|
image: typing.Optional[modal.image.Image] = None,
|
|
1690
1688
|
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
@@ -1722,7 +1720,9 @@ class App:
|
|
|
1722
1720
|
experimental_options: typing.Optional[dict[str, typing.Any]] = None,
|
|
1723
1721
|
_experimental_restrict_output: bool = False,
|
|
1724
1722
|
max_inputs: typing.Optional[int] = None,
|
|
1725
|
-
) -> collections.abc.Callable[
|
|
1723
|
+
) -> collections.abc.Callable[
|
|
1724
|
+
[typing.Union[CLS_T, modal.partial_function.PartialFunction[..., typing.Any, typing.Any]]], CLS_T
|
|
1725
|
+
]:
|
|
1726
1726
|
"""Decorator to register a new Modal [Cls](https://modal.com/docs/sdk/py/latest/Cls) with this App.
|
|
1727
1727
|
|
|
1728
1728
|
Args:
|
|
@@ -1770,7 +1770,6 @@ class App:
|
|
|
1770
1770
|
|
|
1771
1771
|
def server(
|
|
1772
1772
|
self,
|
|
1773
|
-
_warn_parentheses_missing=None,
|
|
1774
1773
|
*,
|
|
1775
1774
|
image: typing.Optional[modal.image.Image] = None,
|
|
1776
1775
|
env: typing.Optional[dict[str, typing.Optional[str]]] = None,
|
|
@@ -1807,7 +1806,8 @@ class App:
|
|
|
1807
1806
|
include_source: typing.Optional[bool] = None,
|
|
1808
1807
|
experimental_options: typing.Optional[dict[str, typing.Any]] = None,
|
|
1809
1808
|
) -> collections.abc.Callable[
|
|
1810
|
-
[typing.Union[type[typing.Any], modal.partial_function.PartialFunction]],
|
|
1809
|
+
[typing.Union[type[typing.Any], modal.partial_function.PartialFunction[..., typing.Any, typing.Any]]],
|
|
1810
|
+
modal.server.Server,
|
|
1811
1811
|
]:
|
|
1812
1812
|
"""Decorator to register a new Modal Server with this App.
|
|
1813
1813
|
|
|
@@ -9,7 +9,7 @@ from typing import Literal, get_args
|
|
|
9
9
|
|
|
10
10
|
import click
|
|
11
11
|
import rich
|
|
12
|
-
from click import UsageError
|
|
12
|
+
from click import ClickException, UsageError
|
|
13
13
|
from google.protobuf.json_format import MessageToDict
|
|
14
14
|
from rich.table import Column, Table
|
|
15
15
|
from rich.text import Text
|
|
@@ -29,6 +29,7 @@ from .._utils.time_utils import timestamp_to_localized_str
|
|
|
29
29
|
from ._help import ModalGroup
|
|
30
30
|
from ._logs import _run_logs_command, _validate_logs_args
|
|
31
31
|
from .utils import (
|
|
32
|
+
HEADER_ONLY,
|
|
32
33
|
confirm_or_suggest_yes,
|
|
33
34
|
display_table,
|
|
34
35
|
env_option,
|
|
@@ -97,10 +98,34 @@ async def resolve_app_identifier(
|
|
|
97
98
|
|
|
98
99
|
@app_cli.command("list")
|
|
99
100
|
@env_option
|
|
100
|
-
@click.option("--json", is_flag=True, default=False)
|
|
101
|
+
@click.option("--json", help="Output as JSON.", is_flag=True, default=False)
|
|
102
|
+
@click.option(
|
|
103
|
+
"--limit",
|
|
104
|
+
default=0,
|
|
105
|
+
help="Show at most N results. Use 0 to list every result. Default is 0.",
|
|
106
|
+
)
|
|
101
107
|
@synchronizer.create_blocking
|
|
102
|
-
async def list_(env: str | None = None, json: bool = False):
|
|
103
|
-
"""List Apps that are running, deployed or recently stopped.
|
|
108
|
+
async def list_(env: str | None = None, json: bool = False, limit: int = 0):
|
|
109
|
+
"""List Apps that are running, deployed or recently stopped.
|
|
110
|
+
|
|
111
|
+
Examples:
|
|
112
|
+
|
|
113
|
+
Limit output to 30 apps:
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
modal app list --limit 30
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Display output in JSON:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
modal app list --json
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
"""
|
|
126
|
+
if not isinstance(limit, int) or limit < 0:
|
|
127
|
+
raise ClickException("--limit must be an integer value greater than or equal to 0.")
|
|
128
|
+
|
|
104
129
|
env = ensure_env(env)
|
|
105
130
|
client = await _Client.from_env()
|
|
106
131
|
|
|
@@ -108,14 +133,6 @@ async def list_(env: str | None = None, json: bool = False):
|
|
|
108
133
|
api_pb2.AppListRequest(environment_name=_get_environment_name(env))
|
|
109
134
|
)
|
|
110
135
|
|
|
111
|
-
columns: list[Column | str] = [
|
|
112
|
-
Column("App ID", min_width=25), # Ensure that App ID is not truncated in slim terminals
|
|
113
|
-
"Description",
|
|
114
|
-
"State",
|
|
115
|
-
"Tasks",
|
|
116
|
-
"Created at",
|
|
117
|
-
"Stopped at",
|
|
118
|
-
]
|
|
119
136
|
rows: list[list[Text | str | None]] = []
|
|
120
137
|
for app_stats in resp.apps:
|
|
121
138
|
state = APP_STATE_TO_MESSAGE.get(app_stats.state, Text("unknown", style="gray"))
|
|
@@ -129,9 +146,24 @@ async def list_(env: str | None = None, json: bool = False):
|
|
|
129
146
|
timestamp_to_localized_str(app_stats.stopped_at, json),
|
|
130
147
|
]
|
|
131
148
|
)
|
|
149
|
+
rows.sort(key=lambda s: (int(s[3]), s[4]), reverse=True) # type: ignore
|
|
150
|
+
rows_trunc = rows
|
|
151
|
+
if limit:
|
|
152
|
+
rows_trunc = rows[:limit]
|
|
153
|
+
|
|
154
|
+
app_id_width = max([len(r[0]) for r in rows]) if len(rows) else 25 # type: ignore
|
|
155
|
+
columns: list[Column | str] = [
|
|
156
|
+
Column("App ID", min_width=app_id_width, no_wrap=True),
|
|
157
|
+
Column("Description", min_width=1, overflow="fold"),
|
|
158
|
+
Column("State", min_width=1, overflow="fold"),
|
|
159
|
+
Column("Tasks", min_width=1, overflow="fold"),
|
|
160
|
+
Column("Created at", min_width=1, overflow="fold"),
|
|
161
|
+
Column("Stopped at", min_width=1, overflow="fold"),
|
|
162
|
+
]
|
|
132
163
|
|
|
133
164
|
env_part = f" in environment '{env}'" if env else ""
|
|
134
|
-
|
|
165
|
+
app_count_part = f" ({len(rows_trunc)} of {len(rows)})" if len(rows_trunc) < len(rows) else ""
|
|
166
|
+
display_table(columns, rows_trunc, json, title=f"Apps{env_part}{app_count_part}", table_box=HEADER_ONLY)
|
|
135
167
|
|
|
136
168
|
|
|
137
169
|
@app_cli.command("logs", no_args_is_help=True)
|
|
@@ -688,7 +720,11 @@ async def info(app_identifier: str, *, env: str | None = None, json: bool = Fals
|
|
|
688
720
|
)
|
|
689
721
|
return
|
|
690
722
|
|
|
723
|
+
name_width = max((Text(name).cell_len for name in [*app_info.functions, *app_info.servers]), default=0)
|
|
724
|
+
label_width = max(len("Deployment:"), name_width + 2)
|
|
691
725
|
header = Table(show_header=False, box=None, pad_edge=False, padding=(0, 1))
|
|
726
|
+
header.add_column(width=label_width)
|
|
727
|
+
header.add_column(overflow="fold")
|
|
692
728
|
header.add_row(Text("App:"), Text(app_info.description))
|
|
693
729
|
header.add_row(Text("App ID:"), Text(app_info.app_id))
|
|
694
730
|
header.add_row(Text("State:"), Text(state.plain))
|
|
@@ -706,7 +742,6 @@ async def info(app_identifier: str, *, env: str | None = None, json: bool = Fals
|
|
|
706
742
|
event("Created", lifecycle.created_at, lifecycle.created_by)
|
|
707
743
|
output.print(header)
|
|
708
744
|
|
|
709
|
-
name_width = max((len(name) for name in [*app_info.functions, *app_info.servers]), default=0)
|
|
710
745
|
for title, entries in (("Functions", app_info.functions), ("Servers", app_info.servers)):
|
|
711
746
|
if not entries:
|
|
712
747
|
continue
|
|
@@ -716,8 +751,8 @@ async def info(app_identifier: str, *, env: str | None = None, json: bool = Fals
|
|
|
716
751
|
if index:
|
|
717
752
|
output.print("")
|
|
718
753
|
identity = Table(show_header=False, box=None, pad_edge=False, padding=(0, 1))
|
|
719
|
-
identity.add_column(width=
|
|
720
|
-
identity.add_column(
|
|
754
|
+
identity.add_column(width=label_width)
|
|
755
|
+
identity.add_column(width=26, overflow="fold")
|
|
721
756
|
identity.add_row(Text(f" {name}"), Text(function_id))
|
|
722
757
|
output.print(identity)
|
|
723
758
|
if function_id not in resp.function_info_summaries:
|