e6data-python-connector 2.3.9rc6__tar.gz → 2.3.9rc8__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.9rc6/e6data_python_connector.egg-info → e6data_python_connector-2.3.9rc8}/PKG-INFO +2 -2
  2. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/README.md +1 -1
  3. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/e6data_grpc.py +26 -50
  4. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/strategy.py +17 -33
  5. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8/e6data_python_connector.egg-info}/PKG-INFO +2 -2
  6. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/setup.py +1 -1
  7. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/LICENSE +0 -0
  8. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/MANIFEST.in +0 -0
  9. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/__init__.py +0 -0
  10. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/cluster_manager.py +0 -0
  11. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/cluster_server/__init__.py +0 -0
  12. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/cluster_server/cluster_pb2.py +0 -0
  13. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/cluster_server/cluster_pb2_grpc.py +0 -0
  14. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/common.py +0 -0
  15. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/constants.py +0 -0
  16. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/datainputstream.py +0 -0
  17. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/date_time_utils.py +0 -0
  18. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/dialect.py +0 -0
  19. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/e6x_vector/__init__.py +0 -0
  20. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/e6x_vector/constants.py +0 -0
  21. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/e6x_vector/ttypes.py +0 -0
  22. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/exceptions.py +0 -0
  23. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/server/QueryEngineService.py +0 -0
  24. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/server/__init__.py +0 -0
  25. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/server/constants.py +0 -0
  26. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/server/e6x_engine_pb2.py +0 -0
  27. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/server/e6x_engine_pb2.pyi +0 -0
  28. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/server/e6x_engine_pb2_grpc.py +0 -0
  29. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/server/ttypes.py +0 -0
  30. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector/typeId.py +0 -0
  31. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector.egg-info/SOURCES.txt +0 -0
  32. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector.egg-info/dependency_links.txt +0 -0
  33. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector.egg-info/entry_points.txt +0 -0
  34. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector.egg-info/requires.txt +0 -0
  35. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/e6data_python_connector.egg-info/top_level.txt +0 -0
  36. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/pyproject.toml +0 -0
  37. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/setup.cfg +0 -0
  38. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/__init__.py +0 -0
  39. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/analyze_38_nines.py +0 -0
  40. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/analyze_all_cases.py +0 -0
  41. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/analyze_binary.py +0 -0
  42. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/analyze_correct_value.py +0 -0
  43. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/analyze_fields.py +0 -0
  44. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/check_decimal_errors.py +0 -0
  45. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/cleanup_test_files.py +0 -0
  46. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/debug_38_nines.py +0 -0
  47. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/debug_binary.py +0 -0
  48. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/final_test.py +0 -0
  49. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/move_tests.py +0 -0
  50. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/quick_test.py +0 -0
  51. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_38_nines.py +0 -0
  52. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_all_decimal128_cases.py +0 -0
  53. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_cluster_manager_efficiency.py +0 -0
  54. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_cluster_manager_none_strategy.py +0 -0
  55. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_cluster_manager_strategy.py +0 -0
  56. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_comprehensive.py +0 -0
  57. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_current_implementation.py +0 -0
  58. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_decimal128_binary_parsing.py +0 -0
  59. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_decimal128_parsing.py +0 -0
  60. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_fix.py +0 -0
  61. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_improved_parsing.py +0 -0
  62. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_known_case.py +0 -0
  63. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_manual_analysis.py +0 -0
  64. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_mock_server.py +0 -0
  65. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_multiprocessing_fix.py +0 -0
  66. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_new_implementation.py +0 -0
  67. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_specific_binary.py +0 -0
  68. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_strategy.py +0 -0
  69. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_strategy_logic.py +0 -0
  70. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_strategy_persistence_fix.py +0 -0
  71. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_strategy_sharing_fix.py +0 -0
  72. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/test_user_binary_value.py +0 -0
  73. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/tests.py +0 -0
  74. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/tests_grpc.py +0 -0
  75. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/validate_decimal128.py +0 -0
  76. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/test/validate_implementation.py +0 -0
  77. {e6data_python_connector-2.3.9rc6 → e6data_python_connector-2.3.9rc8}/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.9rc6
