modal.Stub

class Stub(object)

A Stub is a description of how to create a Modal application.

The stub object principally describes Modal objects (Function, Image, Secret, etc.) associated with the application. It has three responsibilities:

  • Syncing of identities across processes (your local Python interpreter and every Modal worker active in your application).
  • Making Objects stay alive and not be garbage collected for as long as the app lives (see App lifetime below).
  • Manage log collection for everything that happens inside your code.

Registering functions with an app

The most common way to explicitly register an Object with an app is through the @stub.function decorator. It both registers the annotated function itself and other passed objects, like schedules and secrets, with the app:

import modal

stub = modal.Stub()

@stub.function(
    secret=modal.Secret.from_name("some_secret"),
    schedule=modal.Period(days=1),
)
def foo():
    pass

In this example, the secret and schedule are registered with the app.

def __init__(
    self,
    name: str = None,
    *,
    mounts: Collection[_Mount] = [],
    secrets: Collection[_Secret] = [],
    **blueprint,
) -> None:

Construct a new app stub, optionally with default mounts.

name

@property
def name(self) -> str:

The user-provided name of the Stub.

description

@property
def description(self) -> str:

The Stub’s name, if available, or a fallback descriptive identifier.

is_inside

def is_inside(self, image: Optional[_Image] = None) -> bool:

Returns if the program is currently running inside a container for this app.

run

@contextlib.asynccontextmanager
def run(self, client=None, stdout=None, show_progress=None, detach=False) -> AsyncGenerator[_App, None]:

Context manager that runs an app on Modal.

Use this as the main entry point for your Modal application. All calls to Modal functions should be made within the scope of this context manager, and they will correspond to the current app.

See the documentation for the App class for more details.

run_forever

def run_forever(self, client=None, stdout=None, show_progress=None) -> None:

Deprecated. Use .serve() instead.

serve

def serve(self, client=None, stdout=None, show_progress=None, timeout=None) -> None:

Run an app until the program is interrupted. Modal watches source files and mounts for the app, and live updates the app when any changes are detected.

This function is useful for developing and testing cron schedules, job queues, and webhooks, since they will run until the program is interrupted with Ctrl + C or other means. Any changes made to webhook handlers will show up almost immediately the next time the route is hit.

deploy

def deploy(
    self,
    name: str = None,  # Unique name of the deployment. Subsequent deploys with the same name overwrites previous ones. Falls back to the app name
    namespace=api_pb2.DEPLOYMENT_NAMESPACE_ACCOUNT,
    client=None,
    stdout=None,
    show_progress=None,
):

Deploy an app and export its objects persistently.

Typically, using the command-line tool modal app deploy <module or script> should be used, instead of this method.

Usage:

if __name__ == "__main__":
    stub.deploy()

Deployment has two primary purposes:

  • Persists all of the objects in the app, allowing them to live past the current app run. For schedules this enables headless “cron”-like functionality where scheduled functions continue to be invoked after the client has disconnected.
  • Allows for certain kinds of these objects, deployment objects, to be referred to and used by other apps.

registered_functions

@property
def registered_functions(self) -> List[str]:

function

@decorator_with_options
def function(
    self,
    raw_f=None,  # The decorated function
    *,
    image: _Image = None,  # The image to run as the container for the function
    schedule: Optional[Schedule] = None,  # An optional Modal Schedule for the function
    secret: Optional[_Secret] = None,  # An optional Modal Secret with environment variables for the container
    secrets: Collection[_Secret] = (),  # Plural version of `secret` when multiple secrets are needed
    gpu: Union[bool, _GPUConfig] = False,  # Whether a GPU is required
    rate_limit: Optional[RateLimit] = None,  # Optional RateLimit for the function
    serialized: bool = False,  # Whether to send the function over using cloudpickle.
    mounts: Collection[_Mount] = (),
    shared_volumes: Dict[str, _SharedVolume] = {},
    cpu: Optional[float] = None,  # How many CPU cores to request. This is a soft limit.
    memory: Optional[int] = None,  # How much memory to request, in MB. This is a soft limit.
    proxy: Optional[Ref] = None,  # Reference to a Modal Proxy to use in front of this function.
    retries: Optional[int] = None,  # Number of times to retry each input in case of failure.
    concurrency_limit: Optional[int] = None,  # Limit for max concurrent containers running the function.
    timeout: Optional[int] = None,  # Maximum execution time of the function in seconds.
    interactive: bool = False,  # Whether to run the function in interactive mode.
    _is_build_step: bool = False,  # Whether function is a build step; reserved for internal use.
    keep_warm: bool = False,  # Toggles an adaptively-sized warm pool for latency-sensitive apps.
) -> _FunctionHandle:  # Function object - callable as a regular function within a Modal app

Decorator to register a new Modal function with this stub.

generator

