From ae96731bdd46a27768ab5892a958fc8db460b201 Mon Sep 17 00:00:00 2001 From: Rusty Conover Date: Mon, 5 Jan 2026 16:00:03 -0500 Subject: [PATCH 1/2] test: Add tests for Arg.arrow_type functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add comprehensive tests for the new arrow_type feature: TestArgArrowType: - test_explicit_arrow_type_stored - test_default_arrow_type_is_none - test_arrow_type_in_repr - test_arrow_type_not_in_repr_when_none TestExtractArgumentSpecsAutoInference: - test_int_infers_int64 - test_str_infers_utf8 - test_float_infers_float64 - test_bool_infers_bool - test_bytes_infers_binary - test_explicit_overrides_inference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .beads/issues.jsonl | 2 +- tests/test_argument_spec.py | 86 +++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 3e6ca79..7f84988 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -19,7 +19,7 @@ {"id":"vgi-python-aad","title":"Design: DuckDB settings/pragmas access for VGI functions","description":"Design how VGI functions can declare required DuckDB settings/pragmas in their Meta class, and how these settings values should be passed during the bind phase.\n\nKey design decisions:\n1. How to declare required settings in function Meta (e.g., required_settings = ['timezone', 'threads'])\n2. How to add settings to Invocation dataclass\n3. How settings values should be accessed in function code\n4. Serialization format for settings in Arrow IPC\n\nRecommendation: Add 'duckdb_settings: dict[str, str] | None' to Invocation and 'required_settings: list[str]' to Meta class.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-04T13:05:47.619105-05:00","created_by":"rusty","updated_at":"2026-01-04T13:11:13.197139-05:00","closed_at":"2026-01-04T13:11:13.197139-05:00","close_reason":"Design document created at docs/design-duckdb-settings.md"} {"id":"vgi-python-awm","title":"Add AnyValue sentinel type for arguments accepting any Arrow type","status":"closed","priority":2,"issue_type":"feature","created_at":"2026-01-05T10:41:33.898226-05:00","created_by":"rusty","updated_at":"2026-01-05T11:10:17.138416-05:00","closed_at":"2026-01-05T11:10:17.138416-05:00","close_reason":"Closed"} {"id":"vgi-python-bi8","title":"Extract common _process_with_exception_handling into mixin","description":"The _process_with_exception_handling and _process_and_validate methods are duplicated across scalar_function.py:296-346, table_function.py:386-438, and table_in_out_function.py:586-642. All follow same pattern: try _process_and_validate, catch exceptions, return OutputComplete with error message. Extract to ProcessingMixin that all function types inherit from.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-04T20:06:41.02111-05:00","created_by":"rusty","updated_at":"2026-01-04T21:49:46.320532-05:00","closed_at":"2026-01-04T21:49:46.320532-05:00","close_reason":"PR #8 created - extracted _should_terminate and added _create_error_output to Function base class","dependencies":[{"issue_id":"vgi-python-bi8","depends_on_id":"vgi-python-6o0","type":"blocks","created_at":"2026-01-04T20:07:49.181408-05:00","created_by":"rusty"}]} -{"id":"vgi-python-bjl","title":"Add tests for Arg.arrow_type functionality","description":"Add to tests/test_argument_spec.py:\n\nclass TestArgArrowType:\n- test_explicit_arrow_type_stored: Verify arrow_type is stored\n- test_default_arrow_type_is_none: Verify default is None\n\nclass TestExtractArgumentSpecsAutoInference:\n- test_int_infers_int64\n- test_str_infers_utf8\n- test_float_infers_float64\n- test_explicit_overrides_inference","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-05T15:44:56.945537-05:00","created_by":"rusty","updated_at":"2026-01-05T15:44:56.945537-05:00","dependencies":[{"issue_id":"vgi-python-bjl","depends_on_id":"vgi-python-coi","type":"blocks","created_at":"2026-01-05T15:45:14.093359-05:00","created_by":"rusty"}]} +{"id":"vgi-python-bjl","title":"Add tests for Arg.arrow_type functionality","description":"Add to tests/test_argument_spec.py:\n\nclass TestArgArrowType:\n- test_explicit_arrow_type_stored: Verify arrow_type is stored\n- test_default_arrow_type_is_none: Verify default is None\n\nclass TestExtractArgumentSpecsAutoInference:\n- test_int_infers_int64\n- test_str_infers_utf8\n- test_float_infers_float64\n- test_explicit_overrides_inference","status":"in_progress","priority":2,"issue_type":"task","created_at":"2026-01-05T15:44:56.945537-05:00","created_by":"rusty","updated_at":"2026-01-05T15:58:43.162576-05:00","dependencies":[{"issue_id":"vgi-python-bjl","depends_on_id":"vgi-python-coi","type":"blocks","created_at":"2026-01-05T15:45:14.093359-05:00","created_by":"rusty"}]} {"id":"vgi-python-bku","title":"Change cardinality() method to property for consistency with output_schema","description":"Inconsistent access patterns: output_schema is a property but cardinality() is a method. Both return immutable data. Change cardinality() to a property for API consistency. Located in table_function.py:304-314.","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-04T20:06:53.211782-05:00","created_by":"rusty","updated_at":"2026-01-04T21:33:10.617152-05:00","closed_at":"2026-01-04T21:33:10.617152-05:00","close_reason":"PR #6 created: https://github.com/Query-farm/vgi-python/pull/6"} {"id":"vgi-python-bkz","title":"Update metadata.py to detect AnyValue type","description":"Update _get_arg_type_info() to handle AnyValue like TableInput","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-05T10:41:41.534263-05:00","created_by":"rusty","updated_at":"2026-01-05T11:06:27.291747-05:00","closed_at":"2026-01-05T11:06:27.291747-05:00","close_reason":"Updated _get_arg_type_info() to detect AnyArrow type","dependencies":[{"issue_id":"vgi-python-bkz","depends_on_id":"vgi-python-ckg","type":"blocks","created_at":"2026-01-05T10:41:48.678841-05:00","created_by":"rusty"}]} {"id":"vgi-python-bq4","title":"Update vgi/__init__.py with argument_spec exports","description":"## Overview\n\nUpdate the main package `__init__.py` to export the new argument specification classes and functions.\n\n## File Location\n\n`vgi/__init__.py`\n\n## Changes Required\n\n### Add Import Statement\n\nAdd import from the new module:\n\n```python\nfrom vgi.argument_spec import (\n ArgumentSpec,\n argument_specs_to_schema,\n schema_to_argument_specs,\n)\n```\n\n### Update __all__ List\n\nAdd the new exports to `__all__`:\n\n```python\n__all__ = [\n # ... existing exports ...\n \"ArgumentSpec\",\n \"argument_specs_to_schema\",\n \"schema_to_argument_specs\",\n]\n```\n\n### Placement\n\n- Import should be grouped with other argument-related imports (near `Arg`, `Arguments`)\n- Exports in `__all__` should be alphabetically sorted\n\n## Verification\n\nAfter changes, verify:\n1. `from vgi import ArgumentSpec` works\n2. `from vgi import argument_specs_to_schema` works\n3. `from vgi import schema_to_argument_specs` works","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-05T11:19:25.519702-05:00","created_by":"rusty","updated_at":"2026-01-05T11:34:07.676358-05:00","closed_at":"2026-01-05T11:34:07.676358-05:00","close_reason":"Added ArgumentSpec, argument_specs_to_schema, schema_to_argument_specs exports","dependencies":[{"issue_id":"vgi-python-bq4","depends_on_id":"vgi-python-cd0","type":"blocks","created_at":"2026-01-05T11:19:30.860732-05:00","created_by":"rusty"}]} diff --git a/tests/test_argument_spec.py b/tests/test_argument_spec.py index d1af9f2..119a446 100644 --- a/tests/test_argument_spec.py +++ b/tests/test_argument_spec.py @@ -588,3 +588,89 @@ def test_combined_metadata(self) -> None: assert field.metadata is not None assert field.metadata.get(VGI_ARG_KEY) == VGI_ARG_NAMED assert field.metadata.get(VGI_TYPE_KEY) == VGI_TYPE_ANY + + +class TestArgArrowType: + """Test Arg.arrow_type functionality.""" + + def test_explicit_arrow_type_stored(self) -> None: + """Verify arrow_type is stored when explicitly set.""" + arg = Arg[int](0, arrow_type=pa.int32()) + assert arg.arrow_type == pa.int32() + + def test_default_arrow_type_is_none(self) -> None: + """Verify arrow_type defaults to None.""" + arg = Arg[int](0) + assert arg.arrow_type is None + + def test_arrow_type_in_repr(self) -> None: + """Verify arrow_type appears in repr when set.""" + arg = Arg[int](0, arrow_type=pa.int32()) + repr_str = repr(arg) + assert "arrow_type" in repr_str + assert "int32" in repr_str + + def test_arrow_type_not_in_repr_when_none(self) -> None: + """Verify arrow_type does not appear in repr when None.""" + arg = Arg[int](0) + repr_str = repr(arg) + assert "arrow_type" not in repr_str + + +class TestExtractArgumentSpecsAutoInference: + """Test automatic Arrow type inference in extract_argument_specs.""" + + def test_int_infers_int64(self) -> None: + """Type hint int should infer pa.int64().""" + + class FunctionWithInt(TableInOutFunction): + count: int = Arg[int](0) # type: ignore[assignment] + + specs = extract_argument_specs(FunctionWithInt) + assert specs[0].arrow_type == pa.int64() + + def test_str_infers_utf8(self) -> None: + """Type hint str should infer pa.utf8().""" + + class FunctionWithStr(TableInOutFunction): + name: str = Arg[str](0) # type: ignore[assignment] + + specs = extract_argument_specs(FunctionWithStr) + assert specs[0].arrow_type == pa.utf8() + + def test_float_infers_float64(self) -> None: + """Type hint float should infer pa.float64().""" + + class FunctionWithFloat(TableInOutFunction): + ratio: float = Arg[float](0) # type: ignore[assignment] + + specs = extract_argument_specs(FunctionWithFloat) + assert specs[0].arrow_type == pa.float64() + + def test_bool_infers_bool(self) -> None: + """Type hint bool should infer pa.bool_().""" + + class FunctionWithBool(TableInOutFunction): + flag: bool = Arg[bool](0) # type: ignore[assignment] + + specs = extract_argument_specs(FunctionWithBool) + assert specs[0].arrow_type == pa.bool_() + + def test_bytes_infers_binary(self) -> None: + """Type hint bytes should infer pa.binary().""" + + class FunctionWithBytes(TableInOutFunction): + data: bytes = Arg[bytes](0) # type: ignore[assignment] + + specs = extract_argument_specs(FunctionWithBytes) + assert specs[0].arrow_type == pa.binary() + + def test_explicit_overrides_inference(self) -> None: + """Explicit arrow_type should override type hint inference.""" + + class FunctionWithExplicit(TableInOutFunction): + # Type hint says int (would infer int64), but explicit says int32 + count: int = Arg[int](0, arrow_type=pa.int32()) # type: ignore[assignment] + + specs = extract_argument_specs(FunctionWithExplicit) + assert specs[0].arrow_type == pa.int32() From 26ed87963cb84663b9819441b42d3bb93d52e977 Mon Sep 17 00:00:00 2001 From: Rusty Conover Date: Mon, 5 Jan 2026 16:00:21 -0500 Subject: [PATCH 2/2] bd sync: 2026-01-05 16:00:21 --- .beads/issues.jsonl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 7f84988..8bff7aa 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -19,7 +19,7 @@ {"id":"vgi-python-aad","title":"Design: DuckDB settings/pragmas access for VGI functions","description":"Design how VGI functions can declare required DuckDB settings/pragmas in their Meta class, and how these settings values should be passed during the bind phase.\n\nKey design decisions:\n1. How to declare required settings in function Meta (e.g., required_settings = ['timezone', 'threads'])\n2. How to add settings to Invocation dataclass\n3. How settings values should be accessed in function code\n4. Serialization format for settings in Arrow IPC\n\nRecommendation: Add 'duckdb_settings: dict[str, str] | None' to Invocation and 'required_settings: list[str]' to Meta class.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-04T13:05:47.619105-05:00","created_by":"rusty","updated_at":"2026-01-04T13:11:13.197139-05:00","closed_at":"2026-01-04T13:11:13.197139-05:00","close_reason":"Design document created at docs/design-duckdb-settings.md"} {"id":"vgi-python-awm","title":"Add AnyValue sentinel type for arguments accepting any Arrow type","status":"closed","priority":2,"issue_type":"feature","created_at":"2026-01-05T10:41:33.898226-05:00","created_by":"rusty","updated_at":"2026-01-05T11:10:17.138416-05:00","closed_at":"2026-01-05T11:10:17.138416-05:00","close_reason":"Closed"} {"id":"vgi-python-bi8","title":"Extract common _process_with_exception_handling into mixin","description":"The _process_with_exception_handling and _process_and_validate methods are duplicated across scalar_function.py:296-346, table_function.py:386-438, and table_in_out_function.py:586-642. All follow same pattern: try _process_and_validate, catch exceptions, return OutputComplete with error message. Extract to ProcessingMixin that all function types inherit from.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-04T20:06:41.02111-05:00","created_by":"rusty","updated_at":"2026-01-04T21:49:46.320532-05:00","closed_at":"2026-01-04T21:49:46.320532-05:00","close_reason":"PR #8 created - extracted _should_terminate and added _create_error_output to Function base class","dependencies":[{"issue_id":"vgi-python-bi8","depends_on_id":"vgi-python-6o0","type":"blocks","created_at":"2026-01-04T20:07:49.181408-05:00","created_by":"rusty"}]} -{"id":"vgi-python-bjl","title":"Add tests for Arg.arrow_type functionality","description":"Add to tests/test_argument_spec.py:\n\nclass TestArgArrowType:\n- test_explicit_arrow_type_stored: Verify arrow_type is stored\n- test_default_arrow_type_is_none: Verify default is None\n\nclass TestExtractArgumentSpecsAutoInference:\n- test_int_infers_int64\n- test_str_infers_utf8\n- test_float_infers_float64\n- test_explicit_overrides_inference","status":"in_progress","priority":2,"issue_type":"task","created_at":"2026-01-05T15:44:56.945537-05:00","created_by":"rusty","updated_at":"2026-01-05T15:58:43.162576-05:00","dependencies":[{"issue_id":"vgi-python-bjl","depends_on_id":"vgi-python-coi","type":"blocks","created_at":"2026-01-05T15:45:14.093359-05:00","created_by":"rusty"}]} +{"id":"vgi-python-bjl","title":"Add tests for Arg.arrow_type functionality","description":"Add to tests/test_argument_spec.py:\n\nclass TestArgArrowType:\n- test_explicit_arrow_type_stored: Verify arrow_type is stored\n- test_default_arrow_type_is_none: Verify default is None\n\nclass TestExtractArgumentSpecsAutoInference:\n- test_int_infers_int64\n- test_str_infers_utf8\n- test_float_infers_float64\n- test_explicit_overrides_inference","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-05T15:44:56.945537-05:00","created_by":"rusty","updated_at":"2026-01-05T16:00:21.775071-05:00","closed_at":"2026-01-05T16:00:21.775071-05:00","close_reason":"PR #22 created","dependencies":[{"issue_id":"vgi-python-bjl","depends_on_id":"vgi-python-coi","type":"blocks","created_at":"2026-01-05T15:45:14.093359-05:00","created_by":"rusty"}]} {"id":"vgi-python-bku","title":"Change cardinality() method to property for consistency with output_schema","description":"Inconsistent access patterns: output_schema is a property but cardinality() is a method. Both return immutable data. Change cardinality() to a property for API consistency. Located in table_function.py:304-314.","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-04T20:06:53.211782-05:00","created_by":"rusty","updated_at":"2026-01-04T21:33:10.617152-05:00","closed_at":"2026-01-04T21:33:10.617152-05:00","close_reason":"PR #6 created: https://github.com/Query-farm/vgi-python/pull/6"} {"id":"vgi-python-bkz","title":"Update metadata.py to detect AnyValue type","description":"Update _get_arg_type_info() to handle AnyValue like TableInput","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-05T10:41:41.534263-05:00","created_by":"rusty","updated_at":"2026-01-05T11:06:27.291747-05:00","closed_at":"2026-01-05T11:06:27.291747-05:00","close_reason":"Updated _get_arg_type_info() to detect AnyArrow type","dependencies":[{"issue_id":"vgi-python-bkz","depends_on_id":"vgi-python-ckg","type":"blocks","created_at":"2026-01-05T10:41:48.678841-05:00","created_by":"rusty"}]} {"id":"vgi-python-bq4","title":"Update vgi/__init__.py with argument_spec exports","description":"## Overview\n\nUpdate the main package `__init__.py` to export the new argument specification classes and functions.\n\n## File Location\n\n`vgi/__init__.py`\n\n## Changes Required\n\n### Add Import Statement\n\nAdd import from the new module:\n\n```python\nfrom vgi.argument_spec import (\n ArgumentSpec,\n argument_specs_to_schema,\n schema_to_argument_specs,\n)\n```\n\n### Update __all__ List\n\nAdd the new exports to `__all__`:\n\n```python\n__all__ = [\n # ... existing exports ...\n \"ArgumentSpec\",\n \"argument_specs_to_schema\",\n \"schema_to_argument_specs\",\n]\n```\n\n### Placement\n\n- Import should be grouped with other argument-related imports (near `Arg`, `Arguments`)\n- Exports in `__all__` should be alphabetically sorted\n\n## Verification\n\nAfter changes, verify:\n1. `from vgi import ArgumentSpec` works\n2. `from vgi import argument_specs_to_schema` works\n3. `from vgi import schema_to_argument_specs` works","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-05T11:19:25.519702-05:00","created_by":"rusty","updated_at":"2026-01-05T11:34:07.676358-05:00","closed_at":"2026-01-05T11:34:07.676358-05:00","close_reason":"Added ArgumentSpec, argument_specs_to_schema, schema_to_argument_specs exports","dependencies":[{"issue_id":"vgi-python-bq4","depends_on_id":"vgi-python-cd0","type":"blocks","created_at":"2026-01-05T11:19:30.860732-05:00","created_by":"rusty"}]}