mirror of
https://github.com/lancedb/lancedb.git
synced 2026-11-04 17:56:53 +00:00
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:
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user