@decorator_with_options
def generator(
    self,
    raw_f=None,  # The decorated function
    *,
    image: _Image = None,  # The image to run as the container for the function
    secret: Optional[_Secret] = None,  # An optional Modal Secret with environment variables for the container
    secrets: Collection[_Secret] = (),  # Plural version of `secret` when multiple secrets are needed
    gpu: Union[bool, _GPUConfig] = False,  # Whether a GPU is required
    rate_limit: Optional[RateLimit] = None,  # Optional RateLimit for the function
    serialized: bool = False,  # Whether to send the function over using cloudpickle.
    mounts: Collection[_Mount] = (),
    shared_volumes: Dict[str, _SharedVolume] = {},
    cpu: Optional[float] = None,  # How many CPU cores to request. This is a soft limit.
    memory: Optional[int] = None,  # How much memory to request, in MB. This is a soft limit.
    proxy: Optional[Ref] = None,  # Reference to a Modal Proxy to use in front of this function.
    retries: Optional[int] = None,  # Number of times to retry each input in case of failure.
    concurrency_limit: Optional[int] = None,  # Limit for max concurrent containers running the function.
    timeout: Optional[int] = None,  # Maximum execution time of the function in seconds.
    keep_warm: bool = False,  # Toggles an adaptively-sized warm pool for latency-sensitive apps.
) -> _FunctionHandle:

Decorator similar to @modal.function, but it wraps Python generators.

webhook

@decorator_with_options
def webhook(
    self,
    raw_f,
    *,
    method: str = "GET",  # REST method for the created endpoint.
    wait_for_response: bool = True,  # Whether requests should wait for and return the function response.
    image: _Image = None,  # The image to run as the container for the function
    secret: Optional[_Secret] = None,  # An optional Modal Secret with environment variables for the container
    secrets: Collection[_Secret] = (),  # Plural version of `secret` when multiple secrets are needed
    gpu: Union[bool, _GPUConfig] = False,  # Whether a GPU is required
    mounts: Collection[_Mount] = (),
    shared_volumes: Dict[str, _SharedVolume] = {},
    cpu: Optional[float] = None,  # How many CPU cores to request. This is a soft limit.
    memory: Optional[int] = None,  # How much memory to request, in MB. This is a soft limit.
    proxy: Optional[Ref] = None,  # Reference to a Modal Proxy to use in front of this function.
    retries: Optional[int] = None,  # Number of times to retry each input in case of failure.
    concurrency_limit: Optional[int] = None,  # Limit for max concurrent containers running the function.
    timeout: Optional[int] = None,  # Maximum execution time of the function in seconds.
    keep_warm: bool = False,  # Toggles an adaptively-sized warm pool for latency-sensitive apps.
):

Register a basic web endpoint with this application.

This is the simple way to create a web endpoint on Modal. The function behaves as a FastAPI handler and should return a response object to the caller.

Endpoints created with @stub.webhook are meant to be simple, single request handlers and automatically have CORS enabled. For more flexibility, use @stub.asgi.

To learn how to use Modal with popular web frameworks, see the guide on web endpoints.

asgi

@decorator_with_options
def asgi(
    self,
    asgi_app,  # The asgi app
    *,
    wait_for_response: bool = True,  # Whether requests should wait for and return the function response.
    image: _Image = None,  # The image to run as the container for the function
    secret: Optional[_Secret] = None,  # An optional Modal Secret with environment variables for the container
    secrets: Collection[_Secret] = (),  # Plural version of `secret` when multiple secrets are needed
    gpu: Union[bool, _GPUConfig] = False,  # Whether a GPU is required
    mounts: Collection[_Mount] = (),
    shared_volumes: Dict[str, _SharedVolume] = {},
    cpu: Optional[float] = None,  # How many CPU cores to request. This is a soft limit.
    memory: Optional[int] = None,  # How much memory to request, in MB. This is a soft limit.
    proxy: Optional[Ref] = None,  # Reference to a Modal Proxy to use in front of this function.
    retries: Optional[int] = None,  # Number of times to retry each input in case of failure.
    concurrency_limit: Optional[int] = None,  # Limit for max concurrent containers running the function.
    timeout: Optional[int] = None,  # Maximum execution time of the function in seconds.
    keep_warm: bool = False,  # Toggles an adaptively-sized warm pool for latency-sensitive apps.
    _webhook_type=api_pb2.WEBHOOK_TYPE_ASGI_APP,
):

Register an ASGI app with this application.

Asynchronous Server Gateway Interface (ASGI) is a standard for Python synchronous and asynchronous apps, supported by all popular Python web libraries. This is an advanced decorator that gives full flexibility in defining one or more web endpoints on Modal.

To learn how to use Modal with popular web frameworks, see the guide on web endpoints.

wsgi

@decorator_with_options
def wsgi(
    self,
    wsgi_app,
    **kwargs,
):

Exposes a WSGI app. For a list of arguments, see the documentation for asgi.

interactive_shell

def interactive_shell(self, cmd=None, image=None, **kwargs):

Run an interactive shell (like bash) within the image for this app.

This is useful for online debugging and interactive exploration of the contents of this image. If cmd is optionally provided, it will be run instead of the default shell inside this image.

Example

import modal

stub = modal.Stub(image=modal.Image.debian_slim().apt_install(["vim"]))

if __name__ == "__main__":
    stub.interactive_shell("/bin/bash")

Or alternatively:

import modal

stub = modal.Stub()
app_image = modal.Image.debian_slim().apt_install(["vim"])

if __name__ == "__main__":
    stub.interactive_shell(cmd="/bin/bash", image=app_image)