modal.functions

modal.functions.Function

class Function(modal.object.Object)

Functions are the basic units of serverless execution on Modal.

Generally, you will not construct a Function directly. Instead, use the @stub.function() decorator on the Stub object for your application.

def __init__(self, *args, **kwargs):

from_id

@classmethod
def from_id(cls: Type[O], object_id: str, client: Optional[_Client] = None) -> O:

Retrieve an object from its unique ID (accessed through obj.object_id).

persist

def persist(
    self, label: str, namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE, environment_name: Optional[str] = None
):

Object.persist is deprecated for generic objects. See NetworkFileSystem.persisted or Dict.persisted.

from_name

@classmethod
def from_name(
    cls: Type[O],
    app_name: str,
    tag: Optional[str] = None,
    namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
    environment_name: Optional[str] = None,
) -> O:

Retrieve an object with a given name and tag.

Useful for referencing secrets, as well as calling a function from a different app. Use this when attaching the object to a stub or function.

Examples

# Retrieve a secret
stub.my_secret = Secret.from_name("my-secret")

# Retrieve a function from a different app
stub.other_function = Function.from_name("other-app", "function")

# Retrieve a persisted Volume, Queue, or Dict
stub.my_volume = Volume.from_name("my-volume")
stub.my_queue = Queue.from_name("my-queue")
stub.my_dict = Dict.from_name("my-dict")

lookup

@classmethod
def lookup(
    cls: Type[O],
    app_name: str,
    tag: Optional[str] = None,
    namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
    client: Optional[_Client] = None,
    environment_name: Optional[str] = None,
) -> O:

Lookup an object with a given name and tag.

This is a general-purpose method for objects like functions, network file systems, and secrets. It gives a reference to the object in a running app.

Examples

# Lookup a secret
my_secret = Secret.lookup("my-secret")

# Lookup a function from a different app
other_function = Function.lookup("other-app", "function")

# Lookup a persisted Volume, Queue, or Dict
my_volume = Volume.lookup("my-volume")
my_queue = Queue.lookup("my-queue")
my_dict = Dict.lookup("my-dict")

from_parametrized

def from_parametrized(self, obj, args: Iterable[Any], kwargs: Dict[str, Any]) -> "_Function":

stub

@property
def stub(self) -> "modal.stub._Stub":

info

@property
def info(self) -> FunctionInfo:

web_url

@property
def web_url(self) -> str:

URL of a Function running as a web endpoint.

is_generator

@property
def is_generator(self) -> bool:

map

@warn_if_generator_is_not_consumed
@live_method_gen
def map(
    self,
    *input_iterators,  # one input iterator per argument in the mapped-over function/generator
    kwargs={},  # any extra keyword arguments for the function
    order_outputs=None,  # defaults to True for regular functions, False for generators
    return_exceptions=False,  # whether to propogate exceptions (False) or aggregate them in the results list (True)
) -> AsyncGenerator[Any, None]:

Parallel map over a set of inputs.

Takes one iterator argument per argument in the function being mapped over.

Example:

@stub.function()
def my_func(a):
    return a ** 2

@stub.local_entrypoint()
def main():
    assert list(my_func.map([1, 2, 3, 4])) == [1, 4, 9, 16]

If applied to a stub.function, map() returns one result per input and the output order is guaranteed to be the same as the input order. Set order_outputs=False to return results in the order that they are completed instead.

If applied to a stub.generator, the results are returned as they are finished and can be out of order. By yielding zero or more than once, mapping over generators can also be used as a “flat map”.

return_exceptions can be used to treat exceptions as successful results:

@stub.function()
def my_func(a):
    if a == 2:
        raise Exception("ohno")
    return a ** 2

@stub.local_entrypoint()
def main():
    # [0, 1, UserCodeException(Exception('ohno'))]
    print(list(my_func.map(range(3), return_exceptions=True)))

for_each

def for_each(self, *input_iterators, kwargs={}, ignore_exceptions=False):

Execute function for all outputs, ignoring outputs

Convenient alias for .map() in cases where the function just needs to be called. as the caller doesn’t have to consume the generator to process the inputs.

starmap

@warn_if_generator_is_not_consumed
@live_method_gen
def starmap(
    self, input_iterator, kwargs={}, order_outputs=None, return_exceptions=False
) -> AsyncGenerator[Any, None]:

Like map but spreads arguments over multiple function arguments

Assumes every input is a sequence (e.g. a tuple).

Example:

@stub.function()
def my_func(a, b):
    return a + b

@stub.local_entrypoint()
def main():
    assert list(my_func.starmap([(1, 2), (3, 4)])) == [3, 7]

remote

