e6data-python-connector 2.1.20__py3-none-any.whl → 2.1.21.dev0__py3-none-any.whl

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.
@@ -0,0 +1,117 @@
1
+ import threading
2
+ import time
3
+ import e6data_python_connector.cluster_server.cluster_pb2 as cluster_pb2
4
+ import e6data_python_connector.cluster_server.cluster_pb2_grpc as cluster_pb2_grpc
5
+ import grpc
6
+ from grpc._channel import _InactiveRpcError
7
+ import multiprocessing
8
+
9
+
10
+ class _StatusLock:
11
+ _LOCK_TIMEOUT = 500
12
+
13
+ def __init__(self):
14
+ self._status_thread_lock = threading.Lock()
15
+ self._status_multiprocessing_lock = multiprocessing.Semaphore()
16
+ self._is_active = False
17
+
18
+ @property
19
+ def is_active(self) -> bool:
20
+ return self._is_active
21
+
22
+ def set_active(self):
23
+ self._is_active = True
24
+
25
+ def __enter__(self):
26
+ self._status_thread_lock.acquire(timeout=self._LOCK_TIMEOUT)
27
+ self._status_multiprocessing_lock.acquire(timeout=self._LOCK_TIMEOUT)
28
+ print('Locked threads and processes.')
29
+ return self
30
+
31
+ def __exit__(self, exc_type, exc_val, exc_tb):
32
+ self._status_thread_lock.release()
33
+ self._status_multiprocessing_lock.release()
34
+ print('Released threads and processes.')
35
+
36
+
37
+ status_lock = _StatusLock()
38
+
39
+
40
+ class ClusterManager:
41
+ def __init__(self, host: str, port: int, user: str, password: str, secure_channel: bool = False, timeout=60 * 3):
42
+ self._host = host
43
+ self._port = port
44
+ self._user = user
45
+ self._password = password
46
+ self._timeout = time.time() + timeout
47
+ self._secure_channel = secure_channel
48
+
49
+ @property
50
+ def _get_connection(self):
51
+ if self._secure_channel:
52
+ self._channel = grpc.secure_channel(
53
+ target='{}:{}'.format(self._host, self._port),
54
+ credentials=grpc.ssl_channel_credentials()
55
+ )
56
+ else:
57
+ self._channel = grpc.insecure_channel(
58
+ target='{}:{}'.format(self._host, self._port)
59
+ )
60
+ return cluster_pb2_grpc.ClusterServiceStub(self._channel)
61
+
62
+ def resume(self) -> bool:
63
+ """
64
+ Return True if cluster came to active state else False.
65
+ """
66
+ with status_lock as lock:
67
+ if lock.is_active:
68
+ print('Cluster is already active')
69
+ return True
70
+ status_payload = cluster_pb2.ClusterStatusRequest(
71
+ user=self._user,
72
+ password=self._password
73
+ )
74
+ current_status = self._get_connection.status(status_payload)
75
+ print('Current status', current_status)
76
+ if current_status.status == 'suspended':
77
+ payload = cluster_pb2.ResumeRequest(
78
+ user=self._user,
79
+ password=self._password
80
+ )
81
+ response = self._get_connection.resume(payload)
82
+ print('resuming response', response.status)
83
+ elif current_status.status == 'active':
84
+ print('Cluster is already active.')
85
+ return True
86
+ elif current_status.status != 'resuming':
87
+ """
88
+ If cluster is in resuming state already, start watching for the status.
89
+ Cluster is in different state, cannot resume.
90
+ """
91
+ print('Cluster is in different state, cannot resume.')
92
+ return False
93
+ while True:
94
+ try:
95
+ status_payload = cluster_pb2.ClusterStatusRequest(
96
+ user=self._user,
97
+ password=self._password
98
+ )
99
+ response = self._get_connection.status(status_payload)
100
+ print(response)
101
+ if response.status == 'active':
102
+ lock.set_active()
103
+ print('Breaking because of status:', response.status)
104
+ return True
105
+ if response.status in ['suspended', 'failed']:
106
+ print('Breaking because of status:', response.status)
107
+ return False
108
+ if time.time() > self._timeout:
109
+ print('Breaking because of timeout')
110
+ return False
111
+ except _InactiveRpcError as e:
112
+ print('On resume error', e)
113
+ print('Retrying')
114
+ time.sleep(5)
115
+
116
+ def suspend(self):
117
+ pass
File without changes
@@ -0,0 +1,38 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: cluster.proto
4
+ """Generated protocol buffer code."""
5
+ from google.protobuf import descriptor as _descriptor
6
+ from google.protobuf import descriptor_pool as _descriptor_pool
7
+ from google.protobuf import symbol_database as _symbol_database
8
+ from google.protobuf.internal import builder as _builder
9
+ # @@protoc_insertion_point(imports)
10
+
11
+ _sym_db = _symbol_database.Default()
12
+
13
+
14
+
15
+
16
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rcluster.proto\"/\n\rResumeRequest\x12\x0c\n\x04user\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\" \n\x0eResumeResponse\x12\x0e\n\x06status\x18\x01 \x01(\t\"0\n\x0eSuspendRequest\x12\x0c\n\x04user\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\"!\n\x0fSuspendResponse\x12\x0e\n\x06status\x18\x01 \x01(\t\"6\n\x14\x43lusterStatusRequest\x12\x0c\n\x04user\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\"\'\n\x15\x43lusterStatusResponse\x12\x0e\n\x06status\x18\x01 \x01(\t2\xa2\x01\n\x0e\x43lusterService\x12)\n\x06resume\x12\x0e.ResumeRequest\x1a\x0f.ResumeResponse\x12,\n\x07suspend\x12\x0f.SuspendRequest\x1a\x10.SuspendResponse\x12\x37\n\x06status\x12\x15.ClusterStatusRequest\x1a\x16.ClusterStatusResponseB\x02P\x01\x62\x06proto3')
17
+
18
+ _globals = globals()
19
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
20
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'cluster_pb2', _globals)
21
+ if _descriptor._USE_C_DESCRIPTORS == False:
22
+ DESCRIPTOR._options = None
23
+ DESCRIPTOR._serialized_options = b'P\001'
24
+ _globals['_RESUMEREQUEST']._serialized_start=17
25
+ _globals['_RESUMEREQUEST']._serialized_end=64
26
+ _globals['_RESUMERESPONSE']._serialized_start=66
27
+ _globals['_RESUMERESPONSE']._serialized_end=98
28
+ _globals['_SUSPENDREQUEST']._serialized_start=100
29
+ _globals['_SUSPENDREQUEST']._serialized_end=148
30
+ _globals['_SUSPENDRESPONSE']._serialized_start=150
31
+ _globals['_SUSPENDRESPONSE']._serialized_end=183
32
+ _globals['_CLUSTERSTATUSREQUEST']._serialized_start=185
33
+ _globals['_CLUSTERSTATUSREQUEST']._serialized_end=239
34
+ _globals['_CLUSTERSTATUSRESPONSE']._serialized_start=241
35
+ _globals['_CLUSTERSTATUSRESPONSE']._serialized_end=280
36
+ _globals['_CLUSTERSERVICE']._serialized_start=283
37
+ _globals['_CLUSTERSERVICE']._serialized_end=445
38
+ # @@protoc_insertion_point(module_scope)
@@ -0,0 +1,132 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+
5
+ import e6data_python_connector.cluster_server.cluster_pb2 as cluster__pb2
6
+
7
+
8
+ class ClusterServiceStub(object):
9
+ """Missing associated documentation comment in .proto file."""
10
+
11
+ def __init__(self, channel):
12
+ """Constructor.
13
+
14
+ Args:
15
+ channel: A grpc.Channel.
16
+ """
17
+ self.resume = channel.unary_unary(
18
+ '/ClusterService/resume',
19
+ request_serializer=cluster__pb2.ResumeRequest.SerializeToString,
20
+ response_deserializer=cluster__pb2.ResumeResponse.FromString,
21
+ )
22
+ self.suspend = channel.unary_unary(
23
+ '/ClusterService/suspend',
24
+ request_serializer=cluster__pb2.SuspendRequest.SerializeToString,
25
+ response_deserializer=cluster__pb2.SuspendResponse.FromString,
26
+ )
27
+ self.status = channel.unary_unary(
28
+ '/ClusterService/status',
29
+ request_serializer=cluster__pb2.ClusterStatusRequest.SerializeToString,
30
+ response_deserializer=cluster__pb2.ClusterStatusResponse.FromString,
31
+ )
32
+
33
+
34
+ class ClusterServiceServicer(object):
35
+ """Missing associated documentation comment in .proto file."""
36
+
37
+ def resume(self, request, context):
38
+ """Missing associated documentation comment in .proto file."""
39
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
40
+ context.set_details('Method not implemented!')
41
+ raise NotImplementedError('Method not implemented!')
42
+
43
+ def suspend(self, request, context):
44
+ """Missing associated documentation comment in .proto file."""
45
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
46
+ context.set_details('Method not implemented!')
47
+ raise NotImplementedError('Method not implemented!')
48
+
49
+ def status(self, request, context):
50
+ """Missing associated documentation comment in .proto file."""
51
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
52
+ context.set_details('Method not implemented!')
53
+ raise NotImplementedError('Method not implemented!')
54
+
55
+
56
+ def add_ClusterServiceServicer_to_server(servicer, server):
57
+ rpc_method_handlers = {
58
+ 'resume': grpc.unary_unary_rpc_method_handler(
59
+ servicer.resume,
60
+ request_deserializer=cluster__pb2.ResumeRequest.FromString,
61
+ response_serializer=cluster__pb2.ResumeResponse.SerializeToString,
62
+ ),
63
+ 'suspend': grpc.unary_unary_rpc_method_handler(
64
+ servicer.suspend,
65
+ request_deserializer=cluster__pb2.SuspendRequest.FromString,
66
+ response_serializer=cluster__pb2.SuspendResponse.SerializeToString,
67
+ ),
68
+ 'status': grpc.unary_unary_rpc_method_handler(
69
+ servicer.status,
70
+ request_deserializer=cluster__pb2.ClusterStatusRequest.FromString,
71
+ response_serializer=cluster__pb2.ClusterStatusResponse.SerializeToString,
72
+ ),
73
+ }
74
+ generic_handler = grpc.method_handlers_generic_handler(
75
+ 'ClusterService', rpc_method_handlers)
76
+ server.add_generic_rpc_handlers((generic_handler,))
77
+
78
+
79
+ # This class is part of an EXPERIMENTAL API.
80
+ class ClusterService(object):
81
+ """Missing associated documentation comment in .proto file."""
82
+
83
+ @staticmethod
84
+ def resume(request,
85
+ target,
86
+ options=(),
87
+ channel_credentials=None,
88
+ call_credentials=None,
89
+ insecure=False,
90
+ compression=None,
91
+ wait_for_ready=None,
92
+ timeout=None,
93
+ metadata=None):
94
+ return grpc.experimental.unary_unary(request, target, '/ClusterService/resume',
95
+ cluster__pb2.ResumeRequest.SerializeToString,
96
+ cluster__pb2.ResumeResponse.FromString,
97
+ options, channel_credentials,
98
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
99
+
100
+ @staticmethod
101
+ def suspend(request,
102
+ target,
103
+ options=(),
104
+ channel_credentials=None,
105
+ call_credentials=None,
106
+ insecure=False,
107
+ compression=None,
108
+ wait_for_ready=None,
109
+ timeout=None,
110
+ metadata=None):
111
+ return grpc.experimental.unary_unary(request, target, '/ClusterService/suspend',
112
+ cluster__pb2.SuspendRequest.SerializeToString,
113
+ cluster__pb2.SuspendResponse.FromString,
114
+ options, channel_credentials,
115
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
116
+
117
+ @staticmethod
118
+ def status(request,
119
+ target,
120
+ options=(),
121
+ channel_credentials=None,
122
+ call_credentials=None,
123
+ insecure=False,
124
+ compression=None,
125
+ wait_for_ready=None,
126
+ timeout=None,
127
+ metadata=None):
128
+ return grpc.experimental.unary_unary(request, target, '/ClusterService/status',
129
+ cluster__pb2.ClusterStatusRequest.SerializeToString,
130
+ cluster__pb2.ClusterStatusResponse.FromString,
131
+ options, channel_credentials,
132
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@@ -231,11 +231,6 @@ def get_column_from_chunk(vector: Vector) -> list:
231
231
  continue
232
232
  epoch_micros = vector.data.timeData.data[
233
233
  row] if not vector.isConstantVector else vector.data.timeConstantData.data
234
- if ((vector.isConstantVector and vector.data.timeConstantData.zoneData is not None) or
235
- (not vector.isConstantVector and vector.data.timeData.zoneData is not None)):
236
- zone_id = vector.data.timeData.zoneData[
237
- row] if not vector.isConstantVector else vector.data.timeConstantData.zoneData
238
- zone = timezone_from_offset(zone_id)
239
234
  epoch_seconds = floor_div(epoch_micros, 1000_000)
240
235
  micros_of_the_day = floor_mod(epoch_micros, 1000_000)
241
236
  date_time = datetime.fromtimestamp(epoch_seconds, zone)
@@ -286,6 +281,23 @@ def get_column_from_chunk(vector: Vector) -> list:
286
281
  elif d_type == VectorType.NULL:
287
282
  for row in range(vector.size):
288
283
  value_array.append(None)
284
+ elif d_type == VectorType.TIMESTAMP_TZ:
285
+ for row in range(vector.size):
286
+ if get_null(vector, row):
287
+ value_array.append(None)
288
+ continue
289
+ epoch_micros = vector.data.timeData.data[
290
+ row] if not vector.isConstantVector else vector.data.timeConstantData.data
291
+ if ((vector.isConstantVector and vector.data.timeConstantData.zoneData is not None) or
292
+ (not vector.isConstantVector and vector.data.timeData.zoneData is not None)):
293
+ zone_id = vector.data.timeData.zoneData[
294
+ row] if not vector.isConstantVector else vector.data.timeConstantData.zoneData
295
+ zone = timezone_from_offset(zone_id)
296
+ epoch_seconds = floor_div(epoch_micros, 1000_000)
297
+ micros_of_the_day = floor_mod(epoch_micros, 1000_000)
298
+ date_time = datetime.fromtimestamp(epoch_seconds, zone)
299
+ date_time = date_time + timedelta(microseconds=micros_of_the_day)
300
+ value_array.append(date_time.isoformat(timespec='milliseconds'))
289
301
  else:
290
302
  value_array.append(None)
291
303
  except Exception as e:
@@ -16,7 +16,9 @@ from io import BytesIO
16
16
  from ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED
17
17
 
18
18
  import grpc
19
+ from grpc._channel import _InactiveRpcError
19
20
 
21
+ from e6data_python_connector.cluster_manager import ClusterManager
20
22
  from e6data_python_connector.common import DBAPITypeObject, ParamEscaper, DBAPICursor
21
23
  from e6data_python_connector.constants import *
22
24
  from e6data_python_connector.datainputstream import get_query_columns_info, read_rows_from_chunk
@@ -114,6 +116,7 @@ class Connection(object):
114
116
  database: str = None,
115
117
  cluster_uuid: str = None,
116
118
  secure: bool = False,
119
+ auto_resume: bool = False,
117
120
  grpc_options: dict = None,
118
121
  ):
119
122
  """
@@ -137,6 +140,8 @@ class Connection(object):
137
140
  Cluster's uuid
138
141
  secure: bool, Optional
139
142
  Flag to use a secure channel for data transfer
143
+ auto_resume: bool, Optional
144
+ Flag to enable auto resume of the cluster before the query execution
140
145
  grpc_options: dict, Optional
141
146
  Specify gRPC configuration
142
147
  - keepalive_timeout_ms: This parameter defines the time, in milliseconds, that a gRPC connection should remain idle before sending a keepalive ping to check if the connection is still alive.
@@ -160,6 +165,8 @@ class Connection(object):
160
165
 
161
166
  self.catalog_name = catalog
162
167
 
168
+ self._auto_resume = auto_resume
169
+
163
170
  self._keepalive_timeout_ms = 900000
164
171
  self._max_receive_message_length = -1
165
172
  self._max_send_message_length = 300 * 1024 * 1024 # mb
@@ -208,11 +215,38 @@ class Connection(object):
208
215
  )
209
216
  authenticate_response = self._client.authenticate(
210
217
  authenticate_request,
211
- metadata=_get_grpc_header(cluster=self.cluster_uuid)
218
+ metadata=_get_grpc_header(cluster=self.cluster_uuid),
219
+ # timeout=3
212
220
  )
213
221
  self._session_id = authenticate_response.sessionId
214
222
  if not self._session_id:
215
223
  raise ValueError("Invalid credentials.")
224
+ except _InactiveRpcError as e:
225
+ if self._auto_resume:
226
+ if e.code() == grpc.StatusCode.UNKNOWN and 'Stream removed' in e.details():
227
+ status = ClusterManager(
228
+ host=self._host,
229
+ port=self._port,
230
+ user=self.__username,
231
+ password=self.__password,
232
+ secure_channel=self._secure_channel
233
+ ).resume()
234
+ if status:
235
+ authenticate_request = e6x_engine_pb2.AuthenticateRequest(
236
+ user=self.__username,
237
+ password=self.__password
238
+ )
239
+ authenticate_response = self._client.authenticate(
240
+ authenticate_request,
241
+ metadata=_get_grpc_header(cluster=self.cluster_uuid)
242
+ )
243
+ self._session_id = authenticate_response.sessionId
244
+ else:
245
+ raise e
246
+ else:
247
+ raise e
248
+ else:
249
+ raise e
216
250
  except Exception as e:
217
251
  self._channel.close()
218
252
  raise e
@@ -32,6 +32,7 @@ class VectorType(object):
32
32
  MAP = 12
33
33
  ARRAY = 13
34
34
  NULL = 14
35
+ TIMESTAMP_TZ = 15
35
36
 
36
37
  _VALUES_TO_NAMES = {
37
38
  0: "BINARY",
@@ -49,6 +50,7 @@ class VectorType(object):
49
50
  12: "MAP",
50
51
  13: "ARRAY",
51
52
  14: "NULL",
53
+ 15: "TIMESTAMP_TZ",
52
54
  }
53
55
 
54
56
  _NAMES_TO_VALUES = {
@@ -67,6 +69,7 @@ class VectorType(object):
67
69
  "MAP": 12,
68
70
  "ARRAY": 13,
69
71
  "NULL": 14,
72
+ "TIMESTAMP_TZ": 15,
70
73
  }
71
74
 
72
75
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: e6data-python-connector
3
- Version: 2.1.20
3
+ Version: 2.1.21.dev0
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.
@@ -27,7 +27,7 @@ Requires-Dist: sqlalchemy
27
27
 
28
28
  # e6data Python Connector
29
29
 
30
- ![version](https://img.shields.io/badge/version-2.1.20-blue.svg)
30
+ ![version](https://img.shields.io/badge/version-2.1.21-blue.svg)
31
31
 
32
32
  ## Introduction
33
33
 
@@ -1,15 +1,19 @@
1
1
  e6data_python_connector/__init__.py,sha256=x_VwhPQ7XLlthR-NJL9Vl7lkLBRCG2pSjmyZSBHOBpM,103
2
+ e6data_python_connector/cluster_manager.py,sha256=0IcXhcg9Eci4OFTix2J82v6eylCK-Kwg_fLrC3rhURI,4331
2
3
  e6data_python_connector/common.py,sha256=nk0CDQ5j1iu8DctBOXX4QypPYmxSgIgoA-Cn1UZXLic,9976
3
4
  e6data_python_connector/constants.py,sha256=h5w0lWiFsxz__zUZRlo1f72-8mT_vt9gcWvtWh0viFI,682
4
- e6data_python_connector/datainputstream.py,sha256=lkn9lyutj0T8x4mk-ReyUO5qMzzBclQngdi_oYQQpKo,11861
5
+ e6data_python_connector/datainputstream.py,sha256=2XKW__PCGfTQ55Puqgie2LZdk_WU-YKwpEIUOQEF-sY,12592
5
6
  e6data_python_connector/date_time_utils.py,sha256=zmIwRhEGJwDvCOUjAl6VTDWGppluA-DPl_ioHTNpJKI,14413
6
7
  e6data_python_connector/dialect.py,sha256=M7vMHJgbnGqUdlY-XcDyeeXPwll9O7j1YAaySECLNpA,11177
7
- e6data_python_connector/e6data_grpc.py,sha256=nqx0B3VkYYDrk18DvFSWupy3uwLSOTx7IrYrPKRfmbg,24599
8
+ e6data_python_connector/e6data_grpc.py,sha256=3cDR-8etJDr5NBxT1D__w31Lhd_jAlvVR8m-hrS1rk8,26231
8
9
  e6data_python_connector/exceptions.py,sha256=vrUqdzMq3LjbCmvr5_TcRq9eKmdqGfe-uVjR0BJQf5U,382
9
10
  e6data_python_connector/typeId.py,sha256=2EMNWK2SO5CBReNuJphma6xp-69r9GDwwys66t-kSk0,1777
11
+ e6data_python_connector/cluster_server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ e6data_python_connector/cluster_server/cluster_pb2.py,sha256=BWxO5vG1SVkx2y-i6A6wvP5sfb8KNKosyl2N5lIsVd8,2339
13
+ e6data_python_connector/cluster_server/cluster_pb2_grpc.py,sha256=tfnRKs2GQGwdSH8zxT40yveN4XnD9j7aWHGUfGkPHiM,5399
10
14
  e6data_python_connector/e6x_vector/__init__.py,sha256=YFcZTT8Cm-6Y4oTiCaqq0DT1lw2W09WqoEc5_pTAwW0,34
11
15
  e6data_python_connector/e6x_vector/constants.py,sha256=fEiYY_X50Lqtkoew_h1qWBH5QmDiygExYB-6WRsifqg,366
12
- e6data_python_connector/e6x_vector/ttypes.py,sha256=rweZUmPmt-HC0rwnGeQb9VKIPtz9YknAZVXboKOz4BY,55908
16
+ e6data_python_connector/e6x_vector/ttypes.py,sha256=ocyP9ofm1swVRTnQJ0BKHKOLSN9LJFwXReYciWa67W4,55986
13
17
  e6data_python_connector/server/QueryEngineService.py,sha256=IDX2Yi9m_QFZ8L4FoiYrl8i7YL8GjTRonblKKFZsapU,198503
14
18
  e6data_python_connector/server/__init__.py,sha256=8eK3WgN4xfJiSNm4bUrnXb5ZgjMUEjdStbUahQQrJII,56
15
19
  e6data_python_connector/server/constants.py,sha256=QPD8cJw4a7t7JD4PTzbxj1CZKZ1lQ0TPK2Uzg72S9dE,366
@@ -17,9 +21,9 @@ e6data_python_connector/server/e6x_engine_pb2.py,sha256=BxJjbijNrEqXQTWEhzLm54Fq
17
21
  e6data_python_connector/server/e6x_engine_pb2.pyi,sha256=_aQDLFbSCQ7ubK0Z5ZKh9_VAHFaXbMV55MXYXr85srg,18693
18
22
  e6data_python_connector/server/e6x_engine_pb2_grpc.py,sha256=n-eTCsAjsmpgPA_bDansKZq_zMmqkK6TlQGn6IdT6L4,46671
19
23
  e6data_python_connector/server/ttypes.py,sha256=uWxwSp4m6e-7SeSEckbZtSduGYmfzXWM09iy5eltBPA,21227
20
- e6data_python_connector-2.1.20.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
21
- e6data_python_connector-2.1.20.dist-info/METADATA,sha256=ZzxZlthBs4Os1cwkYBF6gGWuEd8rW-MdKQj8F1KRZ50,6944
22
- e6data_python_connector-2.1.20.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
23
- e6data_python_connector-2.1.20.dist-info/entry_points.txt,sha256=MDK4cAOND0preLvq2Tlpnz00wXnP_Y_UopqJsAf3U7Y,77
24
- e6data_python_connector-2.1.20.dist-info/top_level.txt,sha256=ChOS6qLf-SQycXr0uBiVxomIfYfbH2SgwrOWhW79ab0,24
25
- e6data_python_connector-2.1.20.dist-info/RECORD,,
24
+ e6data_python_connector-2.1.21.dev0.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
25
+ e6data_python_connector-2.1.21.dev0.dist-info/METADATA,sha256=_ks_S8Q04Umv8dMki--h-MAr3HWNc50_ZLSDRPDy1Yg,6949
26
+ e6data_python_connector-2.1.21.dev0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
27
+ e6data_python_connector-2.1.21.dev0.dist-info/entry_points.txt,sha256=MDK4cAOND0preLvq2Tlpnz00wXnP_Y_UopqJsAf3U7Y,77
28
+ e6data_python_connector-2.1.21.dev0.dist-info/top_level.txt,sha256=ChOS6qLf-SQycXr0uBiVxomIfYfbH2SgwrOWhW79ab0,24
29
+ e6data_python_connector-2.1.21.dev0.dist-info/RECORD,,