e6data-python-connector 2.2.5rc5__tar.gz → 2.2.5rc6__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-2.2.5rc5/e6data_python_connector.egg-info → e6data_python_connector-2.2.5rc6}/PKG-INFO +2 -2
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/README.md +1 -1
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/e6data_grpc.py +1 -19
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6/e6data_python_connector.egg-info}/PKG-INFO +2 -2
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector.egg-info/SOURCES.txt +15 -1
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector.egg-info/top_level.txt +1 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/setup.py +1 -1
- e6data_python_connector-2.2.5rc6/test/__init__.py +1 -0
- e6data_python_connector-2.2.5rc6/test/analyze_38_nines.py +97 -0
- e6data_python_connector-2.2.5rc6/test/analyze_binary.py +70 -0
- e6data_python_connector-2.2.5rc6/test/check_decimal_errors.py +25 -0
- e6data_python_connector-2.2.5rc6/test/test_decimal128_binary_parsing.py +200 -0
- e6data_python_connector-2.2.5rc6/test/test_decimal128_parsing.py +255 -0
- e6data_python_connector-2.2.5rc6/test/test_fix.py +29 -0
- e6data_python_connector-2.2.5rc6/test/test_improved_parsing.py +113 -0
- e6data_python_connector-2.2.5rc6/test/test_specific_binary.py +99 -0
- e6data_python_connector-2.2.5rc6/test/test_user_binary_value.py +71 -0
- e6data_python_connector-2.2.5rc6/test/tests.py +307 -0
- e6data_python_connector-2.2.5rc6/test/tests_grpc.py +155 -0
- e6data_python_connector-2.2.5rc6/test/validate_decimal128.py +76 -0
- e6data_python_connector-2.2.5rc6/test/verify_decimal_fix.py +36 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/LICENSE +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/MANIFEST.in +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/__init__.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/cluster_manager.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/cluster_server/__init__.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/cluster_server/cluster_pb2.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/cluster_server/cluster_pb2_grpc.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/common.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/constants.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/datainputstream.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/date_time_utils.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/dialect.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/e6x_vector/__init__.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/e6x_vector/constants.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/e6x_vector/ttypes.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/exceptions.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/server/QueryEngineService.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/server/__init__.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/server/constants.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/server/e6x_engine_pb2.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/server/e6x_engine_pb2.pyi +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/server/e6x_engine_pb2_grpc.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/server/ttypes.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/strategy.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/typeId.py +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector.egg-info/dependency_links.txt +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector.egg-info/entry_points.txt +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector.egg-info/requires.txt +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/pyproject.toml +0 -0
- {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: e6data-python-connector
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.5rc6
|
|
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
|
-

|
|
42
42
|
|
|
43
43
|
## Introduction
|
|
44
44
|
|
|
@@ -487,8 +487,6 @@ class Connection(object):
|
|
|
487
487
|
active_strategy = shared_strategy.get('active_strategy')
|
|
488
488
|
session_invalidated = shared_strategy.get('session_invalidated', False)
|
|
489
489
|
|
|
490
|
-
print('self._session_id', self._session_id, pending_strategy, active_strategy, 'invalidated:', session_invalidated)
|
|
491
|
-
|
|
492
490
|
# Check if session was invalidated globally
|
|
493
491
|
if self._session_id and session_invalidated:
|
|
494
492
|
_logger.info("*** Session invalidated due to strategy change, forcing fresh connection")
|
|
@@ -545,7 +543,6 @@ class Connection(object):
|
|
|
545
543
|
# Check for new strategy in authenticate response
|
|
546
544
|
if hasattr(authenticate_response, 'new_strategy') and authenticate_response.new_strategy:
|
|
547
545
|
new_strategy = authenticate_response.new_strategy.lower()
|
|
548
|
-
print('1', new_strategy)
|
|
549
546
|
if new_strategy != active_strategy:
|
|
550
547
|
_logger.info(f"Server indicated new strategy: {new_strategy} (different from current: {active_strategy})")
|
|
551
548
|
_set_pending_strategy(new_strategy)
|
|
@@ -575,7 +572,6 @@ class Connection(object):
|
|
|
575
572
|
# Always try blue first, then green if it fails with 456
|
|
576
573
|
strategies = ['blue', 'green']
|
|
577
574
|
last_error = None
|
|
578
|
-
print('all strategies', strategies)
|
|
579
575
|
for strategy in strategies:
|
|
580
576
|
try:
|
|
581
577
|
_logger.info(f"Trying strategy: {strategy}")
|
|
@@ -592,7 +588,6 @@ class Connection(object):
|
|
|
592
588
|
# Check for new strategy in authenticate response
|
|
593
589
|
if hasattr(authenticate_response, 'new_strategy') and authenticate_response.new_strategy:
|
|
594
590
|
new_strategy = authenticate_response.new_strategy.lower()
|
|
595
|
-
print('2', new_strategy)
|
|
596
591
|
if new_strategy != strategy:
|
|
597
592
|
_logger.info(f"Server indicated new strategy: {new_strategy} (different from current: {strategy})")
|
|
598
593
|
_set_pending_strategy(new_strategy)
|
|
@@ -632,7 +627,6 @@ class Connection(object):
|
|
|
632
627
|
# user=self.__username,
|
|
633
628
|
# password=self.__password
|
|
634
629
|
# )
|
|
635
|
-
# print('_get_active_strategy()', _get_active_strategy())
|
|
636
630
|
# authenticate_response = self._client.authenticate(
|
|
637
631
|
# authenticate_request,
|
|
638
632
|
# metadata=_get_grpc_header(cluster=self.cluster_uuid, strategy=_get_active_strategy())
|
|
@@ -641,7 +635,6 @@ class Connection(object):
|
|
|
641
635
|
# # Check for new strategy in authenticate response
|
|
642
636
|
# if hasattr(authenticate_response, 'new_strategy') and authenticate_response.new_strategy:
|
|
643
637
|
# new_strategy = authenticate_response.new_strategy.lower()
|
|
644
|
-
# print('3', new_strategy)
|
|
645
638
|
# if new_strategy != _get_active_strategy():
|
|
646
639
|
# _logger.info(f"Server indicated new strategy during auto-resume: {new_strategy}")
|
|
647
640
|
# _set_pending_strategy(new_strategy)
|
|
@@ -759,7 +752,6 @@ class Connection(object):
|
|
|
759
752
|
|
|
760
753
|
# Check for new strategy in clear response
|
|
761
754
|
if hasattr(clear_response, 'new_strategy') and clear_response.new_strategy:
|
|
762
|
-
print('4', clear_response.new_strategy)
|
|
763
755
|
_set_pending_strategy(clear_response.new_strategy)
|
|
764
756
|
|
|
765
757
|
def reopen(self):
|
|
@@ -791,7 +783,6 @@ class Connection(object):
|
|
|
791
783
|
|
|
792
784
|
# Check for new strategy in cancel response
|
|
793
785
|
if hasattr(cancel_response, 'new_strategy') and cancel_response.new_strategy:
|
|
794
|
-
print('5', cancel_response.new_strategy)
|
|
795
786
|
_set_pending_strategy(cancel_response.new_strategy)
|
|
796
787
|
|
|
797
788
|
def dry_run(self, query):
|
|
@@ -839,7 +830,6 @@ class Connection(object):
|
|
|
839
830
|
# Check for new strategy in get tables response
|
|
840
831
|
if hasattr(get_table_response, 'new_strategy') and get_table_response.new_strategy:
|
|
841
832
|
_set_pending_strategy(get_table_response.new_strategy)
|
|
842
|
-
print('6', get_table_response.new_strategy)
|
|
843
833
|
return list(get_table_response.tables)
|
|
844
834
|
|
|
845
835
|
def get_columns(self, catalog, database, table):
|
|
@@ -868,7 +858,6 @@ class Connection(object):
|
|
|
868
858
|
# Check for new strategy in get columns response
|
|
869
859
|
if hasattr(get_columns_response, 'new_strategy') and get_columns_response.new_strategy:
|
|
870
860
|
_set_pending_strategy(get_columns_response.new_strategy)
|
|
871
|
-
print('7', get_columns_response.new_strategy)
|
|
872
861
|
return [{'fieldName': row.fieldName, 'fieldType': row.fieldType} for row in get_columns_response.fieldInfo]
|
|
873
862
|
|
|
874
863
|
def get_schema_names(self, catalog):
|
|
@@ -892,7 +881,6 @@ class Connection(object):
|
|
|
892
881
|
|
|
893
882
|
# Check for new strategy in get schema names response
|
|
894
883
|
if hasattr(get_schema_response, 'new_strategy') and get_schema_response.new_strategy:
|
|
895
|
-
print('8', get_schema_response.new_strategy)
|
|
896
884
|
_set_pending_strategy(get_schema_response.new_strategy)
|
|
897
885
|
|
|
898
886
|
return list(get_schema_response.schemas)
|
|
@@ -1189,12 +1177,11 @@ class Cursor(DBAPICursor):
|
|
|
1189
1177
|
|
|
1190
1178
|
# Check for new strategy in status response
|
|
1191
1179
|
if hasattr(status_response, 'new_strategy') and status_response.new_strategy:
|
|
1192
|
-
print('9', status_response.new_strategy)
|
|
1193
1180
|
_set_pending_strategy(status_response.new_strategy)
|
|
1194
1181
|
|
|
1195
1182
|
return status_response
|
|
1196
1183
|
|
|
1197
|
-
|
|
1184
|
+
@re_auth
|
|
1198
1185
|
def execute(self, operation, parameters=None, **kwargs):
|
|
1199
1186
|
"""
|
|
1200
1187
|
Prepare and execute a database operation (query or command).
|
|
@@ -1286,7 +1273,6 @@ class Cursor(DBAPICursor):
|
|
|
1286
1273
|
# Check for new strategy in prepare response
|
|
1287
1274
|
if hasattr(prepare_statement_response, 'new_strategy') and prepare_statement_response.new_strategy:
|
|
1288
1275
|
new_strategy = prepare_statement_response.new_strategy.lower()
|
|
1289
|
-
print('10', new_strategy)
|
|
1290
1276
|
if new_strategy != _get_active_strategy():
|
|
1291
1277
|
_logger.info(f"Server indicated new strategy during prepare: {new_strategy}")
|
|
1292
1278
|
_set_pending_strategy(new_strategy)
|
|
@@ -1312,7 +1298,6 @@ class Cursor(DBAPICursor):
|
|
|
1312
1298
|
# Check for new strategy in execute response
|
|
1313
1299
|
if hasattr(execute_response, 'new_strategy') and execute_response.new_strategy:
|
|
1314
1300
|
new_strategy = execute_response.new_strategy.lower()
|
|
1315
|
-
print('11', new_strategy)
|
|
1316
1301
|
if new_strategy != _get_active_strategy():
|
|
1317
1302
|
_logger.info(f"Server indicated new strategy during execute: {new_strategy}")
|
|
1318
1303
|
_set_pending_strategy(new_strategy)
|
|
@@ -1349,7 +1334,6 @@ class Cursor(DBAPICursor):
|
|
|
1349
1334
|
# Check for new strategy in metadata response
|
|
1350
1335
|
if hasattr(get_result_metadata_response, 'new_strategy') and get_result_metadata_response.new_strategy:
|
|
1351
1336
|
new_strategy = get_result_metadata_response.new_strategy.lower()
|
|
1352
|
-
print('13', new_strategy)
|
|
1353
1337
|
if new_strategy != _get_active_strategy():
|
|
1354
1338
|
_logger.info(f"Server indicated new strategy during metadata: {new_strategy}")
|
|
1355
1339
|
_set_pending_strategy(new_strategy)
|
|
@@ -1431,7 +1415,6 @@ class Cursor(DBAPICursor):
|
|
|
1431
1415
|
# Check for new strategy in batch response
|
|
1432
1416
|
if hasattr(get_next_result_batch_response, 'new_strategy') and get_next_result_batch_response.new_strategy:
|
|
1433
1417
|
new_strategy = get_next_result_batch_response.new_strategy.lower()
|
|
1434
|
-
print('14', new_strategy)
|
|
1435
1418
|
if new_strategy != _get_active_strategy():
|
|
1436
1419
|
_logger.info(f"Server indicated new strategy during batch: {new_strategy}")
|
|
1437
1420
|
_set_pending_strategy(new_strategy)
|
|
@@ -1531,7 +1514,6 @@ class Cursor(DBAPICursor):
|
|
|
1531
1514
|
|
|
1532
1515
|
# Check for new strategy in explain analyze response
|
|
1533
1516
|
if hasattr(explain_analyze_response, 'new_strategy') and explain_analyze_response.new_strategy:
|
|
1534
|
-
print('15', explain_analyze_response.new_strategy)
|
|
1535
1517
|
_set_pending_strategy(explain_analyze_response.new_strategy)
|
|
1536
1518
|
|
|
1537
1519
|
return dict(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: e6data-python-connector
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.5rc6
|
|
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
|
-

|
|
42
42
|
|
|
43
43
|
## Introduction
|
|
44
44
|
|
|
@@ -33,4 +33,18 @@ e6data_python_connector/server/constants.py
|
|
|
33
33
|
e6data_python_connector/server/e6x_engine_pb2.py
|
|
34
34
|
e6data_python_connector/server/e6x_engine_pb2.pyi
|
|
35
35
|
e6data_python_connector/server/e6x_engine_pb2_grpc.py
|
|
36
|
-
e6data_python_connector/server/ttypes.py
|
|
36
|
+
e6data_python_connector/server/ttypes.py
|
|
37
|
+
test/__init__.py
|
|
38
|
+
test/analyze_38_nines.py
|
|
39
|
+
test/analyze_binary.py
|
|
40
|
+
test/check_decimal_errors.py
|
|
41
|
+
test/test_decimal128_binary_parsing.py
|
|
42
|
+
test/test_decimal128_parsing.py
|
|
43
|
+
test/test_fix.py
|
|
44
|
+
test/test_improved_parsing.py
|
|
45
|
+
test/test_specific_binary.py
|
|
46
|
+
test/test_user_binary_value.py
|
|
47
|
+
test/tests.py
|
|
48
|
+
test/tests_grpc.py
|
|
49
|
+
test/validate_decimal128.py
|
|
50
|
+
test/verify_decimal_fix.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Test package for e6data-python-connector."""
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Analyze the binary value that should decode to 38 nines."""
|
|
3
|
+
|
|
4
|
+
# The binary value
|
|
5
|
+
binary_data = b'\xb4\xc4\xb3W\xa5y;\x85\xf6u\xdd\xc0\x00\x00\x00\x02'
|
|
6
|
+
|
|
7
|
+
print(f"Binary data: {binary_data}")
|
|
8
|
+
print(f"Length: {len(binary_data)} bytes")
|
|
9
|
+
print(f"Hex: {binary_data.hex()}")
|
|
10
|
+
|
|
11
|
+
# Expected value
|
|
12
|
+
expected = "99999999999999999999999999999999999999"
|
|
13
|
+
print(f"Expected: {expected} ({len(expected)} digits)")
|
|
14
|
+
|
|
15
|
+
# Convert to 128-bit integer
|
|
16
|
+
bits = int.from_bytes(binary_data, byteorder='big')
|
|
17
|
+
print(f"\n128-bit integer: {bits}")
|
|
18
|
+
print(f"Hex: 0x{bits:032x}")
|
|
19
|
+
print(f"Binary: {bin(bits)}")
|
|
20
|
+
|
|
21
|
+
# Extract IEEE 754-2008 Decimal128 fields
|
|
22
|
+
sign = (bits >> 127) & 1
|
|
23
|
+
combination = (bits >> 110) & 0x1FFFF
|
|
24
|
+
coeff_continuation = bits & 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
|
25
|
+
|
|
26
|
+
print(f"\nIEEE 754-2008 Decimal128 fields:")
|
|
27
|
+
print(f"Sign: {sign} ({'negative' if sign else 'positive'})")
|
|
28
|
+
print(f"Combination: {combination:017b} (decimal: {combination})")
|
|
29
|
+
print(f"Coefficient continuation: {coeff_continuation}")
|
|
30
|
+
|
|
31
|
+
# Analyze combination field
|
|
32
|
+
print(f"\nCombination field analysis:")
|
|
33
|
+
top_2_bits = (combination >> 15)
|
|
34
|
+
print(f"Top 2 bits: {top_2_bits:02b}")
|
|
35
|
+
|
|
36
|
+
if top_2_bits != 0b11:
|
|
37
|
+
exponent_bits = (combination >> 3) & 0x3FFF
|
|
38
|
+
msd = combination & 0x7
|
|
39
|
+
print(f"Exponent bits: {exponent_bits} (0x{exponent_bits:04x})")
|
|
40
|
+
print(f"MSD: {msd}")
|
|
41
|
+
else:
|
|
42
|
+
# Check if it's special or has MSD 8-9
|
|
43
|
+
if (combination >> 12) & 0x7 == 0b111:
|
|
44
|
+
print("This is NaN")
|
|
45
|
+
elif (combination >> 12) & 0x7 == 0b110:
|
|
46
|
+
print("This is Infinity")
|
|
47
|
+
else:
|
|
48
|
+
exponent_bits = (combination >> 3) & 0x3FFF
|
|
49
|
+
msd = 8 + (combination & 0x1)
|
|
50
|
+
print(f"Exponent bits: {exponent_bits} (0x{exponent_bits:04x})")
|
|
51
|
+
print(f"MSD (8-9): {msd}")
|
|
52
|
+
|
|
53
|
+
# Calculate actual exponent
|
|
54
|
+
if 'exponent_bits' in locals():
|
|
55
|
+
exponent = exponent_bits - 6176 # Bias is 6176
|
|
56
|
+
print(f"Actual exponent: {exponent}")
|
|
57
|
+
|
|
58
|
+
# The coefficient for 38 nines should be 99999999999999999999999999999999999999
|
|
59
|
+
# This is a 38-digit number
|
|
60
|
+
print(f"\nExpected coefficient analysis:")
|
|
61
|
+
print(f"38 nines = {int(expected)}")
|
|
62
|
+
print(f"38 nines in hex: 0x{int(expected):x}")
|
|
63
|
+
|
|
64
|
+
# Let's see if the coefficient continuation could encode this
|
|
65
|
+
print(f"\nCoefficient continuation analysis:")
|
|
66
|
+
print(f"Coefficient continuation: {coeff_continuation}")
|
|
67
|
+
print(f"Coefficient continuation hex: 0x{coeff_continuation:x}")
|
|
68
|
+
|
|
69
|
+
# The coefficient continuation has 110 bits
|
|
70
|
+
# It needs to encode 37 more digits (after MSD)
|
|
71
|
+
# Using DPD encoding, 3 decimal digits fit in 10 bits
|
|
72
|
+
# So 37 digits would need about 124 bits, but we only have 110 bits
|
|
73
|
+
|
|
74
|
+
# However, the coefficient for Decimal128 can have at most 34 significant digits
|
|
75
|
+
# So 38 nines might be represented as 1E38 or similar
|
|
76
|
+
|
|
77
|
+
# Let's check what the actual encoding might be
|
|
78
|
+
print(f"\nPossible interpretations:")
|
|
79
|
+
|
|
80
|
+
# If it's truly 38 nines, it might be encoded with an exponent
|
|
81
|
+
# 9.999...E37 would give us the right magnitude
|
|
82
|
+
scientific_form = f"9.{'9' * 33}E4"
|
|
83
|
+
print(f"Scientific notation: {scientific_form}")
|
|
84
|
+
|
|
85
|
+
# Or it could be a special encoding
|
|
86
|
+
# Let's check what the combination field tells us about the exponent
|
|
87
|
+
if 'exponent' in locals():
|
|
88
|
+
print(f"With exponent {exponent}, coefficient would be scaled by 10^{exponent}")
|
|
89
|
+
|
|
90
|
+
# If exponent is 4, then coefficient of 9999...9999 (34 digits) would give us 38 digits total
|
|
91
|
+
if exponent == 4:
|
|
92
|
+
print("This suggests coefficient is 34 nines, scaled by 10^4 to give 38 nines")
|
|
93
|
+
|
|
94
|
+
# Let's also check byte-by-byte
|
|
95
|
+
print(f"\nByte-by-byte analysis:")
|
|
96
|
+
for i, byte in enumerate(binary_data):
|
|
97
|
+
print(f"Byte {i:2d}: 0x{byte:02x} ({byte:3d}) {bin(byte)[2:].zfill(8)}")
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Analyze the specific binary value."""
|
|
3
|
+
|
|
4
|
+
# The specific binary value
|
|
5
|
+
binary_data = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%f\x80'
|
|
6
|
+
|
|
7
|
+
print(f"Binary data: {binary_data}")
|
|
8
|
+
print(f"Length: {len(binary_data)} bytes")
|
|
9
|
+
print(f"Hex: {binary_data.hex()}")
|
|
10
|
+
|
|
11
|
+
# Convert to 128-bit integer
|
|
12
|
+
bits = int.from_bytes(binary_data, byteorder='big')
|
|
13
|
+
print(f"128-bit integer: {bits}")
|
|
14
|
+
print(f"Hex: 0x{bits:032x}")
|
|
15
|
+
print(f"Binary: {bin(bits)}")
|
|
16
|
+
|
|
17
|
+
# Extract IEEE 754-2008 Decimal128 fields
|
|
18
|
+
sign = (bits >> 127) & 1
|
|
19
|
+
combination = (bits >> 110) & 0x1FFFF
|
|
20
|
+
coeff_continuation = bits & 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
|
21
|
+
|
|
22
|
+
print(f"\nIEEE 754-2008 Decimal128 fields:")
|
|
23
|
+
print(f"Sign: {sign}")
|
|
24
|
+
print(f"Combination: {combination:017b} (decimal: {combination})")
|
|
25
|
+
print(f"Coefficient continuation: {coeff_continuation}")
|
|
26
|
+
|
|
27
|
+
# The hex representation shows:
|
|
28
|
+
# 00000000000000000000000000256680
|
|
29
|
+
# This means most of the number is zeros, with the last 4 bytes being 0x00256680
|
|
30
|
+
|
|
31
|
+
# Let's focus on the last 4 bytes: 0x00256680
|
|
32
|
+
last_4_bytes = binary_data[-4:]
|
|
33
|
+
print(f"\nLast 4 bytes: {last_4_bytes.hex()}")
|
|
34
|
+
print(f"As integer: {int.from_bytes(last_4_bytes, byteorder='big')}")
|
|
35
|
+
|
|
36
|
+
# 0x256680 = 2385536 decimal
|
|
37
|
+
# This suggests the number might be related to this value
|
|
38
|
+
|
|
39
|
+
# Let's check if this follows the pattern of a small decimal number
|
|
40
|
+
# The fact that most bits are zero suggests this is a small positive number
|
|
41
|
+
|
|
42
|
+
# Check the combination field
|
|
43
|
+
print(f"\nCombination field analysis:")
|
|
44
|
+
print(f"Top 2 bits: {(combination >> 15):02b}")
|
|
45
|
+
if (combination >> 15) != 0b11:
|
|
46
|
+
exponent_bits = (combination >> 3) & 0x3FFF
|
|
47
|
+
msd = combination & 0x7
|
|
48
|
+
exponent = exponent_bits - 6176
|
|
49
|
+
print(f"Exponent bits: {exponent_bits}")
|
|
50
|
+
print(f"Actual exponent: {exponent}")
|
|
51
|
+
print(f"MSD: {msd}")
|
|
52
|
+
print(f"This is a normal number")
|
|
53
|
+
else:
|
|
54
|
+
print("This is a special value (infinity/NaN)")
|
|
55
|
+
|
|
56
|
+
# Let's see what the actual bytes represent
|
|
57
|
+
print(f"\nByte analysis:")
|
|
58
|
+
for i, byte in enumerate(binary_data):
|
|
59
|
+
print(f"Byte {i:2d}: 0x{byte:02x} ({byte:3d}) {bin(byte)[2:].zfill(8)}")
|
|
60
|
+
|
|
61
|
+
print(f"\nNon-zero bytes:")
|
|
62
|
+
for i, byte in enumerate(binary_data):
|
|
63
|
+
if byte != 0:
|
|
64
|
+
print(f"Byte {i:2d}: 0x{byte:02x} ({byte:3d}) {bin(byte)[2:].zfill(8)}")
|
|
65
|
+
|
|
66
|
+
# The non-zero bytes are at positions 13, 14, 15
|
|
67
|
+
# Byte 13: 0x00 (0)
|
|
68
|
+
# Byte 14: 0x25 (37) -> '%' character
|
|
69
|
+
# Byte 15: 0x66 (102) -> 'f' character
|
|
70
|
+
# Byte 16: 0x80 (128)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Check what exceptions Decimal raises."""
|
|
3
|
+
from decimal import Decimal
|
|
4
|
+
import decimal
|
|
5
|
+
|
|
6
|
+
print("Decimal module exceptions:")
|
|
7
|
+
for attr in dir(decimal):
|
|
8
|
+
if "Error" in attr or "Exception" in attr:
|
|
9
|
+
print(f" - {attr}")
|
|
10
|
+
|
|
11
|
+
print("\nTrying to create invalid Decimal:")
|
|
12
|
+
try:
|
|
13
|
+
result = Decimal("not-a-number")
|
|
14
|
+
except Exception as e:
|
|
15
|
+
print(f"Exception type: {type(e)}")
|
|
16
|
+
print(f"Exception: {e}")
|
|
17
|
+
print(f"Module: {type(e).__module__}")
|
|
18
|
+
|
|
19
|
+
print("\nTrying another invalid case:")
|
|
20
|
+
try:
|
|
21
|
+
result = Decimal("\x00\x01\x02\x03")
|
|
22
|
+
except Exception as e:
|
|
23
|
+
print(f"Exception type: {type(e)}")
|
|
24
|
+
print(f"Exception: {e}")
|
|
25
|
+
print(f"Module: {type(e).__module__}")
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Test script to verify IEEE 754-2008 Decimal128 binary parsing.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import sys
|
|
7
|
+
import os
|
|
8
|
+
from decimal import Decimal
|
|
9
|
+
|
|
10
|
+
# Add the parent directory to the path to import e6data_python_connector
|
|
11
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
|
12
|
+
|
|
13
|
+
from e6data_python_connector.datainputstream import _binary_to_decimal128, _decode_decimal128_binary
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_specific_binary_value():
|
|
17
|
+
"""Test the specific binary value provided by the user."""
|
|
18
|
+
|
|
19
|
+
print("=== Testing Specific Binary Value ===\n")
|
|
20
|
+
|
|
21
|
+
# The specific binary value from the user
|
|
22
|
+
binary_data = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%f\x80'
|
|
23
|
+
|
|
24
|
+
print(f"Binary data: {binary_data}")
|
|
25
|
+
print(f"Length: {len(binary_data)} bytes")
|
|
26
|
+
print(f"Hex representation: {binary_data.hex()}")
|
|
27
|
+
|
|
28
|
+
# Parse it
|
|
29
|
+
result = _binary_to_decimal128(binary_data)
|
|
30
|
+
print(f"Parsed result: {result}")
|
|
31
|
+
print(f"Type: {type(result)}")
|
|
32
|
+
|
|
33
|
+
# Let's also analyze the binary structure
|
|
34
|
+
print("\n=== Binary Analysis ===")
|
|
35
|
+
if len(binary_data) == 16:
|
|
36
|
+
bits = int.from_bytes(binary_data, byteorder='big')
|
|
37
|
+
print(f"128-bit integer: {bits}")
|
|
38
|
+
print(f"Binary representation: {bin(bits)}")
|
|
39
|
+
|
|
40
|
+
# Extract fields
|
|
41
|
+
sign = (bits >> 127) & 1
|
|
42
|
+
combination = (bits >> 110) & 0x1FFFF
|
|
43
|
+
coeff_continuation = bits & 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
|
44
|
+
|
|
45
|
+
print(f"Sign bit: {sign}")
|
|
46
|
+
print(f"Combination field: {combination} (0x{combination:x})")
|
|
47
|
+
print(f"Coefficient continuation: {coeff_continuation}")
|
|
48
|
+
|
|
49
|
+
# Check if this is a special value
|
|
50
|
+
if (combination >> 15) == 0b11:
|
|
51
|
+
print("This appears to be a special value (infinity/NaN)")
|
|
52
|
+
else:
|
|
53
|
+
print("This appears to be a normal number")
|
|
54
|
+
|
|
55
|
+
# Extract exponent and MSD
|
|
56
|
+
exponent_bits = (combination >> 3) & 0x3FFF
|
|
57
|
+
msd = combination & 0x7
|
|
58
|
+
exponent = exponent_bits - 6176
|
|
59
|
+
|
|
60
|
+
print(f"Exponent bits: {exponent_bits}")
|
|
61
|
+
print(f"Actual exponent: {exponent}")
|
|
62
|
+
print(f"Most significant digit: {msd}")
|
|
63
|
+
else:
|
|
64
|
+
print("Invalid length for Decimal128")
|
|
65
|
+
|
|
66
|
+
print("\n=== Test Complete ===")
|
|
67
|
+
return result
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_known_decimal128_values():
|
|
71
|
+
"""Test some known Decimal128 values."""
|
|
72
|
+
|
|
73
|
+
print("\n=== Testing Known Decimal128 Values ===\n")
|
|
74
|
+
|
|
75
|
+
# Test zero
|
|
76
|
+
print("1. Testing zero...")
|
|
77
|
+
# Binary representation of 0 in Decimal128
|
|
78
|
+
zero_binary = b'\x00' * 16
|
|
79
|
+
result = _binary_to_decimal128(zero_binary)
|
|
80
|
+
print(f"Zero: {zero_binary.hex()} -> {result}")
|
|
81
|
+
|
|
82
|
+
# Test positive one
|
|
83
|
+
print("\n2. Testing positive one...")
|
|
84
|
+
# This is a simplified test - actual binary would be more complex
|
|
85
|
+
# For now, let's test the parsing logic
|
|
86
|
+
|
|
87
|
+
# Test various lengths
|
|
88
|
+
print("\n3. Testing various lengths...")
|
|
89
|
+
test_cases = [
|
|
90
|
+
(b'\x00', "1 byte"),
|
|
91
|
+
(b'\x00' * 8, "8 bytes"),
|
|
92
|
+
(b'\x00' * 15, "15 bytes"),
|
|
93
|
+
(b'\x00' * 16, "16 bytes"),
|
|
94
|
+
(b'\x00' * 17, "17 bytes")
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
for binary_data, description in test_cases:
|
|
98
|
+
result = _binary_to_decimal128(binary_data)
|
|
99
|
+
print(f"{description}: {result}")
|
|
100
|
+
|
|
101
|
+
print("\n=== Known Values Test Complete ===")
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_string_compatibility():
|
|
105
|
+
"""Test that string representations still work."""
|
|
106
|
+
|
|
107
|
+
print("\n=== Testing String Compatibility ===\n")
|
|
108
|
+
|
|
109
|
+
test_cases = [
|
|
110
|
+
"123.456",
|
|
111
|
+
"-789.012",
|
|
112
|
+
"0",
|
|
113
|
+
"1.23E+10",
|
|
114
|
+
"0.000000000000000001"
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
for test_str in test_cases:
|
|
118
|
+
binary_data = test_str.encode('utf-8')
|
|
119
|
+
result = _binary_to_decimal128(binary_data)
|
|
120
|
+
expected = Decimal(test_str)
|
|
121
|
+
print(f"String '{test_str}': {result} (expected: {expected})")
|
|
122
|
+
assert result == expected, f"String parsing failed for {test_str}"
|
|
123
|
+
|
|
124
|
+
print("\n✓ String compatibility maintained")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def debug_binary_parsing():
|
|
128
|
+
"""Debug the binary parsing for the specific value."""
|
|
129
|
+
|
|
130
|
+
print("\n=== Debugging Binary Parsing ===\n")
|
|
131
|
+
|
|
132
|
+
binary_data = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%f\x80'
|
|
133
|
+
|
|
134
|
+
print(f"Input: {binary_data.hex()}")
|
|
135
|
+
print(f"Length: {len(binary_data)}")
|
|
136
|
+
|
|
137
|
+
# Let's manually parse this
|
|
138
|
+
bits = int.from_bytes(binary_data, byteorder='big')
|
|
139
|
+
print(f"As 128-bit integer: {bits}")
|
|
140
|
+
print(f"As hex: 0x{bits:032x}")
|
|
141
|
+
print(f"As binary: {bin(bits)}")
|
|
142
|
+
|
|
143
|
+
# The hex is: 00000000000000000000000000256680
|
|
144
|
+
# The last few bytes are: 00256680
|
|
145
|
+
# This translates to: 0x00256680 = 2385536
|
|
146
|
+
|
|
147
|
+
# Let's see what this means in Decimal128 format
|
|
148
|
+
sign = (bits >> 127) & 1
|
|
149
|
+
combination = (bits >> 110) & 0x1FFFF
|
|
150
|
+
coeff_continuation = bits & 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
|
151
|
+
|
|
152
|
+
print(f"\nDecoded fields:")
|
|
153
|
+
print(f"Sign: {sign}")
|
|
154
|
+
print(f"Combination: {combination:017b} ({combination})")
|
|
155
|
+
print(f"Coefficient continuation: {coeff_continuation}")
|
|
156
|
+
|
|
157
|
+
# Check the combination field more closely
|
|
158
|
+
print(f"\nCombination field analysis:")
|
|
159
|
+
print(f"Top 2 bits: {(combination >> 15):02b}")
|
|
160
|
+
print(f"Next 14 bits (exponent): {(combination >> 3) & 0x3FFF}")
|
|
161
|
+
print(f"Bottom 3 bits (MSD): {combination & 0x7}")
|
|
162
|
+
|
|
163
|
+
if (combination >> 15) != 0b11:
|
|
164
|
+
exponent_bits = (combination >> 3) & 0x3FFF
|
|
165
|
+
msd = combination & 0x7
|
|
166
|
+
exponent = exponent_bits - 6176
|
|
167
|
+
print(f"Exponent: {exponent}")
|
|
168
|
+
print(f"MSD: {msd}")
|
|
169
|
+
|
|
170
|
+
# This should give us a clue about the actual value
|
|
171
|
+
print(f"Raw coefficient continuation: {coeff_continuation}")
|
|
172
|
+
|
|
173
|
+
# Try to decode it
|
|
174
|
+
result = _decode_decimal128_binary(binary_data)
|
|
175
|
+
print(f"Decoded result: {result}")
|
|
176
|
+
else:
|
|
177
|
+
print("Special value detected")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def main():
|
|
181
|
+
"""Run all tests."""
|
|
182
|
+
try:
|
|
183
|
+
result = test_specific_binary_value()
|
|
184
|
+
test_known_decimal128_values()
|
|
185
|
+
test_string_compatibility()
|
|
186
|
+
debug_binary_parsing()
|
|
187
|
+
|
|
188
|
+
print(f"\n🎉 All tests completed!")
|
|
189
|
+
print(f"The specific binary value b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00%f\\x80' parsed as: {result}")
|
|
190
|
+
return True
|
|
191
|
+
except Exception as e:
|
|
192
|
+
print(f"\n❌ Test failed: {e}")
|
|
193
|
+
import traceback
|
|
194
|
+
traceback.print_exc()
|
|
195
|
+
return False
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
if __name__ == "__main__":
|
|
199
|
+
success = main()
|
|
200
|
+
sys.exit(0 if success else 1)
|