sqlshell 0.4.4__py3-none-any.whl

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 (54) hide show
  1. sqlshell/__init__.py +84 -0
  2. sqlshell/__main__.py +4926 -0
  3. sqlshell/ai_autocomplete.py +392 -0
  4. sqlshell/ai_settings_dialog.py +337 -0
  5. sqlshell/context_suggester.py +768 -0
  6. sqlshell/create_test_data.py +152 -0
  7. sqlshell/data/create_test_data.py +137 -0
  8. sqlshell/db/__init__.py +6 -0
  9. sqlshell/db/database_manager.py +1318 -0
  10. sqlshell/db/export_manager.py +188 -0
  11. sqlshell/editor.py +1166 -0
  12. sqlshell/editor_integration.py +127 -0
  13. sqlshell/execution_handler.py +421 -0
  14. sqlshell/menus.py +262 -0
  15. sqlshell/notification_manager.py +370 -0
  16. sqlshell/query_tab.py +904 -0
  17. sqlshell/resources/__init__.py +1 -0
  18. sqlshell/resources/icon.png +0 -0
  19. sqlshell/resources/logo_large.png +0 -0
  20. sqlshell/resources/logo_medium.png +0 -0
  21. sqlshell/resources/logo_small.png +0 -0
  22. sqlshell/resources/splash_screen.gif +0 -0
  23. sqlshell/space_invaders.py +501 -0
  24. sqlshell/splash_screen.py +405 -0
  25. sqlshell/sqlshell/__init__.py +5 -0
  26. sqlshell/sqlshell/create_test_data.py +118 -0
  27. sqlshell/sqlshell/create_test_databases.py +96 -0
  28. sqlshell/sqlshell_demo.png +0 -0
  29. sqlshell/styles.py +257 -0
  30. sqlshell/suggester_integration.py +330 -0
  31. sqlshell/syntax_highlighter.py +124 -0
  32. sqlshell/table_list.py +996 -0
  33. sqlshell/ui/__init__.py +6 -0
  34. sqlshell/ui/bar_chart_delegate.py +49 -0
  35. sqlshell/ui/filter_header.py +469 -0
  36. sqlshell/utils/__init__.py +16 -0
  37. sqlshell/utils/profile_cn2.py +1661 -0
  38. sqlshell/utils/profile_column.py +2635 -0
  39. sqlshell/utils/profile_distributions.py +616 -0
  40. sqlshell/utils/profile_entropy.py +347 -0
  41. sqlshell/utils/profile_foreign_keys.py +779 -0
  42. sqlshell/utils/profile_keys.py +2834 -0
  43. sqlshell/utils/profile_ohe.py +934 -0
  44. sqlshell/utils/profile_ohe_advanced.py +754 -0
  45. sqlshell/utils/profile_ohe_comparison.py +237 -0
  46. sqlshell/utils/profile_prediction.py +926 -0
  47. sqlshell/utils/profile_similarity.py +876 -0
  48. sqlshell/utils/search_in_df.py +90 -0
  49. sqlshell/widgets.py +400 -0
  50. sqlshell-0.4.4.dist-info/METADATA +441 -0
  51. sqlshell-0.4.4.dist-info/RECORD +54 -0
  52. sqlshell-0.4.4.dist-info/WHEEL +5 -0
  53. sqlshell-0.4.4.dist-info/entry_points.txt +2 -0
  54. sqlshell-0.4.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,188 @@