3
+ Version: 2.3.9rc8
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.9rc6-blue.svg)
41
+ ![version](https://img.shields.io/badge/version-2.3.9.rc8-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.9rc6-blue.svg)
3
+ ![version](https://img.shields.io/badge/version-2.3.9.rc8-blue.svg)
4
4
 
5
5
  ## Introduction
6
6
 
@@ -7,7 +7,6 @@ from __future__ import absolute_import
7
7
  from __future__ import unicode_literals
8
8
 
9
9
  import datetime
10
- import logging
11
10
  import re
12
11
  import sys
13
12
  import time
@@ -28,9 +27,6 @@ from e6data_python_connector.datainputstream import get_query_columns_info, read
28
27
  from e6data_python_connector.server import e6x_engine_pb2_grpc, e6x_engine_pb2
29
28
  from e6data_python_connector.typeId import *
30
29
 
31
- # Set up logging
32
- logger = logging.getLogger(__name__)
33
-
34
30
  apilevel = '2.0'
35
31
  threadsafety = 2 # Threads may share the e6xdb and connections.
36
32
  paramstyle = 'pyformat' # Python extended format codes, e.g. ...WHERE name=%(name)s
@@ -138,20 +134,20 @@ def _get_shared_strategy():
138
134
  global _strategy_manager, _shared_strategy
139
135
 
140
136
  # Try to use multiprocessing.Manager for process-safe storage
141
- # try:
142
- # if _strategy_manager is None:
143
- # _strategy_manager = multiprocessing.Manager()
144
- # _shared_strategy = _strategy_manager.dict()
145
- # _shared_strategy['active_strategy'] = None
146
- # _shared_strategy['last_check_time'] = 0
147
- # _shared_strategy['pending_strategy'] = None
148
- # _shared_strategy['query_strategy_map'] = _strategy_manager.dict()
149
- # _shared_strategy['last_transition_time'] = 0
150
- # _shared_strategy['session_invalidated'] = False
151
- # return _shared_strategy
152
- # except:
153
- # # Fall back to thread-local storage if Manager fails
154
- return _local_strategy_cache
137
+ try:
138
+ if _strategy_manager is None:
139
+ _strategy_manager = multiprocessing.Manager()
140
+ _shared_strategy = _strategy_manager.dict()
141
+ _shared_strategy['active_strategy'] = None
142
+ _shared_strategy['last_check_time'] = 0
143
+ _shared_strategy['pending_strategy'] = None
144
+ _shared_strategy['query_strategy_map'] = _strategy_manager.dict()
145
+ _shared_strategy['last_transition_time'] = 0
146
+ _shared_strategy['session_invalidated'] = False
147
+ return _shared_strategy
148
+ except:
149
+ # Fall back to thread-local storage if Manager fails
150
+ return _local_strategy_cache
155
151
 
156
152
 
157
153
  def _get_active_strategy():
@@ -181,11 +177,8 @@ def _set_active_strategy(strategy):
181
177
  current_time = time.time()
182
178
 
183
179
  # Only update transition time if strategy actually changed
184
- old_strategy = shared_strategy['active_strategy']
185
- if old_strategy != normalized_strategy:
180
+ if shared_strategy['active_strategy'] != normalized_strategy:
186
181
  shared_strategy['last_transition_time'] = current_time
187
- # Debug log for strategy switches
188
- logger.debug(f"Strategy switched from {old_strategy} to {normalized_strategy}")
189
182
 
190
183
  shared_strategy['active_strategy'] = normalized_strategy
191
184
  shared_strategy['last_check_time'] = current_time
@@ -214,12 +207,7 @@ def _set_pending_strategy(strategy):
214
207
  current_active = shared_strategy['active_strategy']
215
208
 
216
209
  if normalized_strategy != current_active:
217
- old_pending = shared_strategy.get('pending_strategy')
218
210
  shared_strategy['pending_strategy'] = normalized_strategy
219
-
220
- # Debug log for pending strategy changes
221
- if old_pending != normalized_strategy:
222
- logger.debug(f"Pending strategy changed from {old_pending} to {normalized_strategy}")
223
211
 
224
212
 
225
213
  def _apply_pending_strategy():
@@ -227,19 +215,15 @@ def _apply_pending_strategy():
227
215
  with _strategy_lock:
228
216
  shared_strategy = _get_shared_strategy()
229
217
  if shared_strategy['pending_strategy']:
230
- old_strategy = shared_strategy['active_strategy']
231
218
  new_strategy = shared_strategy['pending_strategy']
232
219
  current_time = time.time()
233
220
 
234
- logger.debug(f"Strategy transition initiated: {old_strategy} -> {new_strategy}")
235
-
236
221
  shared_strategy['active_strategy'] = new_strategy
237
222
  shared_strategy['pending_strategy'] = None
238
223
  shared_strategy['last_check_time'] = current_time
239
224
  shared_strategy['last_transition_time'] = current_time
240
225
  shared_strategy['session_invalidated'] = True # Invalidate all sessions
241
226
 
242
- logger.debug(f"Strategy successfully applied and sessions invalidated")
243
227
  return new_strategy
244
228
  return None
245
229
 
@@ -533,7 +517,11 @@ class Connection(object):
533
517
  new_strategy = authenticate_response.new_strategy.lower()
534
518
  if new_strategy != active_strategy:
535
519
  _set_pending_strategy(new_strategy)
536
- # Don't apply immediately - let new queries use fresh connections
520
+ _apply_pending_strategy()
521
+ self._session_id = None
522
+ self.close()
523
+ self._create_client()
524
+ return self.get_session_id
537
525
  except _InactiveRpcError as e:
538
526
  if e.code() == grpc.StatusCode.UNKNOWN and 'status: 456' in e.details():
539
527
  # Strategy changed, clear cache and retry
@@ -568,12 +556,15 @@ class Connection(object):
568
556
  _set_active_strategy(strategy)
569
557
 
570
558
  # Check for new strategy in authenticate response
571
- if hasattr(authenticate_response,
572
- 'new_strategy') and authenticate_response.new_strategy:
559
+ if hasattr(authenticate_response, 'new_strategy') and authenticate_response.new_strategy:
573
560
  new_strategy = authenticate_response.new_strategy.lower()
574
561
  if new_strategy != strategy:
575
562
  _set_pending_strategy(new_strategy)
576
- # Don't apply immediately - let new queries use fresh connections
563
+ _apply_pending_strategy()
564
+ self.close()
565
+ self._create_client()
566
+ self._session_id = None
567
+ return self.get_session_id
577
568
  break
578
569
  except _InactiveRpcError as e:
579
570
  if e.code() == grpc.StatusCode.UNKNOWN and 'status: 456' in e.details():
@@ -604,21 +595,6 @@ class Connection(object):
604
595
  ).resume()
605
596
  if status:
606
597
  return self.get_session_id
607
- # authenticate_request = e6x_engine_pb2.AuthenticateRequest(
608
- # user=self.__username,
609
- # password=self.__password
610
- # )
611
- # authenticate_response = self._client.authenticate(
612
- # authenticate_request,
613
- # metadata=_get_grpc_header(cluster=self.cluster_uuid, strategy=_get_active_strategy())
614
- # )
615
- # self._session_id = authenticate_response.sessionId
616
- # # Check for new strategy in authenticate response
617
- # if hasattr(authenticate_response, 'new_strategy') and authenticate_response.new_strategy:
618
- # new_strategy = authenticate_response.new_strategy.lower()
619
- # if new_strategy != _get_active_strategy():
620
- # _set_pending_strategy(new_strategy)
621
- # # Don't apply immediately - let new queries use fresh connections
622
598
  else:
623
599
  raise e
624
600
  else:
@@ -41,23 +41,23 @@ def _initialize_shared_state():
41
41
  if _shared_strategy is not None:
42
42
  return _shared_strategy
43
43
 
44
- # try:
45
- # # Try to create multiprocessing Manager
46
- # _manager = multiprocessing.Manager()
47
- # _shared_strategy = _manager.dict({
48
- # 'active_strategy': None,
49
- # 'last_check_time': 0,
50
- # 'pending_strategy': None,
51
- # 'query_strategy_map': _manager.dict(),
52
- # 'last_transition_time': 0,
53
- # 'session_invalidated': False
54
- # })
55
- # _logger.debug("Successfully initialized multiprocessing Manager for strategy sharing")
56
- # return _shared_strategy
57
- # except Exception as e:
58
- # # Fall back to thread-local storage if Manager fails
59
- # _logger.warning(f"Failed to initialize multiprocessing Manager: {e}. Using thread-local storage.")
60
- return _local_strategy_cache
44
+ try:
45
+ # Try to create multiprocessing Manager
46
+ _manager = multiprocessing.Manager()
47
+ _shared_strategy = _manager.dict({
48
+ 'active_strategy': None,
49
+ 'last_check_time': 0,
50
+ 'pending_strategy': None,
51
+ 'query_strategy_map': _manager.dict(),
52
+ 'last_transition_time': 0,
53
+ 'session_invalidated': False
54
+ })
55
+ _logger.debug("Successfully initialized multiprocessing Manager for strategy sharing")
56
+ return _shared_strategy
57
+ except Exception as e:
58
+ # Fall back to thread-local storage if Manager fails
59
+ _logger.warning(f"Failed to initialize multiprocessing Manager: {e}. Using thread-local storage.")
60
+ return _local_strategy_cache
61
61
 
62
62
 
63
63
  def _get_shared_strategy():
@@ -85,14 +85,8 @@ def _set_active_strategy(strategy):
85
85
  _logger.warning(f"Invalid strategy value: {strategy}. Must be 'blue' or 'green'.")
86
86
  return
87
87
 
88
- old_strategy = shared_strategy.get('active_strategy')
89
88
  shared_strategy['active_strategy'] = normalized_strategy
90
89
  shared_strategy['last_check_time'] = time.time()
91
-
92
- # Debug log for strategy switches
93
- if old_strategy != normalized_strategy:
94
- _logger.debug(f"Strategy switched from {old_strategy} to {normalized_strategy}")
95
-
96
90
  _logger.info(f"Active deployment strategy set to: {normalized_strategy}")
97
91
 
98
92
 
@@ -111,13 +105,7 @@ def _set_pending_strategy(strategy):
111
105
 
112
106
  current_active = shared_strategy.get('active_strategy')
113
107
  if normalized_strategy != current_active:
114
- old_pending = shared_strategy.get('pending_strategy')
115
108
  shared_strategy['pending_strategy'] = normalized_strategy
116
-
117
- # Debug log for pending strategy changes
118
- if old_pending != normalized_strategy:
119
- _logger.debug(f"Pending strategy changed from {old_pending} to {normalized_strategy}")
120
-
121
109
  _logger.info(f"Pending deployment strategy set to: {normalized_strategy}")
122
110
 
123
111
 
@@ -172,15 +160,11 @@ def _apply_pending_strategy():
172
160
  if len(query_map) == 0:
173
161
  # No active queries, safe to transition
174
162
  _logger.info(f"Last query completed, applying pending strategy: {pending_strategy}")
175
- _logger.debug(f"Strategy transition initiated: {active_strategy} -> {pending_strategy}")
176
-
177
163
  shared_strategy['active_strategy'] = pending_strategy
178
164
  shared_strategy['pending_strategy'] = None
179
165
  shared_strategy['last_transition_time'] = time.time()
180
166
  shared_strategy['session_invalidated'] = True # Invalidate all sessions
181
-
182
167
  _logger.info(f"Strategy transition completed: {active_strategy} -> {pending_strategy}")
183
- _logger.debug(f"Strategy successfully applied and sessions invalidated")
184
168
 
185
169
 
186
170
  def _is_strategy_cache_valid():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: e6data-python-connector
3
- Version: 2.3.9rc6
3
+ Version: 2.3.9rc8
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.9rc6-blue.svg)
41
+ ![version](https://img.shields.io/badge/version-2.3.9.rc8-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, 9,'rc6')
15
+ VERSION = (2, 3, 9, 'rc8')
16
16
 
17
17
 
18
18
  def get_long_desc():