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
.