dbt-polars-catalog-databricks 0.3.0__tar.gz

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.
@@ -0,0 +1,228 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ # Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ # poetry.lock
109
+ # poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ # pdm.lock
116
+ # pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ # pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # Redis
135
+ *.rdb
136
+ *.aof
137
+ *.pid
138
+
139
+ # RabbitMQ
140
+ mnesia/
141
+ rabbitmq/
142
+ rabbitmq-data/
143
+
144
+ # ActiveMQ
145
+ activemq-data/
146
+
147
+ # SageMath parsed files
148
+ *.sage.py
149
+
150
+ # Environments
151
+ .env
152
+ .envrc
153
+ .venv
154
+ env/
155
+ venv/
156
+ ENV/
157
+ env.bak/
158
+ venv.bak/
159
+
160
+ # Spyder project settings
161
+ .spyderproject
162
+ .spyproject
163
+
164
+ # Rope project settings
165
+ .ropeproject
166
+
167
+ # mkdocs documentation
168
+ /site
169
+
170
+ # mypy
171
+ .mypy_cache/
172
+ .dmypy.json
173
+ dmypy.json
174
+
175
+ # Pyre type checker
176
+ .pyre/
177
+
178
+ # pytype static type analyzer
179
+ .pytype/
180
+
181
+ # Cython debug symbols
182
+ cython_debug/
183
+
184
+ # PyCharm
185
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
186
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
187
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
188
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
189
+ # .idea/
190
+
191
+ # Abstra
192
+ # Abstra is an AI-powered process automation framework.
193
+ # Ignore directories containing user credentials, local state, and settings.
194
+ # Learn more at https://abstra.io/docs
195
+ .abstra/
196
+
197
+ # Visual Studio Code
198
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
199
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
200
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
201
+ # you could uncomment the following to ignore the entire vscode folder
202
+ .vscode/
203
+ # Temporary file for partial code execution
204
+ tempCodeRunnerFile.py
205
+
206
+ # Ruff stuff:
207
+ .ruff_cache/
208
+
209
+ # PyPI configuration file
210
+ .pypirc
211
+
212
+ # Marimo
213
+ marimo/_static/
214
+ marimo/_lsp/
215
+ __marimo__/
216
+
217
+ # Streamlit
218
+ .streamlit/secrets.toml
219
+
220
+ # uv.lock
221
+ uv.lock
222
+
223
+ # dbt-polars
224
+ logs/
225
+ test.env
226
+ .claude/
227
+ decisions.md
228
+ test_project*/
@@ -0,0 +1,93 @@
1
+ Metadata-Version: 2.5
2
+ Name: dbt-polars-catalog-databricks
3
+ Version: 0.3.0
4
+ Summary: Databricks Unity Catalog catalog for dbt-polars
5
+ Project-URL: Homepage, https://github.com/datamindedbe/incubator-dbt-polars
6
+ Project-URL: Repository, https://github.com/datamindedbe/incubator-dbt-polars
7
+ Project-URL: Changelog, https://github.com/datamindedbe/incubator-dbt-polars/releases
8
+ Author-email: Jonas Crevecoeur <jonas.crevecoeur@dataminded.com>
9
+ Maintainer-email: Jonas Crevecoeur <jonas.crevecoeur@dataminded.com>
10
+ License-Expression: Apache-2.0
11
+ Keywords: catalog,databricks,dbt,polars,unity-catalog
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Database
20
+ Requires-Python: <3.14,>=3.10
21
+ Requires-Dist: databricks-sdk>=0.30.0
22
+ Requires-Dist: dbt-polars==0.3.0
23
+ Description-Content-Type: text/markdown
24
+
25
+ # dbt-polars
26
+
27
+ dbt-polars integrates the flexibility and performance of Polars with the data governance and lineage capabilities of dbt.
28
+
29
+ Key features of **dbt-polars**:
30
+
31
+ * **Run anywhere**: Polars runs on any compute platform, so you’re not locked into an expensive data warehouse.
32
+ * **Flexible**: Available catalogs let you connect to local storage, Iceberg catalogs, Databricks, and more.
33
+ * **Extensible**: Create a custom catalog to fit your unique storage and warehouse needs.
34
+ * **First-class Python models**: Run Python models with the same performance and capabilities as SQL models.
35
+ * **Mix Python and SQL**: Choose the language that best fits the transformation.
36
+ * **dbt-native**: Bring lineage, documentation, and data testing into your workflow.
37
+ * **Ingestion**: Build efficient, incremental API ingestion with Python models and keep the entire pipeline visible in the lineage graph.
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install dbt-polars
43
+ ```
44
+
45
+ Extra dependencies are required for cloud and Iceberg backends:
46
+
47
+ ```bash
48
+ pip install 'dbt-polars[azure]' # Azure Blob Storage
49
+ pip install 'dbt-polars[databricks]' # Azure Blob Storage
50
+ pip install 'dbt-polars[iceberg]' # Apache Iceberg (SQLite, REST, Databricks, …)
51
+ ```
52
+
53
+ ## Catalogs
54
+
55
+ dbt-polars uses **catalogs** to define where data is stored. Each catalog maps to a storage backend. You can configure multiple catalogs in a single profile and reference them from your models.
56
+
57
+ | Catalog | Backend | Status |
58
+ |---|---|---|
59
+ | `local` | Local filesystem | Usable |
60
+ | `iceberg` with SQLite | Iceberg + SQLite metastore | Usable |
61
+ | `iceberg` with REST + Databricks | Iceberg REST API (Unity Catalog) | Experimental |
62
+ | `iceberg` with other backends | Any pyiceberg-supported backend | Experimental |
63
+ | `azure` | Azure Blob Storage / ADLS Gen2 | Experimental |
64
+ | `databricks` | Unity Catalog REST API + credential vending | Experimental |
65
+
66
+ ## Quick start
67
+
68
+ See the [Getting started](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/demos/getting_started.md) guide.
69
+
70
+ A minimal `profiles.yml` for local development is:
71
+
72
+ ```yaml
73
+ my_project:
74
+ target: dev
75
+ outputs:
76
+ dev:
77
+ type: polars
78
+ schema: dev
79
+
80
+ catalog_type: local
81
+ root: ./data
82
+ ```
83
+
84
+ ## Documentation
85
+
86
+ - [Getting started](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/demos/getting_started.md)
87
+ - [Catalog overview and profile reference](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/catalog-overview.md)
88
+ - [Local catalog](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/catalogs/local.md)
89
+ - [Azure catalog](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/catalogs/azure.md)
90
+ - [Iceberg catalog](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/catalogs/iceberg.md)
91
+ - [Databricks catalog](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/catalogs/databricks.md)
92
+ - [Custom catalogs](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/catalogs/custom.md)
93
+ - [Python models and tests](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/python-models.md)
@@ -0,0 +1,69 @@
1
+ # dbt-polars
2
+
3
+ dbt-polars integrates the flexibility and performance of Polars with the data governance and lineage capabilities of dbt.
4
+
5
+ Key features of **dbt-polars**:
6
+
7
+ * **Run anywhere**: Polars runs on any compute platform, so you’re not locked into an expensive data warehouse.
8
+ * **Flexible**: Available catalogs let you connect to local storage, Iceberg catalogs, Databricks, and more.
9
+ * **Extensible**: Create a custom catalog to fit your unique storage and warehouse needs.
10
+ * **First-class Python models**: Run Python models with the same performance and capabilities as SQL models.
11
+ * **Mix Python and SQL**: Choose the language that best fits the transformation.
12
+ * **dbt-native**: Bring lineage, documentation, and data testing into your workflow.
13
+ * **Ingestion**: Build efficient, incremental API ingestion with Python models and keep the entire pipeline visible in the lineage graph.
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ pip install dbt-polars
19
+ ```
20
+
21
+ Extra dependencies are required for cloud and Iceberg backends:
22
+
23
+ ```bash
24
+ pip install 'dbt-polars[azure]' # Azure Blob Storage
25
+ pip install 'dbt-polars[databricks]' # Azure Blob Storage
26
+ pip install 'dbt-polars[iceberg]' # Apache Iceberg (SQLite, REST, Databricks, …)
27
+ ```
28
+
29
+ ## Catalogs
30
+
31
+ dbt-polars uses **catalogs** to define where data is stored. Each catalog maps to a storage backend. You can configure multiple catalogs in a single profile and reference them from your models.
32
+
33
+ | Catalog | Backend | Status |
34
+ |---|---|---|
35
+ | `local` | Local filesystem | Usable |
36
+ | `iceberg` with SQLite | Iceberg + SQLite metastore | Usable |
37
+ | `iceberg` with REST + Databricks | Iceberg REST API (Unity Catalog) | Experimental |
38
+ | `iceberg` with other backends | Any pyiceberg-supported backend | Experimental |
39
+ | `azure` | Azure Blob Storage / ADLS Gen2 | Experimental |
40
+ | `databricks` | Unity Catalog REST API + credential vending | Experimental |
41
+
42
+ ## Quick start
43
+
44
+ See the [Getting started](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/demos/getting_started.md) guide.
45
+
46
+ A minimal `profiles.yml` for local development is:
47
+
48
+ ```yaml
49
+ my_project:
50
+ target: dev
51
+ outputs:
52
+ dev:
53
+ type: polars
54
+ schema: dev
55
+
56
+ catalog_type: local
57
+ root: ./data
58
+ ```
59
+
60
+ ## Documentation
61
+
62
+ - [Getting started](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/demos/getting_started.md)
63
+ - [Catalog overview and profile reference](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/catalog-overview.md)
64
+ - [Local catalog](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/catalogs/local.md)
65
+ - [Azure catalog](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/catalogs/azure.md)
66
+ - [Iceberg catalog](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/catalogs/iceberg.md)
67
+ - [Databricks catalog](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/catalogs/databricks.md)
68
+ - [Custom catalogs](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/catalogs/custom.md)
69
+ - [Python models and tests](https://github.com/datamindedbe/incubator-dbt-polars/blob/main/docs/python-models.md)
@@ -0,0 +1,23 @@
1
+ from dbt.adapters.polars.catalogs import BaseCatalog
2
+
3
+ from dbt_polars_catalog_databricks.config import DatabricksCatalogConfig
4
+ from dbt_polars_catalog_databricks.delta import DatabricksDeltaCatalog
5
+
6
+ CATALOG_BY_TABLE_FORMAT: dict[str, type[BaseCatalog]] = {
7
+ "delta": DatabricksDeltaCatalog,
8
+ }
9
+
10
+ config_class = DatabricksCatalogConfig
11
+
12
+
13
+ def create_catalog(config: DatabricksCatalogConfig, project_root: str) -> BaseCatalog:
14
+ return CATALOG_BY_TABLE_FORMAT[config.table_format](config, project_root)
15
+
16
+
17
+ __all__ = [
18
+ "CATALOG_BY_TABLE_FORMAT",
19
+ "DatabricksCatalogConfig",
20
+ "DatabricksDeltaCatalog",
21
+ "config_class",
22
+ "create_catalog",
23
+ ]
@@ -0,0 +1,59 @@
1
+ from dbt.adapters.polars.catalogs import CatalogConfig
2
+ from dbt_common.exceptions import DbtRuntimeError
3
+
4
+ SUPPORTED_TABLE_FORMATS = ("delta",)
5
+
6
+
7
+ class DatabricksCatalogConfig(CatalogConfig):
8
+ """Config for the Databricks/Unity Catalog backend.
9
+
10
+ `catalog_name` is the only required dbt-polars-specific field (which Unity
11
+ Catalog catalog to register tables in - schema storage locations are read
12
+ from Unity Catalog itself, not configured here). Every other keyword is
13
+ passed straight through to `databricks.sdk.Config`, so any auth method it
14
+ supports (PAT, OAuth M2M, Azure client-secret, external-browser, azure-cli,
15
+ databricks-cli profile, ...) works by supplying the matching kwargs.
16
+
17
+ `persist_docs_http_path`: docs (table/column comments from persist_docs)
18
+ are always written to the Delta table's own metadata. If a SQL warehouse's
19
+ HTTP path (e.g. `/sql/1.0/warehouses/<warehouse_id>`, as shown on the
20
+ warehouse's Connection Details page) is also set here, they're additionally
21
+ written into Unity Catalog's native comment fields via `COMMENT ON TABLE`/
22
+ `ALTER TABLE ... ALTER COLUMN ... COMMENT` - the only way to set those,
23
+ since Unity Catalog's REST API has no endpoint for it at all. Left unset,
24
+ docs never reach Unity Catalog itself.
25
+ """
26
+
27
+ def __init__(
28
+ self,
29
+ *,
30
+ name: str,
31
+ type: str,
32
+ schema: str,
33
+ catalog_name: str,
34
+ host: str | None = None,
35
+ persist_docs_http_path: str | None = None,
36
+ table_format: str = "delta",
37
+ **kwargs: object,
38
+ ) -> None:
39
+ if table_format not in SUPPORTED_TABLE_FORMATS:
40
+ raise DbtRuntimeError(
41
+ f"Databricks catalog '{name}': table_format '{table_format}' is not "
42
+ f"supported, only {', '.join(SUPPORTED_TABLE_FORMATS)} for now."
43
+ )
44
+ self.name = name
45
+ self.type = type
46
+ self.schema = schema
47
+ self.catalog_name = catalog_name
48
+ self.persist_docs_http_path = persist_docs_http_path
49
+ self.table_format = table_format
50
+ self.sdk_kwargs: dict[str, object] = {
51
+ **({"host": host} if host else {}),
52
+ **kwargs,
53
+ }
54
+
55
+ def unique_field(self) -> str:
56
+ return f"{self.catalog_name}/{self.schema}"
57
+
58
+ def connection_keys(self) -> tuple[str, ...]:
59
+ return ("name", "catalog_name", "host", "persist_docs_http_path")
@@ -0,0 +1,119 @@
1
+ """Maps Polars dtypes to Unity Catalog column type descriptors.
2
+
3
+ Used only to populate column metadata when registering a table via the Unity
4
+ Catalog Tables API (`POST /api/2.1/unity-catalog/tables`). Unity Catalog does
5
+ not validate this against the table's actual Parquet/Delta physical types, so
6
+ this is a best-effort, display/documentation-oriented mapping, not a source of
7
+ truth for how data is physically stored.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import json
13
+ from typing import Any
14
+
15
+ import polars as pl
16
+ from dbt.adapters.events.logging import AdapterLogger
17
+
18
+ logger = AdapterLogger("polars")
19
+
20
+ # Delta/Unity Catalog has no unsigned integer types; describe them as the
21
+ # next signed type wide enough to hold every value (mirrors IcebergCatalog's
22
+ # _cast_unsigned_to_signed rationale in icebergCatalog.py).
23
+ UNSIGNED_TO_SIGNED_NAME_TEXT: dict[type, tuple[str, str]] = {
24
+ pl.UInt8: ("SHORT", "smallint"),
25
+ pl.UInt16: ("INT", "int"),
26
+ pl.UInt32: ("LONG", "bigint"),
27
+ pl.UInt64: ("DECIMAL", "decimal(20,0)"),
28
+ }
29
+
30
+ SIMPLE_NAME_TEXT: dict[type, tuple[str, str]] = {
31
+ pl.Boolean: ("BOOLEAN", "boolean"),
32
+ pl.Int8: ("BYTE", "tinyint"),
33
+ pl.Int16: ("SHORT", "smallint"),
34
+ pl.Int32: ("INT", "int"),
35
+ pl.Int64: ("LONG", "bigint"),
36
+ pl.Float32: ("FLOAT", "float"),
37
+ pl.Float64: ("DOUBLE", "double"),
38
+ pl.Utf8: ("STRING", "string"),
39
+ pl.Categorical: ("STRING", "string"),
40
+ pl.Date: ("DATE", "date"),
41
+ pl.Binary: ("BINARY", "binary"),
42
+ }
43
+
44
+
45
+ def decimal_name_text(dtype: pl.Decimal) -> tuple[str, str]:
46
+ precision = dtype.precision if dtype.precision is not None else 38
47
+ scale = dtype.scale or 0
48
+ return "DECIMAL", f"decimal({precision},{scale})"
49
+
50
+
51
+ def datetime_name_text(dtype: pl.Datetime) -> tuple[str, str]:
52
+ if dtype.time_zone:
53
+ return "TIMESTAMP", "timestamp"
54
+ return "TIMESTAMP_NTZ", "timestamp_ntz"
55
+
56
+
57
+ def json_value(dtype: Any) -> object:
58
+ """Return the JSON-able value (str or dict) describing dtype, Spark-schema style."""
59
+ base = type(dtype)
60
+
61
+ if base in UNSIGNED_TO_SIGNED_NAME_TEXT:
62
+ return UNSIGNED_TO_SIGNED_NAME_TEXT[base][1]
63
+ if base in SIMPLE_NAME_TEXT:
64
+ return SIMPLE_NAME_TEXT[base][1]
65
+ if isinstance(dtype, pl.Decimal):
66
+ return decimal_name_text(dtype)[1]
67
+ if isinstance(dtype, pl.Datetime):
68
+ return datetime_name_text(dtype)[1]
69
+ if isinstance(dtype, (pl.List, pl.Array)):
70
+ return {
71
+ "type": "array",
72
+ "elementType": json_value(dtype.inner),
73
+ "containsNull": True,
74
+ }
75
+ if isinstance(dtype, pl.Struct):
76
+ return {
77
+ "type": "struct",
78
+ "fields": [
79
+ {
80
+ "name": f.name,
81
+ "type": json_value(f.dtype),
82
+ "nullable": True,
83
+ "metadata": {},
84
+ }
85
+ for f in dtype.fields
86
+ ],
87
+ }
88
+ logger.debug(
89
+ f"No Unity Catalog type mapping for Polars dtype {dtype!r}; "
90
+ "describing this column as STRING in the registered table metadata."
91
+ )
92
+ return "string"
93
+
94
+
95
+ def polars_dtype_to_uc_type(dtype: Any) -> tuple[str, str, str]:
96
+ """Return (type_name, type_text, type_json) for a Unity Catalog table column."""
97
+ base = type(dtype)
98
+
99
+ if base in UNSIGNED_TO_SIGNED_NAME_TEXT:
100
+ name, text = UNSIGNED_TO_SIGNED_NAME_TEXT[base]
101
+ elif base in SIMPLE_NAME_TEXT:
102
+ name, text = SIMPLE_NAME_TEXT[base]
103
+ elif isinstance(dtype, pl.Decimal):
104
+ name, text = decimal_name_text(dtype)
105
+ elif isinstance(dtype, pl.Datetime):
106
+ name, text = datetime_name_text(dtype)
107
+ elif isinstance(dtype, (pl.List, pl.Array)):
108
+ _, inner_text, _ = polars_dtype_to_uc_type(dtype.inner)
109
+ name, text = "ARRAY", f"array<{inner_text}>"
110
+ elif isinstance(dtype, pl.Struct):
111
+ field_texts = []
112
+ for f in dtype.fields:
113
+ _, f_text, _ = polars_dtype_to_uc_type(f.dtype)
114
+ field_texts.append(f"{f.name}:{f_text}")
115
+ name, text = "STRUCT", f"struct<{','.join(field_texts)}>"
116
+ else:
117
+ name, text = "STRING", "string"
118
+
119
+ return name, text, json.dumps(json_value(dtype))