Functions and Scaling Groups
Define a Chalk Function with the @chalkcompute.function decorator, call it, and ship the helpers it imports.
To define a Chalk Function, decorate a Python callable with @chalkcompute.function:
import chalkcompute
@chalkcompute.function
def add(x: int, y: int) -> int:
return x + y
if __name__ == "__main__":
add.wait_ready()
result = add.remote(3, 5)
print(result) # 8
Deploy by running the script: the decorator registers the function with
Chalk as soon as it runs. wait_ready() blocks until the deployed function
is available, and .remote(...) invokes it. add(3, 5) runs the Python body
locally instead; use .remote(...) to call the deployed version.
To call an already-deployed function from a different script — without
redeploying — attach to it by name with RemoteFunction.from_name:
import chalkcompute
fn = chalkcompute.RemoteFunction.from_name("add")
result = fn.remote(3, 5)
print(result) # 8
A deployed function often calls helpers defined in other files. Whether a
helper resolves remotely depends on where it lives relative to the decorated
function (the function under @chalkcompute.function):
Image.add_local_python_source.
The same applies to all file-external helpers when the decorated function is
defined in a standalone script rather than a package.If the decorated function’s module runs as part of a package (imported from
an entrypoint, or executed directly with python -m), Chalk ships the whole
top-level package in the deploy image:
# mypkg/helpers.py
def normalize(text: str) -> str:
return text.strip().lower()
# mypkg/pipeline.py
import chalkcompute
from mypkg.helpers import normalize
@chalkcompute.function
def clean(text: str) -> str:
return normalize(text)
# main.py (outside mypkg/)
from mypkg.pipeline import clean
print(clean.remote(" Hello "))
uv run python main.py
Running the entrypoint (or the function’s own module with
uv run python -m mypkg.pipeline) deploys clean with all of mypkg, so
normalize is importable remotely exactly as it is locally.
Running the file by path (uv run python mypkg/pipeline.py) ships only that one file
because Python doesn’t know that it belongs to a package. In this scenario, Chalk will
raise an error at deploy time.
Every run of an entrypoint that imports the decorated function deploys a new
function version. To call an existing deployment without redeploying, attach
to it by name with RemoteFunction.from_name instead.
# call_clean.py: call the deployed function without triggering a redeploy
import chalkcompute
fn = chalkcompute.RemoteFunction.from_name("clean")
print(fn.remote(" Hello "))
uv run python call_clean.py
add_local_python_sourceWhen the decorated function is defined in a standalone script, or imports helpers from outside its own top-level package, list those local modules or packages on the image:
# helpers.py (next to deploy.py)
def normalize(text: str) -> str:
return text.strip().lower()
# deploy.py
import chalkcompute
from helpers import normalize
@chalkcompute.function(
image=chalkcompute.Image.debian_slim().add_local_python_source("helpers"),
)
def clean(text: str) -> str:
return normalize(text)
uv run python deploy.py
add_local_python_source accepts any number of top-level module or package
names. Each must be importable on your local Python path; packages are copied
whole (excluding __pycache__). Dotted names, namespace packages spanning
multiple directories, and compiled extensions are rejected with a
ValueError.
This ships your own source code only. Third-party dependencies still need to
be installed in the image with pip_install or run_commands.