e6data-python-connector 2.3.10rc2__tar.gz → 2.3.10rc3__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 (77) hide show
  1. {e6data_python_connector-2.3.10rc2/e6data_python_connector.egg-info → e6data_python_connector-2.3.10rc3}/PKG-INFO +2 -2
  2. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/README.md +1 -1
  3. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/e6data_grpc.py +30 -17
  4. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3/e6data_python_connector.egg-info}/PKG-INFO +2 -2
  5. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/setup.py +1 -1
  6. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/LICENSE +0 -0
  7. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/MANIFEST.in +0 -0
  8. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/__init__.py +0 -0
  9. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/cluster_manager.py +0 -0
  10. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/cluster_server/__init__.py +0 -0
  11. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/cluster_server/cluster_pb2.py +0 -0
  12. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/cluster_server/cluster_pb2_grpc.py +0 -0
  13. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/common.py +0 -0
  14. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/constants.py +0 -0
  15. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/datainputstream.py +0 -0
  16. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/date_time_utils.py +0 -0
  17. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/dialect.py +0 -0
  18. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/e6x_vector/__init__.py +0 -0
  19. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/e6x_vector/constants.py +0 -0
  20. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/e6x_vector/ttypes.py +0 -0
  21. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/exceptions.py +0 -0
  22. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/server/QueryEngineService.py +0 -0
  23. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/server/__init__.py +0 -0
  24. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/server/constants.py +0 -0
  25. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/server/e6x_engine_pb2.py +0 -0
  26. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/server/e6x_engine_pb2.pyi +0 -0
  27. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/server/e6x_engine_pb2_grpc.py +0 -0
  28. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/server/ttypes.py +0 -0
  29. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/strategy.py +0 -0
  30. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector/typeId.py +0 -0
  31. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector.egg-info/SOURCES.txt +0 -0
  32. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector.egg-info/dependency_links.txt +0 -0
  33. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector.egg-info/entry_points.txt +0 -0
  34. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector.egg-info/requires.txt +0 -0
  35. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/e6data_python_connector.egg-info/top_level.txt +0 -0
  36. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/pyproject.toml +0 -0
  37. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/setup.cfg +0 -0
  38. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/__init__.py +0 -0
  39. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/analyze_38_nines.py +0 -0
  40. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/analyze_all_cases.py +0 -0
  41. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/analyze_binary.py +0 -0
  42. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/analyze_correct_value.py +0 -0
  43. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/analyze_fields.py +0 -0
  44. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/check_decimal_errors.py +0 -0
  45. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/cleanup_test_files.py +0 -0
  46. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/debug_38_nines.py +0 -0
  47. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/debug_binary.py +0 -0
  48. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/final_test.py +0 -0
  49. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/move_tests.py +0 -0
  50. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/quick_test.py +0 -0
  51. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_38_nines.py +0 -0
  52. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_all_decimal128_cases.py +0 -0
  53. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_cluster_manager_efficiency.py +0 -0
  54. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_cluster_manager_none_strategy.py +0 -0
  55. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_cluster_manager_strategy.py +0 -0
  56. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_comprehensive.py +0 -0
  57. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_current_implementation.py +0 -0
  58. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_decimal128_binary_parsing.py +0 -0
  59. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_decimal128_parsing.py +0 -0
  60. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_fix.py +0 -0
  61. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_improved_parsing.py +0 -0
  62. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_known_case.py +0 -0
  63. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_manual_analysis.py +0 -0
  64. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_mock_server.py +0 -0
  65. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_multiprocessing_fix.py +0 -0
  66. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_new_implementation.py +0 -0
  67. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_specific_binary.py +0 -0
  68. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_strategy.py +0 -0
  69. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_strategy_logic.py +0 -0
  70. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_strategy_persistence_fix.py +0 -0
  71. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_strategy_sharing_fix.py +0 -0
  72. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/test_user_binary_value.py +0 -0
  73. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/tests.py +0 -0
  74. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/tests_grpc.py +0 -0
  75. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/validate_decimal128.py +0 -0
  76. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/validate_implementation.py +0 -0
  77. {e6data_python_connector-2.3.10rc2 → e6data_python_connector-2.3.10rc3}/test/verify_decimal_fix.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: e6data-python-connector
3
- Version: 2.3.10rc2
3
+ Version: 2.3.10rc3
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: e6data, Inc.
@@ -38,7 +38,7 @@ Dynamic: summary
38
38
 
