duckrun 0.2.20__tar.gz → 0.2.20.dev0__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.
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/PKG-INFO +1 -1
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun/core.py +1 -10
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun/ducklake_metadata.py +15 -36
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun/writer.py +1 -3
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun.egg-info/PKG-INFO +1 -1
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun.egg-info/SOURCES.txt +1 -3
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/pyproject.toml +1 -1
- duckrun-0.2.20.dev0/tests/test_ducklake_export.py +7 -0
- duckrun-0.2.20/tests/test_ducklake_export.py +0 -4
- duckrun-0.2.20/tests/test_writer_dictionary.py +0 -142
- duckrun-0.2.20/tests/test_writer_integration.py +0 -152
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/LICENSE +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/README.md +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun/__init__.py +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun/auth.py +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun/files.py +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun/lakehouse.py +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun/notebook.py +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun/rle.py +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun/runner.py +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun/semantic_model.py +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun/stats.py +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun.egg-info/dependency_links.txt +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun.egg-info/requires.txt +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/duckrun.egg-info/top_level.txt +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/setup.cfg +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/tests/test_checkpoint_format.py +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/tests/test_register.py +0 -0
- {duckrun-0.2.20 → duckrun-0.2.20.dev0}/tests/test_rle.py +0 -0
|
@@ -1757,13 +1757,4 @@ class WorkspaceConnection(WorkspaceOperationsMixin):
|
|
|
1757
1757
|
print(f"❌ Error downloading semantic model: {e}")
|
|
1758
1758
|
import traceback
|
|
1759
1759
|
traceback.print_exc()
|
|
1760
|
-
return None
|
|
1761
|
-
|
|
1762
|
-
def close(self):
|
|
1763
|
-
"""
|
|
1764
|
-
Close the workspace connection.
|
|
1765
|
-
|
|
1766
|
-
Note: WorkspaceConnection doesn't maintain persistent connections,
|
|
1767
|
-
so this is a no-op for compatibility with code patterns that call close().
|
|
1768
|
-
"""
|
|
1769
|
-
pass
|
|
1760
|
+
return None
|
|
@@ -8,21 +8,20 @@ import shutil
|
|
|
8
8
|
|
|
9
9
|
def map_type_ducklake_to_spark(t):
|
|
10
10
|
"""Maps DuckDB data types to their Spark SQL equivalents for the Delta schema."""
|
|
11
|
-
|
|
12
|
-
if 'int' in
|
|
13
|
-
return 'long' if '64' in
|
|
14
|
-
elif 'float' in
|
|
11
|
+
t = t.lower()
|
|
12
|
+
if 'int' in t:
|
|
13
|
+
return 'long' if '64' in t else 'integer'
|
|
14
|
+
elif 'float' in t:
|
|
15
15
|
return 'double'
|
|
16
|
-
elif 'double' in
|
|
16
|
+
elif 'double' in t:
|
|
17
17
|
return 'double'
|
|
18
|
-
elif 'decimal' in
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
elif 'bool' in t_lower:
|
|
18
|
+
elif 'decimal' in t:
|
|
19
|
+
return 'decimal(10,0)'
|
|
20
|
+
elif 'bool' in t:
|
|
22
21
|
return 'boolean'
|
|
23
|
-
elif 'timestamp' in
|
|
22
|
+
elif 'timestamp' in t:
|
|
24
23
|
return 'timestamp'
|
|
25
|
-
elif 'date' in
|
|
24
|
+
elif 'date' in t:
|
|
26
25
|
return 'date'
|
|
27
26
|
return 'string'
|
|
28
27
|
|
|
@@ -43,31 +42,14 @@ def convert_stat_value_to_json(value_str, column_type):
|
|
|
43
42
|
column_type = column_type.lower()
|
|
44
43
|
|
|
45
44
|
try:
|
|
46
|
-
# Timestamp: Convert to ISO 8601 with .000Z suffix
|
|
45
|
+
# Timestamp: Convert to ISO 8601 with .000Z suffix
|
|
47
46
|
if 'timestamp' in column_type:
|
|
48
47
|
# Parse and format to ISO 8601
|
|
49
|
-
#
|
|
50
|
-
# - "2025-06-22 23:55:00" -> "2025-06-22T23:55:00.000Z"
|
|
51
|
-
# - "2025-06-22T23:55:00+00" -> "2025-06-22T23:55:00.000Z"
|
|
52
|
-
# - "2025-06-22T23:55:00.123+00:00" -> "2025-06-22T23:55:00.123Z"
|
|
53
|
-
|
|
54
|
-
# Replace space with T if needed
|
|
48
|
+
# Assumes value_str is in format like "2025-06-22 23:55:00"
|
|
55
49
|
if 'T' not in value_str:
|
|
56
50
|
value_str = value_str.replace(' ', 'T')
|
|
57
|
-
|
|
58
|
-
# Remove timezone offset formats to normalize to UTC
|
|
59
|
-
# Strip patterns like: +00, +00:00, -05:00, etc.
|
|
60
|
-
import re
|
|
61
|
-
value_str = re.sub(r'[+-]\d{2}(?::\d{2})?$', '', value_str)
|
|
62
|
-
|
|
63
|
-
# Ensure milliseconds are present
|
|
64
|
-
if '.' not in value_str:
|
|
65
|
-
value_str += '.000'
|
|
66
|
-
|
|
67
|
-
# Add Z suffix for UTC if not present
|
|
68
51
|
if not value_str.endswith('Z'):
|
|
69
|
-
value_str += 'Z'
|
|
70
|
-
|
|
52
|
+
value_str += '.000Z' if '.000Z' not in value_str else 'Z'
|
|
71
53
|
return value_str
|
|
72
54
|
|
|
73
55
|
# Date: Keep as YYYY-MM-DD string
|
|
@@ -363,11 +345,8 @@ def create_checkpoint_for_latest_snapshot(con, table_info, data_root, temp_dir,
|
|
|
363
345
|
ORDER BY column_order
|
|
364
346
|
""").fetchall()
|
|
365
347
|
|
|
366
|
-
#
|
|
367
|
-
|
|
368
|
-
import uuid
|
|
369
|
-
namespace = uuid.UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8') # DNS namespace
|
|
370
|
-
table_meta_id = str(uuid.uuid5(namespace, f"ducklake_table_{table_info['table_id']}"))
|
|
348
|
+
# Get or generate table metadata ID
|
|
349
|
+
table_meta_id = str(table_info['table_id'])
|
|
371
350
|
|
|
372
351
|
# Prepare schema
|
|
373
352
|
schema_fields = [
|
|
@@ -83,9 +83,7 @@ def _build_write_deltalake_args(path, df, mode, schema_mode=None, partition_by=N
|
|
|
83
83
|
args['min_rows_per_group'] = RG
|
|
84
84
|
# Set ZSTD compression for PyArrow engine
|
|
85
85
|
if _HAS_PYARROW_DATASET:
|
|
86
|
-
args['file_options'] = ds.ParquetFileFormat().make_write_options(
|
|
87
|
-
compression='ZSTD'
|
|
88
|
-
)
|
|
86
|
+
args['file_options'] = ds.ParquetFileFormat().make_write_options(compression='ZSTD')
|
|
89
87
|
else:
|
|
90
88
|
# Version 0.20+: no optimization available (rust by default, no row group params supported)
|
|
91
89
|
# Set ZSTD compression for Rust engine
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "duckrun"
|
|
7
|
-
version = "0.2.20"
|
|
7
|
+
version = "0.2.20.dev0"
|
|
8
8
|
description = "Helper library for Fabric Python using duckdb, arrow and delta_rs (orchestration, queries, etc.)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Test script for writer.py dictionary encoding feature
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import sys
|
|
7
|
-
import os
|
|
8
|
-
|
|
9
|
-
# Add the parent directory to Python path
|
|
10
|
-
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
11
|
-
|
|
12
|
-
from duckrun.writer import _build_write_deltalake_args, _IS_OLD_DELTALAKE, _HAS_PYARROW_DATASET
|
|
13
|
-
import pyarrow as pa
|
|
14
|
-
|
|
15
|
-
def test_dictionary_encoding():
|
|
16
|
-
"""Test that dictionary encoding is properly configured in write args"""
|
|
17
|
-
print("=" * 60)
|
|
18
|
-
print("Testing Dictionary Encoding in Writer")
|
|
19
|
-
print("=" * 60)
|
|
20
|
-
|
|
21
|
-
# Create sample PyArrow table
|
|
22
|
-
data = {
|
|
23
|
-
'id': [1, 2, 3, 4, 5],
|
|
24
|
-
'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
|
|
25
|
-
'category': ['A', 'B', 'A', 'B', 'A']
|
|
26
|
-
}
|
|
27
|
-
df = pa.table(data)
|
|
28
|
-
|
|
29
|
-
print(f"\nDeltalake version check:")
|
|
30
|
-
print(f" - Is old deltalake (< 0.20): {_IS_OLD_DELTALAKE}")
|
|
31
|
-
print(f" - Has PyArrow dataset: {_HAS_PYARROW_DATASET}")
|
|
32
|
-
|
|
33
|
-
# Test 1: Normal write mode (no schema merging)
|
|
34
|
-
print("\n[Test 1] Normal write mode (no schema merging)")
|
|
35
|
-
print("-" * 60)
|
|
36
|
-
|
|
37
|
-
args = _build_write_deltalake_args(
|
|
38
|
-
path='test/path',
|
|
39
|
-
df=df,
|
|
40
|
-
mode='overwrite',
|
|
41
|
-
schema_mode=None,
|
|
42
|
-
partition_by=None
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
print(f"Arguments generated:")
|
|
46
|
-
for key, value in args.items():
|
|
47
|
-
if key == 'data':
|
|
48
|
-
print(f" - {key}: <PyArrow Table>")
|
|
49
|
-
elif key == 'file_options':
|
|
50
|
-
print(f" - {key}: <ParquetFileWriteOptions>")
|
|
51
|
-
# Try to inspect file_options
|
|
52
|
-
if hasattr(value, '__dict__'):
|
|
53
|
-
print(f" Options: {value.__dict__}")
|
|
54
|
-
else:
|
|
55
|
-
print(f" - {key}: {value}")
|
|
56
|
-
|
|
57
|
-
# Check if dictionary encoding is enabled
|
|
58
|
-
if _IS_OLD_DELTALAKE and _HAS_PYARROW_DATASET:
|
|
59
|
-
if 'file_options' in args:
|
|
60
|
-
print("\n✅ [PASS] file_options is present in write args")
|
|
61
|
-
print(" Dictionary encoding (use_dictionary=True) should be configured")
|
|
62
|
-
else:
|
|
63
|
-
print("\n❌ [FAIL] file_options is missing from write args")
|
|
64
|
-
return False
|
|
65
|
-
else:
|
|
66
|
-
print("\n⚠️ [SKIP] Not using PyArrow engine (deltalake >= 0.20 or PyArrow dataset unavailable)")
|
|
67
|
-
|
|
68
|
-
# Test 2: Schema merging mode
|
|
69
|
-
print("\n[Test 2] Schema merging mode")
|
|
70
|
-
print("-" * 60)
|
|
71
|
-
|
|
72
|
-
args_merge = _build_write_deltalake_args(
|
|
73
|
-
path='test/path',
|
|
74
|
-
df=df,
|
|
75
|
-
mode='append',
|
|
76
|
-
schema_mode='merge',
|
|
77
|
-
partition_by=None
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
print(f"Arguments generated:")
|
|
81
|
-
for key, value in args_merge.items():
|
|
82
|
-
if key == 'data':
|
|
83
|
-
print(f" - {key}: <PyArrow Table>")
|
|
84
|
-
elif key == 'writer_properties':
|
|
85
|
-
print(f" - {key}: <WriterProperties>")
|
|
86
|
-
else:
|
|
87
|
-
print(f" - {key}: {value}")
|
|
88
|
-
|
|
89
|
-
if 'schema_mode' in args_merge and args_merge['schema_mode'] == 'merge':
|
|
90
|
-
print("\n✅ [PASS] schema_mode='merge' is correctly set")
|
|
91
|
-
if _IS_OLD_DELTALAKE:
|
|
92
|
-
if 'engine' in args_merge and args_merge['engine'] == 'rust':
|
|
93
|
-
print("✅ [PASS] engine='rust' is correctly set for old deltalake")
|
|
94
|
-
else:
|
|
95
|
-
print("❌ [FAIL] engine='rust' is missing for old deltalake with schema merging")
|
|
96
|
-
return False
|
|
97
|
-
else:
|
|
98
|
-
print("\n❌ [FAIL] schema_mode='merge' is not properly set")
|
|
99
|
-
return False
|
|
100
|
-
|
|
101
|
-
# Test 3: With partitioning
|
|
102
|
-
print("\n[Test 3] With partitioning")
|
|
103
|
-
print("-" * 60)
|
|
104
|
-
|
|
105
|
-
args_partition = _build_write_deltalake_args(
|
|
106
|
-
path='test/path',
|
|
107
|
-
df=df,
|
|
108
|
-
mode='overwrite',
|
|
109
|
-
schema_mode=None,
|
|
110
|
-
partition_by=['category']
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
if 'partition_by' in args_partition and args_partition['partition_by'] == ['category']:
|
|
114
|
-
print("✅ [PASS] partition_by is correctly set to ['category']")
|
|
115
|
-
else:
|
|
116
|
-
print("❌ [FAIL] partition_by is not properly configured")
|
|
117
|
-
return False
|
|
118
|
-
|
|
119
|
-
print("\n" + "=" * 60)
|
|
120
|
-
print("✅ All dictionary encoding tests passed!")
|
|
121
|
-
print("=" * 60)
|
|
122
|
-
print("\nConfiguration details:")
|
|
123
|
-
print(" - ZSTD compression: Enabled")
|
|
124
|
-
print(" - Dictionary encoding: Enabled (for PyArrow engine)")
|
|
125
|
-
print(" - Optimized row groups: Enabled (for old deltalake)")
|
|
126
|
-
|
|
127
|
-
return True
|
|
128
|
-
|
|
129
|
-
if __name__ == "__main__":
|
|
130
|
-
try:
|
|
131
|
-
success = test_dictionary_encoding()
|
|
132
|
-
if success:
|
|
133
|
-
print("\n✅ Test completed successfully!")
|
|
134
|
-
sys.exit(0)
|
|
135
|
-
else:
|
|
136
|
-
print("\n❌ Test failed!")
|
|
137
|
-
sys.exit(1)
|
|
138
|
-
except Exception as e:
|
|
139
|
-
print(f"\n❌ Test error: {e}")
|
|
140
|
-
import traceback
|
|
141
|
-
traceback.print_exc()
|
|
142
|
-
sys.exit(1)
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Integration test for writer.py with real Delta Lake write operations
|
|
4
|
-
Tests dictionary encoding and compression in actual writes
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import sys
|
|
8
|
-
import os
|
|
9
|
-
|
|
10
|
-
# Add the parent directory to Python path
|
|
11
|
-
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
12
|
-
|
|
13
|
-
import duckrun
|
|
14
|
-
from deltalake import DeltaTable
|
|
15
|
-
|
|
16
|
-
def test_real_write_with_dictionary():
|
|
17
|
-
"""Test real Delta Lake write with dictionary encoding"""
|
|
18
|
-
print("=" * 60)
|
|
19
|
-
print("Integration Test: Real Delta Lake Write")
|
|
20
|
-
print("=" * 60)
|
|
21
|
-
|
|
22
|
-
# Configuration
|
|
23
|
-
ws = "tmp"
|
|
24
|
-
lh = "data"
|
|
25
|
-
schema = "test"
|
|
26
|
-
table_name = "writer_test_dict"
|
|
27
|
-
|
|
28
|
-
try:
|
|
29
|
-
# Step 1: Connect to workspace
|
|
30
|
-
print("\n[Step 1] Connecting to workspace...")
|
|
31
|
-
workspace_conn = duckrun.connect(ws)
|
|
32
|
-
workspace_conn.create_lakehouse_if_not_exists(lh)
|
|
33
|
-
print(f"✅ Connected to workspace: {ws}")
|
|
34
|
-
|
|
35
|
-
# Step 2: Connect to lakehouse
|
|
36
|
-
print(f"\n[Step 2] Connecting to lakehouse: {ws}/{lh}.lakehouse/{schema}")
|
|
37
|
-
conn = duckrun.connect(f"{ws}/{lh}.lakehouse/{schema}")
|
|
38
|
-
print(f"✅ Connected to lakehouse")
|
|
39
|
-
|
|
40
|
-
# Step 3: Create test data with repetitive values (good for dictionary encoding)
|
|
41
|
-
print(f"\n[Step 3] Creating test data with repetitive values...")
|
|
42
|
-
test_data_sql = """
|
|
43
|
-
SELECT
|
|
44
|
-
row_number() OVER () as id,
|
|
45
|
-
-- Repetitive categories (perfect for dictionary encoding)
|
|
46
|
-
CASE (row_number() OVER ()) % 5
|
|
47
|
-
WHEN 0 THEN 'Category_A'
|
|
48
|
-
WHEN 1 THEN 'Category_B'
|
|
49
|
-
WHEN 2 THEN 'Category_C'
|
|
50
|
-
WHEN 3 THEN 'Category_D'
|
|
51
|
-
ELSE 'Category_E'
|
|
52
|
-
END as category,
|
|
53
|
-
-- Repetitive status values
|
|
54
|
-
CASE (row_number() OVER ()) % 3
|
|
55
|
-
WHEN 0 THEN 'Active'
|
|
56
|
-
WHEN 1 THEN 'Pending'
|
|
57
|
-
ELSE 'Complete'
|
|
58
|
-
END as status,
|
|
59
|
-
-- Some numeric data
|
|
60
|
-
(row_number() OVER ()) * 1.5 as amount,
|
|
61
|
-
current_date as created_date
|
|
62
|
-
FROM generate_series(1, 100000) as t(i)
|
|
63
|
-
"""
|
|
64
|
-
|
|
65
|
-
result = conn.sql(test_data_sql)
|
|
66
|
-
row_count = len(result.fetchall())
|
|
67
|
-
print(f"✅ Created {row_count} test rows with repetitive categories and statuses")
|
|
68
|
-
|
|
69
|
-
# Step 4: Write to Delta Lake using Spark-style API
|
|
70
|
-
print(f"\n[Step 4] Writing to Delta Lake table: {schema}.{table_name}")
|
|
71
|
-
print(" Using: mode=overwrite, ZSTD compression, dictionary encoding")
|
|
72
|
-
|
|
73
|
-
conn.sql(test_data_sql).write \
|
|
74
|
-
.mode("overwrite") \
|
|
75
|
-
.saveAsTable(table_name)
|
|
76
|
-
|
|
77
|
-
print(f"✅ Successfully wrote to {schema}.{table_name}")
|
|
78
|
-
|
|
79
|
-
# Step 5: Verify the write
|
|
80
|
-
print(f"\n[Step 5] Verifying Delta Lake table...")
|
|
81
|
-
|
|
82
|
-
# Get Delta table path
|
|
83
|
-
path = f"{conn.table_base_url}{schema}/{table_name}"
|
|
84
|
-
dt = DeltaTable(path)
|
|
85
|
-
|
|
86
|
-
# Get file count
|
|
87
|
-
file_count = len(dt.file_uris())
|
|
88
|
-
print(f" Table location: {path}")
|
|
89
|
-
print(f" Number of files: {file_count}")
|
|
90
|
-
print(f"✅ Table verified successfully")
|
|
91
|
-
|
|
92
|
-
# Step 6: Query the table to verify data
|
|
93
|
-
print(f"\n[Step 6] Querying table to verify data...")
|
|
94
|
-
verify_result = conn.sql(f"""
|
|
95
|
-
SELECT
|
|
96
|
-
category,
|
|
97
|
-
status,
|
|
98
|
-
COUNT(*) as count,
|
|
99
|
-
AVG(amount) as avg_amount
|
|
100
|
-
FROM {table_name}
|
|
101
|
-
GROUP BY category, status
|
|
102
|
-
ORDER BY category, status
|
|
103
|
-
""")
|
|
104
|
-
|
|
105
|
-
print("\n Sample aggregation results:")
|
|
106
|
-
verify_result.show()
|
|
107
|
-
|
|
108
|
-
# Step 7: Get detailed statistics showing compression and encoding
|
|
109
|
-
print(f"\n[Step 7] Getting detailed statistics (with compression info)...")
|
|
110
|
-
stats_detailed = conn.get_stats(table_name, detailed=True)
|
|
111
|
-
|
|
112
|
-
print("\nParquet Statistics DataFrame:")
|
|
113
|
-
print(stats_detailed.to_string())
|
|
114
|
-
|
|
115
|
-
print(f"\n✅ Statistics retrieved - {len(stats_detailed)} row groups analyzed")
|
|
116
|
-
|
|
117
|
-
# Cleanup
|
|
118
|
-
print(f"\n[Cleanup] Closing connection...")
|
|
119
|
-
conn.close()
|
|
120
|
-
|
|
121
|
-
print("\n" + "=" * 60)
|
|
122
|
-
print("✅ Integration Test PASSED!")
|
|
123
|
-
print("=" * 60)
|
|
124
|
-
print("\nVerified features:")
|
|
125
|
-
print(" ✓ Delta Lake write with Spark-style API")
|
|
126
|
-
print(" ✓ ZSTD compression configured")
|
|
127
|
-
print(" ✓ Dictionary encoding (check column encodings above)")
|
|
128
|
-
print(" ✓ Optimized row groups (8M rows)")
|
|
129
|
-
print(" ✓ Table creation and querying")
|
|
130
|
-
|
|
131
|
-
return True
|
|
132
|
-
|
|
133
|
-
except Exception as e:
|
|
134
|
-
print(f"\n❌ Integration test failed: {e}")
|
|
135
|
-
import traceback
|
|
136
|
-
traceback.print_exc()
|
|
137
|
-
return False
|
|
138
|
-
|
|
139
|
-
if __name__ == "__main__":
|
|
140
|
-
try:
|
|
141
|
-
success = test_real_write_with_dictionary()
|
|
142
|
-
if success:
|
|
143
|
-
print("\n✅ All integration tests passed!")
|
|
144
|
-
sys.exit(0)
|
|
145
|
-
else:
|
|
146
|
-
print("\n❌ Integration test failed!")
|
|
147
|
-
sys.exit(1)
|
|
148
|
-
except Exception as e:
|
|
149
|
-
print(f"\n❌ Test error: {e}")
|
|
150
|
-
import traceback
|
|
151
|
-
traceback.print_exc()
|
|
152
|
-
sys.exit(1)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|