kyuubi-dlc-client 0.1.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.
Files changed (30) hide show
  1. kyuubi_dlc_client-0.1.0/PKG-INFO +185 -0
  2. kyuubi_dlc_client-0.1.0/README.md +154 -0
  3. kyuubi_dlc_client-0.1.0/setup.cfg +4 -0
  4. kyuubi_dlc_client-0.1.0/setup.py +77 -0
  5. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/TCLIService/TCLIService.py +3986 -0
  6. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/TCLIService/__init__.py +1 -0
  7. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/TCLIService/constants.py +68 -0
  8. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/TCLIService/ttypes.py +7210 -0
  9. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/__init__.py +60 -0
  10. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/__version__.py +1 -0
  11. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/auth.py +125 -0
  12. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/common.py +152 -0
  13. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/config.py +151 -0
  14. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/dbapi.py +65 -0
  15. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/exceptions.py +56 -0
  16. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/rest/__init__.py +19 -0
  17. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/rest/client.py +350 -0
  18. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/rest/models.py +81 -0
  19. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/thrift/__init__.py +6 -0
  20. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/thrift/arrow.py +83 -0
  21. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/thrift/cloud_fetch.py +226 -0
  22. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/thrift/connection.py +318 -0
  23. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/thrift/cursor.py +382 -0
  24. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/thrift/sasl_compat.py +59 -0
  25. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client/types.py +78 -0
  26. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client.egg-info/PKG-INFO +185 -0
  27. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client.egg-info/SOURCES.txt +28 -0
  28. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client.egg-info/dependency_links.txt +1 -0
  29. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client.egg-info/requires.txt +28 -0
  30. kyuubi_dlc_client-0.1.0/src/kyuubi_dlc_client.egg-info/top_level.txt +1 -0
