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.
Files changed (42) hide show
  1. {e6data-python-connector-1.1.12/e6data_python_connector.egg-info → e6data-python-connector-2.0.0}/PKG-INFO +8 -5
  2. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/README.md +6 -4
  3. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/datainputstream.py +105 -14
  4. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/e6data_grpc.py +9 -27
  5. e6data-python-connector-2.0.0/e6data_python_connector/e6x_vector/__init__.py +1 -0
  6. {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
  7. e6data-python-connector-2.0.0/e6data_python_connector/e6x_vector/ttypes.py +1609 -0
  8. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/server/QueryEngineService.py +1 -237
  9. e6data-python-connector-2.0.0/e6data_python_connector/server/constants.py +14 -0
  10. e6data-python-connector-2.0.0/e6data_python_connector/server/e6x_engine_pb2.py +136 -0
  11. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/server/e6x_engine_pb2.pyi +0 -16
  12. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/server/e6x_engine_pb2_grpc.py +0 -33
  13. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/server/ttypes.py +1 -1
  14. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0/e6data_python_connector.egg-info}/PKG-INFO +8 -5
  15. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector.egg-info/SOURCES.txt +3 -0
  16. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector.egg-info/requires.txt +1 -0
  17. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/datainputstream.py +70 -15
  18. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/e6x.py +10 -24
  19. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/setup.py +2 -1
  20. e6data-python-connector-1.1.12/e6data_python_connector/server/e6x_engine_pb2.py +0 -140
  21. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/LICENSE +0 -0
  22. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/MANIFEST.in +0 -0
  23. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/__init__.py +0 -0
  24. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/common.py +0 -0
  25. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/constants.py +0 -0
  26. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/date_time_utils.py +0 -0
  27. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/dialect.py +0 -0
  28. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/exceptions.py +0 -0
  29. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/server/__init__.py +0 -0
  30. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector/typeId.py +0 -0
  31. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector.egg-info/dependency_links.txt +0 -0
  32. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector.egg-info/entry_points.txt +0 -0
  33. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6data_python_connector.egg-info/top_level.txt +0 -0
  34. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/__init__.py +0 -0
  35. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/common.py +0 -0
  36. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/constants.py +0 -0
  37. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/date_time_utils.py +0 -0
  38. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/exceptions.py +0 -0
  39. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/sqlalchemy_e6x.py +0 -0
  40. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/e6xdb/typeId.py +0 -0
  41. {e6data-python-connector-1.1.12 → e6data-python-connector-2.0.0}/pyproject.toml +0 -0
  42. {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: 1.1.12
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
- ![version](https://img.shields.io/badge/version-1.1.12-blue.svg)
30
+ ![version](https://img.shields.io/badge/version-2.0.0-blue.svg)
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 Wheel dependency
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
- ![version](https://img.shields.io/badge/version-1.1.12-blue.svg)
3
+ ![version](https://img.shields.io/badge/version-2.0.0-blue.svg)
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 Wheel dependency
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
- from e6xdb.date_time_utils import FORMATS, floor_div, floor_mod
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 read_rows_from_batch(query_columns_description: list, dis: DataInputStream):
157
- is_row_present = dis.read_byte()
158
- if not is_row_present:
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
- while is_row_present == 1:
162
- if is_row_present:
163
- row = read_values_from_array(query_columns_description, dis)
164
- rows.append(row)
165
- # if rows become 1000, break it
166
- # if len(rows) == 1000:
167
- # _logger.info("Read Batch - Breaking the loop after 1000 records")
168
- # break
169
- is_row_present = dis.read_byte()
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, read_rows_from_batch, \
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 = 100 * 1024 * 1024 # mb
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 read_rows_from_batch(self._query_columns_description, dis)
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
- rows_to_return = []
534
- client = self.connection.client
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
- buffer = BytesIO(buffer)
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']
@@ -1,5 +1,5 @@
1
1
  #
2
- # Autogenerated by Thrift Compiler (0.18.1)
2
+ # Autogenerated by Thrift Compiler (0.19.0)
3
3
  #
4
4
  # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
5
  #