1
+ """Export functionality for SQLShell application."""
2
+
3
+ import os
4
+ import pandas as pd
5
+ import numpy as np
6
+ from typing import Optional, Tuple, Dict, Any
7
+
8
+ class ExportManager:
9
+ """Manages data export functionality for SQLShell."""
10
+
11
+ def __init__(self, db_manager):
12
+ """Initialize the export manager.
13
+
14
+ Args:
15
+ db_manager: The database manager instance to use for table registration
16
+ """
17
+ self.db_manager = db_manager
18
+
19
+ def export_to_excel(self, df: pd.DataFrame, file_name: str) -> Tuple[str, Dict[str, Any]]:
20
+ """Export data to Excel format.
21
+
22
+ Args:
23
+ df: The DataFrame to export
24
+ file_name: The target file path
25
+
26
+ Returns:
27
+ Tuple containing:
28
+ - The generated table name
29
+ - Dictionary with export metadata
30
+ """
31
+ try:
32
+ # Export to Excel
33
+ df.to_excel(file_name, index=False)
34
+
35
+ # Generate table name from file name
36
+ base_name = os.path.splitext(os.path.basename(file_name))[0]
37
+ table_name = self.db_manager.sanitize_table_name(base_name)
38
+
39
+ # Ensure unique table name
40
+ original_name = table_name
41
+ counter = 1
42
+ while table_name in self.db_manager.loaded_tables:
43
+ table_name = f"{original_name}_{counter}"
44
+ counter += 1
45
+
46
+ # Register the table in the database manager
47
+ self.db_manager.register_dataframe(df, table_name, file_name)
48
+
49
+ # Update tracking
50
+ self.db_manager.loaded_tables[table_name] = file_name
51
+ self.db_manager.table_columns[table_name] = [str(col) for col in df.columns.tolist()]
52
+
53
+ return table_name, {
54
+ 'file_path': file_name,
55
+ 'columns': df.columns.tolist(),
56
+ 'row_count': len(df)
57
+ }
58
+
59
+ except Exception as e:
60
+ raise Exception(f"Failed to export to Excel: {str(e)}")
61
+
62
+ def export_to_parquet(self, df: pd.DataFrame, file_name: str) -> Tuple[str, Dict[str, Any]]:
63
+ """Export data to Parquet format.
64
+
65
+ Args:
66
+ df: The DataFrame to export
67
+ file_name: The target file path
68
+
69
+ Returns:
70
+ Tuple containing:
71
+ - The generated table name
72
+ - Dictionary with export metadata
73
+ """
74
+ try:
75
+ # Export to Parquet using fastparquet engine (lighter than pyarrow - saves 147MB in builds)
76
+ df.to_parquet(file_name, index=False, engine='fastparquet')
77
+
78
+ # Generate table name from file name
79
+ base_name = os.path.splitext(os.path.basename(file_name))[0]
80
+ table_name = self.db_manager.sanitize_table_name(base_name)
81
+
82
+ # Ensure unique table name
83
+ original_name = table_name
84
+ counter = 1
85
+ while table_name in self.db_manager.loaded_tables:
86
+ table_name = f"{original_name}_{counter}"
87
+ counter += 1
88
+
89
+ # Register the table in the database manager
90
+ self.db_manager.register_dataframe(df, table_name, file_name)
91
+
92
+ # Update tracking
93
+ self.db_manager.loaded_tables[table_name] = file_name
94
+ self.db_manager.table_columns[table_name] = [str(col) for col in df.columns.tolist()]
95
+
96
+ return table_name, {
97
+ 'file_path': file_name,
98
+ 'columns': df.columns.tolist(),
99
+ 'row_count': len(df)
100
+ }
101
+
102
+ except Exception as e:
103
+ raise Exception(f"Failed to export to Parquet: {str(e)}")
104
+
105
+ def convert_table_to_dataframe(self, table_widget) -> Optional[pd.DataFrame]:
106
+ """Convert a QTableWidget to a pandas DataFrame with proper data types.
107
+
108
+ Args:
109
+ table_widget: The QTableWidget containing the data
110
+
111
+ Returns:
112
+ DataFrame with properly typed data, or None if conversion fails
113
+ """
114
+ if not table_widget or table_widget.rowCount() == 0:
115
+ return None
116
+
117
+ # Get headers
118
+ headers = [table_widget.horizontalHeaderItem(i).text()
119
+ for i in range(table_widget.columnCount())]
120
+
121
+ # Get data
122
+ data = []
123
+ for row in range(table_widget.rowCount()):
124
+ row_data = []
125
+ for column in range(table_widget.columnCount()):
126
+ item = table_widget.item(row, column)
127
+ row_data.append(item.text() if item else '')
128
+ data.append(row_data)
129
+
130
+ # Create DataFrame from raw string data
131
+ df_raw = pd.DataFrame(data, columns=headers)
132
+
133
+ # Try to use the original dataframe's dtypes if available
134
+ if hasattr(table_widget, 'current_df') and table_widget.current_df is not None:
135
+ original_df = table_widget.current_df
136
+
137
+ # Create a new DataFrame with appropriate types
138
+ df_typed = pd.DataFrame()
139
+
140
+ for col in df_raw.columns:
141
+ if col in original_df.columns:
142
+ # Get the original column type
143
+ orig_type = original_df[col].dtype
144
+
145
+ # Special handling for different data types
146
+ if pd.api.types.is_numeric_dtype(orig_type):
147
+ try:
148
+ numeric_col = pd.to_numeric(
149
+ df_raw[col].str.replace(',', '').replace('NULL', np.nan)
150
+ )
151
+ df_typed[col] = numeric_col
152
+ except:
153
+ df_typed[col] = df_raw[col]
154
+ elif pd.api.types.is_datetime64_dtype(orig_type):
155
+ try:
156
+ df_typed[col] = pd.to_datetime(df_raw[col].replace('NULL', np.nan))
157
+ except:
158
+ df_typed[col] = df_raw[col]
159
+ elif pd.api.types.is_bool_dtype(orig_type):
160
+ try:
161
+ df_typed[col] = df_raw[col].map({'True': True, 'False': False}).replace('NULL', np.nan)
162
+ except:
163
+ df_typed[col] = df_raw[col]
164
+ else:
165
+ df_typed[col] = df_raw[col]
166
+ else:
167
+ df_typed[col] = df_raw[col]
168
+
169
+ return df_typed
170
+
171
+ else:
172
+ # If we don't have the original dataframe, try to infer types
173
+ df_raw.replace('NULL', np.nan, inplace=True)
174
+
175
+ for col in df_raw.columns:
176
+ try:
177
+ df_raw[col] = pd.to_numeric(df_raw[col].str.replace(',', ''))
178
+ except:
179
+ try:
180
+ df_raw[col] = pd.to_datetime(df_raw[col])
181
+ except:
182
+ try:
183
+ if df_raw[col].dropna().isin(['True', 'False']).all():
184
+ df_raw[col] = df_raw[col].map({'True': True, 'False': False})
185
+ except:
186
+ pass
187
+
188
+ return df_raw