Functions can define a nested Meta class to provide introspection metadata. No inheritance is required - just define the attributes you need.
Metadata works with all function types: ScalarFunction, TableFunctionGenerator, and TableInOutFunction.
from typing import Annotated, Any
from vgi import ScalarFunction, Param, Returns
import pyarrow as pa
import pyarrow.compute as pc
class MultiplyFunction(ScalarFunction):
"""Multiplies a value by a constant factor."""
class Meta:
name = "multiply"
description = "Multiplies a value by a constant factor"
categories = ["numeric", "transform"]
@classmethod
def compute(
cls,
value: Annotated[pa.Int64Array, Param(doc="Integer value to multiply")],
factor: Annotated[int, ConstParam("Multiplication factor")],
) -> Annotated[pa.Int64Array, Returns()]:
return pc.multiply(value, factor)from typing import Annotated, Any
from vgi import ScalarFunction, Param, Returns
from vgi.scalar_function import BindParameters, BindResult
import pyarrow as pa
import pyarrow.compute as pc
class DoubleFunction(ScalarFunction):
"""Double numeric values."""
class Meta:
name = "double"
description = "Doubles numeric values"
categories = ["numeric", "transform"]
@classmethod
def on_bind(cls, params: BindParameters) -> BindResult:
field = params.arguments_schema.field(0)
return BindResult(field.type)
@classmethod
def compute(
cls,
value: Annotated[pa.Array[Any], Param(doc="Numeric value to double")],
) -> Annotated[pa.Array[Any], Returns()]:
return pc.multiply(value, 2)# Get resolved metadata
meta = SumValuesFunction.get_metadata()
print(meta.name) # "sum_values"
print(meta.max_workers) # 1
print(meta.parameters) # [ParameterInfo(name='column_name', ...)]
# Get as JSON-serializable dict
info = SumValuesFunction.describe()| Attribute | Type | Default | Description |
|---|---|---|---|
name |
str |
Class name → snake_case | Function registration name |
description |
str |
First docstring line | Human-readable description |
categories |
list[str] |
[] |
Classification tags |
tags |
dict[str, str] |
{} |
Custom key-value tags |
examples |
list |
[] |
SQL examples (str or FunctionExample) |
max_workers |
int|None |
None (unlimited) |
Max parallel workers |
stability |
FunctionStability |
CONSISTENT |
Output determinism |
null_handling |
NullHandling |
DEFAULT |
NULL input behavior |
argument_monotonicity |
list[ArgumentMonotonicity]|None |
None |
Scalar-only monotonicity claims in argument declaration order |
required_settings |
list[str] |
[] |
Required DuckDB settings |
projection_pushdown |
bool |
True |
Enable column pruning |
filter_pushdown |
bool |
False |
Enable filter pushdown |
preserves_order |
OrderPreservation |
PRESERVES_ORDER |
Row order guarantee |
order_dependent |
OrderDependence |
NOT_ORDER_DEPENDENT |
Aggregate order sensitivity |
distinct_dependent |
DistinctDependence |
NOT_DISTINCT_DEPENDENT |
Aggregate DISTINCT sensitivity |
output_type |
pa.DataType|AnyArrow |
Required for ScalarFunction | Scalar output type |
argument_monotonicity is only valid on scalar functions. When present, it
contains exactly one entry for every field in the function's argument schema.
Fixed, defaulted, and constant parameters each occupy one entry, and a vararg
declaration also occupies one entry regardless of how many values a call
supplies. The ordering is the declaration order, so named SQL calls do not
reorder the metadata. Use None to make no claims; use
ArgumentMonotonicity.UNKNOWN for an explicitly unknown individual slot.
Meta attributes are inherited from parent classes:
class FilterFunction(TableInOutFunction):
class Meta:
categories = ["filter"]
preserves_order = OrderPreservation.PRESERVES_ORDER
class PositiveFilter(FilterFunction):
class Meta:
description = "Keep only positive values"
# Inherits categories=["filter"] from parentMetadata can be serialized to Arrow for worker registration:
from vgi import functions_to_arrow
from vgi.metadata import arrow_to_functions
# Worker sends available functions to client
batch = functions_to_arrow([EchoFunction, SumFunction])
# Client deserializes
function_infos = arrow_to_functions(batch)
for info in function_infos:
print(f"{info.name}: {info.description}")