vgi-python 0.8.2__py3-none-any.whl → 0.8.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
vgi/__init__.py CHANGED
@@ -39,6 +39,7 @@ from vgi.arguments import (
39
39
  Param,
40
40
  Returns,
41
41
  TableInput,
42
+ TaggedUnion,
42
43
  )
43
44
  from vgi.auth import AuthContext, CallContext
44
45
  from vgi.metadata import (
@@ -143,6 +144,7 @@ __all__ = [
143
144
  "TableInOutGenerator",
144
145
  "TableInput",
145
146
  "TableInputValidationError",
147
+ "TaggedUnion",
146
148
  "TypeMismatchError",
147
149
  "Worker",
148
150
  "functions_to_arrow",
vgi/arguments.py CHANGED
@@ -159,6 +159,7 @@ __all__ = [
159
159
  "PYTHON_TO_ARROW",
160
160
  "Returns",
161
161
  "TableInput",
162
+ "TaggedUnion",
162
163
  "TypeBoundPredicate",
163
164
  "OutputLength",
164
165
  "Setting",
@@ -168,6 +169,58 @@ __all__ = [
168
169
  ]
169
170
 
170
171
 
172
+ @dataclass(frozen=True, slots=True)
173
+ class TaggedUnion:
174
+ """A decoded union-typed argument: which member is set (``tag``) and its ``value``.
175
+
176
+ DuckDB ``UNION`` / Arrow union arguments are *tagged*: the discriminator
177
+ (which member is present) lives in the Arrow ``UnionScalar.type_code``, not
178
+ in the member value. Plain ``Scalar.as_py()`` returns only the member value
179
+ and drops that tag, so union arguments are decoded into this wrapper
180
+ instead — ``tag`` is the active member's field name and ``value`` is its
181
+ Python value.
182
+
183
+ Example::
184
+
185
+ config: Annotated[TaggedUnion, Arg("config", arrow_type=pa.sparse_union([...]))]
186
+ ...
187
+ cfg = params.args.config # TaggedUnion(tag=..., value=...)
188
+ if cfg.tag == "random_forest_classifier":
189
+ grid = cfg.value # the member struct, as a dict
190
+
191
+ """
192
+
193
+ tag: str | None
194
+ value: Any
195
+
196
+
197
+ def _scalar_to_py(scalar: "Scalar[Any]") -> Any:
198
+ """Convert an argument scalar to a Python value, preserving union tags.
199
+
200
+ Identical to ``scalar.as_py()`` for every type except unions: a
201
+ ``UnionScalar`` is decoded to a [`TaggedUnion`][] so the member
202
+ discriminator (which ``as_py()`` discards) is retained.
203
+
204
+ Args:
205
+ scalar: The argument scalar to convert.
206
+
207
+ Returns:
208
+ ``scalar.as_py()`` for non-union scalars; a [`TaggedUnion`][] for unions.
209
+
210
+ """
211
+ if isinstance(scalar, pa.UnionScalar):
212
+ # Map the active ``type_code`` to its member field name via the union
213
+ # type's parallel ``type_codes`` / ``field()``. (``type_code`` is coerced
214
+ # to int — it is an integer at runtime regardless of the stub's typing.)
215
+ union_type = scalar.type
216
+ type_codes = list(union_type.type_codes)
217
+ code = int(scalar.type_code)
218
+ tag = union_type.field(type_codes.index(code)).name if code in type_codes else None
219
+ inner = scalar.value
220
+ return TaggedUnion(tag=tag, value=inner.as_py() if inner is not None else None)
221
+ return scalar.as_py()
222
+
223
+
171
224
  class TableInput:
172
225
  """Sentinel type for table input parameters in table-in-out functions.
173
226
 
@@ -377,7 +430,7 @@ class Arguments:
377
430
  else:
378
431
  raise TypeError(f"Argument '{key}': expected {type}, got {scalar.type}")
379
432
 
380
- return scalar.as_py()
433
+ return _scalar_to_py(scalar)
381
434
 
382
435
  def get_varargs(
383
436
  self,
@@ -410,7 +463,7 @@ class Arguments:
410
463
  if type is not None and scalar.type != type:
411
464
  raise TypeError(f"Argument {i}: expected {type}, got {scalar.type}")
412
465
 
413
- values.append(scalar.as_py())
466
+ values.append(_scalar_to_py(scalar))
414
467
 
415
468
  return tuple(values)
416
469
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vgi-python
3
- Version: 0.8.2
3
+ Version: 0.8.3
4
4
  Summary: Vector Gateway Interface - Connect DuckDB to external programs via Apache Arrow
5
5
  Project-URL: Homepage, https://query.farm
6
6
  Project-URL: Repository, https://github.com/Query-farm/vgi-python
@@ -1,9 +1,9 @@
1
- vgi/__init__.py,sha256=RHimcHtz9s4swAt2q3qFTYBFGWSIpqi9ZXonaaqwuPk,3378
1
+ vgi/__init__.py,sha256=PRtFvXxhHEbY_0KVhyXIbGigZDYKHzMS-4gp0p6IJSQ,3414
2
2
  vgi/_duckdb.py,sha256=YB5D7N3Bwg_xP6X8a5QlumtlAovSej1A1Go5XlNGVko,2162
3
3
  vgi/_storage_profile.py,sha256=VkTsXojuE0tHEzurmteQSAiL1vI3CZSgYkL6D_h8GvE,5061
4
4
  vgi/aggregate_function.py,sha256=vn9TjQEHxAKJl_xzQOzdj5TY_6LplcZjv06JkQMnUyo,25184
5
5
  vgi/argument_spec.py,sha256=fVO17BDDfjnTMUrRoILNr2oFLTl4KKedMObFUk2GRrI,17072
6
- vgi/arguments.py,sha256=cnM9qsHlnUsyufSGVvQoCB4RjJGF1YfjExl1FMUlnJc,64940
6
+ vgi/arguments.py,sha256=02tIMGIR_cRS73u-bsgpFERxhje-rnTokjBgGsm9pQA,67019
7
7
  vgi/auth.py,sha256=3HD2zM-Mt0Ie-_HT5RorpND1OusUw2CPROjPNs7rgbo,1478
8
8
  vgi/exceptions.py,sha256=oX_sZc9xGWi7Xf8cJQf89fX19i3ocDEj_V_76GINgBQ,7294
9
9
  vgi/function.py,sha256=SLXA3qErHIsDsn4R0nm56z83Kcw12SMZMYXnPnCzhZg,8520
@@ -122,8 +122,8 @@ vgi/transactor/_duckdb_compat.py,sha256=sXVZ9JLKAQyGR1BjWczSwdQEavtr-TcZPoVZZnTr
122
122
  vgi/transactor/client.py,sha256=7DTeMksogsw6ANjQjGOPpKYrV76rg4_kGjktMJf54jg,4486
123
123
  vgi/transactor/protocol.py,sha256=Mtmll3CdrLFL1B4NY4NZUTO_yi3PT0qhvMQnzapuBWU,4780
124
124
  vgi/transactor/server.py,sha256=WpIqjzy2Mebw17Jui4-w7vyGEo9pD-pEZJG-3Ob1Sk8,29705
125
- vgi_python-0.8.2.dist-info/METADATA,sha256=N8axskbzq44l8JCTbwLv-g_bIEvNecVon3vkg-VwtlY,24725
126
- vgi_python-0.8.2.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
127
- vgi_python-0.8.2.dist-info/entry_points.txt,sha256=3Kz1vgodw3pOL_xjtSyDB55-ZRy-U2X-X_Bdr582x0Q,165
128
- vgi_python-0.8.2.dist-info/licenses/LICENSE,sha256=pbJb4zZasP6n5ifEV81wFu017TarjydaYVmGbHcehtY,6103
129
- vgi_python-0.8.2.dist-info/RECORD,,
125
+ vgi_python-0.8.3.dist-info/METADATA,sha256=1IObmLQGq14cxyOL9Q-3rdWmX5HR9y9br2CJf7az7R0,24725
126
+ vgi_python-0.8.3.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
127
+ vgi_python-0.8.3.dist-info/entry_points.txt,sha256=3Kz1vgodw3pOL_xjtSyDB55-ZRy-U2X-X_Bdr582x0Q,165
128
+ vgi_python-0.8.3.dist-info/licenses/LICENSE,sha256=pbJb4zZasP6n5ifEV81wFu017TarjydaYVmGbHcehtY,6103
129
+ vgi_python-0.8.3.dist-info/RECORD,,