hyperlake 0.1.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.
- hyperlake-0.1.1/PKG-INFO +659 -0
- hyperlake-0.1.1/README.md +586 -0
- hyperlake-0.1.1/hyperlake/__init__.py +40 -0
- hyperlake-0.1.1/hyperlake/_version.py +7 -0
- hyperlake-0.1.1/hyperlake/auth.py +609 -0
- hyperlake-0.1.1/hyperlake/client.py +1324 -0
- hyperlake-0.1.1/hyperlake/constants.py +67 -0
- hyperlake-0.1.1/hyperlake/dbapi.py +798 -0
- hyperlake-0.1.1/hyperlake/exceptions.py +164 -0
- hyperlake-0.1.1/hyperlake/logging.py +30 -0
- hyperlake-0.1.1/hyperlake/mapper.py +374 -0
- hyperlake-0.1.1/hyperlake/sqlalchemy/__init__.py +16 -0
- hyperlake-0.1.1/hyperlake/sqlalchemy/compiler.py +272 -0
- hyperlake-0.1.1/hyperlake/sqlalchemy/datatype.py +291 -0
- hyperlake-0.1.1/hyperlake/sqlalchemy/dialect.py +465 -0
- hyperlake-0.1.1/hyperlake/sqlalchemy/error.py +26 -0
- hyperlake-0.1.1/hyperlake/sqlalchemy/util.py +111 -0
- hyperlake-0.1.1/hyperlake/transaction.py +105 -0
- hyperlake-0.1.1/hyperlake/types.py +134 -0
- hyperlake-0.1.1/hyperlake.egg-info/PKG-INFO +659 -0
- hyperlake-0.1.1/hyperlake.egg-info/SOURCES.txt +26 -0
- hyperlake-0.1.1/hyperlake.egg-info/dependency_links.txt +1 -0
- hyperlake-0.1.1/hyperlake.egg-info/entry_points.txt +2 -0
- hyperlake-0.1.1/hyperlake.egg-info/requires.txt +38 -0
- hyperlake-0.1.1/hyperlake.egg-info/top_level.txt +1 -0
- hyperlake-0.1.1/setup.cfg +24 -0
- hyperlake-0.1.1/setup.py +106 -0
hyperlake-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: hyperlake
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Python Client for the Hyperlake distributed SQL Engine
|
|
5
|
+
Home-page: https://github.com/ockhamlabs/hyperlake-python-client
|
|
6
|
+
Author: Ockham Labs Team
|
|
7
|
+
Author-email: pythonclient+hello@ockhamlabs.ai
|
|
8
|
+
License: Apache-2.0
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
13
|
+
Classifier: Operating System :: POSIX
|
|
14
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
23
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
24
|
+
Classifier: Topic :: Database :: Front-Ends
|
|
25
|
+
Requires-Python: >=3.9
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
Requires-Dist: lz4
|
|
28
|
+
Requires-Dist: python-dateutil
|
|
29
|
+
Requires-Dist: pytz
|
|
30
|
+
Requires-Dist: requests>=2.31.0
|
|
31
|
+
Requires-Dist: tzlocal
|
|
32
|
+
Requires-Dist: zstandard
|
|
33
|
+
Provides-Extra: all
|
|
34
|
+
Requires-Dist: requests_kerberos; extra == "all"
|
|
35
|
+
Requires-Dist: sqlalchemy>=1.3; extra == "all"
|
|
36
|
+
Provides-Extra: kerberos
|
|
37
|
+
Requires-Dist: requests_kerberos; extra == "kerberos"
|
|
38
|
+
Provides-Extra: gssapi
|
|
39
|
+
Requires-Dist: requests_gssapi; extra == "gssapi"
|
|
40
|
+
Requires-Dist: krb5==0.5.1; extra == "gssapi"
|
|
41
|
+
Provides-Extra: sqlalchemy
|
|
42
|
+
Requires-Dist: sqlalchemy>=1.3; extra == "sqlalchemy"
|
|
43
|
+
Provides-Extra: tests
|
|
44
|
+
Requires-Dist: requests_kerberos; extra == "tests"
|
|
45
|
+
Requires-Dist: sqlalchemy>=1.3; extra == "tests"
|
|
46
|
+
Requires-Dist: requests_gssapi; extra == "tests"
|
|
47
|
+
Requires-Dist: krb5==0.5.1; extra == "tests"
|
|
48
|
+
Requires-Dist: httpretty<1.1; extra == "tests"
|
|
49
|
+
Requires-Dist: pytest; extra == "tests"
|
|
50
|
+
Requires-Dist: pytest-runner; extra == "tests"
|
|
51
|
+
Requires-Dist: pre-commit; extra == "tests"
|
|
52
|
+
Requires-Dist: black; extra == "tests"
|
|
53
|
+
Requires-Dist: isort; extra == "tests"
|
|
54
|
+
Requires-Dist: keyring; extra == "tests"
|
|
55
|
+
Requires-Dist: testcontainers; extra == "tests"
|
|
56
|
+
Requires-Dist: boto3; extra == "tests"
|
|
57
|
+
Provides-Extra: external-authentication-token-cache
|
|
58
|
+
Requires-Dist: keyring; extra == "external-authentication-token-cache"
|
|
59
|
+
Dynamic: author
|
|
60
|
+
Dynamic: author-email
|
|
61
|
+
Dynamic: classifier
|
|
62
|
+
Dynamic: description
|
|
63
|
+
Dynamic: description-content-type
|
|
64
|
+
Dynamic: home-page
|
|
65
|
+
Dynamic: license
|
|
66
|
+
Dynamic: provides-extra
|
|
67
|
+
Dynamic: requires-dist
|
|
68
|
+
Dynamic: requires-python
|
|
69
|
+
Dynamic: summary
|
|
70
|
+
|
|
71
|
+
# Hyperlake Python client
|
|
72
|
+
|
|
73
|
+
## About
|
|
74
|
+
This project, `hyperlake`, is a fork of the [Trino Python Client](https://github.com/trinodb/trino-python-client) developed by the Trino Team. It is licensed under the Apache License 2.0.
|
|
75
|
+
|
|
76
|
+
## Acknowledgments
|
|
77
|
+
This package is based on the original work by the Trino Team. See the [original repository](https://github.com/trinodb/trino-python-client) for more details.
|
|
78
|
+
|
|
79
|
+
Client for Hyperlake, a distributed SQL engine (based on Trino) for interactive and batch big data processing.
|
|
80
|
+
Provides a low-level client and a DBAPI 2.0 implementation and a SQLAlchemy adapter.
|
|
81
|
+
It supports Python>=3.9 and PyPy.
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
## Usage
|
|
86
|
+
|
|
87
|
+
### The Python Database API (DBAPI)
|
|
88
|
+
|
|
89
|
+
**Installation**
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
$ pip install hyperlake
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Quick Start**
|
|
96
|
+
|
|
97
|
+
Use the DBAPI interface to query hyperlake:
|
|
98
|
+
|
|
99
|
+
if `host` is a valid url, the port and http schema will be automatically determined. For example `https://my-hyperlake-server:9999` will assign the `http_schema` property to `https` and port to `9999`.
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from hyperlake.dbapi import connect
|
|
103
|
+
|
|
104
|
+
conn = connect(
|
|
105
|
+
host="<host>",
|
|
106
|
+
port=<port>,
|
|
107
|
+
user="<username>",
|
|
108
|
+
catalog="<catalog>",
|
|
109
|
+
schema="<schema>",
|
|
110
|
+
)
|
|
111
|
+
cur = conn.cursor()
|
|
112
|
+
cur.execute("SELECT * FROM system.runtime.nodes")
|
|
113
|
+
rows = cur.fetchall()
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
This will query the `system.runtime.nodes` system tables that shows the nodes
|
|
117
|
+
in the hyperlake cluster.
|
|
118
|
+
|
|
119
|
+
The DBAPI implementation in `hyperlake.dbapi` provides methods to retrieve fewer
|
|
120
|
+
rows for example `Cursor.fetchone()` or `Cursor.fetchmany()`. By default
|
|
121
|
+
`Cursor.fetchmany()` fetches one row. Please set
|
|
122
|
+
`hyperlake.dbapi.Cursor.arraysize` accordingly.
|
|
123
|
+
|
|
124
|
+
### SQLAlchemy
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
**Compatibility**
|
|
129
|
+
|
|
130
|
+
`hyperlake.sqlalchemy` is compatible with the latest 1.3.x, 1.4.x and 2.0.x SQLAlchemy
|
|
131
|
+
versions at the time of release of a particular version of the client.
|
|
132
|
+
|
|
133
|
+
**Installation**
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
$ pip install hyperlake[sqlalchemy]
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Usage**
|
|
140
|
+
|
|
141
|
+
To connect to hyperlake using SQLAlchemy, use a connection string (URL) following this pattern:
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
hyperlake://<username>:<password>@<host>:<port>/<catalog>/<schema>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
NOTE: `password` and `schema` are optional
|
|
148
|
+
|
|
149
|
+
**Examples**:
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
from sqlalchemy import create_engine
|
|
153
|
+
from sqlalchemy.schema import Table, MetaData
|
|
154
|
+
from sqlalchemy.sql.expression import select, text
|
|
155
|
+
|
|
156
|
+
engine = create_engine('hyperlake://user@localhost:8080/system')
|
|
157
|
+
connection = engine.connect()
|
|
158
|
+
|
|
159
|
+
rows = connection.execute(text("SELECT * FROM runtime.nodes")).fetchall()
|
|
160
|
+
|
|
161
|
+
# or using SQLAlchemy schema
|
|
162
|
+
nodes = Table(
|
|
163
|
+
'nodes',
|
|
164
|
+
MetaData(schema='runtime'),
|
|
165
|
+
autoload=True,
|
|
166
|
+
autoload_with=engine
|
|
167
|
+
)
|
|
168
|
+
rows = connection.execute(select(nodes)).fetchall()
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
In order to pass additional connection attributes use [connect_args](https://docs.sqlalchemy.org/en/14/core/engines.html#sqlalchemy.create_engine.params.connect_args) method.
|
|
172
|
+
Attributes can also be passed in the connection string.
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
from sqlalchemy import create_engine
|
|
176
|
+
from hyperlake.sqlalchemy import URL
|
|
177
|
+
|
|
178
|
+
engine = create_engine(
|
|
179
|
+
URL(
|
|
180
|
+
host="localhost",
|
|
181
|
+
port=8080,
|
|
182
|
+
catalog="system"
|
|
183
|
+
),
|
|
184
|
+
connect_args={
|
|
185
|
+
"session_properties": {'query_max_run_time': '1d'},
|
|
186
|
+
"client_tags": ["tag1", "tag2"],
|
|
187
|
+
"roles": {"catalog1": "role1"},
|
|
188
|
+
}
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
# or in connection string
|
|
192
|
+
engine = create_engine(
|
|
193
|
+
'hyperlake://user@localhost:8080/system?'
|
|
194
|
+
'session_properties={"query_max_run_time": "1d"}'
|
|
195
|
+
'&client_tags=["tag1", "tag2"]'
|
|
196
|
+
'&roles={"catalog1": "role1"}'
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
# or using the URL factory method
|
|
200
|
+
engine = create_engine(URL(
|
|
201
|
+
host="localhost",
|
|
202
|
+
port=8080,
|
|
203
|
+
client_tags=["tag1", "tag2"]
|
|
204
|
+
))
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Authentication mechanisms
|
|
208
|
+
|
|
209
|
+
### Basic authentication
|
|
210
|
+
|
|
211
|
+
The `BasicAuthentication` class can be used to connect to a hyperlake cluster configured with
|
|
212
|
+
the [Password file, LDAP or Salesforce authentication type](https://trino.io/docs/current/security/authentication-types.html):
|
|
213
|
+
|
|
214
|
+
- DBAPI
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
from hyperlake.dbapi import connect
|
|
218
|
+
from hyperlake.auth import BasicAuthentication
|
|
219
|
+
|
|
220
|
+
conn = connect(
|
|
221
|
+
user="<username>",
|
|
222
|
+
auth=BasicAuthentication("<username>", "<password>"),
|
|
223
|
+
http_scheme="https",
|
|
224
|
+
...
|
|
225
|
+
)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
- SQLAlchemy
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
from sqlalchemy import create_engine
|
|
232
|
+
|
|
233
|
+
engine = create_engine("hyperlake://<username>:<password>@<host>:<port>/<catalog>")
|
|
234
|
+
|
|
235
|
+
# or as connect_args
|
|
236
|
+
from hyperlake.auth import BasicAuthentication
|
|
237
|
+
engine = create_engine(
|
|
238
|
+
"hyperlake://<username>@<host>:<port>/<catalog>",
|
|
239
|
+
connect_args={
|
|
240
|
+
"auth": BasicAuthentication("<username>", "<password>"),
|
|
241
|
+
"http_scheme": "https",
|
|
242
|
+
}
|
|
243
|
+
)
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### JWT authentication
|
|
247
|
+
|
|
248
|
+
The `JWTAuthentication` class can be used to connect to a hyperlake cluster configured with
|
|
249
|
+
the [`JWT` authentication type](https://trino.io/docs/current/security/jwt.html):
|
|
250
|
+
|
|
251
|
+
- DBAPI
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
from hyperlake.dbapi import connect
|
|
255
|
+
from hyperlake.auth import JWTAuthentication
|
|
256
|
+
|
|
257
|
+
conn = connect(
|
|
258
|
+
user="<username>",
|
|
259
|
+
auth=JWTAuthentication("<jwt_token>"),
|
|
260
|
+
http_scheme="https",
|
|
261
|
+
...
|
|
262
|
+
)
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
- SQLAlchemy
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
from sqlalchemy import create_engine
|
|
269
|
+
|
|
270
|
+
engine = create_engine("hyperlake://<username>@<host>:<port>/<catalog>/<schema>?access_token=<jwt_token>")
|
|
271
|
+
|
|
272
|
+
# or as connect_args
|
|
273
|
+
from hyperlake.auth import JWTAuthentication
|
|
274
|
+
engine = create_engine(
|
|
275
|
+
"hyperlake://<username>@<host>:<port>/<catalog>",
|
|
276
|
+
connect_args={
|
|
277
|
+
"auth": JWTAuthentication("<jwt_token>"),
|
|
278
|
+
"http_scheme": "https",
|
|
279
|
+
}
|
|
280
|
+
)
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### OAuth2 authentication
|
|
284
|
+
|
|
285
|
+
The `OAuth2Authentication` class can be used to connect to a hyperlake cluster configured with
|
|
286
|
+
the [OAuth2 authentication type](https://trino.io/docs/current/security/oauth2.html).
|
|
287
|
+
|
|
288
|
+
A callback to handle the redirect url can be provided via param `redirect_auth_url_handler` of the `hyperlake.auth.OAuth2Authentication` class. By default, it will try to launch a web browser (`hyperlake.auth.WebBrowserRedirectHandler`) to go through the authentication flow and output the redirect url to stdout (`hyperlake.auth.ConsoleRedirectHandler`). Multiple redirect handlers are combined using the `hyperlake.auth.CompositeRedirectHandler` class.
|
|
289
|
+
|
|
290
|
+
The OAuth2 token will be cached either per `hyperlake.auth.OAuth2Authentication` instance and username or, when keyring is installed, it will be cached within a secure backend (MacOS keychain, Windows credential locker, etc) under a key including host of the hyperlake connection. Keyring can be installed using `pip install 'hyperlake[external-authentication-token-cache]'`.
|
|
291
|
+
|
|
292
|
+
> [!WARNING]
|
|
293
|
+
> If username is not specified then the OAuth2 token cache is shared and stored per host.
|
|
294
|
+
|
|
295
|
+
- DBAPI
|
|
296
|
+
|
|
297
|
+
```python
|
|
298
|
+
from hyperlake.dbapi import connect
|
|
299
|
+
from hyperlake.auth import OAuth2Authentication
|
|
300
|
+
|
|
301
|
+
conn = connect(
|
|
302
|
+
user="<username>",
|
|
303
|
+
auth=OAuth2Authentication(),
|
|
304
|
+
http_scheme="https",
|
|
305
|
+
...
|
|
306
|
+
)
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
- SQLAlchemy
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
from sqlalchemy import create_engine
|
|
313
|
+
from hyperlake.auth import OAuth2Authentication
|
|
314
|
+
|
|
315
|
+
engine = create_engine(
|
|
316
|
+
"hyperlake://<username>@<host>:<port>/<catalog>",
|
|
317
|
+
connect_args={
|
|
318
|
+
"auth": OAuth2Authentication(),
|
|
319
|
+
"http_scheme": "https",
|
|
320
|
+
}
|
|
321
|
+
)
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Certificate authentication
|
|
325
|
+
|
|
326
|
+
`CertificateAuthentication` class can be used to connect to hyperlake cluster configured with [certificate based authentication](https://trino.io/docs/current/security/certificate.html). `CertificateAuthentication` requires paths to a valid client certificate and private key.
|
|
327
|
+
|
|
328
|
+
- DBAPI
|
|
329
|
+
|
|
330
|
+
```python
|
|
331
|
+
from hyperlake.dbapi import connect
|
|
332
|
+
from hyperlake.auth import CertificateAuthentication
|
|
333
|
+
|
|
334
|
+
conn = connect(
|
|
335
|
+
user="<username>",
|
|
336
|
+
auth=CertificateAuthentication("/path/to/cert.pem", "/path/to/key.pem"),
|
|
337
|
+
http_scheme="https",
|
|
338
|
+
...
|
|
339
|
+
)
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
- SQLAlchemy
|
|
343
|
+
|
|
344
|
+
```python
|
|
345
|
+
from sqlalchemy import create_engine
|
|
346
|
+
from hyperlake.auth import CertificateAuthentication
|
|
347
|
+
|
|
348
|
+
engine = create_engine("hyperlake://<username>@<host>:<port>/<catalog>/<schema>?cert=<cert>&key=<key>")
|
|
349
|
+
|
|
350
|
+
# or as connect_args
|
|
351
|
+
engine = create_engine(
|
|
352
|
+
"hyperlake://<username>@<host>:<port>/<catalog>",
|
|
353
|
+
connect_args={
|
|
354
|
+
"auth": CertificateAuthentication("/path/to/cert.pem", "/path/to/key.pem"),
|
|
355
|
+
"http_scheme": "https",
|
|
356
|
+
}
|
|
357
|
+
)
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Kerberos authentication
|
|
361
|
+
|
|
362
|
+
Make sure that the Kerberos support is installed using `pip install hyperlake[kerberos]`.
|
|
363
|
+
The `KerberosAuthentication` class can be used to connect to a hyperlake cluster configured with
|
|
364
|
+
the [`Kerberos` authentication type](https://trino.io/docs/current/security/kerberos.html):
|
|
365
|
+
|
|
366
|
+
- DBAPI
|
|
367
|
+
|
|
368
|
+
```python
|
|
369
|
+
from hyperlake.dbapi import connect
|
|
370
|
+
from hyperlake.auth import KerberosAuthentication
|
|
371
|
+
|
|
372
|
+
conn = connect(
|
|
373
|
+
user="<username>",
|
|
374
|
+
auth=KerberosAuthentication(...),
|
|
375
|
+
http_scheme="https",
|
|
376
|
+
...
|
|
377
|
+
)
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
- SQLAlchemy
|
|
381
|
+
|
|
382
|
+
```python
|
|
383
|
+
from sqlalchemy import create_engine
|
|
384
|
+
from hyperlake.auth import KerberosAuthentication
|
|
385
|
+
|
|
386
|
+
engine = create_engine(
|
|
387
|
+
"hyperlake://<username>@<host>:<port>/<catalog>",
|
|
388
|
+
connect_args={
|
|
389
|
+
"auth": KerberosAuthentication(...),
|
|
390
|
+
"http_scheme": "https",
|
|
391
|
+
}
|
|
392
|
+
)
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### GSSAPI authentication
|
|
396
|
+
|
|
397
|
+
Make sure that the GSSAPI support is installed using `pip install hyperlake[gssapi]`.
|
|
398
|
+
The `GSSAPIAuthentication` class can be used to connect to a hyperlake cluster configured with
|
|
399
|
+
the [`Kerberos` authentication type](https://trino.io/docs/current/security/kerberos.html):
|
|
400
|
+
|
|
401
|
+
It follows the interface for `KerberosAuthentication`, but is using
|
|
402
|
+
[requests-gssapi](https://github.com/pythongssapi/requests-gssapi), instead of [requests-kerberos](https://github.com/requests/requests-kerberos) under the hood.
|
|
403
|
+
|
|
404
|
+
- DBAPI
|
|
405
|
+
|
|
406
|
+
```python
|
|
407
|
+
from hyperlake.dbapi import connect
|
|
408
|
+
from hyperlake.auth import GSSAPIAuthentication
|
|
409
|
+
|
|
410
|
+
conn = connect(
|
|
411
|
+
user="<username>",
|
|
412
|
+
auth=GSSAPIAuthentication(...),
|
|
413
|
+
http_scheme="https",
|
|
414
|
+
...
|
|
415
|
+
)
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
- SQLAlchemy
|
|
419
|
+
|
|
420
|
+
```python
|
|
421
|
+
from sqlalchemy import create_engine
|
|
422
|
+
from hyperlake.auth import GSSAPIAuthentication
|
|
423
|
+
|
|
424
|
+
engine = create_engine(
|
|
425
|
+
"hyperlake://<username>@<host>:<port>/<catalog>",
|
|
426
|
+
connect_args={
|
|
427
|
+
"auth": GSSAPIAuthentication(...),
|
|
428
|
+
"http_scheme": "https",
|
|
429
|
+
}
|
|
430
|
+
)
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## User impersonation
|
|
434
|
+
|
|
435
|
+
In the case where user who submits the query is not the same as user who authenticates to hyperlake server (e.g in Superset),
|
|
436
|
+
you can set `username` to be different from `principal_id`. Note that `principal_id` is extracted from `auth`,
|
|
437
|
+
for example `username` in BasicAuthentication, `sub` in JWT token or `service-name` in KerberosAuthentication.
|
|
438
|
+
You need to make sure that [`principal_id` has permission to impersonate `username`](https://trino.io/docs/current/security/file-system-access-control.html#impersonation-rules).
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
```python
|
|
443
|
+
import hyperlake
|
|
444
|
+
conn = hyperlake.dbapi.connect(
|
|
445
|
+
host='localhost',
|
|
446
|
+
port=443,
|
|
447
|
+
user='the-user',
|
|
448
|
+
extra_credential=[('a.username', 'bar'), ('a.password', 'foo')],
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
cur = conn.cursor()
|
|
452
|
+
cur.execute('SELECT * FROM system.runtime.nodes')
|
|
453
|
+
rows = cur.fetchall()
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
## Roles
|
|
457
|
+
|
|
458
|
+
Authorization roles to use for catalogs, specified as a dict with key-value pairs for the catalog and role. For example, `{"catalog1": "roleA", "catalog2": "roleB"}` sets `roleA` for `catalog1` and `roleB` for `catalog2`.
|
|
459
|
+
|
|
460
|
+
```python
|
|
461
|
+
import hyperlake
|
|
462
|
+
conn = hyperlake.dbapi.connect(
|
|
463
|
+
host='localhost',
|
|
464
|
+
port=443,
|
|
465
|
+
user='the-user',
|
|
466
|
+
roles={"catalog1": "roleA", "catalog2": "roleB"},
|
|
467
|
+
)
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
You could also pass `system` role without explicitly specifing "system" catalog:
|
|
471
|
+
|
|
472
|
+
```python
|
|
473
|
+
import hyperlake
|
|
474
|
+
conn = hyperlake.dbapi.connect(
|
|
475
|
+
host='localhost',
|
|
476
|
+
port=443,
|
|
477
|
+
user='the-user',
|
|
478
|
+
roles="role1" # equivalent to {"system": "role1"}
|
|
479
|
+
)
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
## Timezone
|
|
483
|
+
|
|
484
|
+
The time zone for the session can be explicitly set using the IANA time zone
|
|
485
|
+
name. When not set the time zone defaults to the client side local timezone.
|
|
486
|
+
|
|
487
|
+
```python
|
|
488
|
+
import hyperlake
|
|
489
|
+
conn = hyperlake.dbapi.connect(
|
|
490
|
+
host='localhost',
|
|
491
|
+
port=443,
|
|
492
|
+
user='username',
|
|
493
|
+
timezone='Europe/Brussels',
|
|
494
|
+
)
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
> **NOTE: The behaviour till version 0.320.0 was the same as setting session timezone to UTC.**
|
|
498
|
+
> **To preserve that behaviour pass `timezone='UTC'` when creating the connection.**
|
|
499
|
+
|
|
500
|
+
## SSL
|
|
501
|
+
|
|
502
|
+
### SSL verification
|
|
503
|
+
|
|
504
|
+
In order to disable SSL verification, set the `verify` parameter to `False`.
|
|
505
|
+
|
|
506
|
+
```python
|
|
507
|
+
from hyperlake.dbapi import connect
|
|
508
|
+
from hyperlake.auth import BasicAuthentication
|
|
509
|
+
|
|
510
|
+
conn = connect(
|
|
511
|
+
user="<username>",
|
|
512
|
+
auth=BasicAuthentication("<username>", "<password>"),
|
|
513
|
+
http_scheme="https",
|
|
514
|
+
verify=False
|
|
515
|
+
)
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### Self-signed certificates
|
|
519
|
+
|
|
520
|
+
To use self-signed certificates, specify a path to the certificate in `verify` parameter.
|
|
521
|
+
More details can be found in [the Python requests library documentation](https://requests.readthedocs.io/en/latest/user/advanced/#ssl-cert-verification).
|
|
522
|
+
|
|
523
|
+
```python
|
|
524
|
+
from hyperlake.dbapi import connect
|
|
525
|
+
from hyperlake.auth import BasicAuthentication
|
|
526
|
+
|
|
527
|
+
conn = connect(
|
|
528
|
+
user="<username>",
|
|
529
|
+
auth=BasicAuthentication("<username>", "<password>"),
|
|
530
|
+
http_scheme="https",
|
|
531
|
+
verify="/path/to/cert.crt"
|
|
532
|
+
)
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
## Spooled protocol
|
|
536
|
+
|
|
537
|
+
The client spooling protocol requires [a hyperlake server based on hyperlake with spooling protocol support](https://trino.io/docs/current/client/client-protocol.html#spooling-protocol).
|
|
538
|
+
|
|
539
|
+
Enable the spooling protocol by specifying a supported encoding in the `encoding` parameter:
|
|
540
|
+
|
|
541
|
+
Supported encodings are `json`, `json+lz4` and `json+zstd`.
|
|
542
|
+
|
|
543
|
+
```python
|
|
544
|
+
from hyperlake.dbapi import connect
|
|
545
|
+
|
|
546
|
+
conn = connect(
|
|
547
|
+
encoding="json+zstd"
|
|
548
|
+
)
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
or a list of supported encodings in order of preference:
|
|
552
|
+
|
|
553
|
+
```python
|
|
554
|
+
from hyperlake.dbapi import connect
|
|
555
|
+
|
|
556
|
+
conn = connect(
|
|
557
|
+
encoding=["json+zstd", "json"]
|
|
558
|
+
)
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
## Transactions
|
|
562
|
+
|
|
563
|
+
The client runs by default in *autocommit* mode. To enable transactions, set
|
|
564
|
+
*isolation_level* to a value different than `IsolationLevel.AUTOCOMMIT`:
|
|
565
|
+
|
|
566
|
+
```python
|
|
567
|
+
from hyperlake.dbapi import connect
|
|
568
|
+
from hyperlake.transaction import IsolationLevel
|
|
569
|
+
|
|
570
|
+
with connect(
|
|
571
|
+
isolation_level=IsolationLevel.REPEATABLE_READ,
|
|
572
|
+
...
|
|
573
|
+
) as conn:
|
|
574
|
+
cur = conn.cursor()
|
|
575
|
+
cur.execute('INSERT INTO sometable VALUES (1, 2, 3)')
|
|
576
|
+
cur.fetchall()
|
|
577
|
+
cur.execute('INSERT INTO sometable VALUES (4, 5, 6)')
|
|
578
|
+
cur.fetchall()
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
The transaction is created when the first SQL statement is executed.
|
|
582
|
+
`hyperlake.dbapi.Connection.commit()` will be automatically called when the code
|
|
583
|
+
exits the *with* context and the queries succeed, otherwise
|
|
584
|
+
`hyperlake.dbapi.Connection.rollback()` will be called.
|
|
585
|
+
|
|
586
|
+
## Custom requests Session
|
|
587
|
+
|
|
588
|
+
You can create a custom [requests.Session object](https://requests.readthedocs.io/en/latest/user/advanced/#session-objects) and pass it to the `http_session` parameter. This can be used for things like setting additional HTTP headers, client certificates, etc.
|
|
589
|
+
|
|
590
|
+
```python
|
|
591
|
+
import requests
|
|
592
|
+
from hyperlake.dbapi import connect
|
|
593
|
+
|
|
594
|
+
s = requests.Session()
|
|
595
|
+
s.cert = '/path/client.cert'
|
|
596
|
+
|
|
597
|
+
conn = connect(
|
|
598
|
+
http_session=s,
|
|
599
|
+
...
|
|
600
|
+
)
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
## Legacy Primitive types
|
|
604
|
+
|
|
605
|
+
By default, the client will convert the results of the query to the
|
|
606
|
+
corresponding Python types. For example, if the query returns a `DECIMAL` column, the result will be a `Decimal` object.
|
|
607
|
+
If you want to disable this behaviour, set flag `legacy_primitive_types` to `True`.
|
|
608
|
+
|
|
609
|
+
Limitations of the Python types are described in the
|
|
610
|
+
[Python types documentation](https://docs.python.org/3/library/datatypes.html). These limitations will generate an
|
|
611
|
+
exception `trino.exceptions.TrinoDataError` if the query returns a value that cannot be converted to the corresponding Python
|
|
612
|
+
type.
|
|
613
|
+
|
|
614
|
+
```python
|
|
615
|
+
import hyperlake
|
|
616
|
+
|
|
617
|
+
conn = hyperlake.dbapi.connect(
|
|
618
|
+
legacy_primitive_types=True,
|
|
619
|
+
...
|
|
620
|
+
)
|
|
621
|
+
|
|
622
|
+
cur = conn.cursor()
|
|
623
|
+
# Negative DATE cannot be represented with Python types
|
|
624
|
+
# legacy_primitive_types needs to be enabled
|
|
625
|
+
cur.execute("SELECT DATE '-2001-08-22'")
|
|
626
|
+
rows = cur.fetchall()
|
|
627
|
+
|
|
628
|
+
assert rows[0][0] == "-2001-08-22"
|
|
629
|
+
assert cur.description[0][1] == "date"
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### hyperlake Trino to Python type mappings
|
|
633
|
+
|
|
634
|
+
| Trino type | Python type |
|
|
635
|
+
|------------|-------------------|
|
|
636
|
+
| BOOLEAN | bool |
|
|
637
|
+
| TINYINT | int |
|
|
638
|
+
| SMALLINT | int |
|
|
639
|
+
| INTEGER | int |
|
|
640
|
+
| BIGINT | int |
|
|
641
|
+
| REAL | float |
|
|
642
|
+
| DOUBLE | float |
|
|
643
|
+
| DECIMAL | decimal.Decimal |
|
|
644
|
+
| VARCHAR | str |
|
|
645
|
+
| CHAR | str |
|
|
646
|
+
| VARBINARY | bytes |
|
|
647
|
+
| DATE | datetime.date |
|
|
648
|
+
| TIME | datetime.time |
|
|
649
|
+
| TIMESTAMP | datetime.datetime |
|
|
650
|
+
| ARRAY | list |
|
|
651
|
+
| MAP | dict |
|
|
652
|
+
| ROW | tuple |
|
|
653
|
+
|
|
654
|
+
Trino types other than those listed above are not mapped to Python types. To use those use [legacy primitive types](#legacy-primitive-types).
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
Forked from: https://github.com/trinodb/trino-python-client
|