diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 055facd..be32417 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,7 +1,7 @@ {"id":"vgi-python-0fe","title":"Add is_varargs to ParameterInfo and metadata extraction","description":"In vgi/metadata.py:\n- Add is_varargs: bool = False to ParameterInfo\n- Update to_dict() and from_dict()\n- Add is_varargs field to _PARAMETER_STRUCT for Arrow serialization\n- Extract varargs flag in extract_parameters()\n- Add _validate_varargs() with rules:\n - Only one varargs parameter allowed\n - Must be positional (not named)\n - Must be last positional (before TableInput if present)\n - Cannot have default value","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-05T10:49:20.141375-05:00","created_by":"rusty","updated_at":"2026-01-05T10:58:21.242603-05:00","closed_at":"2026-01-05T10:58:21.242603-05:00","close_reason":"Added is_varargs to ParameterInfo, _PARAMETER_STRUCT, extract_parameters(), and _validate_varargs()","dependencies":[{"issue_id":"vgi-python-0fe","depends_on_id":"vgi-python-jrf","type":"blocks","created_at":"2026-01-05T10:49:26.421664-05:00","created_by":"rusty"}]} {"id":"vgi-python-0hr","title":"Remove redundant InitInputType class attribute","description":"InitInputType class attribute duplicates the generic type parameter: 'class ScalarFunctionGenerator(Function[FunctionInitInput])' already specifies the type, but 'InitInputType = FunctionInitInput' repeats it. Investigate using get_type_hints or __orig_bases__ to infer the type and remove the redundant attribute.","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-04T20:06:53.780529-05:00","created_by":"rusty","updated_at":"2026-01-04T22:00:40.221423-05:00","closed_at":"2026-01-04T22:00:40.221423-05:00","close_reason":"PR #10 created - uses _get_init_input_type() to infer type from generic parameter"} {"id":"vgi-python-1s5","title":"Move distributed state management to optional mixin","description":"The Function base class in function.py includes ~200 lines for distributed state management (store_state, collect_states, enqueue_work, dequeue_work, work queue storage). Not all functions need this. Extract to DistributedStateMixin that functions can opt into, keeping Function base class simpler for basic use cases.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-04T20:06:53.606614-05:00","created_by":"rusty","updated_at":"2026-01-04T21:22:09.772825-05:00","closed_at":"2026-01-04T21:22:09.772825-05:00","close_reason":"Analysis complete: extraction not recommended. The distributed state methods are tightly coupled with execution_identifier and storage, which are used by core initialization methods. Extraction would require moving initialize_global_state/load_global_state to the mixin, breaking the protocol and requiring multiple inheritance. Current API is already opt-in (just don't call the methods) and well-documented."} -{"id":"vgi-python-229","title":"Add tests for example function Arrow serialization","description":"Add to tests/test_argument_spec.py:\n\nclass TestExampleFunctionsSerialization:\n- test_scalar_functions: DoubleColumnFunction, AddColumnsFunction, UpperCaseFunction\n- test_table_functions: SequenceFunction, RangeFunction, ConstantTableFunction\n- test_table_in_out_functions: EchoFunction, BufferInputFunction, RepeatInputsFunction, SumAllColumnsFunction\n\nEach test should:\n1. Call extract_argument_specs(cls)\n2. Verify all specs have non-null arrow_type\n3. Verify schema roundtrip works","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-05T15:44:57.064847-05:00","created_by":"rusty","updated_at":"2026-01-05T15:44:57.064847-05:00","dependencies":[{"issue_id":"vgi-python-229","depends_on_id":"vgi-python-coi","type":"blocks","created_at":"2026-01-05T15:45:14.210202-05:00","created_by":"rusty"}]} +{"id":"vgi-python-229","title":"Add tests for example function Arrow serialization","description":"Add to tests/test_argument_spec.py:\n\nclass TestExampleFunctionsSerialization:\n- test_scalar_functions: DoubleColumnFunction, AddColumnsFunction, UpperCaseFunction\n- test_table_functions: SequenceFunction, RangeFunction, ConstantTableFunction\n- test_table_in_out_functions: EchoFunction, BufferInputFunction, RepeatInputsFunction, SumAllColumnsFunction\n\nEach test should:\n1. Call extract_argument_specs(cls)\n2. Verify all specs have non-null arrow_type\n3. Verify schema roundtrip works","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-05T15:44:57.064847-05:00","created_by":"rusty","updated_at":"2026-01-05T16:02:18.537006-05:00","closed_at":"2026-01-05T16:02:18.537006-05:00","close_reason":"PR #23 created","dependencies":[{"issue_id":"vgi-python-229","depends_on_id":"vgi-python-coi","type":"blocks","created_at":"2026-01-05T15:45:14.210202-05:00","created_by":"rusty"}]} {"id":"vgi-python-29x","title":"Add tests for varargs metadata validation","description":"In tests/test_metadata.py:\n- Varargs must be positional - error if named\n- Only one varargs allowed - error if multiple\n- Varargs must be last positional - error if regular arg after\n- Varargs + TableInput ordering works correctly\n- Arrow serialization round-trip preserves is_varargs\n- ParameterInfo.is_varargs correctly extracted","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-05T10:49:20.406998-05:00","created_by":"rusty","updated_at":"2026-01-05T11:02:41.043316-05:00","closed_at":"2026-01-05T11:02:41.043316-05:00","close_reason":"Added tests for varargs metadata extraction and validation","dependencies":[{"issue_id":"vgi-python-29x","depends_on_id":"vgi-python-jrf","type":"blocks","created_at":"2026-01-05T10:49:26.482596-05:00","created_by":"rusty"},{"issue_id":"vgi-python-29x","depends_on_id":"vgi-python-0fe","type":"blocks","created_at":"2026-01-05T10:49:26.512138-05:00","created_by":"rusty"}]} {"id":"vgi-python-2ln","title":"Add varargs support for trailing positional arguments","description":"Allow a single trailing positional argument to accept one or more values of the same type using Arg[T](position, varargs=True). Returns tuple[T, ...]. Requires at least 1 value. Must be last positional arg (before TableInput if present).","status":"closed","priority":2,"issue_type":"feature","created_at":"2026-01-05T10:49:07.327391-05:00","created_by":"rusty","updated_at":"2026-01-05T11:02:41.151847-05:00","closed_at":"2026-01-05T11:02:41.151847-05:00","close_reason":"Completed varargs support for trailing positional arguments"} {"id":"vgi-python-35i","title":"Test SchemaValidationError detailed message paths","notes":"Coverage: 67% in vgi/exceptions.py. Missing tests for:\n- Lines 116-123: Type mismatch detection in _build_detailed_message\n- Lines 128-131: Field order difference detection \n- Lines 149-151: Type mismatch reporting\n- Lines 155-157: Field order difference reporting\n\nTest scenarios needed:\n1. Schema with same fields but different types\n2. Schema with nullable vs non-nullable mismatch\n3. Schema with same fields in different order","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-04T22:15:25.858704-05:00","created_by":"rusty","updated_at":"2026-01-04T22:25:58.697852-05:00","closed_at":"2026-01-04T22:25:58.697852-05:00","close_reason":"Added comprehensive tests for SchemaValidationError. Coverage improved from 67% to 99%."} @@ -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":"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"}]} @@ -44,6 +44,7 @@ {"id":"vgi-python-k7x","title":"Use Mapping instead of dict in extract_argument_specs signature","description":"The arg_types parameter in extract_argument_specs() is typed as dict[str, pa.DataType]. Using Mapping[str, pa.DataType] from collections.abc would be more flexible, accepting any mapping type.","status":"closed","priority":4,"issue_type":"task","created_at":"2026-01-05T11:51:21.021496-05:00","created_by":"rusty","updated_at":"2026-01-05T12:03:51.771301-05:00","closed_at":"2026-01-05T12:03:51.771301-05:00","close_reason":"Closed"} {"id":"vgi-python-kz4","title":"Rename TableInOutGeneratorFunction to TableInOutGenerator for consistency","description":"Naming inconsistency: TableFunctionGenerator uses *Generator suffix, but TableInOutGeneratorFunction uses *GeneratorFunction suffix. Rename TableInOutGeneratorFunction to TableInOutGenerator for consistency. Also consider renaming ScalarFunctionGenerator if needed.","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-04T20:06:41.581028-05:00","created_by":"rusty","updated_at":"2026-01-04T21:43:58.141038-05:00","closed_at":"2026-01-04T21:43:58.141038-05:00","close_reason":"PR #7 created: https://github.com/Query-farm/vgi-python/pull/7"} {"id":"vgi-python-l1u","title":"Consider custom __repr__ for ArgumentSpec","description":"The default dataclass __repr__ includes the full Arrow type repr which can be verbose. Consider a custom __repr__ that's more concise for debugging, e.g., 'ArgumentSpec(name=\"count\", pos=0, type=int64)' instead of showing the full pa.DataType object.","status":"closed","priority":4,"issue_type":"task","created_at":"2026-01-05T11:51:21.415976-05:00","created_by":"rusty","updated_at":"2026-01-05T12:15:02.029743-05:00","closed_at":"2026-01-05T12:15:02.029743-05:00","close_reason":"Closed"} +{"id":"vgi-python-l5z","title":"Update existing tests that use arg_types parameter","description":"In tests/test_argument_spec.py:\n- Update all calls to extract_argument_specs() that pass arg_types\n- Remove the arg_types parameter from test function calls\n- Ensure tests still pass with auto-inference","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-05T15:44:56.81929-05:00","created_by":"rusty","updated_at":"2026-01-05T15:56:39.371768-05:00","closed_at":"2026-01-05T15:56:39.371768-05:00","close_reason":"Completed as part of PR #20","dependencies":[{"issue_id":"vgi-python-l5z","depends_on_id":"vgi-python-coi","type":"blocks","created_at":"2026-01-05T15:45:13.980985-05:00","created_by":"rusty"}]} {"id":"vgi-python-lec","title":"Add test coverage for testing.py helper edge cases","notes":"Coverage: 89% in vgi/testing.py. Missing tests for:\n- Lines 421-422, 450-451: StopIteration handling in _process_batch\n- Lines 468-472: FINISHED status during data phase\n- Lines 485-486, 502-503: _finalize edge cases\n\nLow priority since these are test helpers.","status":"closed","priority":4,"issue_type":"task","created_at":"2026-01-04T22:15:34.006563-05:00","created_by":"rusty","updated_at":"2026-01-05T12:07:48.026786-05:00","closed_at":"2026-01-05T12:07:48.026786-05:00","close_reason":"Closed"} {"id":"vgi-python-lzc","title":"Extract duplicated sort_key function in argument_spec","description":"The sort_key function is duplicated at lines 139-142 and 309-312 in argument_spec.py. Extract it to a module-level function to follow DRY principles.","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-05T11:51:19.141041-05:00","created_by":"rusty","updated_at":"2026-01-05T11:55:22.535816-05:00","closed_at":"2026-01-05T11:55:22.535816-05:00","close_reason":"Closed"} {"id":"vgi-python-m45","title":"Create tests/test_argument_spec.py","description":"## Overview\n\nCreate comprehensive tests for the argument specification serialization module.\n\n## File Location\n\n`tests/test_argument_spec.py`\n\n## Test Classes and Cases\n\n### TestArgumentSpecToSchema\n\nTest converting ArgumentSpec objects to Arrow schema.\n\n#### test_positional_arguments_preserve_order\n- Create specs with positions 0, 1, 2\n- Convert to schema\n- Verify field order matches position order\n- Verify field types are preserved\n\n#### test_named_arguments_have_metadata\n- Create spec with position='key' (named)\n- Convert to schema\n- Verify field has `vgi_arg=named` metadata\n\n#### test_mixed_positional_and_named\n- Create mix of positional (0, 1) and named ('format', 'verbose') specs\n- Convert to schema\n- Verify positional come first, then named\n- Verify named have correct metadata\n\n#### test_table_input_uses_null_type\n- Create spec with is_table_input=True\n- Convert to schema\n- Verify field type is pa.null()\n- Verify field has `vgi_type=table` metadata\n\n#### test_any_type_uses_null_type\n- Create spec with is_any_type=True\n- Convert to schema\n- Verify field type is pa.null()\n- Verify field has `vgi_type=any` metadata\n\n#### test_varargs_has_metadata\n- Create spec with is_varargs=True and arrow_type=pa.int64()\n- Convert to schema\n- Verify field type is pa.int64() (element type preserved)\n- Verify field has `vgi_varargs=true` metadata\n\n### TestSchemaToArgumentSpecs\n\nTest converting Arrow schema back to ArgumentSpec objects.\n\n#### test_positional_arguments_from_schema\n- Create schema with 3 fields (no metadata)\n- Convert to specs\n- Verify positions are 0, 1, 2\n\n#### test_named_arguments_from_metadata\n- Create schema with `vgi_arg=named` metadata on fields\n- Convert to specs\n- Verify position is field name string\n\n#### test_table_input_detected\n- Create schema with `vgi_type=table` metadata\n- Convert to specs\n- Verify is_table_input=True\n\n#### test_any_type_detected\n- Create schema with `vgi_type=any` metadata\n- Convert to specs\n- Verify is_any_type=True\n\n#### test_varargs_detected\n- Create schema with `vgi_varargs=true` metadata\n- Convert to specs\n- Verify is_varargs=True\n\n### TestRoundTrip\n\nTest that specs survive serialization round-trip.\n\n#### test_complex_arrow_types_preserved\nTest each of these types round-trips correctly:\n- pa.int64(), pa.float32(), pa.utf8()\n- pa.list_(pa.float64())\n- pa.struct([pa.field('a', pa.int32()), pa.field('b', pa.string())])\n- pa.map_(pa.string(), pa.int64())\n- pa.decimal128(10, 2)\n- pa.timestamp('us', tz='UTC')\n\n#### test_full_function_signature_roundtrip\n- Create specs matching a realistic function:\n - count: int, position 0\n - data: TableInput, position 1\n - extra: float varargs, position 2\n - format: str, named 'format'\n- Convert to schema, serialize to bytes, deserialize, convert back to specs\n- Verify all specs match original\n\n### TestExtractArgumentSpecs\n\nTest extracting specs from function classes.\n\n#### test_extract_from_simple_function\n- Define function class with Arg descriptors\n- Call extract_argument_specs with arg_types dict\n- Verify specs match descriptors\n\n#### test_extract_table_input\n- Define function with Arg[TableInput]\n- Extract specs\n- Verify is_table_input=True\n\n#### test_extract_any_arrow\n- Define function with Arg[AnyArrow]\n- Extract specs\n- Verify is_any_type=True\n\n#### test_extract_varargs\n- Define function with Arg[int](2, varargs=True)\n- Extract specs\n- Verify is_varargs=True\n\n### TestEdgeCases\n\n#### test_empty_schema\n- Convert empty list of specs to schema\n- Verify empty schema works\n- Convert back, verify empty list\n\n#### test_only_named_arguments\n- Create specs with only named arguments (no positional)\n- Round-trip and verify\n\n#### test_only_positional_arguments\n- Create specs with only positional arguments (no named)\n- Round-trip and verify\n\n## Test Utilities\n\nConsider creating fixtures for common patterns:\n- `make_spec()` helper for creating ArgumentSpec\n- Sample function classes for extraction tests","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-05T11:18:53.312911-05:00","created_by":"rusty","updated_at":"2026-01-05T11:32:35.580879-05:00","closed_at":"2026-01-05T11:32:35.580879-05:00","close_reason":"Created comprehensive tests with 43 passing test cases","dependencies":[{"issue_id":"vgi-python-m45","depends_on_id":"vgi-python-cd0","type":"blocks","created_at":"2026-01-05T11:19:30.779207-05:00","created_by":"rusty"}]} diff --git a/tests/test_argument_spec.py b/tests/test_argument_spec.py index b0ca71e..c9b78c6 100644 --- a/tests/test_argument_spec.py +++ b/tests/test_argument_spec.py @@ -590,6 +590,92 @@ def test_combined_metadata(self) -> None: 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() + + class TestArgumentSpecRepr: """Test ArgumentSpec __repr__ method."""