unitycatalog-client 0.2.1__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.
- unitycatalog_client-0.2.1/.gitignore +29 -0
- unitycatalog_client-0.2.1/PKG-INFO +199 -0
- unitycatalog_client-0.2.1/README.md +160 -0
- unitycatalog_client-0.2.1/pyproject.toml +97 -0
- unitycatalog_client-0.2.1/setup.py +75 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/__init__.py +102 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/api/__init__.py +13 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/api/catalogs_api.py +1404 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/api/functions_api.py +1135 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/api/grants_api.py +630 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/api/model_versions_api.py +1748 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/api/registered_models_api.py +1438 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/api/schemas_api.py +1421 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/api/tables_api.py +1135 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/api/temporary_credentials_api.py +1109 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/api/volumes_api.py +1421 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/api_client.py +773 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/api_response.py +21 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/configuration.py +432 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/exceptions.py +199 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/__init__.py +77 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/aws_credentials.py +91 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/azure_user_delegation_sas.py +87 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/catalog_info.py +103 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/column_info.py +108 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/column_type_name.py +56 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/create_catalog.py +91 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/create_function.py +163 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/create_function_request.py +91 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/create_model_version.py +97 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/create_registered_model.py +93 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/create_schema.py +93 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/create_table.py +113 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/create_volume_request_content.py +99 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/data_source_format.py +42 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/dependency.py +97 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/dependency_list.py +95 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/finalize_model_version.py +89 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/function_dependency.py +87 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/function_info.py +189 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/function_parameter_info.py +112 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/function_parameter_infos.py +95 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/function_parameter_mode.py +36 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/function_parameter_type.py +37 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/gcp_oauth_token.py +87 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/generate_temporary_model_version_credential.py +96 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/generate_temporary_path_credential.py +90 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/generate_temporary_table_credential.py +90 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/generate_temporary_volume_credential.py +90 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/list_catalogs_response.py +97 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/list_functions_response.py +97 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/list_model_versions_response.py +97 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/list_registered_models_response.py +97 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/list_schemas_response.py +97 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/list_tables_response.py +97 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/list_volumes_response_content.py +97 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/model_version_info.py +114 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/model_version_operation.py +38 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/model_version_status.py +39 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/path_operation.py +39 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/permissions_change.py +92 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/permissions_list.py +95 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/principal_type.py +37 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/privilege.py +47 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/privilege_assignment.py +90 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/registered_model_info.py +109 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/schema_info.py +107 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/securable_type.py +42 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/table_dependency.py +87 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/table_info.py +125 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/table_operation.py +38 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/table_type.py +37 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/temporary_credentials.py +105 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/update_catalog.py +91 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/update_model_version.py +87 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/update_permissions.py +95 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/update_registered_model.py +89 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/update_schema.py +91 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/update_volume_request_content.py +90 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/volume_info.py +113 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/volume_operation.py +38 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/models/volume_type.py +37 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/py.typed +0 -0
- unitycatalog_client-0.2.1/src/unitycatalog/client/rest.py +215 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
etc/db/h2db.mv.db
|
|
2
|
+
etc/db/h2db.trace.db
|
|
3
|
+
target/
|
|
4
|
+
|
|
5
|
+
# Intellij IDEA files
|
|
6
|
+
.idea/
|
|
7
|
+
*.iml
|
|
8
|
+
|
|
9
|
+
.bsp/
|
|
10
|
+
etc/logs/
|
|
11
|
+
api/.openapi-generator
|
|
12
|
+
build/sbt-launch-*
|
|
13
|
+
venv
|
|
14
|
+
uc_docs_venv
|
|
15
|
+
.venv
|
|
16
|
+
.DS_Store
|
|
17
|
+
server_pid.txt
|
|
18
|
+
site
|
|
19
|
+
python_engine.log
|
|
20
|
+
.python-version
|
|
21
|
+
.java-version
|
|
22
|
+
|
|
23
|
+
# Signing keys and access tokens
|
|
24
|
+
etc/conf/certs.json
|
|
25
|
+
etc/conf/*.txt
|
|
26
|
+
etc/conf/*.der
|
|
27
|
+
connectors/spark/etc/conf/certs.json
|
|
28
|
+
connectors/spark/etc/conf/*.txt
|
|
29
|
+
connectors/spark/etc/conf/*.der
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: unitycatalog-client
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Official Python SDK for Unity Catalog
|
|
5
|
+
Project-URL: homepage, https://www.unitycatalog.io/
|
|
6
|
+
Project-URL: issues, https://github.com/unitycatalog/unitycatalog/issues
|
|
7
|
+
Project-URL: repository, https://github.com/unitycatalog/unitycatalog
|
|
8
|
+
Author-email: Unity Catalog Developers <dev-feedback@unitycatalog.com>
|
|
9
|
+
Maintainer-email: Denny Lee <denny.lee@databricks.com>, Ben Wilson <benjamin.wilson@databricks.com>, Tathagata Das <tathagata.das1565@gmail.com>
|
|
10
|
+
License: Apache-2.0
|
|
11
|
+
Keywords: sdk,unitycatalog
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Education
|
|
15
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
16
|
+
Classifier: Intended Audience :: Information Technology
|
|
17
|
+
Classifier: Intended Audience :: Other Audience
|
|
18
|
+
Classifier: Intended Audience :: Science/Research
|
|
19
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Topic :: Scientific/Engineering
|
|
27
|
+
Classifier: Topic :: Software Development
|
|
28
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
29
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
30
|
+
Classifier: Topic :: Software Development :: User Interfaces
|
|
31
|
+
Requires-Python: >=3.9
|
|
32
|
+
Requires-Dist: aiohttp-retry>=2.8.3
|
|
33
|
+
Requires-Dist: aiohttp>=3.8.4
|
|
34
|
+
Requires-Dist: pydantic<3,>=2
|
|
35
|
+
Requires-Dist: python-dateutil>=2.8.2
|
|
36
|
+
Requires-Dist: typing-extensions>=4.7.1
|
|
37
|
+
Requires-Dist: urllib3>=1.25.3
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
# Unity Catalog Python Client SDK
|
|
41
|
+
|
|
42
|
+
Welcome to the official Python Client SDK for Unity Catalog!
|
|
43
|
+
|
|
44
|
+
Unity Catalog is the industry's only universal catalog for data and AI.
|
|
45
|
+
|
|
46
|
+
- **Multimodal interface supports any format, engine, and asset**
|
|
47
|
+
- Multi-format support: It is extensible and supports Delta Lake, Apache Iceberg and Apache Hudi via UniForm, Apache Parquet, JSON, CSV, and many others.
|
|
48
|
+
- Multi-engine support: With its open APIs, data cataloged in Unity can be read by many leading compute engines.
|
|
49
|
+
- Multimodal: It supports all your data and AI assets, including tables, files, functions, AI models.
|
|
50
|
+
- **Open source API and implementation** - OpenAPI spec and OSS implementation (Apache 2.0 license). It is also compatible with Apache Hive's metastore API and Apache Iceberg's REST catalog API. Unity Catalog is currently a sandbox project with LF AI and Data Foundation (part of the Linux Foundation).
|
|
51
|
+
- **Unified governance** for data and AI - Govern and secure tabular data, unstructured assets, and AI assets with a single interface.
|
|
52
|
+
|
|
53
|
+
## Python Client SDK
|
|
54
|
+
|
|
55
|
+
The Unity Catalog Python SDK provides a convenient Python-native interface to all of the functionality of the Unity Catalog
|
|
56
|
+
REST APIs. The library includes interfaces for all supported public modules.
|
|
57
|
+
|
|
58
|
+
This library is generated using the [OpenAPI Generator](https://openapi-generator.tech/docs/generators/python) toolkit, providing client interfaces using the `aiohttp` request handling library.
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
The Python Client SDK and associated shared namespace package for Unity Catalog use [hatch](https://hatch.pypa.io/latest/) as their supported build backend.
|
|
63
|
+
|
|
64
|
+
To ensure that you can install the package, install `hatch` via any of the listed options [here](https://hatch.pypa.io/latest/install/).
|
|
65
|
+
|
|
66
|
+
To use the `unitycatalog-client` SDK, you can install directly from PyPI:
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
pip install unitycatalog-client
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
To install from source, you will need to fork and clone the [unitycatalog repository](https://github.com/unitycatalog/unitycatalog) locally.
|
|
73
|
+
|
|
74
|
+
To build the Python source locally, you will need to have `JDK17` installed and activated.
|
|
75
|
+
|
|
76
|
+
Once your configuration supports the execution of [sbt](https://www.scala-sbt.org/), you can run the following within the root
|
|
77
|
+
of the repository to generate the Python Client SDK source:
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
build/sbt pythonClient/generate
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The source code will be generated at `unitycatalog/clients/python/target`.
|
|
84
|
+
|
|
85
|
+
You can then install the package in editable mode from the repository root:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
pip install -e clients/python/target
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Usage
|
|
92
|
+
|
|
93
|
+
To get started with using the Python Client SDK, first ensure that you have a running Unity Catalog server to connect to.
|
|
94
|
+
You can follow instructions [here](https://docs.unitycatalog.io/quickstart/) to quickly get started with setting up
|
|
95
|
+
a local Unity Catalog server if needed.
|
|
96
|
+
|
|
97
|
+
Once the server is running, you can set up the Python client to make async requests to the Unity Catalog server.
|
|
98
|
+
|
|
99
|
+
For the examples listed here, we will be using a local unauthenticated server for simplicity's sake.
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from unitycatalog.client import Configuration
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
config = Configuration()
|
|
106
|
+
config.host = "http://localhost:8080/api/2.1/unity-catalog"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Once we have our configuration, we can set our client that we will be using for each request:
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from unitycatalog.client import ApiClient
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
client = ApiClient(configuration=config)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
With our client configured and instantiated, we can use any of the Unity Catalog APIs by importing from the
|
|
119
|
+
`client` namespace directly and send requests to the server.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from unitycatalog.client import CatalogsApi
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
catalogs_api = CatalogsApi(api_client=client)
|
|
126
|
+
my_catalogs = await catalogs_api.list_catalogs()
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
>Note: APIs that support pagination (such as `list_catalogs`) should have continutation token logic for assembling the paginated
|
|
130
|
+
return values into a single collection.
|
|
131
|
+
|
|
132
|
+
A simple example of consuming a paginated response is:
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
async def list_all_catalogs(catalog_api):
|
|
136
|
+
token = None
|
|
137
|
+
catalogs = []
|
|
138
|
+
while True:
|
|
139
|
+
results = await catalog_api.list_catalogs(page_token=token)
|
|
140
|
+
catalogs += results.catalogs
|
|
141
|
+
if next_token := results.next_page_token:
|
|
142
|
+
token = next_token
|
|
143
|
+
else:
|
|
144
|
+
break
|
|
145
|
+
return catalogs
|
|
146
|
+
|
|
147
|
+
my_catalogs = await list_all_catalogs(catalogs_api)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Creating a new catalog with the Python SDK is straight-forward:
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from unitycatalog.client.models import CreateCatalog, CatalogInfo
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
async def create_catalog(catalog_name, catalog_api, comment=None):
|
|
157
|
+
new_catalog = CreateCatalog(
|
|
158
|
+
name=catalog_name,
|
|
159
|
+
comment=comment or ""
|
|
160
|
+
)
|
|
161
|
+
return await catalog_api.create_catalog(create_catalog=new_catalog)
|
|
162
|
+
|
|
163
|
+
await create_catalog("MyNewCatalog", catalog_api=catalogs_api, comment="This is a new catalog.")
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Adding a new Schema to our created Catalog is similarly simple:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
from unitycatalog.client import SchemasApi
|
|
170
|
+
from unitycatalog.client import CreateSchema, SchemaInfo
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
schemas_api = SchemasApi(api_client=client)
|
|
174
|
+
|
|
175
|
+
async def create_schema(schema_name, catalog_name, schema_api, comment=None):
|
|
176
|
+
new_schema = CreateSchema(
|
|
177
|
+
name=schema_name,
|
|
178
|
+
catalog_name=catalog_name,
|
|
179
|
+
comment=comment or ""
|
|
180
|
+
)
|
|
181
|
+
return await schema_api.create_schema(create_schema=new_schema)
|
|
182
|
+
|
|
183
|
+
await create_schema(schema_name="MyNewSchema", catalog_name="MyNewCatalog", schema_api=schemas_api, comment="This is a new schema.")
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
And listing the schemas within our newly created Catalog (note that if you expect paginated responses, ensure that you are passing
|
|
187
|
+
continuation tokens as shown above in `list_all_catalogs`):
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
await schemas_api.list_schemas(catalog_name="MyNewCatalog")
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Feedback
|
|
194
|
+
|
|
195
|
+
Have requests for the Unity Catalog project? Interested in getting involved in the Open Source project?
|
|
196
|
+
|
|
197
|
+
See the [repository on GitHub](https://github.com/unitycatalog/unitycatalog)
|
|
198
|
+
|
|
199
|
+
Read [the documentation](https://www.unitycatalog.io/) for more guidance and examples!
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Unity Catalog Python Client SDK
|
|
2
|
+
|
|
3
|
+
Welcome to the official Python Client SDK for Unity Catalog!
|
|
4
|
+
|
|
5
|
+
Unity Catalog is the industry's only universal catalog for data and AI.
|
|
6
|
+
|
|
7
|
+
- **Multimodal interface supports any format, engine, and asset**
|
|
8
|
+
- Multi-format support: It is extensible and supports Delta Lake, Apache Iceberg and Apache Hudi via UniForm, Apache Parquet, JSON, CSV, and many others.
|
|
9
|
+
- Multi-engine support: With its open APIs, data cataloged in Unity can be read by many leading compute engines.
|
|
10
|
+
- Multimodal: It supports all your data and AI assets, including tables, files, functions, AI models.
|
|
11
|
+
- **Open source API and implementation** - OpenAPI spec and OSS implementation (Apache 2.0 license). It is also compatible with Apache Hive's metastore API and Apache Iceberg's REST catalog API. Unity Catalog is currently a sandbox project with LF AI and Data Foundation (part of the Linux Foundation).
|
|
12
|
+
- **Unified governance** for data and AI - Govern and secure tabular data, unstructured assets, and AI assets with a single interface.
|
|
13
|
+
|
|
14
|
+
## Python Client SDK
|
|
15
|
+
|
|
16
|
+
The Unity Catalog Python SDK provides a convenient Python-native interface to all of the functionality of the Unity Catalog
|
|
17
|
+
REST APIs. The library includes interfaces for all supported public modules.
|
|
18
|
+
|
|
19
|
+
This library is generated using the [OpenAPI Generator](https://openapi-generator.tech/docs/generators/python) toolkit, providing client interfaces using the `aiohttp` request handling library.
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
The Python Client SDK and associated shared namespace package for Unity Catalog use [hatch](https://hatch.pypa.io/latest/) as their supported build backend.
|
|
24
|
+
|
|
25
|
+
To ensure that you can install the package, install `hatch` via any of the listed options [here](https://hatch.pypa.io/latest/install/).
|
|
26
|
+
|
|
27
|
+
To use the `unitycatalog-client` SDK, you can install directly from PyPI:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
pip install unitycatalog-client
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
To install from source, you will need to fork and clone the [unitycatalog repository](https://github.com/unitycatalog/unitycatalog) locally.
|
|
34
|
+
|
|
35
|
+
To build the Python source locally, you will need to have `JDK17` installed and activated.
|
|
36
|
+
|
|
37
|
+
Once your configuration supports the execution of [sbt](https://www.scala-sbt.org/), you can run the following within the root
|
|
38
|
+
of the repository to generate the Python Client SDK source:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
build/sbt pythonClient/generate
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The source code will be generated at `unitycatalog/clients/python/target`.
|
|
45
|
+
|
|
46
|
+
You can then install the package in editable mode from the repository root:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
pip install -e clients/python/target
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Usage
|
|
53
|
+
|
|
54
|
+
To get started with using the Python Client SDK, first ensure that you have a running Unity Catalog server to connect to.
|
|
55
|
+
You can follow instructions [here](https://docs.unitycatalog.io/quickstart/) to quickly get started with setting up
|
|
56
|
+
a local Unity Catalog server if needed.
|
|
57
|
+
|
|
58
|
+
Once the server is running, you can set up the Python client to make async requests to the Unity Catalog server.
|
|
59
|
+
|
|
60
|
+
For the examples listed here, we will be using a local unauthenticated server for simplicity's sake.
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from unitycatalog.client import Configuration
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
config = Configuration()
|
|
67
|
+
config.host = "http://localhost:8080/api/2.1/unity-catalog"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Once we have our configuration, we can set our client that we will be using for each request:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from unitycatalog.client import ApiClient
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
client = ApiClient(configuration=config)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
With our client configured and instantiated, we can use any of the Unity Catalog APIs by importing from the
|
|
80
|
+
`client` namespace directly and send requests to the server.
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from unitycatalog.client import CatalogsApi
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
catalogs_api = CatalogsApi(api_client=client)
|
|
87
|
+
my_catalogs = await catalogs_api.list_catalogs()
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
>Note: APIs that support pagination (such as `list_catalogs`) should have continutation token logic for assembling the paginated
|
|
91
|
+
return values into a single collection.
|
|
92
|
+
|
|
93
|
+
A simple example of consuming a paginated response is:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
async def list_all_catalogs(catalog_api):
|
|
97
|
+
token = None
|
|
98
|
+
catalogs = []
|
|
99
|
+
while True:
|
|
100
|
+
results = await catalog_api.list_catalogs(page_token=token)
|
|
101
|
+
catalogs += results.catalogs
|
|
102
|
+
if next_token := results.next_page_token:
|
|
103
|
+
token = next_token
|
|
104
|
+
else:
|
|
105
|
+
break
|
|
106
|
+
return catalogs
|
|
107
|
+
|
|
108
|
+
my_catalogs = await list_all_catalogs(catalogs_api)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Creating a new catalog with the Python SDK is straight-forward:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from unitycatalog.client.models import CreateCatalog, CatalogInfo
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
async def create_catalog(catalog_name, catalog_api, comment=None):
|
|
118
|
+
new_catalog = CreateCatalog(
|
|
119
|
+
name=catalog_name,
|
|
120
|
+
comment=comment or ""
|
|
121
|
+
)
|
|
122
|
+
return await catalog_api.create_catalog(create_catalog=new_catalog)
|
|
123
|
+
|
|
124
|
+
await create_catalog("MyNewCatalog", catalog_api=catalogs_api, comment="This is a new catalog.")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Adding a new Schema to our created Catalog is similarly simple:
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
from unitycatalog.client import SchemasApi
|
|
131
|
+
from unitycatalog.client import CreateSchema, SchemaInfo
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
schemas_api = SchemasApi(api_client=client)
|
|
135
|
+
|
|
136
|
+
async def create_schema(schema_name, catalog_name, schema_api, comment=None):
|
|
137
|
+
new_schema = CreateSchema(
|
|
138
|
+
name=schema_name,
|
|
139
|
+
catalog_name=catalog_name,
|
|
140
|
+
comment=comment or ""
|
|
141
|
+
)
|
|
142
|
+
return await schema_api.create_schema(create_schema=new_schema)
|
|
143
|
+
|
|
144
|
+
await create_schema(schema_name="MyNewSchema", catalog_name="MyNewCatalog", schema_api=schemas_api, comment="This is a new schema.")
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
And listing the schemas within our newly created Catalog (note that if you expect paginated responses, ensure that you are passing
|
|
148
|
+
continuation tokens as shown above in `list_all_catalogs`):
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
await schemas_api.list_schemas(catalog_name="MyNewCatalog")
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Feedback
|
|
155
|
+
|
|
156
|
+
Have requests for the Unity Catalog project? Interested in getting involved in the Open Source project?
|
|
157
|
+
|
|
158
|
+
See the [repository on GitHub](https://github.com/unitycatalog/unitycatalog)
|
|
159
|
+
|
|
160
|
+
Read [the documentation](https://www.unitycatalog.io/) for more guidance and examples!
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "unitycatalog-client"
|
|
3
|
+
version = "0.2.1"
|
|
4
|
+
description = "Official Python SDK for Unity Catalog"
|
|
5
|
+
authors = [
|
|
6
|
+
{ name="Unity Catalog Developers", email="dev-feedback@unitycatalog.com" }
|
|
7
|
+
]
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
license = { text="Apache-2.0" }
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"urllib3>=1.25.3",
|
|
13
|
+
"aiohttp>=3.8.4",
|
|
14
|
+
"aiohttp-retry>=2.8.3",
|
|
15
|
+
"python-dateutil>=2.8.2",
|
|
16
|
+
"typing-extensions>=4.7.1",
|
|
17
|
+
"pydantic<3,>=2",
|
|
18
|
+
]
|
|
19
|
+
maintainers = [
|
|
20
|
+
{name="Denny Lee", email="denny.lee@databricks.com"},
|
|
21
|
+
{name="Ben Wilson", email="benjamin.wilson@databricks.com"},
|
|
22
|
+
{name="Tathagata Das", email="tathagata.das1565@gmail.com"}
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
keywords = ["unitycatalog", "sdk"]
|
|
26
|
+
classifiers = [
|
|
27
|
+
"Development Status :: 4 - Beta",
|
|
28
|
+
"Intended Audience :: Developers",
|
|
29
|
+
"Intended Audience :: Education",
|
|
30
|
+
"Intended Audience :: End Users/Desktop",
|
|
31
|
+
"Intended Audience :: Science/Research",
|
|
32
|
+
"Intended Audience :: Information Technology",
|
|
33
|
+
"Intended Audience :: Other Audience",
|
|
34
|
+
"License :: OSI Approved :: Apache Software License",
|
|
35
|
+
"Operating System :: OS Independent",
|
|
36
|
+
"Programming Language :: Python :: 3",
|
|
37
|
+
"Programming Language :: Python :: 3.9",
|
|
38
|
+
"Programming Language :: Python :: 3.10",
|
|
39
|
+
"Programming Language :: Python :: 3.11",
|
|
40
|
+
"Programming Language :: Python :: 3.12",
|
|
41
|
+
"Topic :: Scientific/Engineering",
|
|
42
|
+
"Topic :: Software Development",
|
|
43
|
+
"Topic :: Software Development :: Libraries",
|
|
44
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
45
|
+
"Topic :: Software Development :: User Interfaces",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[project.urls]
|
|
49
|
+
homepage = "https://www.unitycatalog.io/"
|
|
50
|
+
issues = "https://github.com/unitycatalog/unitycatalog/issues"
|
|
51
|
+
repository = "https://github.com/unitycatalog/unitycatalog"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
[tool.hatch.build.targets.wheel]
|
|
55
|
+
packages = ["src/unitycatalog"]
|
|
56
|
+
|
|
57
|
+
[build-system]
|
|
58
|
+
requires = ["hatchling"]
|
|
59
|
+
build-backend = "hatchling.build"
|
|
60
|
+
|
|
61
|
+
[tool.hatch.envs.default]
|
|
62
|
+
dependencies = [
|
|
63
|
+
"urllib3>=1.25.3",
|
|
64
|
+
"aiohttp>= 3.8.4",
|
|
65
|
+
"aiohttp-retry>= 2.8.3",
|
|
66
|
+
"python-dateutil>=2.8.2",
|
|
67
|
+
"pydantic>=2",
|
|
68
|
+
"typing-extensions>=4.7.1"
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
[tool.hatch.envs.test]
|
|
72
|
+
dependencies = [
|
|
73
|
+
"pytest>=7.2.1",
|
|
74
|
+
"pytest-asyncio>=0.24.0",
|
|
75
|
+
"tox>=3.9.0",
|
|
76
|
+
"flake8>=4.0.0",
|
|
77
|
+
"types-python-dateutil>=2.8.19.14",
|
|
78
|
+
"mypy>=1.4.1"
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
[tool.pylint."MESSAGES CONTROL"]
|
|
82
|
+
extension-pkg-whitelist = "pydantic"
|
|
83
|
+
|
|
84
|
+
[tool.mypy]
|
|
85
|
+
files = [
|
|
86
|
+
"unitycatalog/client",
|
|
87
|
+
"tests",
|
|
88
|
+
]
|
|
89
|
+
warn_unused_configs = true
|
|
90
|
+
warn_redundant_casts = true
|
|
91
|
+
warn_unused_ignores = true
|
|
92
|
+
|
|
93
|
+
strict_equality = true
|
|
94
|
+
strict_concatenate = true
|
|
95
|
+
check_untyped_defs = true
|
|
96
|
+
disallow_subclassing_any = true
|
|
97
|
+
disallow_untyped_decorators = true
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Unity Catalog API
|
|
5
|
+
Official Python SDK for Unity Catalog
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from setuptools import setup, find_packages
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
# Read the long description from README.md
|
|
12
|
+
this_directory = Path(__file__).parent
|
|
13
|
+
long_description = (this_directory / "README.md").read_text()
|
|
14
|
+
|
|
15
|
+
setup(
|
|
16
|
+
name="unitycatalog-client",
|
|
17
|
+
version="0.2.1",
|
|
18
|
+
description="Official Python SDK for Unity Catalog",
|
|
19
|
+
long_description=long_description,
|
|
20
|
+
long_description_content_type="text/markdown",
|
|
21
|
+
author="Unity Catalog Developers",
|
|
22
|
+
license="Apache-2.0",
|
|
23
|
+
python_requires=">=3.9",
|
|
24
|
+
install_requires=[
|
|
25
|
+
"urllib3>=1.25.3",
|
|
26
|
+
"aiohttp>=3.8.4",
|
|
27
|
+
"aiohttp-retry>=2.8.3",
|
|
28
|
+
"python-dateutil>=2.8.2",
|
|
29
|
+
"typing-extensions>=4.7.1",
|
|
30
|
+
"pydantic<3,>=2",
|
|
31
|
+
],
|
|
32
|
+
classifiers=[
|
|
33
|
+
"Development Status :: 4 - Beta",
|
|
34
|
+
"Intended Audience :: Developers",
|
|
35
|
+
"Intended Audience :: Education",
|
|
36
|
+
"Intended Audience :: End Users/Desktop",
|
|
37
|
+
"Intended Audience :: Science/Research",
|
|
38
|
+
"Intended Audience :: Information Technology",
|
|
39
|
+
"Intended Audience :: Other Audience",
|
|
40
|
+
"License :: OSI Approved :: Apache Software License",
|
|
41
|
+
"Operating System :: OS Independent",
|
|
42
|
+
"Programming Language :: Python :: 3",
|
|
43
|
+
"Programming Language :: Python :: 3.9",
|
|
44
|
+
"Programming Language :: Python :: 3.10",
|
|
45
|
+
"Programming Language :: Python :: 3.11",
|
|
46
|
+
"Programming Language :: Python :: 3.12",
|
|
47
|
+
"Topic :: Scientific/Engineering",
|
|
48
|
+
"Topic :: Software Development",
|
|
49
|
+
"Topic :: Software Development :: Libraries",
|
|
50
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
51
|
+
"Topic :: Software Development :: User Interfaces",
|
|
52
|
+
],
|
|
53
|
+
keywords=["unitycatalog", "sdk"],
|
|
54
|
+
url="https://www.unitycatalog.io/",
|
|
55
|
+
project_urls={
|
|
56
|
+
"Homepage": "https://www.unitycatalog.io/",
|
|
57
|
+
"Issues": "https://github.com/unitycatalog/unitycatalog/issues",
|
|
58
|
+
"Repository": "https://github.com/unitycatalog/unitycatalog",
|
|
59
|
+
},
|
|
60
|
+
packages=find_packages(include=["unitycatalog.client"], exclude=["test", "tests"]),
|
|
61
|
+
include_package_data=True,
|
|
62
|
+
package_data={
|
|
63
|
+
"unitycatalog.client": ["py.typed"],
|
|
64
|
+
},
|
|
65
|
+
extras_require={
|
|
66
|
+
"test": [
|
|
67
|
+
"pytest>=7.2.1",
|
|
68
|
+
"pytest-asyncio>=0.24.0",
|
|
69
|
+
"tox>=3.9.0",
|
|
70
|
+
"flake8>=4.0.0",
|
|
71
|
+
"types-python-dateutil>=2.8.19.14",
|
|
72
|
+
"mypy>=1.4.1",
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
# flake8: noqa
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Unity Catalog API
|
|
7
|
+
|
|
8
|
+
No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
|
9
|
+
|
|
10
|
+
The version of the OpenAPI document: 0.1
|
|
11
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
|
12
|
+
|
|
13
|
+
Do not edit the class manually.
|
|
14
|
+
""" # noqa: E501
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
__version__ = "0.2.1"
|
|
18
|
+
|
|
19
|
+
# import apis into sdk package
|
|
20
|
+
from unitycatalog.client.api.catalogs_api import CatalogsApi
|
|
21
|
+
from unitycatalog.client.api.functions_api import FunctionsApi
|
|
22
|
+
from unitycatalog.client.api.grants_api import GrantsApi
|
|
23
|
+
from unitycatalog.client.api.model_versions_api import ModelVersionsApi
|
|
24
|
+
from unitycatalog.client.api.registered_models_api import RegisteredModelsApi
|
|
25
|
+
from unitycatalog.client.api.schemas_api import SchemasApi
|
|
26
|
+
from unitycatalog.client.api.tables_api import TablesApi
|
|
27
|
+
from unitycatalog.client.api.temporary_credentials_api import TemporaryCredentialsApi
|
|
28
|
+
from unitycatalog.client.api.volumes_api import VolumesApi
|
|
29
|
+
|
|
30
|
+
# import ApiClient
|
|
31
|
+
from unitycatalog.client.api_response import ApiResponse
|
|
32
|
+
from unitycatalog.client.api_client import ApiClient
|
|
33
|
+
from unitycatalog.client.configuration import Configuration
|
|
34
|
+
from unitycatalog.client.exceptions import OpenApiException
|
|
35
|
+
from unitycatalog.client.exceptions import ApiTypeError
|
|
36
|
+
from unitycatalog.client.exceptions import ApiValueError
|
|
37
|
+
from unitycatalog.client.exceptions import ApiKeyError
|
|
38
|
+
from unitycatalog.client.exceptions import ApiAttributeError
|
|
39
|
+
from unitycatalog.client.exceptions import ApiException
|
|
40
|
+
|
|
41
|
+
# import models into sdk package
|
|
42
|
+
from unitycatalog.client.models.aws_credentials import AwsCredentials
|
|
43
|
+
from unitycatalog.client.models.azure_user_delegation_sas import AzureUserDelegationSAS
|
|
44
|
+
from unitycatalog.client.models.catalog_info import CatalogInfo
|
|
45
|
+
from unitycatalog.client.models.column_info import ColumnInfo
|
|
46
|
+
from unitycatalog.client.models.column_type_name import ColumnTypeName
|
|
47
|
+
from unitycatalog.client.models.create_catalog import CreateCatalog
|
|
48
|
+
from unitycatalog.client.models.create_function import CreateFunction
|
|
49
|
+
from unitycatalog.client.models.create_function_request import CreateFunctionRequest
|
|
50
|
+
from unitycatalog.client.models.create_model_version import CreateModelVersion
|
|
51
|
+
from unitycatalog.client.models.create_registered_model import CreateRegisteredModel
|
|
52
|
+
from unitycatalog.client.models.create_schema import CreateSchema
|
|
53
|
+
from unitycatalog.client.models.create_table import CreateTable
|
|
54
|
+
from unitycatalog.client.models.create_volume_request_content import CreateVolumeRequestContent
|
|
55
|
+
from unitycatalog.client.models.data_source_format import DataSourceFormat
|
|
56
|
+
from unitycatalog.client.models.dependency import Dependency
|
|
57
|
+
from unitycatalog.client.models.dependency_list import DependencyList
|
|
58
|
+
from unitycatalog.client.models.finalize_model_version import FinalizeModelVersion
|
|
59
|
+
from unitycatalog.client.models.function_dependency import FunctionDependency
|
|
60
|
+
from unitycatalog.client.models.function_info import FunctionInfo
|
|
61
|
+
from unitycatalog.client.models.function_parameter_info import FunctionParameterInfo
|
|
62
|
+
from unitycatalog.client.models.function_parameter_infos import FunctionParameterInfos
|
|
63
|
+
from unitycatalog.client.models.function_parameter_mode import FunctionParameterMode
|
|
64
|
+
from unitycatalog.client.models.function_parameter_type import FunctionParameterType
|
|
65
|
+
from unitycatalog.client.models.gcp_oauth_token import GcpOauthToken
|
|
66
|
+
from unitycatalog.client.models.generate_temporary_model_version_credential import GenerateTemporaryModelVersionCredential
|
|
67
|
+
from unitycatalog.client.models.generate_temporary_path_credential import GenerateTemporaryPathCredential
|
|
68
|
+
from unitycatalog.client.models.generate_temporary_table_credential import GenerateTemporaryTableCredential
|
|
69
|
+
from unitycatalog.client.models.generate_temporary_volume_credential import GenerateTemporaryVolumeCredential
|
|
70
|
+
from unitycatalog.client.models.list_catalogs_response import ListCatalogsResponse
|
|
71
|
+
from unitycatalog.client.models.list_functions_response import ListFunctionsResponse
|
|
72
|
+
from unitycatalog.client.models.list_model_versions_response import ListModelVersionsResponse
|
|
73
|
+
from unitycatalog.client.models.list_registered_models_response import ListRegisteredModelsResponse
|
|
74
|
+
from unitycatalog.client.models.list_schemas_response import ListSchemasResponse
|
|
75
|
+
from unitycatalog.client.models.list_tables_response import ListTablesResponse
|
|
76
|
+
from unitycatalog.client.models.list_volumes_response_content import ListVolumesResponseContent
|
|
77
|
+
from unitycatalog.client.models.model_version_info import ModelVersionInfo
|
|
78
|
+
from unitycatalog.client.models.model_version_operation import ModelVersionOperation
|
|
79
|
+
from unitycatalog.client.models.model_version_status import ModelVersionStatus
|
|
80
|
+
from unitycatalog.client.models.path_operation import PathOperation
|
|
81
|
+
from unitycatalog.client.models.permissions_change import PermissionsChange
|
|
82
|
+
from unitycatalog.client.models.permissions_list import PermissionsList
|
|
83
|
+
from unitycatalog.client.models.principal_type import PrincipalType
|
|
84
|
+
from unitycatalog.client.models.privilege import Privilege
|
|
85
|
+
from unitycatalog.client.models.privilege_assignment import PrivilegeAssignment
|
|
86
|
+
from unitycatalog.client.models.registered_model_info import RegisteredModelInfo
|
|
87
|
+
from unitycatalog.client.models.schema_info import SchemaInfo
|
|
88
|
+
from unitycatalog.client.models.securable_type import SecurableType
|
|
89
|
+
from unitycatalog.client.models.table_dependency import TableDependency
|
|
90
|
+
from unitycatalog.client.models.table_info import TableInfo
|
|
91
|
+
from unitycatalog.client.models.table_operation import TableOperation
|
|
92
|
+
from unitycatalog.client.models.table_type import TableType
|
|
93
|
+
from unitycatalog.client.models.temporary_credentials import TemporaryCredentials
|
|
94
|
+
from unitycatalog.client.models.update_catalog import UpdateCatalog
|
|
95
|
+
from unitycatalog.client.models.update_model_version import UpdateModelVersion
|
|
96
|
+
from unitycatalog.client.models.update_permissions import UpdatePermissions
|
|
97
|
+
from unitycatalog.client.models.update_registered_model import UpdateRegisteredModel
|
|
98
|
+
from unitycatalog.client.models.update_schema import UpdateSchema
|
|
99
|
+
from unitycatalog.client.models.update_volume_request_content import UpdateVolumeRequestContent
|
|
100
|
+
from unitycatalog.client.models.volume_info import VolumeInfo
|
|
101
|
+
from unitycatalog.client.models.volume_operation import VolumeOperation
|
|
102
|
+
from unitycatalog.client.models.volume_type import VolumeType
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# flake8: noqa
|
|
2
|
+
|
|
3
|
+
# import apis into api package
|
|
4
|
+
from unitycatalog.client.api.catalogs_api import CatalogsApi
|
|
5
|
+
from unitycatalog.client.api.functions_api import FunctionsApi
|
|
6
|
+
from unitycatalog.client.api.grants_api import GrantsApi
|
|
7
|
+
from unitycatalog.client.api.model_versions_api import ModelVersionsApi
|
|
8
|
+
from unitycatalog.client.api.registered_models_api import RegisteredModelsApi
|
|
9
|
+
from unitycatalog.client.api.schemas_api import SchemasApi
|
|
10
|
+
from unitycatalog.client.api.tables_api import TablesApi
|
|
11
|
+
from unitycatalog.client.api.temporary_credentials_api import TemporaryCredentialsApi
|
|
12
|
+
from unitycatalog.client.api.volumes_api import VolumesApi
|
|
13
|
+
|