@live_method
def remote(self, *args, **kwargs) -> Awaitable[Any]:  # TODO: Generics/TypeVars

Calls the function remotely, executing it with the given arguments and returning the execution’s result.

remote_gen

@live_method_gen
def remote_gen(self, *args, **kwargs) -> AsyncGenerator[Any, None]:  # TODO: Generics/TypeVars

Calls the generator remotely, executing it with the given arguments and returning the execution’s result.

call

def call(self, *args, **kwargs) -> Awaitable[Any]:  # TODO: Generics/TypeVars

shell

@live_method
def shell(self, *args, **kwargs) -> None:

local

@synchronizer.nowrap
def local(self, *args, **kwargs) -> Any:
    # TODO(erikbern): it would be nice to remove the nowrap thing, but right now that would cause
    # "user code" to run on the synchronicity thread, which seems bad

spawn

def spawn(self, *args, **kwargs) -> Optional["_FunctionCall"]:

Calls the function with the given arguments, without waiting for the results.

Returns a modal.functions.FunctionCall object, that can later be polled or waited for using .get(timeout=...). Conceptually similar to multiprocessing.pool.apply_async, or a Future/Promise in other contexts.

Note: .spawn() on a modal generator function does call and execute the generator, but does not currently return a function handle for polling the result.

get_raw_f

def get_raw_f(self) -> Callable[..., Any]:

Return the inner Python object wrapped by this Modal Function.

get_current_stats

@live_method
def get_current_stats(self) -> FunctionStats:

Return a FunctionStats object describing the current function’s queue and runner counts.

modal.functions.FunctionCall

class FunctionCall(modal.object.Object)

A reference to an executed function call.

Constructed using .spawn(...) on a Modal function with the same arguments that a function normally takes. Acts as a reference to an ongoing function call that can be passed around and used to poll or fetch function results at some later time.

Conceptually similar to a Future/Promise/AsyncResult in other contexts and languages.

def __init__(self, *args, **kwargs):

from_id

@classmethod
def from_id(cls: Type[O], object_id: str, client: Optional[_Client] = None) -> O:

Retrieve an object from its unique ID (accessed through obj.object_id).

persist

def persist(
    self, label: str, namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE, environment_name: Optional[str] = None
):

Object.persist is deprecated for generic objects. See NetworkFileSystem.persisted or Dict.persisted.

from_name

@classmethod
def from_name(
    cls: Type[O],
    app_name: str,
    tag: Optional[str] = None,
    namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
    environment_name: Optional[str] = None,
) -> O:

Retrieve an object with a given name and tag.

Useful for referencing secrets, as well as calling a function from a different app. Use this when attaching the object to a stub or function.

Examples

# Retrieve a secret
stub.my_secret = Secret.from_name("my-secret")

# Retrieve a function from a different app
stub.other_function = Function.from_name("other-app", "function")

# Retrieve a persisted Volume, Queue, or Dict
stub.my_volume = Volume.from_name("my-volume")
stub.my_queue = Queue.from_name("my-queue")
stub.my_dict = Dict.from_name("my-dict")

lookup

@classmethod
def lookup(
    cls: Type[O],
    app_name: str,
    tag: Optional[str] = None,
    namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
    client: Optional[_Client] = None,
    environment_name: Optional[str] = None,
) -> O:

Lookup an object with a given name and tag.

This is a general-purpose method for objects like functions, network file systems, and secrets. It gives a reference to the object in a running app.

Examples

# Lookup a secret
my_secret = Secret.lookup("my-secret")

# Lookup a function from a different app
other_function = Function.lookup("other-app", "function")

# Lookup a persisted Volume, Queue, or Dict
my_volume = Volume.lookup("my-volume")
my_queue = Queue.lookup("my-queue")
my_dict = Dict.lookup("my-dict")

get

def get(self, timeout: Optional[float] = None):

Get the result of the function call.

This function waits indefinitely by default. It takes an optional timeout argument that specifies the maximum number of seconds to wait, which can be set to 0 to poll for an output immediately.

The returned coroutine is not cancellation-safe.

get_call_graph

def get_call_graph(self) -> List[InputInfo]:

Returns a structure representing the call graph from a given root call ID, along with the status of execution for each node.

See modal.call_graph reference page for documentation on the structure of the returned InputInfo items.

cancel

def cancel(self):

modal.functions.FunctionStats

class FunctionStats(object)

Simple data structure storing stats for a running function.

def __init__(self, backlog: int, num_active_runners: int, num_total_runners: int) -> None

modal.functions.PartialFunction

class PartialFunction(object)

Intermediate function, produced by @method or @web_endpoint