39
39
  # e6data Python Connector
40
40
 
41
- ![version](https://img.shields.io/badge/version-2.3.10,rc2-blue.svg)
41
+ ![version](https://img.shields.io/badge/version-2.3.10,rc3-blue.svg)
42
42
 
43
43
  ## Introduction
44
44
 
@@ -1,6 +1,6 @@
1
1
  # e6data Python Connector
2
2
 
3
- ![version](https://img.shields.io/badge/version-2.3.10,rc2-blue.svg)
3
+ ![version](https://img.shields.io/badge/version-2.3.10,rc3-blue.svg)
4
4
 
5
5
  ## Introduction
6
6
 
@@ -243,7 +243,7 @@ def _invalidate_all_sessions():
243
243
  shared_strategy['session_invalidated'] = True
244
244
 
245
245
 
246
- def _register_query_strategy(query_id, strategy):
246
+ def _register_query_strategy(query_id, strategy, session_id=None):
247
247
  """Register the strategy used for a specific query."""
248
248
  if not query_id or not strategy:
249
249
  return
@@ -257,7 +257,8 @@ def _register_query_strategy(query_id, strategy):
257
257
  query_map = shared_strategy.get('query_strategy_map', {})
258
258
  query_map[query_id] = normalized_strategy
259
259
  shared_strategy['query_strategy_map'] = query_map
260
- _strategy_debug_log(f"Query {query_id} registered with strategy: {normalized_strategy}")
260
+ session_info = f", session: {session_id}" if session_id else ""
261
+ _strategy_debug_log(f"Query {query_id} registered with strategy: {normalized_strategy}{session_info}")
261
262
 
262
263
 
263
264
  def _get_query_strategy(query_id):
@@ -271,7 +272,7 @@ def _get_query_strategy(query_id):
271
272
  return query_map.get(query_id, current_active_strategy)
272
273
 
273
274
 
274
- def _cleanup_query_strategy(query_id):
275
+ def _cleanup_query_strategy(query_id, session_id=None):
275
276
  """Remove the strategy mapping for a completed query."""
276
277
  if not query_id:
277
278
  return
@@ -283,7 +284,8 @@ def _cleanup_query_strategy(query_id):
283
284
  del query_map[query_id]
284
285
  shared_strategy['query_strategy_map'] = query_map
285
286
  remaining_queries = len(query_map)
286
- _strategy_debug_log(f"Query {query_id} completed (was using {strategy}). Remaining active queries: {remaining_queries}")
287
+ session_info = f", session: {session_id}" if session_id else ""
288
+ _strategy_debug_log(f"Query {query_id} completed (was using {strategy}{session_info}). Remaining active queries: {remaining_queries}")
287
289
 
288
290
 
289
291
  def _get_strategy_debug_info():
@@ -518,9 +520,11 @@ class Connection(object):
518
520
  # Check if session strategy matches current active strategy
519
521
  elif self._session_id and self._session_strategy and self._session_strategy != _get_active_strategy():
520
522
  # Session was created with different strategy, need to re-authenticate
521
- _strategy_debug_log(f"Session strategy mismatch: session created with {self._session_strategy}, current active is {_get_active_strategy()}")
523
+ _strategy_debug_log(f"Session strategy mismatch: session {self._session_id} created with {self._session_strategy}, current active is {_get_active_strategy()}")
524
+ old_session_id = self._session_id
522
525
  self._session_id = None
523
526
  self._session_strategy = None
527
+ _strategy_debug_log(f"Invalidating session {old_session_id} due to strategy mismatch")
524
528
  self.close()
525
529
  self._create_client()
526
530
 
@@ -538,7 +542,7 @@ class Connection(object):
538
542
 
539
543
  if active_strategy and not pending_strategy:
540
544
  # Use cached strategy only if there's no pending strategy
541
- _strategy_debug_log(f"Authenticating with cached strategy: {active_strategy}")
545
+ _strategy_debug_log(f"Authenticating with cached strategy: {active_strategy} (session: {self._session_id})")
542
546
  try:
543
547
  authenticate_response = self._client.authenticate(
544
548
  authenticate_request,
@@ -549,21 +553,25 @@ class Connection(object):
549
553
  raise ValueError("Invalid credentials.")
550
554
  # Track which strategy was used for this session
551
555
  self._session_strategy = active_strategy
556
+ _strategy_debug_log(f"Authentication successful with strategy: {active_strategy}, session: {self._session_id}")
552
557
  # Check for new strategy in authenticate response
553
558
  if hasattr(authenticate_response, 'new_strategy') and authenticate_response.new_strategy:
554
559
  new_strategy = authenticate_response.new_strategy.lower()
555
560
  if new_strategy != active_strategy:
561
+ _strategy_debug_log(f"Strategy changed from {active_strategy} to {new_strategy} in authenticate response, session: {self._session_id}")
556
562
  _set_pending_strategy(new_strategy)
557
563
  _apply_pending_strategy()
564
+ old_session_id = self._session_id
558
565
  self._session_id = None
559
566
  self._session_strategy = None
567
+ _strategy_debug_log(f"Resetting session {old_session_id} due to new strategy: {new_strategy}")
560
568
  self.close()
561
569
  self._create_client()
562
570
  return self.get_session_id
563
571
  except _InactiveRpcError as e:
564
572
  if e.code() == grpc.StatusCode.UNKNOWN and 'status: 456' in e.details():
565
573
  # Strategy changed, clear cache and retry
566
- _strategy_debug_log(f"Got 456 error with strategy {active_strategy}, clearing cache and retrying")
574
+ _strategy_debug_log(f"Got 456 error with strategy {active_strategy}, session: {self._session_id}, clearing cache and retrying")
567
575
  _clear_strategy_cache()
568
576
  active_strategy = None
569
577
  else:
@@ -585,7 +593,7 @@ class Connection(object):
585
593
  _strategy_debug_log(f"No cached strategy, will try strategies in order: {strategies}")
586
594
  last_error = None
587
595
  for strategy in strategies:
588
- _strategy_debug_log(f"Attempting authentication with strategy: {strategy}")
596
+ _strategy_debug_log(f"Attempting authentication with strategy: {strategy} (no session yet)")
589
597
  try:
590
598
  authenticate_response = self._client.authenticate(
591
599
  authenticate_request,
@@ -594,7 +602,7 @@ class Connection(object):
594
602
  self._session_id = authenticate_response.sessionId
595
603
  if self._session_id:
596
604
  # Success! Cache this strategy
597
- _strategy_debug_log(f"Authentication successful with strategy: {strategy}")
605
+ _strategy_debug_log(f"Authentication successful with strategy: {strategy}, session: {self._session_id}")
598
606
  _set_active_strategy(strategy)
599
607
  # Track which strategy was used for this session
600
608
  self._session_strategy = strategy
@@ -603,9 +611,12 @@ class Connection(object):
603
611
  if hasattr(authenticate_response, 'new_strategy') and authenticate_response.new_strategy:
604
612
  new_strategy = authenticate_response.new_strategy.lower()
605
613
  if new_strategy != strategy:
614
+ _strategy_debug_log(f"Strategy changed from {strategy} to {new_strategy} in authenticate response, session: {self._session_id}")
606
615
  _set_pending_strategy(new_strategy)
607
616
  _apply_pending_strategy()
617
+ old_session_id = self._session_id
608
618
  self.close()
619
+ _strategy_debug_log(f"Resetting session {old_session_id} due to new strategy: {new_strategy}")
609
620
  self._create_client()
610
621
  self._session_id = None
611
622
  self._session_strategy = None
@@ -614,7 +625,7 @@ class Connection(object):
614
625
  except _InactiveRpcError as e:
615
626
  if e.code() == grpc.StatusCode.UNKNOWN and 'status: 456' in e.details():
616
627
  # Wrong strategy, try the next one
617
- _strategy_debug_log(f"Strategy {strategy} failed with 456 error, trying next")
628
+ _strategy_debug_log(f"Strategy {strategy} failed with 456 error (session attempt failed), trying next")
618
629
  last_error = e
619
630
  continue
620
631
  else:
@@ -682,6 +693,7 @@ class Connection(object):
682
693
 
683
694
  This method ensures that the gRPC channel is properly closed and the session ID is reset to None.
684
695
  """
696
+ old_session = self._session_id
685
697
  if self._channel is not None:
686
698
  self._channel.close()
687
699
  self._channel = None
@@ -691,7 +703,8 @@ class Connection(object):
691
703
  # Remove from debug connections if debug was enabled
692
704
  if self._debug:
693
705
  _debug_connections.discard(id(self))
694
- _strategy_debug_log(f"Debug mode disabled for connection {id(self)}")
706
+ session_info = f", session was: {old_session}" if old_session else ""
707
+ _strategy_debug_log(f"Debug mode disabled for connection {id(self)}{session_info}")
695
708
 
696
709
  def check_connection(self):
697
710
  """
@@ -1136,7 +1149,7 @@ class Cursor(DBAPICursor):
1136
1149
 
1137
1150
  # Clean up query strategy mapping
1138
1151
  if query_id:
1139
- _cleanup_query_strategy(query_id)
1152
+ _cleanup_query_strategy(query_id, self.connection.get_session_id)
1140
1153
 
1141
1154
  # Check if this was the last query and we have a pending strategy
1142
1155
  shared_strategy = _get_shared_strategy()
@@ -1144,7 +1157,7 @@ class Cursor(DBAPICursor):
1144
1157
  query_map = shared_strategy.get('query_strategy_map', {})
1145
1158
 
1146
1159
  if pending_strategy and len(query_map) == 0:
1147
- _strategy_debug_log(f"Last query cleared, triggering pending strategy transition")
1160
+ _strategy_debug_log(f"Last query cleared for session {self.connection.get_session_id}, triggering pending strategy transition from {_get_active_strategy()} to {pending_strategy}")
1148
1161
  _apply_pending_strategy()
1149
1162
 
1150
1163
  return clear_response
@@ -1160,7 +1173,7 @@ class Cursor(DBAPICursor):
1160
1173
  self.connection.query_cancel(engine_ip=self._engine_ip, query_id=query_id)
1161
1174
 
1162
1175
  if query_id:
1163
- _cleanup_query_strategy(query_id)
1176
+ _cleanup_query_strategy(query_id, self.connection.get_session_id)
1164
1177
 
1165
1178
  # Check if this was the last query and we have a pending strategy
1166
1179
  shared_strategy = _get_shared_strategy()
@@ -1168,7 +1181,7 @@ class Cursor(DBAPICursor):
1168
1181
  query_map = shared_strategy.get('query_strategy_map', {})
1169
1182
 
1170
1183
  if pending_strategy and len(query_map) == 0:
1171
- _strategy_debug_log(f"Last query cleared, triggering pending strategy transition")
1184
+ _strategy_debug_log(f"Last query cleared for session {self.connection.get_session_id}, triggering pending strategy transition from {_get_active_strategy()} to {pending_strategy}")
1172
1185
  _apply_pending_strategy()
1173
1186
 
1174
1187
  def status(self, query_id):
@@ -1242,7 +1255,7 @@ class Cursor(DBAPICursor):
1242
1255
  # Register this query with the current strategy
1243
1256
  current_strategy = _get_active_strategy()
1244
1257
  if current_strategy:
1245
- _register_query_strategy(self._query_id, current_strategy)
1258
+ _register_query_strategy(self._query_id, current_strategy, self.connection.get_session_id)
1246
1259
 
1247
1260
  execute_statement_request = e6x_engine_pb2.ExecuteStatementRequest(
1248
1261
  engineIP=self._engine_ip,
@@ -1289,7 +1302,7 @@ class Cursor(DBAPICursor):
1289
1302
  current_strategy = _get_active_strategy()
1290
1303
 
1291
1304
  if current_strategy:
1292
- _register_query_strategy(self._query_id, current_strategy)
1305
+ _register_query_strategy(self._query_id, current_strategy, self.connection.get_session_id)
1293
1306
 
1294
1307
  execute_statement_request = e6x_engine_pb2.ExecuteStatementV2Request(
1295
1308
  engineIP=self._engine_ip,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: e6data-python-connector
3
- Version: 2.3.10rc2
3
+ Version: 2.3.10rc3
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: e6data, Inc.
@@ -38,7 +38,7 @@ Dynamic: summary
38
38
 
39
39
  # e6data Python Connector
40
40
 
41
- ![version](https://img.shields.io/badge/version-2.3.10,rc2-blue.svg)
41
+ ![version](https://img.shields.io/badge/version-2.3.10,rc3-blue.svg)
42
42
 
43
43
  ## Introduction
44
44
 
@@ -12,7 +12,7 @@
12
12
 
13
13
  import setuptools
14
14
 
15
- VERSION = (2, 3, 10, 'rc2')
15
+ VERSION = (2, 3, 10, 'rc3')
16
16
 
17
17
 
18
18
  def get_long_desc():