Skip to content

Commit 6b33f4d

Browse files
rustyconoverclaude
andcommitted
fix(lint): green the ruff/mypy/pydoclint gates + refresh landing golden
The 0.16 scalar-cache + blended delta left the quality gates red: - ruff: E501 line-length in protocol.py, D-series docstring nits. - mypy: ScalarFunction lacked the CACHE_CONTROL attr (declared only on the *Generator* base but read off ScalarFunction subclasses in protocol.py); TableCardinality(estimate=1) missing the required max; cached_label declared LargeStringArray but returns a string() array. - pydoclint: FunctionInfo/ResolvedMetadata/InitRequest gained input_from_args / substream_id without documenting them. - landing describe.expected.json golden stale after the new fixtures. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 7245913 commit 6b33f4d

12 files changed

Lines changed: 289 additions & 91 deletions

‎tests/landing/describe.expected.json‎

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{
44
"attach_options": [],
55
"counts": {
6-
"functions": 188,
6+
"functions": 199,
77
"schemas": 2,
88
"tables": 59,
99
"views": 3
@@ -655,6 +655,50 @@
655655
"returns": "binary",
656656
"type": "scalar"
657657
},
658+
{
659+
"args": [
660+
{
661+
"desc": "Value",
662+
"name": "value",
663+
"type": "int64"
664+
},
665+
{
666+
"desc": "Constant addend",
667+
"name": "addend",
668+
"type": "int64"
669+
}
670+
],
671+
"doc": "value + const addend (advertises vgi.cache.ttl)",
672+
"name": "cached_add_const",
673+
"returns": "int64",
674+
"type": "scalar"
675+
},
676+
{
677+
"args": [
678+
{
679+
"desc": "Value to double",
680+
"name": "value",
681+
"type": "int64"
682+
}
683+
],
684+
"doc": "Doubles a BIGINT value (advertises vgi.cache.ttl for per-value memo)",
685+
"name": "cached_double_scalar",
686+
"returns": "int64",
687+
"type": "scalar"
688+
},
689+
{
690+
"args": [
691+
{
692+
"desc": "Value",
693+
"name": "value",
694+
"type": "int64"
695+
}
696+
],
697+
"doc": "value -> 'lbl-<value>' or NULL for negatives (advertises vgi.cache.ttl)",
698+
"name": "cached_label",
699+
"returns": "string",
700+
"type": "scalar"
701+
},
658702
{
659703
"args": [
660704
{
@@ -1259,6 +1303,18 @@
12591303
"name": "blended_drop",
12601304
"type": "table"
12611305
},
1306+
{
1307+
"args": [
1308+
{
1309+
"desc": "Fan-out count: emit rows 0..n-1 for this input row",
1310+
"name": "n",
1311+
"type": "int64"
1312+
}
1313+
],
1314+
"doc": "Blended 1->N fan-out (emit 0..n-1 per input row) with row provenance",
1315+
"name": "blended_explode",
1316+
"type": "table"
1317+
},
12621318
{
12631319
"args": [
12641320
{
@@ -1563,6 +1619,42 @@
15631619
"name": "cacheable_numbers",
15641620
"type": "table"
15651621
},
1622+
{
1623+
"args": [
1624+
{
1625+
"desc": "Input column",
1626+
"name": "x",
1627+
"type": "int64"
1628+
}
1629+
],
1630+
"doc": "Cacheable blended map x -> x*2 (advertises vgi.cache.ttl)",
1631+
"name": "cached_double",
1632+
"type": "table"
1633+
},
1634+
{
1635+
"args": [],
1636+
"doc": "Cacheable classic (TABLE-input) passthrough (advertises vgi.cache.ttl)",
1637+
"name": "cached_echo",
1638+
"type": "table"
1639+
},
1640+
{
1641+
"args": [
1642+
{
1643+
"desc": "Input column",
1644+
"name": "x",
1645+
"type": "int64"
1646+
}
1647+
],
1648+
"doc": "Blended map x->x*2 with always-revalidate (304 not_modified) contract",
1649+
"name": "cached_reval_double",
1650+
"type": "table"
1651+
},
1652+
{
1653+
"args": [],
1654+
"doc": "Classic passthrough with always-revalidate (304 not_modified) contract",
1655+
"name": "cached_reval_echo",
1656+
"type": "table"
1657+
},
15661658
{
15671659
"args": [],
15681660
"doc": "Scan colors table (ENUM column)",
@@ -1885,6 +1977,25 @@
18851977
"name": "geo_encode",
18861978
"type": "table"
18871979
},
1980+
{
1981+
"args": [
1982+
{
1983+
"desc": "Input column (echoed as output)",
1984+
"name": "x",
1985+
"type": "int64"
1986+
},
1987+
{
1988+
"default": "\"range\"",
1989+
"desc": "range | length | base64",
1990+
"name": "mode",
1991+
"named": true,
1992+
"type": "string"
1993+
}
1994+
],
1995+
"doc": "Adversarial blended fixture emitting malformed vgi_rpc.parent_row",
1996+
"name": "hostile_provenance",
1997+
"type": "table"
1998+
},
18881999
{
18892000
"args": [
18902001
{
@@ -2302,6 +2413,18 @@
23022413
"name": "profiling_demo",
23032414
"type": "table"
23042415
},
2416+
{
2417+
"args": [
2418+
{
2419+
"desc": "Input column",
2420+
"name": "x",
2421+
"type": "int64"
2422+
}
2423+
],
2424+
"doc": "Blended 1->1 map with projection_pushdown + two output columns",
2425+
"name": "projectable_blended",
2426+
"type": "table"
2427+
},
23052428
{
23062429
"args": [
23072430
{
@@ -2815,6 +2938,20 @@
28152938
"name": "buffer_input",
28162939
"type": "table_in_out"
28172940
},
2941+
{
2942+
"args": [
2943+
{
2944+
"default": "false",
2945+
"desc": "Whether to log during processing",
2946+
"name": "logging",
2947+
"named": true,
2948+
"type": "bool"
2949+
}
2950+
],
2951+
"doc": "Cacheable column-wise sum across all input (advertises vgi.cache.ttl)",
2952+
"name": "cached_sum_all",
2953+
"type": "table_in_out"
2954+
},
28182955
{
28192956
"args": [],
28202957
"doc": "Worker raises during combine (test)",

‎vgi/_test_fixtures/scalar/arithmetic.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ class Meta:
202202
def compute(
203203
cls,
204204
value: Annotated[pa.Int64Array, Param(doc="Value")],
205-
) -> Annotated[pa.LargeStringArray, Returns(pa.string())]:
205+
) -> Annotated[pa.StringArray, Returns(pa.string())]:
206206
"""Label non-negative values; NULL for negatives."""
207207
labels = ["lbl-" + str(v.as_py()) if (v.is_valid and v.as_py() >= 0) else None for v in value]
208208
return pa.array(labels, type=pa.string())

‎vgi/_test_fixtures/table_in_out.py‎

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ class Meta:
155155

156156
@classmethod
157157
def cardinality(cls, params: BindParams[SingleTableArguments]) -> TableCardinality:
158-
# One row per substream; unknown up-front, so leave the estimate open.
159-
return TableCardinality(estimate=1)
158+
# One row per substream; the substream count is unknown up-front.
159+
return TableCardinality(estimate=1, max=None)
160160

161161
@classmethod
162162
def on_bind(cls, params: BindParams[SingleTableArguments]) -> BindResponse:
@@ -1586,9 +1586,7 @@ def process(
15861586
lats = batch.column("latitude").to_pylist()
15871587
lons = batch.column("longitude").to_pylist()
15881588
codes = [
1589-
None
1590-
if lat is None or lon is None
1591-
else f"{round(lat, precision)}:{round(lon, precision)}"
1589+
None if lat is None or lon is None else f"{round(lat, precision)}:{round(lon, precision)}"
15921590
for lat, lon in zip(lats, lons, strict=True)
15931591
]
15941592
out.emit(pa.record_batch({"geohash": pa.array(codes, type=pa.string())}))
@@ -1638,9 +1636,7 @@ def process(
16381636
lons = batch.column("longitude").to_pylist()
16391637
alts = batch.column("altitude").to_pylist()
16401638
codes = [
1641-
None
1642-
if lat is None or lon is None or alt is None
1643-
else f"{round(lat, p)}:{round(lon, p)}:{round(alt, p)}"
1639+
None if lat is None or lon is None or alt is None else f"{round(lat, p)}:{round(lon, p)}:{round(alt, p)}"
16441640
for lat, lon, alt in zip(lats, lons, alts, strict=True)
16451641
]
16461642
out.emit(pa.record_batch({"geohash": pa.array(codes, type=pa.string())}))
@@ -1994,9 +1990,9 @@ class Meta(SumAllColumnsFunction.Meta):
19941990
@classmethod
19951991
def finalize(
19961992
cls,
1997-
params: "TableBufferingParams[SumAllColumnsFunctionArguments]",
1993+
params: TableBufferingParams[SumAllColumnsFunctionArguments],
19981994
finalize_state_id: bytes,
1999-
state: "_LogDrainState",
1995+
state: _LogDrainState,
20001996
out: OutputCollector,
20011997
) -> None:
20021998
rows = params.storage.state_log_scan(state.ns, b"", after_id=state.after_id, limit=1)

‎vgi/_test_fixtures/worker.py‎

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,11 @@
7575
AnyMixedStrFunction,
7676
BernoulliFunction,
7777
BinaryPacketFunction,
78-
ConcatValuesIntFunction,
79-
ConcatValuesStrFunction,
8078
CachedAddConstScalarFunction,
8179
CachedDoubleScalarFunction,
8280
CachedLabelScalarFunction,
81+
ConcatValuesIntFunction,
82+
ConcatValuesStrFunction,
8383
ConditionalMessageFunction,
8484
DoubleFunction,
8585
FormatNumberDefaultFunction,
@@ -226,34 +226,34 @@
226226
)
227227
from vgi._test_fixtures.table_in_out import (
228228
BatchIndexBufferInputFunction,
229+
BlendedDropFunction,
230+
BlendedExplodeFunction,
229231
BufferEmitWideFunction,
230232
BufferInputFunction,
231-
CrashOnCombineFunction,
232-
CrashOnFinalizeFunction,
233-
CrashOnProcessFunction,
234-
BlendedExplodeFunction,
235233
CachedDoubleFunction,
236234
CachedEchoFunction,
237-
CachedRevalidatingEchoFunction,
238235
CachedRevalidatingDoubleFunction,
236+
CachedRevalidatingEchoFunction,
239237
CachedSumAllColumnsFunction,
240-
HostileProvenanceFunction,
241-
ProjectableBlendedFunction,
238+
CrashOnCombineFunction,
239+
CrashOnFinalizeFunction,
240+
CrashOnProcessFunction,
242241
EchoBufferingFunction,
243242
EchoFunction,
244-
GeoEncode3Function,
245-
GeoEncodeFunction,
246-
RowSumFunction,
247-
BlendedDropFunction,
248243
EchoWitnessFunction,
249244
ExceptionFinalizeFunction,
250245
ExceptionProcessFunction,
251246
FilterBySettingFunction,
247+
GeoEncode3Function,
248+
GeoEncodeFunction,
252249
HangOnProcessFunction,
250+
HostileProvenanceFunction,
253251
LargeStateFunction,
254252
OrderedBufferInputFunction,
255253
OrderedSourceFunction,
254+
ProjectableBlendedFunction,
256255
RepeatInputsFunction,
256+
RowSumFunction,
257257
SecretInOutFunction,
258258
SubstreamPartialSumFunction,
259259
SumAllColumnsFunction,

‎vgi/catalog/catalog_interface.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,13 @@ class FunctionInfo(CatalogSchemaObject, ArrowSerializableDataclass):
695695
carries a globally-unique monotonic batch_index from DuckDB's source.
696696
Workers can sort by it in combine() to reconstruct source order under
697697
parallel ingest. Mutually exclusive with ``sink_order_dependent``.
698+
input_from_args: True for a blended ``RowTransformFunction`` — its
699+
positional args ARE its per-row input columns (real typed args, no
700+
``TABLE`` placeholder), so one registration serves the literal /
701+
column / LATERAL call shapes. Set from ``RowTransformFunction``
702+
subclassing; the C++ extension reads it to enter the in-out
703+
registration branch with real-typed args and drive the literal
704+
single-row scan-mode.
698705
required_settings: Settings required by the function.
699706
required_secrets: Secrets required by the function (each entry has
700707
secret_type, optional secret_name, optional scope).

‎vgi/metadata.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,10 @@ class ResolvedMetadata:
408408
BatchIndex()`` so each process() call carries a globally-unique
409409
monotonic batch_index for reconstructing source order under parallel
410410
ingest. Mutually exclusive with ``sink_order_dependent``.
411+
input_from_args: True for a blended ``RowTransformFunction`` — its
412+
positional args ARE its per-row input columns, so one registration
413+
serves the literal / column / LATERAL call shapes. Detected from
414+
``RowTransformFunction`` subclassing.
411415
412416
"""
413417

‎vgi/protocol.py‎

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,13 @@ class InitRequest(ArrowSerializableDataclass):
258258
``None`` for global init, set for secondary init.
259259
init_opaque_data: Opaque per-init state threaded back into the stream;
260260
same producer/wire/consumer contract as ``bind_opaque_data``.
261+
substream_id: Stable, client-owned identity of the streaming
262+
table-in-out substream this request opens (per DuckDB
263+
PipelineExecutor). Rides every InitRequest a substream's worker
264+
builds — INPUT and FINALIZE — so a worker can locate that
265+
substream's accumulated state even when an HTTP load balancer
266+
routes its init / process / finalize to different backends. ``None``
267+
for non-substream function types.
261268
order_by_column_name: Column name of the order-pushdown hint from DuckDB's
262269
RowGroupPruner optimizer; ``None`` when no hint.
263270
order_by_direction: Sort direction of the order-pushdown hint; ``None``
@@ -789,7 +796,7 @@ def exchange(self, input: AnnotatedBatch, out: OutputCollector, ctx: CallContext
789796
# Result-cache opt-in: a scalar declaring CACHE_CONTROL rides its vgi.cache.* keys on
790797
# the emit path's batch custom_metadata (per-batch — not the fixed IPC schema), so the
791798
# extension can memoize the output per distinct input value.
792-
cc_meta = cls.CACHE_CONTROL.to_metadata() if getattr(cls, "CACHE_CONTROL", None) is not None else None
799+
cc_meta = cls.CACHE_CONTROL.to_metadata() if cls.CACHE_CONTROL is not None else None
793800
out.emit(output, metadata=cc_meta)
794801

795802

@@ -939,7 +946,9 @@ def _serialize_partition_values_batch(batch: pa.RecordBatch) -> str:
939946
sink = pa.BufferOutputStream()
940947
with pa.ipc.new_stream(sink, batch.schema) as writer:
941948
writer.write_batch(batch)
942-
return base64.b64encode(sink.getvalue().to_pybytes()).decode("ascii")
949+
# b64encode accepts buffer-protocol objects — no need to copy the
950+
# pa.Buffer into an intermediate bytes first.
951+
return base64.b64encode(sink.getvalue()).decode("ascii")
943952

944953

945954
def _merge_partition_values(
@@ -1351,7 +1360,9 @@ def rehydrate(self, implementation: object) -> None:
13511360
proj_ids = _effective_projection_ids(func_cls, self._init_call.projection_ids)
13521361
output_schema = project_schema(proj_ids, self._init_call.output_schema)
13531362
self._params = ProcessParams(
1354-
args=func_cls._parse_arguments(func_cls.FunctionArguments, self._init_call.bind_call.arguments, blended=func_cls._is_blended()),
1363+
args=func_cls._parse_arguments(
1364+
func_cls.FunctionArguments, self._init_call.bind_call.arguments, blended=func_cls._is_blended()
1365+
),
13551366
init_call=self._init_call,
13561367
init_response=self._init_response,
13571368
output_schema=output_schema,
@@ -1527,7 +1538,9 @@ def rehydrate(self, implementation: object) -> None:
15271538
proj_ids = _effective_projection_ids(func_cls, self._init_call.projection_ids)
15281539
output_schema = project_schema(proj_ids, self._init_call.output_schema)
15291540
self._params = ProcessParams(
1530-
args=func_cls._parse_arguments(func_cls.FunctionArguments, self._init_call.bind_call.arguments, blended=func_cls._is_blended()),
1541+
args=func_cls._parse_arguments(
1542+
func_cls.FunctionArguments, self._init_call.bind_call.arguments, blended=func_cls._is_blended()
1543+
),
15311544
init_call=self._init_call,
15321545
init_response=self._init_response,
15331546
output_schema=output_schema,

0 commit comments

Comments
 (0)