def __init__(
    self,
    raw_f: Callable[..., Any],
    webhook_config: Optional[api_pb2.WebhookConfig] = None,
    is_generator: Optional[bool] = None,
):

modal.functions.asgi_app

@typechecked
def asgi_app(
    _warn_parentheses_missing=None,
    *,
    label: Optional[str] = None,  # Label for created endpoint. Final subdomain will be <workspace>--<label>.modal.run.
    wait_for_response: bool = True,  # Whether requests should wait for and return the function response.
    custom_domains: Optional[
        Iterable[str]
    ] = None,  # Create an endpoint using a custom domain fully-qualified domain name.
) -> Callable[[Callable[..., Any]], _PartialFunction]:

Decorator for registering an ASGI app with a Modal function.

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.

Usage:

from typing import Callable

@stub.function()
@modal.asgi_app()
def create_asgi() -> Callable:
    ...

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

The two wait_for_response modes for webhooks are as follows:

  • wait_for_response=True - tries to fulfill the request on the original URL, but returns a 302 redirect after ~150s to a result URL (original URL with an added __modal_function_id=fc-1234abcd query parameter)
  • wait_for_response=False - immediately returns a 202 ACCEPTED response with a JSON payload: {"result_url": "..."} containing the result “redirect” url from above (which in turn redirects to itself every 150s)

modal.functions.current_input_id

def current_input_id() -> str:

Returns the input ID for the currently processed input.

Can only be called from Modal function (i.e. in a container context).

from modal import current_input_id

@stub.function()
def process_stuff():
    print(f"Starting to process {current_input_id()}")

modal.functions.gather

async def gather(*function_calls: _FunctionCall):

Wait until all Modal function calls have results before returning

Accepts a variable number of FunctionCall objects as returned by Function.spawn().

Returns a list of results from each function call, or raises an exception of the first failing function call.

E.g.

function_call_1 = slow_func_1.spawn()
function_call_2 = slow_func_2.spawn()

result_1, result_2 = gather(function_call_1, function_call_2)

modal.functions.method

def method(
    _warn_parentheses_missing=None,
    *,
    # Set this to True if it's a non-generator function returning
    # a [sync/async] generator object
    is_generator: Optional[bool] = None,
) -> Callable[[Callable[..., Any]], _PartialFunction]:

Decorator for methods that should be transformed into a Modal Function registered against this class’s stub.

Usage:

@stub.cls(cpu=8)
class MyCls:

    @modal.method()
    def f(self):
        ...

modal.functions.web_endpoint

@typechecked
def web_endpoint(
    _warn_parentheses_missing=None,
    *,
    method: str = "GET",  # REST method for the created endpoint.
    label: Optional[str] = None,  # Label for created endpoint. Final subdomain will be <workspace>--<label>.modal.run.
    wait_for_response: bool = True,  # Whether requests should wait for and return the function response.
    custom_domains: Optional[
        Iterable[str]
    ] = None,  # Create an endpoint using a custom domain fully-qualified domain name.
) -> Callable[[Callable[..., Any]], _PartialFunction]:

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.web_endpoint are meant to be simple, single request handlers and automatically have CORS enabled. For more flexibility, use @stub.asgi_app.

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

All webhook requests have a 150s maximum request time for the HTTP request itself. However, the underlying functions can run for longer and return results to the caller on completion.

The two wait_for_response modes for webhooks are as follows:

  • wait_for_response=True - tries to fulfill the request on the original URL, but returns a 302 redirect after ~150s to a result URL (original URL with an added __modal_function_id=... query parameter)
  • wait_for_response=False - immediately returns a 202 ACCEPTED response with a JSON payload: {"result_url": "..."} containing the result “redirect” URL from above (which in turn redirects to itself every ~150s)

modal.functions.wsgi_app

@typechecked
def wsgi_app(
    _warn_parentheses_missing=None,
    *,
    label: Optional[str] = None,  # Label for created endpoint. Final subdomain will be <workspace>--<label>.modal.run.
    wait_for_response: bool = True,  # Whether requests should wait for and return the function response.
    custom_domains: Optional[
        Iterable[str]
    ] = None,  # Create an endpoint using a custom domain fully-qualified domain name.
) -> Callable[[Callable[..., Any]], _PartialFunction]:

Decorator for registering a WSGI app with a Modal function.

Web Server Gateway Interface (WSGI) is a standard for synchronous Python web apps. It has been succeeded by the ASGI interface which is compatible with ASGI and supports additional functionality such as web sockets. Modal supports ASGI via asgi_app.

Usage:

from typing import Callable

@stub.function()
@modal.wsgi_app()
def create_wsgi() -> Callable:
    ...

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

For documentation on this decorator’s arguments see asgi_app.