modAL 1.3.1.dev26__tar.gz → 1.3.1.dev27__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.3.1.dev26 → modal-1.3.1.dev27}/PKG-INFO +1 -1
- modal-1.3.1.dev27/modal/_server.py +246 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/client.pyi +2 -2
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/experimental/flash.py +2 -7
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/functions.pyi +6 -6
- modal-1.3.1.dev27/modal/server.py +5 -0
- modal-1.3.1.dev27/modal/server.pyi +147 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal.egg-info/SOURCES.txt +3 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_version/__init__.py +1 -1
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/LICENSE +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/README.md +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/__init__.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/__main__.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_billing.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_clustered_functions.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_clustered_functions.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_container_entrypoint.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_functions.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_grpc_client.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_ipython.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_load_context.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_location.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_object.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_output.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_partial_function.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_pty.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_resolver.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_resources.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_runtime/__init__.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_runtime/asgi.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_runtime/execution_context.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_runtime/telemetry.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_serialization.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_traceback.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_tunnel.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_tunnel.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_type_manager.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/__init__.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/app_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/async_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/blob_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/deprecation.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/docker_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/function_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/git_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/hash_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/http_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/logger.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/mount_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/name_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/package_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/shell_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_utils/time_utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_vendor/__init__.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_vendor/tblib.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/_watcher.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/app.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/app.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/billing.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/builder/2023.12.txt +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/builder/2024.04.txt +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/builder/2024.10.txt +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/builder/2025.06.txt +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/builder/README.md +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/builder/base-images.json +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/call_graph.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/__init__.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/_download.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/_traceback.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/app.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/cluster.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/config.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/container.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/dict.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/entry_point.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/environment.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/import_refs.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/launch.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/network_file_system.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/profile.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/programs/__init__.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/programs/vscode.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/queues.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/run.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/secret.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/shell.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/token.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/utils.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cli/volume.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/client.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cls.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/cls.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/config.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/container_process.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/container_process.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/dict.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/dict.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/environments.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/environments.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/exception.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/experimental/__init__.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/experimental/flash.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/experimental/ipython.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/file_io.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/file_io.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/file_pattern_matcher.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/functions.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/gpu.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/image.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/image.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/io_streams.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/io_streams.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/mount.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/mount.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/network_file_system.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/network_file_system.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/object.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/object.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/output.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/parallel_map.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/parallel_map.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/partial_function.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/partial_function.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/proxy.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/proxy.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/py.typed +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/queue.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/queue.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/retries.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/runner.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/runner.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/running_app.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/sandbox.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/sandbox.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/schedule.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/scheduler_placement.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/secret.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/secret.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/serving.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/serving.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/snapshot.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/snapshot.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/stream_type.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/token_flow.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/token_flow.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/volume.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal/volume.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal.egg-info/requires.txt +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal.egg-info/top_level.txt +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_docs/__init__.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_proto/__init__.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_proto/api.proto +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_proto/api_grpc.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_proto/api_pb2.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_proto/api_pb2.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_proto/py.typed +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_proto/task_command_router.proto +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/modal_version/__main__.py +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/pyproject.toml +0 -0
- {modal-1.3.1.dev26 → modal-1.3.1.dev27}/setup.cfg +0 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# Copyright Modal Labs 2025
|
|
2
|
+
import inspect
|
|
3
|
+
import typing
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from ._functions import _Function
|
|
7
|
+
from ._load_context import LoadContext
|
|
8
|
+
from ._object import live_method
|
|
9
|
+
from ._partial_function import (
|
|
10
|
+
_find_partial_methods_for_user_cls,
|
|
11
|
+
_PartialFunction,
|
|
12
|
+
_PartialFunctionFlags,
|
|
13
|
+
)
|
|
14
|
+
from .client import _Client
|
|
15
|
+
from .cls import is_parameter
|
|
16
|
+
from .exception import InvalidError
|
|
17
|
+
|
|
18
|
+
if typing.TYPE_CHECKING:
|
|
19
|
+
import modal.app
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def validate_http_server_config(
|
|
23
|
+
port: int,
|
|
24
|
+
proxy_regions: list[str], # The regions to proxy the HTTP server to.
|
|
25
|
+
startup_timeout: int, # Maximum number of seconds to wait for the HTTP server to start.
|
|
26
|
+
exit_grace_period: Optional[int], # The time to wait for the HTTP server to exit gracefully.
|
|
27
|
+
):
|
|
28
|
+
if not isinstance(port, int) or port < 1 or port > 65535:
|
|
29
|
+
raise InvalidError("Port must be a positive integer between 1 and 65535.")
|
|
30
|
+
if startup_timeout <= 0:
|
|
31
|
+
raise InvalidError("The `startup_timeout` argument must be positive.")
|
|
32
|
+
if exit_grace_period is not None and exit_grace_period < 0:
|
|
33
|
+
raise InvalidError("The `exit_grace_period` argument must be non-negative.")
|
|
34
|
+
if not proxy_regions:
|
|
35
|
+
raise InvalidError("The `proxy_regions` argument must be non-empty.")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class _Server:
|
|
39
|
+
"""Server runs an HTTP server started in an `@modal.enter` method.
|
|
40
|
+
|
|
41
|
+
See [lifecycle hooks](https://modal.com/docs/guide/lifecycle-functions) for more information.
|
|
42
|
+
|
|
43
|
+
Generally, you will not construct a Server directly.
|
|
44
|
+
Instead, use the [`@app.server()`](https://modal.com/docs/reference/modal.App#server) decorator.
|
|
45
|
+
|
|
46
|
+
```python notest
|
|
47
|
+
@app.server(port=8000, proxy_regions=["us-east", "us-west"])
|
|
48
|
+
class MyServer:
|
|
49
|
+
@modal.enter()
|
|
50
|
+
def start_server(self):
|
|
51
|
+
self.process = subprocess.Popen(["python3", "-m", "http.server", "8080"])
|
|
52
|
+
```
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
_user_cls: Optional[type] = None # None if remote
|
|
56
|
+
_service_function: _Function
|
|
57
|
+
_app: Optional["modal.app._App"] = None # None if remote
|
|
58
|
+
|
|
59
|
+
def _get_user_cls(self) -> type:
|
|
60
|
+
assert self._user_cls is not None
|
|
61
|
+
return self._user_cls
|
|
62
|
+
|
|
63
|
+
def _get_app(self) -> "modal.app._App":
|
|
64
|
+
assert self._app
|
|
65
|
+
return self._app
|
|
66
|
+
|
|
67
|
+
def _get_service_function(self) -> _Function:
|
|
68
|
+
return self._service_function
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
def _extract_user_cls(wrapped_user_cls: "type | _PartialFunction") -> type:
|
|
72
|
+
if isinstance(wrapped_user_cls, _PartialFunction):
|
|
73
|
+
assert wrapped_user_cls.user_cls
|
|
74
|
+
return wrapped_user_cls.user_cls
|
|
75
|
+
else:
|
|
76
|
+
return wrapped_user_cls
|
|
77
|
+
|
|
78
|
+
# ============ Live Methods ============
|
|
79
|
+
|
|
80
|
+
@live_method
|
|
81
|
+
async def get_urls(self) -> Optional[list[str]]:
|
|
82
|
+
return await self._get_service_function()._experimental_get_flash_urls()
|
|
83
|
+
|
|
84
|
+
@live_method
|
|
85
|
+
async def update_autoscaler(
|
|
86
|
+
self,
|
|
87
|
+
*,
|
|
88
|
+
min_containers: Optional[int] = None,
|
|
89
|
+
max_containers: Optional[int] = None,
|
|
90
|
+
buffer_containers: Optional[int] = None,
|
|
91
|
+
scaledown_window: Optional[int] = None,
|
|
92
|
+
) -> None:
|
|
93
|
+
"""Override the current autoscaler behavior for this Server.
|
|
94
|
+
|
|
95
|
+
Unspecified parameters will retain their current value.
|
|
96
|
+
|
|
97
|
+
Examples:
|
|
98
|
+
```python notest
|
|
99
|
+
server = modal.Server.from_name("my-app", "Server")
|
|
100
|
+
|
|
101
|
+
# Always have at least 2 containers running, with an extra buffer of 2 containers
|
|
102
|
+
server.update_autoscaler(min_containers=2, buffer_containers=1)
|
|
103
|
+
|
|
104
|
+
# Limit this Server to avoid spinning up more than 5 containers
|
|
105
|
+
server.update_autoscaler(max_containers=5)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
"""
|
|
109
|
+
return await self._get_service_function().update_autoscaler(
|
|
110
|
+
min_containers=min_containers,
|
|
111
|
+
max_containers=max_containers,
|
|
112
|
+
scaledown_window=scaledown_window,
|
|
113
|
+
buffer_containers=buffer_containers,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# ============ Hydration ============
|
|
117
|
+
async def hydrate(self, client: Optional[_Client] = None) -> "_Server":
|
|
118
|
+
# This is required since we want to support @livemethod() decorated methods
|
|
119
|
+
service_function = self._get_service_function()
|
|
120
|
+
await service_function.hydrate(client)
|
|
121
|
+
return self
|
|
122
|
+
|
|
123
|
+
# ============ Construction ============
|
|
124
|
+
@staticmethod
|
|
125
|
+
def _from_local(
|
|
126
|
+
wrapped_user_cls: "type | _PartialFunction",
|
|
127
|
+
app: "modal.app._App",
|
|
128
|
+
service_function: _Function,
|
|
129
|
+
) -> "_Server":
|
|
130
|
+
"""Create a Server from a local class definition."""
|
|
131
|
+
|
|
132
|
+
# Note: Validation should be done by the caller (app.server()) BEFORE creating the Server.
|
|
133
|
+
# Extract the underlying class if wrapped in a _PartialFunction (e.g., from @modal.clustered())
|
|
134
|
+
user_cls = _Server._extract_user_cls(wrapped_user_cls)
|
|
135
|
+
|
|
136
|
+
server = _Server()
|
|
137
|
+
server._app = app
|
|
138
|
+
server._user_cls = user_cls
|
|
139
|
+
server._service_function = service_function
|
|
140
|
+
return server
|
|
141
|
+
|
|
142
|
+
@classmethod
|
|
143
|
+
def from_name(
|
|
144
|
+
cls: type["_Server"],
|
|
145
|
+
app_name: str,
|
|
146
|
+
name: str,
|
|
147
|
+
*,
|
|
148
|
+
environment_name: Optional[str] = None,
|
|
149
|
+
client: Optional[_Client] = None,
|
|
150
|
+
) -> "_Server":
|
|
151
|
+
"""Reference a Server from a deployed App by its name.
|
|
152
|
+
|
|
153
|
+
This is a lazy method that defers hydrating the local
|
|
154
|
+
object with metadata from Modal servers until the first
|
|
155
|
+
time it is actually used.
|
|
156
|
+
|
|
157
|
+
```python notest
|
|
158
|
+
server = modal.Server.from_name("other-app", "Server")
|
|
159
|
+
```
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
load_context_overrides = LoadContext(client=client, environment_name=environment_name)
|
|
163
|
+
|
|
164
|
+
server = _Server()
|
|
165
|
+
server._service_function = _Function._from_name(
|
|
166
|
+
app_name,
|
|
167
|
+
name,
|
|
168
|
+
load_context_overrides=load_context_overrides,
|
|
169
|
+
)
|
|
170
|
+
return server
|
|
171
|
+
|
|
172
|
+
def _is_local(self) -> bool:
|
|
173
|
+
"""Returns True if this Server has local source code available."""
|
|
174
|
+
return self._user_cls is not None
|
|
175
|
+
|
|
176
|
+
# ============ Validation ============
|
|
177
|
+
|
|
178
|
+
@staticmethod
|
|
179
|
+
def _validate_wrapped_user_cls_decorators(
|
|
180
|
+
wrapped_user_cls: "type | _PartialFunction", enable_memory_snapshot: bool
|
|
181
|
+
):
|
|
182
|
+
user_cls = _Server._extract_user_cls(wrapped_user_cls)
|
|
183
|
+
|
|
184
|
+
if not inspect.isclass(user_cls):
|
|
185
|
+
raise TypeError("The @app.server() decorator must be used on a class.")
|
|
186
|
+
|
|
187
|
+
# Check for modal.parameter() - not allowed on server classes
|
|
188
|
+
params = {k: v for k, v in user_cls.__dict__.items() if is_parameter(v)}
|
|
189
|
+
if params:
|
|
190
|
+
raise InvalidError(
|
|
191
|
+
f"Server class {user_cls.__name__} cannot use modal.parameter(). "
|
|
192
|
+
"Servers do not support parameterization."
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
if not _find_partial_methods_for_user_cls(
|
|
196
|
+
user_cls, _PartialFunctionFlags.ENTER_PRE_SNAPSHOT
|
|
197
|
+
) and not _find_partial_methods_for_user_cls(user_cls, _PartialFunctionFlags.ENTER_POST_SNAPSHOT):
|
|
198
|
+
raise InvalidError("Server class must have an @modal.enter() to setup the server.")
|
|
199
|
+
|
|
200
|
+
# Check for disallowed decorators
|
|
201
|
+
# @modal.method() not allowed
|
|
202
|
+
if _find_partial_methods_for_user_cls(user_cls, _PartialFunctionFlags.CALLABLE_INTERFACE).values():
|
|
203
|
+
raise InvalidError(
|
|
204
|
+
f"Server class {user_cls.__name__} cannot have `@modal.method()` decorated functions. "
|
|
205
|
+
"Servers only expose HTTP endpoints."
|
|
206
|
+
)
|
|
207
|
+
# @enter with snap=True without enable_memory_snapshot
|
|
208
|
+
if (
|
|
209
|
+
_find_partial_methods_for_user_cls(user_cls, _PartialFunctionFlags.ENTER_PRE_SNAPSHOT)
|
|
210
|
+
and not enable_memory_snapshot
|
|
211
|
+
):
|
|
212
|
+
raise InvalidError(
|
|
213
|
+
"Server must have `enable_memory_snapshot=True` to use `snap=True` on `@modal.enter` methods."
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
if isinstance(wrapped_user_cls, _PartialFunction):
|
|
217
|
+
# @modal.concurrent not allowed on server classes
|
|
218
|
+
if wrapped_user_cls.flags & _PartialFunctionFlags.CONCURRENT:
|
|
219
|
+
raise InvalidError(
|
|
220
|
+
f"Server class {user_cls.__name__} cannot be decorated with `@modal.concurrent()`. "
|
|
221
|
+
"Please use `target_concurrency` param instead."
|
|
222
|
+
)
|
|
223
|
+
# @modal.http_server not allowed on server classes
|
|
224
|
+
if wrapped_user_cls.flags & _PartialFunctionFlags.HTTP_WEB_INTERFACE:
|
|
225
|
+
raise InvalidError(
|
|
226
|
+
f"Server class {user_cls.__name__} cannot have @modal.experimental.http_server() decorator. "
|
|
227
|
+
"Servers already expose HTTP endpoints."
|
|
228
|
+
)
|
|
229
|
+
# @modal.web_server not allowed on server classes
|
|
230
|
+
if wrapped_user_cls.flags & _PartialFunctionFlags.WEB_INTERFACE:
|
|
231
|
+
raise InvalidError(
|
|
232
|
+
f"Server class {user_cls.__name__} cannot be decorated with `@modal.web_server()`. "
|
|
233
|
+
"Servers already expose HTTP endpoints."
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
@staticmethod
|
|
237
|
+
def _validate_construction_mechanism(wrapped_user_cls: "type | _PartialFunction"):
|
|
238
|
+
"""Validate that the server class doesn't have a custom constructor."""
|
|
239
|
+
# Extract the underlying class if wrapped in a _PartialFunction (e.g., from @modal.clustered())
|
|
240
|
+
user_cls = _Server._extract_user_cls(wrapped_user_cls)
|
|
241
|
+
|
|
242
|
+
if user_cls.__init__ != object.__init__: # type: ignore
|
|
243
|
+
raise InvalidError(
|
|
244
|
+
f"Server class {user_cls.__name__} cannot have a custom __init__ method. "
|
|
245
|
+
"Use @modal.enter() for initialization logic instead."
|
|
246
|
+
)
|
|
@@ -33,7 +33,7 @@ class _Client:
|
|
|
33
33
|
server_url: str,
|
|
34
34
|
client_type: int,
|
|
35
35
|
credentials: typing.Optional[tuple[str, str]],
|
|
36
|
-
version: str = "1.3.1.
|
|
36
|
+
version: str = "1.3.1.dev27",
|
|
37
37
|
):
|
|
38
38
|
"""mdmd:hidden
|
|
39
39
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -163,7 +163,7 @@ class Client:
|
|
|
163
163
|
server_url: str,
|
|
164
164
|
client_type: int,
|
|
165
165
|
credentials: typing.Optional[tuple[str, str]],
|
|
166
|
-
version: str = "1.3.1.
|
|
166
|
+
version: str = "1.3.1.dev27",
|
|
167
167
|
):
|
|
168
168
|
"""mdmd:hidden
|
|
169
169
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -15,6 +15,7 @@ from modal.cls import _Cls
|
|
|
15
15
|
from modal.dict import _Dict
|
|
16
16
|
from modal_proto import api_pb2
|
|
17
17
|
|
|
18
|
+
from .._server import validate_http_server_config
|
|
18
19
|
from .._tunnel import _forward as _forward_tunnel
|
|
19
20
|
from .._utils.async_utils import synchronize_api, synchronizer
|
|
20
21
|
from ..client import _Client
|
|
@@ -142,7 +143,6 @@ class _FlashManager:
|
|
|
142
143
|
)
|
|
143
144
|
self.num_failures += 1
|
|
144
145
|
await self.client.stub.FlashContainerDeregister(api_pb2.FlashContainerDeregisterRequest())
|
|
145
|
-
|
|
146
146
|
except asyncio.CancelledError:
|
|
147
147
|
logger.warning("[Modal Flash] Shutting down...")
|
|
148
148
|
break
|
|
@@ -670,12 +670,7 @@ def _http_server(
|
|
|
670
670
|
raise InvalidError(
|
|
671
671
|
"Positional arguments are not allowed. Did you forget parentheses? Suggestion: `@modal.http_server()`."
|
|
672
672
|
)
|
|
673
|
-
|
|
674
|
-
raise InvalidError("First argument of `@http_server` must be a local port, such as `@http_server(8000)`.")
|
|
675
|
-
if startup_timeout <= 0:
|
|
676
|
-
raise InvalidError("The `startup_timeout` argument of `@http_server` must be positive.")
|
|
677
|
-
if exit_grace_period is not None and exit_grace_period < 0:
|
|
678
|
-
raise InvalidError("The `exit_grace_period` argument of `@http_server` must be non-negative.")
|
|
673
|
+
validate_http_server_config(port, proxy_regions, startup_timeout, exit_grace_period)
|
|
679
674
|
|
|
680
675
|
from modal._partial_function import _PartialFunction, _PartialFunctionParams
|
|
681
676
|
|
|
@@ -407,7 +407,7 @@ class Function(
|
|
|
407
407
|
|
|
408
408
|
_call_generator: ___call_generator_spec
|
|
409
409
|
|
|
410
|
-
class __remote_spec(typing_extensions.Protocol[
|
|
410
|
+
class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
|
|
411
411
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
|
412
412
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
|
413
413
|
...
|
|
@@ -416,7 +416,7 @@ class Function(
|
|
|
416
416
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
|
417
417
|
...
|
|
418
418
|
|
|
419
|
-
remote: __remote_spec[modal._functions.
|
|
419
|
+
remote: __remote_spec[modal._functions.ReturnType, modal._functions.P]
|
|
420
420
|
|
|
421
421
|
class __remote_gen_spec(typing_extensions.Protocol):
|
|
422
422
|
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
|
|
@@ -443,7 +443,7 @@ class Function(
|
|
|
443
443
|
"""
|
|
444
444
|
...
|
|
445
445
|
|
|
446
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
|
446
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
|
|
447
447
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
448
448
|
"""[Experimental] Calls the function with the given arguments, without waiting for the results.
|
|
449
449
|
|
|
@@ -466,7 +466,7 @@ class Function(
|
|
|
466
466
|
"""
|
|
467
467
|
...
|
|
468
468
|
|
|
469
|
-
_experimental_spawn: ___experimental_spawn_spec[modal._functions.
|
|
469
|
+
_experimental_spawn: ___experimental_spawn_spec[modal._functions.ReturnType, modal._functions.P]
|
|
470
470
|
|
|
471
471
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
|
|
472
472
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
|
|
@@ -474,7 +474,7 @@ class Function(
|
|
|
474
474
|
|
|
475
475
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
|
|
476
476
|
|
|
477
|
-
class __spawn_spec(typing_extensions.Protocol[
|
|
477
|
+
class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
|
|
478
478
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
479
479
|
"""Calls the function with the given arguments, without waiting for the results.
|
|
480
480
|
|
|
@@ -495,7 +495,7 @@ class Function(
|
|
|
495
495
|
"""
|
|
496
496
|
...
|
|
497
497
|
|
|
498
|
-
spawn: __spawn_spec[modal._functions.
|
|
498
|
+
spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P]
|
|
499
499
|
|
|
500
500
|
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
|
|
501
501
|
"""Return the inner Python object wrapped by this Modal Function."""
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import modal.app
|
|
2
|
+
import modal.client
|
|
3
|
+
import modal.functions
|
|
4
|
+
import modal.partial_function
|
|
5
|
+
import typing
|
|
6
|
+
import typing_extensions
|
|
7
|
+
|
|
8
|
+
class Server:
|
|
9
|
+
"""Server runs an HTTP server started in an `@modal.enter` method.
|
|
10
|
+
|
|
11
|
+
See [lifecycle hooks](https://modal.com/docs/guide/lifecycle-functions) for more information.
|
|
12
|
+
|
|
13
|
+
Generally, you will not construct a Server directly.
|
|
14
|
+
Instead, use the [`@app.server()`](https://modal.com/docs/reference/modal.App#server) decorator.
|
|
15
|
+
|
|
16
|
+
```python notest
|
|
17
|
+
@app.server(port=8000, proxy_regions=["us-east", "us-west"])
|
|
18
|
+
class MyServer:
|
|
19
|
+
@modal.enter()
|
|
20
|
+
def start_server(self):
|
|
21
|
+
self.process = subprocess.Popen(["python3", "-m", "http.server", "8080"])
|
|
22
|
+
```
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
_user_cls: typing.Optional[type]
|
|
26
|
+
_service_function: modal.functions.Function
|
|
27
|
+
_app: typing.Optional[modal.app.App]
|
|
28
|
+
|
|
29
|
+
def __init__(self, /, *args, **kwargs):
|
|
30
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
def _get_user_cls(self) -> type: ...
|
|
34
|
+
def _get_app(self) -> modal.app.App: ...
|
|
35
|
+
def _get_service_function(self) -> modal.functions.Function: ...
|
|
36
|
+
@staticmethod
|
|
37
|
+
def _extract_user_cls(wrapped_user_cls: typing.Union[type, modal.partial_function.PartialFunction]) -> type: ...
|
|
38
|
+
|
|
39
|
+
class __get_urls_spec(typing_extensions.Protocol):
|
|
40
|
+
def __call__(self, /) -> typing.Optional[list[str]]: ...
|
|
41
|
+
async def aio(self, /) -> typing.Optional[list[str]]: ...
|
|
42
|
+
|
|
43
|
+
get_urls: __get_urls_spec
|
|
44
|
+
|
|
45
|
+
class __update_autoscaler_spec(typing_extensions.Protocol):
|
|
46
|
+
def __call__(
|
|
47
|
+
self,
|
|
48
|
+
/,
|
|
49
|
+
*,
|
|
50
|
+
min_containers: typing.Optional[int] = None,
|
|
51
|
+
max_containers: typing.Optional[int] = None,
|
|
52
|
+
buffer_containers: typing.Optional[int] = None,
|
|
53
|
+
scaledown_window: typing.Optional[int] = None,
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Override the current autoscaler behavior for this Server.
|
|
56
|
+
|
|
57
|
+
Unspecified parameters will retain their current value.
|
|
58
|
+
|
|
59
|
+
Examples:
|
|
60
|
+
```python notest
|
|
61
|
+
server = modal.Server.from_name("my-app", "Server")
|
|
62
|
+
|
|
63
|
+
# Always have at least 2 containers running, with an extra buffer of 2 containers
|
|
64
|
+
server.update_autoscaler(min_containers=2, buffer_containers=1)
|
|
65
|
+
|
|
66
|
+
# Limit this Server to avoid spinning up more than 5 containers
|
|
67
|
+
server.update_autoscaler(max_containers=5)
|
|
68
|
+
```
|
|
69
|
+
"""
|
|
70
|
+
...
|
|
71
|
+
|
|
72
|
+
async def aio(
|
|
73
|
+
self,
|
|
74
|
+
/,
|
|
75
|
+
*,
|
|
76
|
+
min_containers: typing.Optional[int] = None,
|
|
77
|
+
max_containers: typing.Optional[int] = None,
|
|
78
|
+
buffer_containers: typing.Optional[int] = None,
|
|
79
|
+
scaledown_window: typing.Optional[int] = None,
|
|
80
|
+
) -> None:
|
|
81
|
+
"""Override the current autoscaler behavior for this Server.
|
|
82
|
+
|
|
83
|
+
Unspecified parameters will retain their current value.
|
|
84
|
+
|
|
85
|
+
Examples:
|
|
86
|
+
```python notest
|
|
87
|
+
server = modal.Server.from_name("my-app", "Server")
|
|
88
|
+
|
|
89
|
+
# Always have at least 2 containers running, with an extra buffer of 2 containers
|
|
90
|
+
server.update_autoscaler(min_containers=2, buffer_containers=1)
|
|
91
|
+
|
|
92
|
+
# Limit this Server to avoid spinning up more than 5 containers
|
|
93
|
+
server.update_autoscaler(max_containers=5)
|
|
94
|
+
```
|
|
95
|
+
"""
|
|
96
|
+
...
|
|
97
|
+
|
|
98
|
+
update_autoscaler: __update_autoscaler_spec
|
|
99
|
+
|
|
100
|
+
class __hydrate_spec(typing_extensions.Protocol):
|
|
101
|
+
def __call__(self, /, client: typing.Optional[modal.client.Client] = None) -> Server: ...
|
|
102
|
+
async def aio(self, /, client: typing.Optional[modal.client.Client] = None) -> Server: ...
|
|
103
|
+
|
|
104
|
+
hydrate: __hydrate_spec
|
|
105
|
+
|
|
106
|
+
@staticmethod
|
|
107
|
+
def _from_local(
|
|
108
|
+
wrapped_user_cls: typing.Union[type, modal.partial_function.PartialFunction],
|
|
109
|
+
app: modal.app.App,
|
|
110
|
+
service_function: modal.functions.Function,
|
|
111
|
+
) -> Server:
|
|
112
|
+
"""Create a Server from a local class definition."""
|
|
113
|
+
...
|
|
114
|
+
|
|
115
|
+
@classmethod
|
|
116
|
+
def from_name(
|
|
117
|
+
cls: type[Server],
|
|
118
|
+
app_name: str,
|
|
119
|
+
name: str,
|
|
120
|
+
*,
|
|
121
|
+
environment_name: typing.Optional[str] = None,
|
|
122
|
+
client: typing.Optional[modal.client.Client] = None,
|
|
123
|
+
) -> Server:
|
|
124
|
+
"""Reference a Server from a deployed App by its name.
|
|
125
|
+
|
|
126
|
+
This is a lazy method that defers hydrating the local
|
|
127
|
+
object with metadata from Modal servers until the first
|
|
128
|
+
time it is actually used.
|
|
129
|
+
|
|
130
|
+
```python notest
|
|
131
|
+
server = modal.Server.from_name("other-app", "Server")
|
|
132
|
+
```
|
|
133
|
+
"""
|
|
134
|
+
...
|
|
135
|
+
|
|
136
|
+
def _is_local(self) -> bool:
|
|
137
|
+
"""Returns True if this Server has local source code available."""
|
|
138
|
+
...
|
|
139
|
+
|
|
140
|
+
@staticmethod
|
|
141
|
+
def _validate_wrapped_user_cls_decorators(
|
|
142
|
+
wrapped_user_cls: typing.Union[type, modal.partial_function.PartialFunction], enable_memory_snapshot: bool
|
|
143
|
+
): ...
|
|
144
|
+
@staticmethod
|
|
145
|
+
def _validate_construction_mechanism(wrapped_user_cls: typing.Union[type, modal.partial_function.PartialFunction]):
|
|
146
|
+
"""Validate that the server class doesn't have a custom constructor."""
|
|
147
|
+
...
|
|
@@ -19,6 +19,7 @@ modal/_pty.py
|
|
|
19
19
|
modal/_resolver.py
|
|
20
20
|
modal/_resources.py
|
|
21
21
|
modal/_serialization.py
|
|
22
|
+
modal/_server.py
|
|
22
23
|
modal/_traceback.py
|
|
23
24
|
modal/_tunnel.py
|
|
24
25
|
modal/_tunnel.pyi
|
|
@@ -78,6 +79,8 @@ modal/schedule.py
|
|
|
78
79
|
modal/scheduler_placement.py
|
|
79
80
|
modal/secret.py
|
|
80
81
|
modal/secret.pyi
|
|
82
|
+
modal/server.py
|
|
83
|
+
modal/server.pyi
|
|
81
84
|
modal/serving.py
|
|
82
85
|
modal/serving.pyi
|
|
83
86
|
modal/snapshot.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|