vgi-python 0.8.0__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.
Files changed (124) hide show
  1. vgi/__init__.py +152 -0
  2. vgi/_duckdb.py +62 -0
  3. vgi/_storage_profile.py +132 -0
  4. vgi/_test_fixtures/__init__.py +20 -0
  5. vgi/_test_fixtures/accumulate/__init__.py +19 -0
  6. vgi/_test_fixtures/accumulate/worker.py +762 -0
  7. vgi/_test_fixtures/aggregate/__init__.py +62 -0
  8. vgi/_test_fixtures/aggregate/_common.py +21 -0
  9. vgi/_test_fixtures/aggregate/basic.py +232 -0
  10. vgi/_test_fixtures/aggregate/dynamic.py +409 -0
  11. vgi/_test_fixtures/aggregate/generic.py +86 -0
  12. vgi/_test_fixtures/aggregate/listagg.py +71 -0
  13. vgi/_test_fixtures/aggregate/percentile.py +107 -0
  14. vgi/_test_fixtures/aggregate/streaming.py +192 -0
  15. vgi/_test_fixtures/aggregate/varargs.py +75 -0
  16. vgi/_test_fixtures/aggregate/window.py +380 -0
  17. vgi/_test_fixtures/attach_options.py +308 -0
  18. vgi/_test_fixtures/bad_protocol.py +62 -0
  19. vgi/_test_fixtures/cancellable.py +336 -0
  20. vgi/_test_fixtures/catalog.py +813 -0
  21. vgi/_test_fixtures/http_server.py +394 -0
  22. vgi/_test_fixtures/nest_tensor.py +614 -0
  23. vgi/_test_fixtures/orchard_catalog.py +47 -0
  24. vgi/_test_fixtures/projection_repro/__init__.py +6 -0
  25. vgi/_test_fixtures/projection_repro/worker.py +454 -0
  26. vgi/_test_fixtures/scalar/__init__.py +116 -0
  27. vgi/_test_fixtures/scalar/_common.py +69 -0
  28. vgi/_test_fixtures/scalar/arithmetic.py +321 -0
  29. vgi/_test_fixtures/scalar/binary.py +120 -0
  30. vgi/_test_fixtures/scalar/formatting.py +176 -0
  31. vgi/_test_fixtures/scalar/geo.py +300 -0
  32. vgi/_test_fixtures/scalar/null_handling.py +107 -0
  33. vgi/_test_fixtures/scalar/random_demo.py +171 -0
  34. vgi/_test_fixtures/scalar/settings_secrets.py +102 -0
  35. vgi/_test_fixtures/scalar/type_info.py +219 -0
  36. vgi/_test_fixtures/schema_reconcile/__init__.py +29 -0
  37. vgi/_test_fixtures/schema_reconcile/worker.py +653 -0
  38. vgi/_test_fixtures/simple_writable.py +793 -0
  39. vgi/_test_fixtures/table/__init__.py +221 -0
  40. vgi/_test_fixtures/table/_common.py +162 -0
  41. vgi/_test_fixtures/table/batch_index.py +283 -0
  42. vgi/_test_fixtures/table/batch_index_broken.py +200 -0
  43. vgi/_test_fixtures/table/catalog_scans.py +162 -0
  44. vgi/_test_fixtures/table/filters.py +1005 -0
  45. vgi/_test_fixtures/table/late_materialization.py +249 -0
  46. vgi/_test_fixtures/table/make_series.py +273 -0
  47. vgi/_test_fixtures/table/misc.py +499 -0
  48. vgi/_test_fixtures/table/order_modes.py +164 -0
  49. vgi/_test_fixtures/table/pairs.py +437 -0
  50. vgi/_test_fixtures/table/partition_columns.py +472 -0
  51. vgi/_test_fixtures/table/partition_columns_broken.py +304 -0
  52. vgi/_test_fixtures/table/profiling_example.py +195 -0
  53. vgi/_test_fixtures/table/required_filters.py +234 -0
  54. vgi/_test_fixtures/table/sequence.py +710 -0
  55. vgi/_test_fixtures/table/settings.py +426 -0
  56. vgi/_test_fixtures/table/transaction_storage.py +162 -0
  57. vgi/_test_fixtures/table/tt_pushdown.py +191 -0
  58. vgi/_test_fixtures/table/versioned.py +230 -0
  59. vgi/_test_fixtures/table_in_out.py +1392 -0
  60. vgi/_test_fixtures/versioned.py +155 -0
  61. vgi/_test_fixtures/versioned_tables.py +595 -0
  62. vgi/_test_fixtures/worker.py +1631 -0
  63. vgi/_test_fixtures/writable/__init__.py +8 -0
  64. vgi/_test_fixtures/writable/generic.py +236 -0
  65. vgi/_test_fixtures/writable/table.py +149 -0
  66. vgi/_test_fixtures/writable/worker.py +1148 -0
  67. vgi/aggregate_function.py +607 -0
  68. vgi/argument_spec.py +472 -0
  69. vgi/arguments.py +1747 -0
  70. vgi/auth.py +55 -0
  71. vgi/catalog/__init__.py +88 -0
  72. vgi/catalog/attach_option.py +206 -0
  73. vgi/catalog/catalog_interface.py +2767 -0
  74. vgi/catalog/descriptors.py +870 -0
  75. vgi/catalog/duckdb_statistics.py +377 -0
  76. vgi/catalog/secret_type.py +96 -0
  77. vgi/catalog/setting.py +253 -0
  78. vgi/catalog/storage.py +372 -0
  79. vgi/client/__init__.py +67 -0
  80. vgi/client/catalog_mixin.py +1251 -0
  81. vgi/client/cli.py +582 -0
  82. vgi/client/cli_catalog.py +182 -0
  83. vgi/client/cli_schema.py +270 -0
  84. vgi/client/cli_table.py +907 -0
  85. vgi/client/cli_transaction.py +97 -0
  86. vgi/client/cli_utils.py +441 -0
  87. vgi/client/cli_view.py +303 -0
  88. vgi/client/client.py +2183 -0
  89. vgi/exceptions.py +205 -0
  90. vgi/function.py +245 -0
  91. vgi/function_storage.py +1636 -0
  92. vgi/function_storage_azure_sql.py +922 -0
  93. vgi/function_storage_cf_do.py +740 -0
  94. vgi/http/__init__.py +25 -0
  95. vgi/http/demo_storage.py +212 -0
  96. vgi/http/worker_page.py +1252 -0
  97. vgi/invocation.py +154 -0
  98. vgi/logging_config.py +93 -0
  99. vgi/meta_worker.py +661 -0
  100. vgi/metadata.py +1403 -0
  101. vgi/otel.py +406 -0
  102. vgi/protocol.py +2418 -0
  103. vgi/protocol_version.txt +1 -0
  104. vgi/py.typed +0 -0
  105. vgi/scalar_function.py +1211 -0
  106. vgi/schema_utils.py +234 -0
  107. vgi/secret_protocol.py +124 -0
  108. vgi/secret_service.py +238 -0
  109. vgi/serve.py +769 -0
  110. vgi/table_buffering_function.py +443 -0
  111. vgi/table_filter_pushdown.py +1528 -0
  112. vgi/table_function.py +1130 -0
  113. vgi/table_in_out_function.py +383 -0
  114. vgi/transactor/__init__.py +24 -0
  115. vgi/transactor/_duckdb_compat.py +27 -0
  116. vgi/transactor/client.py +137 -0
  117. vgi/transactor/protocol.py +149 -0
  118. vgi/transactor/server.py +740 -0
  119. vgi/worker.py +4761 -0
  120. vgi_python-0.8.0.dist-info/METADATA +735 -0
  121. vgi_python-0.8.0.dist-info/RECORD +124 -0
  122. vgi_python-0.8.0.dist-info/WHEEL +4 -0
  123. vgi_python-0.8.0.dist-info/entry_points.txt +5 -0
  124. vgi_python-0.8.0.dist-info/licenses/LICENSE +134 -0
