e6data-python-connector 1.1.12__tar.gz → 2.0.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.
- {e6data-python-connector-1.1.12/e6data_python_connector.egg-info → e6data-python-connector-2.0.0}/PKG-INFO +8 -5
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/README.md +6 -4
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/datainputstream.py +105 -14
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/e6data_grpc.py +9 -27
- e6data-python-connector-2.0.0/e6data_python_connector/e6x_vector/__init__.py +1 -0
- {e6data-python-connector-1.1.12/e6data_python_connector/server → e6data-python-connector-2.0.0/e6data_python_connector/e6x_vector}/constants.py +1 -1
- e6data-python-connector-2.0.0/e6data_python_connector/e6x_vector/ttypes.py +1609 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/server/QueryEngineService.py +1 -237
- e6data-python-connector-2.0.0/e6data_python_connector/server/constants.py +14 -0
- e6data-python-connector-2.0.0/e6data_python_connector/server/e6x_engine_pb2.py +136 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/server/e6x_engine_pb2.pyi +0 -16
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/server/e6x_engine_pb2_grpc.py +0 -33
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/server/ttypes.py +1 -1
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0/e6data_python_connector.egg-info}/PKG-INFO +8 -5
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector.egg-info/SOURCES.txt +3 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector.egg-info/requires.txt +1 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/datainputstream.py +70 -15
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/e6x.py +10 -24
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/setup.py +2 -1
- e6data-python-connector-1.1.12/e6data_python_connector/server/e6x_engine_pb2.py +0 -140
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/LICENSE +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/MANIFEST.in +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/__init__.py +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/common.py +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/constants.py +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/date_time_utils.py +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/dialect.py +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/exceptions.py +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/server/__init__.py +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/typeId.py +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector.egg-info/dependency_links.txt +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector.egg-info/entry_points.txt +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector.egg-info/top_level.txt +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/__init__.py +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/common.py +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/constants.py +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/date_time_utils.py +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/exceptions.py +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/sqlalchemy_e6x.py +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/typeId.py +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/pyproject.toml +0 -0
- {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: e6data-python-connector
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: Client for the e6data distributed SQL Engine.
|
|
5
5
|
Home-page: https://github.com/e6x-labs/e6data-python-connector
|
|
6
6
|
Author: Uniphi, Inc.
|
|
@@ -16,6 +16,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE
|
|
18
18
|
Requires-Dist: sqlalchemy>=1.0.0
|
|
19
|
+
Requires-Dist: future
|
|
19
20
|
Requires-Dist: python-dateutil
|
|
20
21
|
Requires-Dist: pycryptodome
|
|
21
22
|
Requires-Dist: pytz
|
|
@@ -26,21 +27,23 @@ Requires-Dist: sqlalchemy
|
|
|
26
27
|
|
|
27
28
|
# e6data Python Connector
|
|
28
29
|
|
|
29
|
-

|
|
30
31
|
|
|
31
32
|
## Introduction
|
|
32
33
|
|
|
33
34
|
The e6data Connector for Python provides an interface for writing Python applications that can connect to e6data and perform operations.
|
|
34
35
|
|
|
35
|
-
#### Amazon Linux
|
|
36
|
-
Make sure to install wheel before install e6data-python-connector.
|
|
36
|
+
#### Amazon Linux dependency
|
|
37
|
+
Make sure to install C compiler dependencies and wheel before install e6data-python-connector.
|
|
37
38
|
```shell
|
|
39
|
+
yum install python3-devel gcc-c++ -y
|
|
40
|
+
|
|
38
41
|
pip install wheel
|
|
39
42
|
```
|
|
40
43
|
|
|
41
44
|
To install the Python package, use the command below:
|
|
42
45
|
```shell
|
|
43
|
-
pip install e6data-python-connector
|
|
46
|
+
pip install --no-cache-dir e6data-python-connector
|
|
44
47
|
```
|
|
45
48
|
### Prerequisites
|
|
46
49
|
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
# e6data Python Connector
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|
|
|
5
5
|
## Introduction
|
|
6
6
|
|
|
7
7
|
The e6data Connector for Python provides an interface for writing Python applications that can connect to e6data and perform operations.
|
|
8
8
|
|
|
9
|
-
#### Amazon Linux
|
|
10
|
-
Make sure to install wheel before install e6data-python-connector.
|
|
9
|
+
#### Amazon Linux dependency
|
|
10
|
+
Make sure to install C compiler dependencies and wheel before install e6data-python-connector.
|
|
11
11
|
```shell
|
|
12
|
+
yum install python3-devel gcc-c++ -y
|
|
13
|
+
|
|
12
14
|
pip install wheel
|
|
13
15
|
```
|
|
14
16
|
|
|
15
17
|
To install the Python package, use the command below:
|
|
16
18
|
```shell
|
|
17
|
-
pip install e6data-python-connector
|
|
19
|
+
pip install --no-cache-dir e6data-python-connector
|
|
18
20
|
```
|
|
19
21
|
### Prerequisites
|
|
20
22
|
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import struct
|
|
2
1
|
import logging
|
|
3
|
-
|
|
2
|
+
import struct
|
|
4
3
|
from datetime import datetime, timedelta
|
|
4
|
+
|
|
5
|
+
import pytz
|
|
6
|
+
from thrift.protocol import TBinaryProtocol
|
|
7
|
+
from thrift.transport import TTransport
|
|
8
|
+
|
|
9
|
+
from e6data_python_connector.e6x_vector.ttypes import Chunk, Vector, VectorType
|
|
5
10
|
from e6xdb.constants import ZONE
|
|
11
|
+
from e6xdb.date_time_utils import floor_div, floor_mod
|
|
6
12
|
|
|
7
13
|
_logger = logging.getLogger(__name__)
|
|
8
14
|
|
|
@@ -153,18 +159,103 @@ def read_values_from_array(query_columns_description: list, dis: DataInputStream
|
|
|
153
159
|
return value_array
|
|
154
160
|
|
|
155
161
|
|
|
156
|
-
def
|
|
157
|
-
|
|
158
|
-
|
|
162
|
+
def read_rows_from_chunk(query_columns_description: list, buffer):
|
|
163
|
+
# Create a transport and protocol instance for deserialization
|
|
164
|
+
transport = TTransport.TMemoryBuffer(buffer)
|
|
165
|
+
protocol = TBinaryProtocol.TBinaryProtocolAccelerated(transport)
|
|
166
|
+
|
|
167
|
+
# Create an instance of the Thrift struct and read from the protocol
|
|
168
|
+
chunk = Chunk()
|
|
169
|
+
chunk.read(protocol)
|
|
170
|
+
|
|
171
|
+
if chunk.size <= 0:
|
|
159
172
|
return None
|
|
173
|
+
|
|
160
174
|
rows = list()
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
175
|
+
columns = list()
|
|
176
|
+
|
|
177
|
+
for col, colName in enumerate(query_columns_description):
|
|
178
|
+
columns.append(get_column_from_chunk(chunk.vectors[col]))
|
|
179
|
+
|
|
180
|
+
for rowIndex in range(chunk.size):
|
|
181
|
+
value = list()
|
|
182
|
+
for colIndex, colName in enumerate(query_columns_description):
|
|
183
|
+
value.append(columns[colIndex][rowIndex])
|
|
184
|
+
rows.append(value)
|
|
185
|
+
|
|
170
186
|
return rows
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def get_column_from_chunk(vector: Vector) -> list:
|
|
190
|
+
value_array = list()
|
|
191
|
+
d_type = vector.vectorType
|
|
192
|
+
try:
|
|
193
|
+
if d_type == VectorType.LONG:
|
|
194
|
+
for row in range(vector.size):
|
|
195
|
+
if vector.nullSet[row]:
|
|
196
|
+
value_array.append(None)
|
|
197
|
+
continue
|
|
198
|
+
value_array.append(vector.data.int64Data.data[row] if not vector.isConstantVector else vector.data.numericConstantData.data)
|
|
199
|
+
elif d_type == VectorType.DATE:
|
|
200
|
+
for row in range(vector.size):
|
|
201
|
+
if vector.nullSet[row]:
|
|
202
|
+
value_array.append(None)
|
|
203
|
+
continue
|
|
204
|
+
epoch_seconds = floor_div(vector.data.dateData.data[row] if not vector.isConstantVector else vector.data.dateConstantData.data, 1000_000)
|
|
205
|
+
zone_offset = pytz.timezone('UTC') if vector.zoneOffset == 'Z' else pytz.timezone(vector.zoneOffset)
|
|
206
|
+
date = datetime.fromtimestamp(epoch_seconds, zone_offset)
|
|
207
|
+
value_array.append(date.strftime("%Y-%m-%d"))
|
|
208
|
+
elif d_type == VectorType.DATETIME:
|
|
209
|
+
for row in range(vector.size):
|
|
210
|
+
if vector.nullSet[row]:
|
|
211
|
+
value_array.append(None)
|
|
212
|
+
continue
|
|
213
|
+
epoch_micros = vector.data.timeData.data[row] if not vector.isConstantVector else vector.data.timeConstantData.data
|
|
214
|
+
epoch_seconds = floor_div(epoch_micros, 1000_000)
|
|
215
|
+
micros_of_the_day = floor_mod(epoch_micros, 1000_000)
|
|
216
|
+
zone_offset = pytz.timezone('UTC') if vector.zoneOffset == 'Z' else pytz.timezone(vector.zoneOffset)
|
|
217
|
+
date_time = datetime.fromtimestamp(epoch_seconds, zone_offset)
|
|
218
|
+
date_time = date_time + timedelta(microseconds=micros_of_the_day)
|
|
219
|
+
value_array.append(date_time.strftime("%Y-%m-%d %H:%M:%S"))
|
|
220
|
+
elif d_type == VectorType.STRING or d_type == VectorType.ARRAY or d_type == VectorType.MAP or d_type == VectorType.STRUCT:
|
|
221
|
+
for row in range(vector.size):
|
|
222
|
+
if vector.nullSet[row]:
|
|
223
|
+
value_array.append(None)
|
|
224
|
+
continue
|
|
225
|
+
value_array.append(vector.data.varcharData.data[row] if not vector.isConstantVector else vector.data.varcharConstantData.data)
|
|
226
|
+
elif d_type == VectorType.DOUBLE:
|
|
227
|
+
for row in range(vector.size):
|
|
228
|
+
if vector.nullSet[row]:
|
|
229
|
+
value_array.append(None)
|
|
230
|
+
continue
|
|
231
|
+
value_array.append(vector.data.float64Data.data[row] if not vector.isConstantVector else vector.data.numericDecimalConstantData.data)
|
|
232
|
+
elif d_type == VectorType.BINARY:
|
|
233
|
+
for row in range(vector.size):
|
|
234
|
+
if vector.nullSet[row]:
|
|
235
|
+
value_array.append(None)
|
|
236
|
+
continue
|
|
237
|
+
value_array.append(vector.data.varcharData.data[row] if not vector.isConstantVector else vector.data.varcharConstantData.data)
|
|
238
|
+
elif d_type == VectorType.FLOAT:
|
|
239
|
+
for row in range(vector.size):
|
|
240
|
+
if vector.nullSet[row]:
|
|
241
|
+
value_array.append(None)
|
|
242
|
+
continue
|
|
243
|
+
value_array.append(vector.data.float32Data.data[row] if not vector.isConstantVector else vector.data.numericDecimalConstantData.data)
|
|
244
|
+
elif d_type == VectorType.BOOLEAN:
|
|
245
|
+
for row in range(vector.size):
|
|
246
|
+
if vector.nullSet[row]:
|
|
247
|
+
value_array.append(None)
|
|
248
|
+
continue
|
|
249
|
+
value_array.append(vector.data.boolData.data[row] if not vector.isConstantVector else vector.data.boolConstantData.data)
|
|
250
|
+
elif d_type == VectorType.INTEGER:
|
|
251
|
+
for row in range(vector.size):
|
|
252
|
+
if vector.nullSet[row]:
|
|
253
|
+
value_array.append(None)
|
|
254
|
+
continue
|
|
255
|
+
value_array.append(vector.data.int32Data.data[row] if not vector.isConstantVector else vector.data.numericConstantData.data)
|
|
256
|
+
else:
|
|
257
|
+
value_array.append(None)
|
|
258
|
+
except Exception as e:
|
|
259
|
+
_logger.error(e)
|
|
260
|
+
value_array.append('Failed to parse.')
|
|
261
|
+
return value_array
|
|
@@ -19,7 +19,7 @@ import grpc
|
|
|
19
19
|
|
|
20
20
|
from e6data_python_connector.common import DBAPITypeObject, ParamEscaper, DBAPICursor
|
|
21
21
|
from e6data_python_connector.constants import *
|
|
22
|
-
from e6data_python_connector.datainputstream import DataInputStream, get_query_columns_info,
|
|
22
|
+
from e6data_python_connector.datainputstream import DataInputStream, get_query_columns_info, read_rows_from_chunk, \
|
|
23
23
|
read_values_from_array
|
|
24
24
|
from e6data_python_connector.server import e6x_engine_pb2_grpc, e6x_engine_pb2
|
|
25
25
|
from e6data_python_connector.typeId import *
|
|
@@ -126,7 +126,7 @@ class Connection(object):
|
|
|
126
126
|
self.catalog_name = catalog
|
|
127
127
|
|
|
128
128
|
self._keepalive_timeout_ms = 900000
|
|
129
|
-
self._max_receive_message_length =
|
|
129
|
+
self._max_receive_message_length = -1
|
|
130
130
|
self._max_send_message_length = 300 * 1024 * 1024 # mb
|
|
131
131
|
|
|
132
132
|
if type(grpc_options) == dict:
|
|
@@ -490,32 +490,28 @@ class Cursor(DBAPICursor):
|
|
|
490
490
|
get_next_result_batch_request = e6x_engine_pb2.GetNextResultBatchRequest(
|
|
491
491
|
engineIP=self._engine_ip,
|
|
492
492
|
sessionId=self.connection.get_session_id,
|
|
493
|
-
queryId=self._query_id
|
|
494
|
-
asRowData=True
|
|
493
|
+
queryId=self._query_id
|
|
495
494
|
)
|
|
496
495
|
get_next_result_batch_response = client.getNextResultBatch(get_next_result_batch_request)
|
|
497
496
|
buffer = get_next_result_batch_response.resultBatch
|
|
498
497
|
if not self._is_metadata_updated:
|
|
499
498
|
self.update_mete_data()
|
|
500
499
|
self._is_metadata_updated = True
|
|
501
|
-
if not buffer:
|
|
500
|
+
if not buffer or len(buffer) == 0:
|
|
502
501
|
return None
|
|
503
|
-
buffer = BytesIO(buffer)
|
|
504
|
-
dis = DataInputStream(buffer)
|
|
505
502
|
# one batch retrieves the predefined set of rows
|
|
506
|
-
return
|
|
503
|
+
return read_rows_from_chunk(self._query_columns_description, buffer)
|
|
507
504
|
|
|
508
505
|
def fetchall(self):
|
|
509
506
|
return self._fetch_all()
|
|
510
507
|
|
|
511
|
-
def fetchmany(self, size=None):
|
|
508
|
+
def fetchmany(self, size: int = None):
|
|
512
509
|
# _logger.info("fetching all from overriden method")
|
|
513
510
|
if size is None:
|
|
514
511
|
size = self.arraysize
|
|
515
512
|
if self._data is None:
|
|
516
513
|
self._data = list()
|
|
517
514
|
while len(self._data) < size:
|
|
518
|
-
# _logger.info("fetching next batch from fetch many")
|
|
519
515
|
rows = self.fetch_batch()
|
|
520
516
|
if rows is None:
|
|
521
517
|
break
|
|
@@ -530,24 +526,10 @@ class Cursor(DBAPICursor):
|
|
|
530
526
|
|
|
531
527
|
def fetchone(self):
|
|
532
528
|
# _logger.info("fetch One returning the batch itself which is limited by predefined no.of rows")
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
get_next_result_row_request = e6x_engine_pb2.GetNextResultRowRequest(
|
|
536
|
-
engineIP=self._engine_ip,
|
|
537
|
-
sessionId=self.connection.get_session_id,
|
|
538
|
-
queryId=self._query_id
|
|
539
|
-
)
|
|
540
|
-
get_next_result_row_response = client.getNextResultRow(get_next_result_row_request)
|
|
541
|
-
buffer = get_next_result_row_response.resultRow
|
|
542
|
-
if not self._is_metadata_updated:
|
|
543
|
-
self.update_mete_data()
|
|
544
|
-
self._is_metadata_updated = True
|
|
545
|
-
if not buffer:
|
|
529
|
+
rows = self.fetchmany(1)
|
|
530
|
+
if rows is None or len(rows) == 0:
|
|
546
531
|
return None
|
|
547
|
-
|
|
548
|
-
dis = DataInputStream(buffer)
|
|
549
|
-
rows_to_return.append(read_values_from_array(self._query_columns_description, dis))
|
|
550
|
-
return rows_to_return
|
|
532
|
+
return rows
|
|
551
533
|
|
|
552
534
|
def explain(self):
|
|
553
535
|
explain_request = e6x_engine_pb2.ExplainRequest(
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__all__ = ['ttypes', 'constants']
|