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.
Files changed (51) hide show
  1. {e6data_python_connector-2.2.5rc5/e6data_python_connector.egg-info → e6data_python_connector-2.2.5rc6}/PKG-INFO +2 -2
  2. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/README.md +1 -1
  3. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/e6data_grpc.py +1 -19
  4. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6/e6data_python_connector.egg-info}/PKG-INFO +2 -2
  5. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector.egg-info/SOURCES.txt +15 -1
  6. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector.egg-info/top_level.txt +1 -0
  7. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/setup.py +1 -1
  8. e6data_python_connector-2.2.5rc6/test/__init__.py +1 -0
  9. e6data_python_connector-2.2.5rc6/test/analyze_38_nines.py +97 -0
  10. e6data_python_connector-2.2.5rc6/test/analyze_binary.py +70 -0
  11. e6data_python_connector-2.2.5rc6/test/check_decimal_errors.py +25 -0
  12. e6data_python_connector-2.2.5rc6/test/test_decimal128_binary_parsing.py +200 -0
  13. e6data_python_connector-2.2.5rc6/test/test_decimal128_parsing.py +255 -0
  14. e6data_python_connector-2.2.5rc6/test/test_fix.py +29 -0
  15. e6data_python_connector-2.2.5rc6/test/test_improved_parsing.py +113 -0
  16. e6data_python_connector-2.2.5rc6/test/test_specific_binary.py +99 -0
  17. e6data_python_connector-2.2.5rc6/test/test_user_binary_value.py +71 -0
  18. e6data_python_connector-2.2.5rc6/test/tests.py +307 -0
  19. e6data_python_connector-2.2.5rc6/test/tests_grpc.py +155 -0
  20. e6data_python_connector-2.2.5rc6/test/validate_decimal128.py +76 -0
  21. e6data_python_connector-2.2.5rc6/test/verify_decimal_fix.py +36 -0
  22. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/LICENSE +0 -0
  23. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/MANIFEST.in +0 -0
  24. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/__init__.py +0 -0
  25. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/cluster_manager.py +0 -0
  26. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/cluster_server/__init__.py +0 -0
  27. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/cluster_server/cluster_pb2.py +0 -0
  28. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/cluster_server/cluster_pb2_grpc.py +0 -0
  29. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/common.py +0 -0
  30. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/constants.py +0 -0
  31. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/datainputstream.py +0 -0
  32. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/date_time_utils.py +0 -0
  33. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/dialect.py +0 -0
  34. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/e6x_vector/__init__.py +0 -0
  35. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/e6x_vector/constants.py +0 -0
  36. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/e6x_vector/ttypes.py +0 -0
  37. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/exceptions.py +0 -0
  38. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/server/QueryEngineService.py +0 -0
  39. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/server/__init__.py +0 -0
  40. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/server/constants.py +0 -0
  41. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/server/e6x_engine_pb2.py +0 -0
  42. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/server/e6x_engine_pb2.pyi +0 -0
  43. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/server/e6x_engine_pb2_grpc.py +0 -0
  44. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/server/ttypes.py +0 -0
  45. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/strategy.py +0 -0
  46. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector/typeId.py +0 -0
  47. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector.egg-info/dependency_links.txt +0 -0
  48. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector.egg-info/entry_points.txt +0 -0
  49. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/e6data_python_connector.egg-info/requires.txt +0 -0
  50. {e6data_python_connector-2.2.5rc5 → e6data_python_connector-2.2.5rc6}/pyproject.toml +0 -0
  51. {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.5rc5
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
- ![version](https://img.shields.io/badge/version-2.2.5rc5-blue.svg)
41
+ ![version](https://img.shields.io/badge/version-2.2.5rc6-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.2.5rc5-blue.svg)
3
+ ![version](https://img.shields.io/badge/version-2.2.5rc6-blue.svg)
4
4
 
5
5
  ## Introduction
6
6
 
@@ -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
- # @re_auth
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.5rc5
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
- ![version](https://img.shields.io/badge/version-2.2.5rc5-blue.svg)
41
+ ![version](https://img.shields.io/badge/version-2.2.5rc6-blue.svg)
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
@@ -12,7 +12,7 @@
12
12
 
13
13
  import setuptools
14
14
 
15
- VERSION = (2, 2, 5, 'rc5',)
15
+ VERSION = (2, 2, 5, 'rc6',)
16
16
 
17
17
 
18
18
  def get_long_desc():
@@ -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)