@@ -0,0 +1,182 @@
1
+ # Copyright 2025, 2026 Query Farm LLC - https://query.farm
2
+
3
+ """Catalog CLI commands for VGI.
4
+
5
+ This module provides CLI commands for catalog operations, organized hierarchically:
6
+
7
+ catalog
8
+ ├── list # List available catalogs
9
+ ├── attach <name> # Attach to a catalog
10
+ ├── detach <attach_opaque_data> # Detach from a catalog
11
+ ├── create <name> # Create a new catalog
12
+ ├── drop <name> # Drop a catalog
13
+ ├── version # Get catalog version (--attach-opaque-data or --catalog)
14
+ ├── schema # Schema operations
15
+ │ ├── list/get/create/drop/contents
16
+ ├── table # Table operations
17
+ │ ├── get/create/drop/rename/...
18
+ ├── view # View operations
19
+ │ ├── get/create/drop/rename/...
20
+ └── transaction # Transaction operations
21
+ ├── begin/commit/rollback
22
+
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ import click
28
+
29
+ from vgi.catalog import OnConflict
30
+ from vgi.client.cli_schema import schema
31
+ from vgi.client.cli_table import table
32
+ from vgi.client.cli_transaction import transaction
33
+ from vgi.client.cli_utils import (
34
+ bytes_to_hex,
35
+ catalog_attach_result_to_dict,
36
+ get_attach_opaque_data_from_options,
37
+ hex_to_attach_opaque_data,
38
+ hex_to_transaction_opaque_data,
39
+ output_json,
40
+ parse_json_option,
41
+ )
42
+ from vgi.client.cli_view import view
43
+ from vgi.client.client import Client
44
+
45
+
46
+ @click.group()
47
+ def catalog() -> None:
48
+ """Manage catalogs, schemas, tables, views, and transactions."""
49
+
50
+
51
+ @catalog.command("list")
52
+ @click.option("--worker", "-w", required=True, help="VGI worker command")
53
+ def catalog_list(worker: str) -> None:
54
+ """List available catalogs."""
55
+ client = Client(worker)
56
+ catalogs = client.catalogs()
57
+ output_json(
58
+ [
59
+ {
60
+ "name": c.name,
61
+ "implementation_version": c.implementation_version,
62
+ "data_version_spec": c.data_version_spec,
63
+ }
64
+ for c in catalogs
65
+ ]
66
+ )
67
+
68
+
69
+ @catalog.command("attach")
70
+ @click.argument("name")
71
+ @click.option("--worker", "-w", required=True, help="VGI worker command")
72
+ @click.option("--options", default="{}", help="Catalog options as JSON object")
73
+ def catalog_attach(name: str, worker: str, options: str) -> None:
74
+ """Attach to a catalog and return attach_opaque_data.
75
+
76
+ NAME is the catalog name to attach to.
77
+
78
+ """
79
+ opts = parse_json_option(options, "--options")
80
+ client = Client(worker)
81
+ result = client.catalog_attach(
82
+ name=name,
83
+ options=opts,
84
+ data_version_spec=None,
85
+ implementation_version=None,
86
+ )
87
+ output_json(catalog_attach_result_to_dict(result))
88
+
89
+
90
+ @catalog.command("detach")
91
+ @click.argument("attach_opaque_data")
92
+ @click.option("--worker", "-w", required=True, help="VGI worker command")
93
+ def catalog_detach(attach_opaque_data: str, worker: str) -> None:
94
+ """Detach from a catalog.
95
+
96
+ ATTACH_ID is the hex-encoded attach ID from catalog attach.
97
+
98
+ """
99
+ client = Client(worker)
100
+ client.catalog_detach(attach_opaque_data=hex_to_attach_opaque_data(attach_opaque_data))
101
+ output_json({"status": "detached"})
102
+
103
+
104
+ @catalog.command("create")
105
+ @click.argument("name")
106
+ @click.option("--worker", "-w", required=True, help="VGI worker command")
107
+ @click.option(
108
+ "--on-conflict",
109
+ type=click.Choice(["error", "ignore", "replace"]),
110
+ default="error",
111
+ help="Behavior if catalog already exists",
112
+ )
113
+ @click.option("--options", default="{}", help="Catalog options as JSON object")
114
+ def catalog_create(name: str, worker: str, on_conflict: str, options: str) -> None:
115
+ """Create a new catalog.
116
+
117
+ NAME is the name for the new catalog.
118
+
119
+ """
120
+ opts = parse_json_option(options, "--options")
121
+ client = Client(worker)
122
+ client.catalog_create(
123
+ name=name,
124
+ on_conflict=OnConflict(on_conflict),
125
+ options=opts,
126
+ )
127
+ output_json({"status": "created", "name": name})
128
+
129
+
130
+ @catalog.command("drop")
131
+ @click.argument("name")
132
+ @click.option("--worker", "-w", required=True, help="VGI worker command")
133
+ def catalog_drop(name: str, worker: str) -> None:
134
+ """Drop a catalog.
135
+
136
+ NAME is the name of the catalog to drop.
137
+
138
+ """
139
+ client = Client(worker)
140
+ client.catalog_drop(name=name)
141
+ output_json({"status": "dropped", "name": name})
142
+
143
+
144
+ @catalog.command("version")
145
+ @click.option("--attach-opaque-data", help="Hex-encoded attach ID")
146
+ @click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
147
+ @click.option("--attach-options", default="{}", help="Attach options as JSON")
148
+ @click.option("--worker", "-w", required=True, help="VGI worker command")
149
+ @click.option("--transaction-opaque-data", help="Transaction ID (hex) for transactional read")
150
+ def catalog_version(
151
+ attach_opaque_data: str | None,
152
+ catalog_name: str | None,
153
+ attach_options: str,
154
+ worker: str,
155
+ transaction_opaque_data: str | None,
156
+ ) -> None:
157
+ """Get the current catalog version."""
158
+ client = Client(worker)
159
+ opts = parse_json_option(attach_options, "--attach-options")
160
+ resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
161
+ client, attach_opaque_data, catalog_name, opts
162
+ )
163
+ if is_stateful and catalog_name:
164
+ click.echo(
165
+ "Warning: Using --catalog with a stateful catalog. "
166
+ "Consider using --attach-opaque-data for session persistence.",
167
+ err=True,
168
+ )
169
+ version = client.catalog_version(
170
+ attach_opaque_data=resolved_attach_opaque_data,
171
+ transaction_opaque_data=(
172
+ hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
173
+ ),
174
+ )
175
+ output_json({"version": version, "attach_opaque_data": bytes_to_hex(resolved_attach_opaque_data)})
176
+
177
+
178
+ # Add nested subcommand groups
179
+ catalog.add_command(schema)
180
+ catalog.add_command(table)
181
+ catalog.add_command(view)
182
+ catalog.add_command(transaction)
@@ -0,0 +1,270 @@
1
+ # Copyright 2025, 2026 Query Farm LLC - https://query.farm
2
+
3
+ """Schema CLI commands for VGI.
4
+
5
+ This module provides CLI commands for schema operations:
6
+ - list: List schemas in a catalog
7
+ - get: Get schema info
8
+ - create: Create a new schema
9
+ - drop: Drop a schema
10
+ - contents: List contents of a schema (tables, views, functions)
11
+
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import click
17
+
18
+ from vgi.catalog import FunctionInfo, SchemaObjectType, TableInfo, ViewInfo
19
+ from vgi.client.cli_utils import (
20
+ function_info_to_dict,
21
+ get_attach_opaque_data_from_options,
22
+ hex_to_transaction_opaque_data,
23
+ output_json,
24
+ parse_json_option,
25
+ schema_info_to_dict,
26
+ table_info_to_dict,
27
+ view_info_to_dict,
28
+ )
29
+ from vgi.client.client import Client
30
+
31
+
32
+ @click.group()
33
+ def schema() -> None:
34
+ """Manage schemas in a catalog."""
35
+
36
+
37
+ @schema.command("list")
38
+ @click.option("--attach-opaque-data", help="Hex-encoded attach ID")
39
+ @click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
40
+ @click.option("--attach-options", default="{}", help="Attach options as JSON")
41
+ @click.option("--worker", "-w", required=True, help="VGI worker command")
42
+ @click.option("--transaction-opaque-data", help="Transaction ID (hex) for transactional read")
43
+ def schema_list(
44
+ attach_opaque_data: str | None,
45
+ catalog_name: str | None,
46
+ attach_options: str,
47
+ worker: str,
48
+ transaction_opaque_data: str | None,
49
+ ) -> None:
50
+ """List schemas in a catalog."""
51
+ client = Client(worker)
52
+ opts = parse_json_option(attach_options, "--attach-options")
53
+ resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
54
+ client, attach_opaque_data, catalog_name, opts
55
+ )
56
+ if is_stateful and catalog_name:
57
+ click.echo(
58
+ "Warning: Using --catalog with a stateful catalog. "
59
+ "Consider using --attach-opaque-data for session persistence.",
60
+ err=True,
61
+ )
62
+ for schema_info in client.schemas(
63
+ attach_opaque_data=resolved_attach_opaque_data,
64
+ transaction_opaque_data=(
65
+ hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
66
+ ),
67
+ ):
68
+ output_json(schema_info_to_dict(schema_info))
69
+
70
+
71
+ @schema.command("get")
72
+ @click.argument("name")
73
+ @click.option("--attach-opaque-data", help="Hex-encoded attach ID")
74
+ @click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
75
+ @click.option("--attach-options", default="{}", help="Attach options as JSON")
76
+ @click.option("--worker", "-w", required=True, help="VGI worker command")
77
+ @click.option("--transaction-opaque-data", help="Transaction ID (hex) for transactional read")
78
+ def schema_get(
79
+ name: str,
80
+ attach_opaque_data: str | None,
81
+ catalog_name: str | None,
82
+ attach_options: str,
83
+ worker: str,
84
+ transaction_opaque_data: str | None,
85
+ ) -> None:
86
+ """Get information about a schema.
87
+
88
+ NAME is the schema name.
89
+
90
+ """
91
+ client = Client(worker)
92
+ opts = parse_json_option(attach_options, "--attach-options")
93
+ resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
94
+ client, attach_opaque_data, catalog_name, opts
95
+ )
96
+ if is_stateful and catalog_name:
97
+ click.echo(
98
+ "Warning: Using --catalog with a stateful catalog. "
99
+ "Consider using --attach-opaque-data for session persistence.",
100
+ err=True,
101
+ )
102
+ schema_info = client.schema_get(
103
+ attach_opaque_data=resolved_attach_opaque_data,
104
+ transaction_opaque_data=(
105
+ hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
106
+ ),
107
+ name=name,
108
+ )
109
+ if schema_info:
110
+ output_json(schema_info_to_dict(schema_info))
111
+ else:
112
+ output_json({"error": "not_found", "name": name})
113
+
114
+
115
+ @schema.command("create")
116
+ @click.argument("name")
117
+ @click.option("--attach-opaque-data", help="Hex-encoded attach ID")
118
+ @click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
119
+ @click.option("--attach-options", default="{}", help="Attach options as JSON")
120
+ @click.option("--worker", "-w", required=True, help="VGI worker command")
121
+ @click.option("--transaction-opaque-data", help="Transaction ID (hex)")
122
+ @click.option("--comment", help="Description of the schema")
123
+ @click.option("--tags", default="{}", help="Metadata tags as JSON object")
124
+ def schema_create(
125
+ name: str,
126
+ attach_opaque_data: str | None,
127
+ catalog_name: str | None,
128
+ attach_options: str,
129
+ worker: str,
130
+ transaction_opaque_data: str | None,
131
+ comment: str | None,
132
+ tags: str,
133
+ ) -> None:
134
+ """Create a new schema.
135
+
136
+ NAME is the name for the new schema.
137
+
138
+ """
139
+ client = Client(worker)
140
+ opts = parse_json_option(attach_options, "--attach-options")
141
+ resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
142
+ client, attach_opaque_data, catalog_name, opts
143
+ )
144
+ if is_stateful and catalog_name:
145
+ click.echo(
146
+ "Warning: Using --catalog with a stateful catalog. "
147
+ "Consider using --attach-opaque-data for session persistence.",
148
+ err=True,
149
+ )
150
+ tags_dict = parse_json_option(tags, "--tags")
151
+ client.schema_create(
152
+ attach_opaque_data=resolved_attach_opaque_data,
153
+ transaction_opaque_data=(
154
+ hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
155
+ ),
156
+ name=name,
157
+ comment=comment,
158
+ tags=tags_dict,
159
+ )
160
+ output_json({"status": "created", "name": name})
161
+
162
+
163
+ @schema.command("drop")
164
+ @click.argument("name")
165
+ @click.option("--attach-opaque-data", help="Hex-encoded attach ID")
166
+ @click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
167
+ @click.option("--attach-options", default="{}", help="Attach options as JSON")
168
+ @click.option("--worker", "-w", required=True, help="VGI worker command")
169
+ @click.option("--transaction-opaque-data", help="Transaction ID (hex)")
170
+ @click.option("--ignore-not-found", is_flag=True, help="Don't error if not found")
171
+ @click.option("--cascade", is_flag=True, help="Drop contained tables and views")
172
+ def schema_drop(
173
+ name: str,
174
+ attach_opaque_data: str | None,
175
+ catalog_name: str | None,
176
+ attach_options: str,
177
+ worker: str,
178
+ transaction_opaque_data: str | None,
179
+ ignore_not_found: bool,
180
+ cascade: bool,
181
+ ) -> None:
182
+ """Drop a schema.
183
+
184
+ NAME is the name of the schema to drop.
185
+
186
+ """
187
+ client = Client(worker)
188
+ opts = parse_json_option(attach_options, "--attach-options")
189
+ resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
190
+ client, attach_opaque_data, catalog_name, opts
191
+ )
192
+ if is_stateful and catalog_name:
193
+ click.echo(
194
+ "Warning: Using --catalog with a stateful catalog. "
195
+ "Consider using --attach-opaque-data for session persistence.",
196
+ err=True,
197
+ )
198
+ client.schema_drop(
199
+ attach_opaque_data=resolved_attach_opaque_data,
200
+ transaction_opaque_data=(
201
+ hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
202
+ ),
203
+ name=name,
204
+ ignore_not_found=ignore_not_found,
205
+ cascade=cascade,
206
+ )
207
+ output_json({"status": "dropped", "name": name})
208
+
209
+
210
+ @schema.command("contents")
211
+ @click.argument("name")
212
+ @click.option("--attach-opaque-data", help="Hex-encoded attach ID")
213
+ @click.option("--catalog", "catalog_name", help="Catalog name for auto-attach")
214
+ @click.option("--attach-options", default="{}", help="Attach options as JSON")
215
+ @click.option("--worker", "-w", required=True, help="VGI worker command")
216
+ @click.option("--transaction-opaque-data", help="Transaction ID (hex) for transactional read")
217
+ @click.option(
218
+ "--type",
219
+ "object_type",
220
+ type=click.Choice(["table", "view", "scalar_function", "table_function", "aggregate_function"]),
221
+ required=True,
222
+ help="Object type to list (required)",
223
+ )
224
+ def schema_contents(
225
+ name: str,
226
+ attach_opaque_data: str | None,
227
+ catalog_name: str | None,
228
+ attach_options: str,
229
+ worker: str,
230
+ transaction_opaque_data: str | None,
231
+ object_type: str,
232
+ ) -> None:
233
+ """List contents of a schema by object type.
234
+
235
+ NAME is the schema name.
236
+
237
+ Requires --type to specify which object type to list.
238
+
239
+ """
240
+ client = Client(worker)
241
+ opts = parse_json_option(attach_options, "--attach-options")
242
+ resolved_attach_opaque_data, is_stateful = get_attach_opaque_data_from_options(
243
+ client, attach_opaque_data, catalog_name, opts
244
+ )
245
+ if is_stateful and catalog_name:
246
+ click.echo(
247
+ "Warning: Using --catalog with a stateful catalog. "
248
+ "Consider using --attach-opaque-data for session persistence.",
249
+ err=True,
250
+ )
251
+
252
+ # Convert string type to SchemaObjectType enum
253
+ type_filter = SchemaObjectType(object_type)
254
+
255
+ for item in client.schema_contents(
256
+ attach_opaque_data=resolved_attach_opaque_data,
257
+ transaction_opaque_data=(
258
+ hex_to_transaction_opaque_data(transaction_opaque_data) if transaction_opaque_data else None
259
+ ),
260
+ name=name,
261
+ type=type_filter,
262
+ ):
263
+ if isinstance(item, TableInfo):
264
+ output_json({"type": "table", **table_info_to_dict(item)})
265
+ elif isinstance(item, ViewInfo):
266
+ output_json({"type": "view", **view_info_to_dict(item)})
267
+ elif isinstance(item, FunctionInfo):
268
+ output_json({"type": "function", **function_info_to_dict(item)})
269
+ else:
270
+ output_json({"type": "unknown", "name": getattr(item, "name", "unknown")})