docs: show stateful class Functions

The Functions page only showed a plain function, so it never said where a class's `__init__` runs. Users loading a large model need to know it is not the client: registration reads the signature and ships the source.

This adds a section on class Functions: `__init__` runs once per instance on the worker, then `__call__` per row or batch and `close()` on retirement, state is per instance, and `__init__` parameters are initialization fields set per binding. The example's test asserts that registering the class does not construct it.
This commit is contained in:
Wyatt Alt
2026-10-29 04:41:23 +08:00
committed by GitHub
parent 057a39a1c7
commit b4cbaf2f67
3 changed files with 89 additions and 0 deletions
+44
View File
@@ -50,6 +50,25 @@ def describe(value: float):
return {"half": value / 2, "note": None}
# --8<-- [start:function_class_define]
@udf(pip=["sentence-transformers"])
class embed:
def __init__(self, model: str = "all-MiniLM-L6-v2"):
# Runs on the worker, once per instance: only the worker needs the package.
from sentence_transformers import SentenceTransformer
self.model = SentenceTransformer(model)
def __call__(self, text: str) -> list[float]:
return self.model.encode(text).tolist()
def close(self):
del self.model
# --8<-- [end:function_class_define]
# A Function version as the service returns it after registration: the SDK's
# shared golden reply, with the name and signature of the definition above.
SERVICE_REPLY = (
@@ -166,6 +185,31 @@ def test_function_version_binds_a_column(tmp_path):
table.add_columns({"doubled": application})
def test_class_function_is_constructed_only_where_it_runs():
# Registration reads __init__'s signature; it never constructs the class,
# so the model's package need not be installed here.
assert "sentence_transformers" not in sys.modules
signature = embed.registration_request.signature
assert [
(field.name, field.arrow_type, field.nullable)
for field in signature.initialization
] == [("model", "utf8", True)]
assert [(p.name, p.arrow_type) for p in signature.inputs] == [("text", "utf8")]
assert "sentence_transformers" not in sys.modules
embedder = registered_version(embed)
# --8<-- [start:function_class_apply]
from lancedb import col
application = embedder(text=col("text"), model="all-mpnet-base-v2")
# --8<-- [end:function_class_apply]
assert application.initialization == {"model": "all-mpnet-base-v2"}
# The default applies to an omitted field.
assert embedder(text=col("text")).initialization == {}
with pytest.raises(TypeError, match="unknown arguments"):
embedder(text=col("text"), device="cuda")
def test_function_enterprise(monkeypatch):
require_deployment()