@@ -0,0 +1,185 @@
1
+ Metadata-Version: 2.1
2
+ Name: kyuubi_dlc_client
3
+ Version: 0.1.0
4
+ Summary: Python client for Apache Kyuubi (DLC fork): DB-API 2.0 over Thrift + REST API
5
+ Home-page: https://git.example.com/dlc/kyuubi-dlc-client
6
+ Author: DLC Kyuubi Team
7
+ License: Apache-2.0
8
+ Project-URL: Source, https://git.example.com/dlc/kyuubi-dlc-client
9
+ Project-URL: Documentation, https://kyuubi-dlc-client.readthedocs.io/
10
+ Project-URL: Homepage, https://git.example.com/dlc/kyuubi-dlc-client
11
+ Description: # kyuubi-dlc-client
12
+
13
+ Python client for the Kyuubi SQL gateway (DLC fork). Provides two independent
14
+ layers over the two protocol entrances of a Kyuubi server:
15
+
16
+ | Layer | Protocol | Port | Use case |
17
+ |---|---|---|---|
18
+ | `kyuubi_dlc_client.dbapi` | Thrift (HiveServer2) | 10009 | Interactive SQL, low latency, session state, streamed columnar results |
19
+ | `kyuubi_dlc_client.rest` | REST API v1 | 10099 | Spark batch jobs (`/batches`), interactive SQL over HTTP |
20
+
21
+ Both layers share the same authentication modes.
22
+
23
+ ## Highlights
24
+
25
+ - **DB-API 2.0** (PEP 249) compliant Thrift interface: `connect()` / `cursor()` /
26
+ `execute()` / `fetch*()`, plus non-standard async execution (`async_=True`),
27
+ polling, progress logs and cancellation.
28
+ - **REST batch client** with UUID-based idempotent submission, exponential
29
+ backoff polling, local log retrieval and cancellation.
30
+ - **Authentication**: `NONE`, `CUSTOM`, and DLC `AK/SK` (access key) modes.
31
+ - Robustness patches validated against Kyuubi: empty column payloads,
32
+ unknown type codes, custom SSL contexts.
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ pip install . # runtime only
38
+ pip install -e '.[dev]' # development (tests, lint)
39
+ ```
40
+
41
+ Requires Python 3.9+.
42
+
43
+ ## Quickstart: interactive SQL (Thrift)
44
+
45
+ ```python
46
+ import kyuubi_dlc_client
47
+
48
+ conn = kyuubi_dlc_client.connect(
49
+ host="127.0.0.1",
50
+ port=10009,
51
+ configuration={ # session-level settings
52
+ "kyuubi.engine.share.level": "USER",
53
+ },
54
+ )
55
+ try:
56
+ cur = conn.cursor()
57
+ cur.execute("SELECT 1 AS id, 'hello' AS msg")
58
+ print(cur.fetchall()) # [(1, 'hello')]
59
+ finally:
60
+ conn.close()
61
+ ```
62
+
63
+ Async execution with timeout and cancellation:
64
+
65
+ ```python
66
+ cur.execute("SELECT count(*) FROM range(1000000)", async_=True)
67
+ cur.wait(timeout_s=300) # raises ExecutionTimeoutError + cancels
68
+ print(cur.fetchall())
69
+ ```
70
+
71
+ ## Quickstart: Spark batch (REST)
72
+
73
+ ```python
74
+ import uuid
75
+ from kyuubi_dlc_client.rest import KyuubiRestClient
76
+
77
+ with KyuubiRestClient("http://127.0.0.1:10099/api/v1") as client:
78
+ batch = client.submit_batch(
79
+ resource="cos://bucket/spark-examples.jar",
80
+ class_name="org.apache.spark.examples.SparkPi",
81
+ args=["10"],
82
+ batch_id=str(uuid.uuid4()), # UUID is mandatory; enables idempotent retry
83
+ )
84
+ finished = client.wait_batch(batch.id, timeout_s=600)
85
+ print(finished.state, finished.appId)
86
+ logs = client.get_batch_local_log(batch.id, size=50)
87
+ ```
88
+
89
+ ## Authentication
90
+
91
+ ```python
92
+ # Anonymous (Kyuubi NONE auth)
93
+ conn = kyuubi_dlc_client.connect(host, port)
94
+
95
+ # Username/password against a custom authenticator
96
+ conn = kyuubi_dlc_client.connect(host, port, auth="CUSTOM",
97
+ username="user", password="pass")
98
+
99
+ # DLC access key
100
+ conn = kyuubi_dlc_client.connect(
101
+ host, port,
102
+ secret_id=os.environ["SECRET_ID"],
103
+ secret_key=os.environ["SECRET_KEY"],
104
+ )
105
+ ```
106
+
107
+ > AK/SK wire format: the default presents `secret_id`/`secret_key` over
108
+ > SASL/PLAIN. Align `auth.AkSkAuth.credentials()` with the Kyuubi DLC
109
+ > authenticator plugin once its contract is frozen.
110
+
111
+ ## Interactive SQL over HTTP (REST sessions)
112
+
113
+ Use when only the HTTP port is reachable. Note that result sets are JSON
114
+ rows (slower for large data) and multi-instance deployments require routing
115
+ requests to the owning `kyuubiInstance`.
116
+
117
+ ```python
118
+ session = client.open_session()
119
+ operation = client.execute_statement(session, "SELECT 1", run_async=True)
120
+ # poll GET /operations/{id}/event, then:
121
+ rowset = client.fetch_rowset(operation)
122
+ client.close_session(session)
123
+ ```
124
+
125
+ ## Examples & smoke test
126
+
127
+ ```bash
128
+ # Thrift SQL quickstart
129
+ KYUUBI_HOST=127.0.0.1 python examples/sql_quickstart.py
130
+
131
+ # Batch quickstart (needs a spark-examples jar reachable by the server)
132
+ KYUUBI_HOST=127.0.0.1 \
133
+ BATCH_RESOURCE=local:///abs/path/spark-examples_2.12-3.5.1.jar \
134
+ python examples/batch_submit.py
135
+
136
+ # End-to-end smoke (SQL + batch)
137
+ KYUUBI_HOST=127.0.0.1 bash scripts/e2e_smoke.sh
138
+ ```
139
+
140
+ ## Development
141
+
142
+ ```bash
143
+ pip install -e '.[dev]'
144
+ ruff check src tests
145
+ pytest -m "not integration"
146
+ ```
147
+
148
+ ## Security notes
149
+
150
+ - Never hard-code credentials; read them from environment variables or a
151
+ secret store.
152
+ - The Thrift/REST ports of a Kyuubi server are internal infrastructure;
153
+ production access must go through the managed network entry point.
154
+ - Batch `resource` paths are validated by the gateway (e.g. `cos://`
155
+ allow-list); clients must not accept arbitrary resource URIs from
156
+ untrusted input (SSRF).
157
+
158
+ ## Credits & license
159
+
160
+ The TCLIService thrift bindings derive from PyHive (Apache-2.0), accepted into
161
+ Apache Kyuubi via Apache IP Clearance. The pure-sasl compatibility layer
162
+ originates from Impyla (Apache-2.0). See `NOTICE`.
163
+
164
+ Licensed under the Apache License, Version 2.0 (see `LICENSE`).
165
+
166
+ Keywords: kyuubi,dlc,spark,sql,hiveserver2,dbapi,thrift
167
+ Platform: UNKNOWN
168
+ Classifier: Development Status :: 3 - Alpha
169
+ Classifier: Intended Audience :: Developers
170
+ Classifier: License :: OSI Approved :: Apache Software License
171
+ Classifier: Operating System :: OS Independent
172
+ Classifier: Programming Language :: Python :: 3
173
+ Classifier: Programming Language :: Python :: 3.9
174
+ Classifier: Programming Language :: Python :: 3.10
175
+ Classifier: Programming Language :: Python :: 3.11
176
+ Classifier: Programming Language :: Python :: 3.12
177
+ Classifier: Topic :: Database
178
+ Classifier: Topic :: Database :: Front-Ends
179
+ Requires-Python: >=3.9
180
+ Description-Content-Type: text/markdown
181
+ Provides-Extra: yaml
182
+ Provides-Extra: sqlalchemy
183
+ Provides-Extra: arrow
184
+ Provides-Extra: dev
185
+ Provides-Extra: thrift
@@ -0,0 +1,154 @@
1
+ # kyuubi-dlc-client
2
+
3
+ Python client for the Kyuubi SQL gateway (DLC fork). Provides two independent
4
+ layers over the two protocol entrances of a Kyuubi server:
5
+
6
+ | Layer | Protocol | Port | Use case |
7
+ |---|---|---|---|
8
+ | `kyuubi_dlc_client.dbapi` | Thrift (HiveServer2) | 10009 | Interactive SQL, low latency, session state, streamed columnar results |
9
+ | `kyuubi_dlc_client.rest` | REST API v1 | 10099 | Spark batch jobs (`/batches`), interactive SQL over HTTP |
10
+
11
+ Both layers share the same authentication modes.
12
+
13
+ ## Highlights
14
+
15
+ - **DB-API 2.0** (PEP 249) compliant Thrift interface: `connect()` / `cursor()` /
16
+ `execute()` / `fetch*()`, plus non-standard async execution (`async_=True`),
17
+ polling, progress logs and cancellation.
18
+ - **REST batch client** with UUID-based idempotent submission, exponential
19
+ backoff polling, local log retrieval and cancellation.
20
+ - **Authentication**: `NONE`, `CUSTOM`, and DLC `AK/SK` (access key) modes.
21
+ - Robustness patches validated against Kyuubi: empty column payloads,
22
+ unknown type codes, custom SSL contexts.
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ pip install . # runtime only
28
+ pip install -e '.[dev]' # development (tests, lint)
29
+ ```
30
+
31
+ Requires Python 3.9+.
32
+
33
+ ## Quickstart: interactive SQL (Thrift)
34
+
35
+ ```python
36
+ import kyuubi_dlc_client
37
+
38
+ conn = kyuubi_dlc_client.connect(
39
+ host="127.0.0.1",
40
+ port=10009,
41
+ configuration={ # session-level settings
42
+ "kyuubi.engine.share.level": "USER",
43
+ },
44
+ )
45
+ try:
46
+ cur = conn.cursor()
47
+ cur.execute("SELECT 1 AS id, 'hello' AS msg")
48
+ print(cur.fetchall()) # [(1, 'hello')]
49
+ finally:
50
+ conn.close()
51
+ ```
52
+
53
+ Async execution with timeout and cancellation:
54
+
55
+ ```python
56
+ cur.execute("SELECT count(*) FROM range(1000000)", async_=True)
57
+ cur.wait(timeout_s=300) # raises ExecutionTimeoutError + cancels
58
+ print(cur.fetchall())
59
+ ```
60
+
61
+ ## Quickstart: Spark batch (REST)
62
+
63
+ ```python
64
+ import uuid
65
+ from kyuubi_dlc_client.rest import KyuubiRestClient
66
+
67
+ with KyuubiRestClient("http://127.0.0.1:10099/api/v1") as client:
68
+ batch = client.submit_batch(
69
+ resource="cos://bucket/spark-examples.jar",
70
+ class_name="org.apache.spark.examples.SparkPi",
71
+ args=["10"],
72
+ batch_id=str(uuid.uuid4()), # UUID is mandatory; enables idempotent retry
73
+ )
74
+ finished = client.wait_batch(batch.id, timeout_s=600)
75
+ print(finished.state, finished.appId)
76
+ logs = client.get_batch_local_log(batch.id, size=50)
77
+ ```
78
+
79
+ ## Authentication
80
+
81
+ ```python
82
+ # Anonymous (Kyuubi NONE auth)
83
+ conn = kyuubi_dlc_client.connect(host, port)
84
+
85
+ # Username/password against a custom authenticator
86
+ conn = kyuubi_dlc_client.connect(host, port, auth="CUSTOM",
87
+ username="user", password="pass")
88
+
89
+ # DLC access key
90
+ conn = kyuubi_dlc_client.connect(
91
+ host, port,
92
+ secret_id=os.environ["SECRET_ID"],
93
+ secret_key=os.environ["SECRET_KEY"],
94
+ )
95
+ ```
96
+
97
+ > AK/SK wire format: the default presents `secret_id`/`secret_key` over
98
+ > SASL/PLAIN. Align `auth.AkSkAuth.credentials()` with the Kyuubi DLC
99
+ > authenticator plugin once its contract is frozen.
100
+
101
+ ## Interactive SQL over HTTP (REST sessions)
102
+
103
+ Use when only the HTTP port is reachable. Note that result sets are JSON
104
+ rows (slower for large data) and multi-instance deployments require routing
105
+ requests to the owning `kyuubiInstance`.
106
+
107
+ ```python
108
+ session = client.open_session()
109
+ operation = client.execute_statement(session, "SELECT 1", run_async=True)
110
+ # poll GET /operations/{id}/event, then:
111
+ rowset = client.fetch_rowset(operation)
112
+ client.close_session(session)
113
+ ```
114
+
115
+ ## Examples & smoke test
116
+
117
+ ```bash
118
+ # Thrift SQL quickstart
119
+ KYUUBI_HOST=127.0.0.1 python examples/sql_quickstart.py
120
+
121
+ # Batch quickstart (needs a spark-examples jar reachable by the server)
122
+ KYUUBI_HOST=127.0.0.1 \
123
+ BATCH_RESOURCE=local:///abs/path/spark-examples_2.12-3.5.1.jar \
124
+ python examples/batch_submit.py
125
+
126
+ # End-to-end smoke (SQL + batch)
127
+ KYUUBI_HOST=127.0.0.1 bash scripts/e2e_smoke.sh
128
+ ```
129
+
130
+ ## Development
131
+
132
+ ```bash
133
+ pip install -e '.[dev]'
134
+ ruff check src tests
135
+ pytest -m "not integration"
136
+ ```
137
+
138
+ ## Security notes
139
+
140
+ - Never hard-code credentials; read them from environment variables or a
141
+ secret store.
142
+ - The Thrift/REST ports of a Kyuubi server are internal infrastructure;
143
+ production access must go through the managed network entry point.
144
+ - Batch `resource` paths are validated by the gateway (e.g. `cos://`
145
+ allow-list); clients must not accept arbitrary resource URIs from
146
+ untrusted input (SSRF).
147
+
148
+ ## Credits & license
149
+
150
+ The TCLIService thrift bindings derive from PyHive (Apache-2.0), accepted into
151
+ Apache Kyuubi via Apache IP Clearance. The pure-sasl compatibility layer
152
+ originates from Impyla (Apache-2.0). See `NOTICE`.
153
+
154
+ Licensed under the Apache License, Version 2.0 (see `LICENSE`).
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,77 @@
1
+ import io
2
+ import os
3
+ import re
4
+
5
+ from setuptools import find_packages, setup
6
+
7
+ ROOT = os.path.dirname(os.path.abspath(__file__))
8
+
9
+
10
+ def read(relative_path):
11
+ with io.open(os.path.join(ROOT, relative_path), encoding="utf-8") as source: # noqa: UP020
12
+ return source.read()
13
+
14
+
15
+ version_source = read("src/kyuubi_dlc_client/__version__.py")
16
+ version_match = re.search(r"^__version__\s*=\s*['\"]([^'\"]+)['\"]", version_source, re.M)
17
+ if version_match is None:
18
+ raise RuntimeError("Unable to find version string.")
19
+
20
+
21
+ if __name__ == "__main__":
22
+ setup(
23
+ name="kyuubi_dlc_client",
24
+ version=version_match.group(1),
25
+ description="Python client for Apache Kyuubi (DLC fork): DB-API 2.0 over Thrift + REST API",
26
+ long_description=read("README.md"),
27
+ long_description_content_type="text/markdown",
28
+ python_requires=">=3.9",
29
+ license="Apache-2.0",
30
+ license_files=["LICENSE", "NOTICE"],
31
+ author="DLC Kyuubi Team",
32
+ url="https://git.example.com/dlc/kyuubi-dlc-client",
33
+ project_urls={
34
+ "Homepage": "https://git.example.com/dlc/kyuubi-dlc-client",
35
+ "Documentation": "https://kyuubi-dlc-client.readthedocs.io/",
36
+ "Source": "https://git.example.com/dlc/kyuubi-dlc-client",
37
+ },
38
+ keywords=["kyuubi", "dlc", "spark", "sql", "hiveserver2", "dbapi", "thrift"],
39
+ classifiers=[
40
+ "Development Status :: 3 - Alpha",
41
+ "Intended Audience :: Developers",
42
+ "License :: OSI Approved :: Apache Software License",
43
+ "Operating System :: OS Independent",
44
+ "Programming Language :: Python :: 3",
45
+ "Programming Language :: Python :: 3.9",
46
+ "Programming Language :: Python :: 3.10",
47
+ "Programming Language :: Python :: 3.11",
48
+ "Programming Language :: Python :: 3.12",
49
+ "Topic :: Database",
50
+ "Topic :: Database :: Front-Ends",
51
+ ],
52
+ package_dir={"": "src"},
53
+ packages=find_packages(where="src"),
54
+ install_requires=["requests>=2.28.0"],
55
+ extras_require={
56
+ "thrift": [
57
+ "thrift>=0.16.0,<0.19.0",
58
+ "thrift-sasl>=0.4.3",
59
+ "pure-sasl>=0.6.2",
60
+ ],
61
+ "sqlalchemy": ["sqlalchemy>=1.4"],
62
+ "arrow": ["pyarrow>=12.0", "pytz>=2024.1"],
63
+ "yaml": ["pyyaml>=6.0"],
64
+ "dev": [
65
+ "pytest>=7.0",
66
+ "pytest-cov>=4.0",
67
+ "ruff>=0.1",
68
+ "build>=1.0",
69
+ "responses>=0.23",
70
+ "thrift>=0.16.0,<0.19.0",
71
+ "thrift-sasl>=0.4.3",
72
+ "pure-sasl>=0.6.2",
73
+ "pyarrow>=12.0",
74
+ "pyyaml>=6.0",
75
+ ],
76
+ },
77
+ )