sqlshell 0.1.6__py3-none-any.whl → 0.1.9__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.

Potentially problematic release.


This version of sqlshell might be problematic. Click here for more details.

@@ -0,0 +1,403 @@
1
+ from PyQt6.QtWidgets import (QHeaderView, QMenu, QCheckBox, QWidgetAction,
2
+ QWidget, QVBoxLayout, QLineEdit, QHBoxLayout, QPushButton, QTableWidget)
3
+ from PyQt6.QtCore import Qt, QRect, QPoint
4
+ from PyQt6.QtGui import QColor, QFont, QPolygon, QPainterPath, QBrush
5
+
6
+ class FilterHeader(QHeaderView):
7
+ def __init__(self, parent=None):
8
+ super().__init__(Qt.Orientation.Horizontal, parent)
9
+ self.filter_buttons = []
10
+ self.active_filters = {} # Track active filters for each column
11
+ self.columns_with_bars = set() # Track which columns show bar charts
12
+ self.bar_delegates = {} # Store delegates for columns with bars
13
+ self.setSectionsClickable(True)
14
+ self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
15
+ self.customContextMenuRequested.connect(self.show_header_context_menu)
16
+ self.main_window = None # Store reference to main window
17
+ self.filter_icon_color = QColor("#3498DB") # Bright blue color for filter icon
18
+
19
+ def toggle_bar_chart(self, column_index):
20
+ """Toggle bar chart visualization for a column"""
21
+ table = self.parent()
22
+ if not table:
23
+ return
24
+
25
+ if column_index in self.columns_with_bars:
26
+ # Remove bars
27
+ self.columns_with_bars.remove(column_index)
28
+ if column_index in self.bar_delegates:
29
+ table.setItemDelegateForColumn(column_index, None)
30
+ del self.bar_delegates[column_index]
31
+ else:
32
+ # Add bars
33
+ self.columns_with_bars.add(column_index)
34
+
35
+ # Get all values for normalization
36
+ values = []
37
+ for row in range(table.rowCount()):
38
+ item = table.item(row, column_index)
39
+ if item:
40
+ try:
41
+ value = float(item.text().replace(',', ''))
42
+ values.append(value)
43
+ except ValueError:
44
+ continue
45
+
46
+ if not values:
47
+ return
48
+
49
+ # Calculate min and max for normalization
50
+ min_val = min(values)
51
+ max_val = max(values)
52
+
53
+ # Import BarChartDelegate here to avoid circular imports
54
+ from sqlshell.ui.bar_chart_delegate import BarChartDelegate
55
+
56
+ # Create and set up delegate
57
+ delegate = BarChartDelegate(table)
58
+ delegate.set_range(min_val, max_val)
59
+ self.bar_delegates[column_index] = delegate
60
+ table.setItemDelegateForColumn(column_index, delegate)
61
+
62
+ # Update the view
63
+ table.viewport().update()
64
+
65
+ def show_header_context_menu(self, pos):
66
+ """Show context menu for header section"""
67
+ logical_index = self.logicalIndexAt(pos)
68
+ if logical_index < 0:
69
+ return
70
+
71
+ # Create context menu
72
+ context_menu = QMenu(self)
73
+ context_menu.setStyleSheet("""
74
+ QMenu {
75
+ background-color: white;
76
+ border: 1px solid #BDC3C7;
77
+ padding: 5px;
78
+ }
79
+ QMenu::item {
80
+ padding: 5px 20px;
81
+ }
82
+ QMenu::item:selected {
83
+ background-color: #3498DB;
84
+ color: white;
85
+ }
86
+ """)
87
+
88
+ # Add sort actions
89
+ sort_asc_action = context_menu.addAction("Sort Ascending")
90
+ sort_desc_action = context_menu.addAction("Sort Descending")
91
+ context_menu.addSeparator()
92
+ filter_action = context_menu.addAction("Filter...")
93
+
94
+ # Add bar chart action if column is numeric
95
+ table = self.parent()
96
+ if table and table.rowCount() > 0:
97
+ try:
98
+ # Check if column contains numeric values
99
+ sample_value = table.item(0, logical_index).text()
100
+ float(sample_value.replace(',', '')) # Try converting to float
101
+
102
+ context_menu.addSeparator()
103
+ toggle_bar_action = context_menu.addAction(
104
+ "Remove Bar Chart" if logical_index in self.columns_with_bars
105
+ else "Add Bar Chart"
106
+ )
107
+ except (ValueError, AttributeError):
108
+ toggle_bar_action = None
109
+ else:
110
+ toggle_bar_action = None
111
+
112
+ # Show menu and get selected action
113
+ action = context_menu.exec(self.mapToGlobal(pos))
114
+
115
+ if not action:
116
+ return
117
+
118
+ table = self.parent()
119
+ if not table:
120
+ return
121
+
122
+ if action == sort_asc_action:
123
+ table.sortItems(logical_index, Qt.SortOrder.AscendingOrder)
124
+ elif action == sort_desc_action:
125
+ table.sortItems(logical_index, Qt.SortOrder.DescendingOrder)
126
+ elif action == filter_action:
127
+ self.show_filter_menu(logical_index)
128
+ elif action == toggle_bar_action:
129
+ self.toggle_bar_chart(logical_index)
130
+
131
+ def set_main_window(self, window):
132
+ """Set the reference to the main window"""
133
+ self.main_window = window
134
+
135
+ def paintSection(self, painter, rect, logical_index):
136
+ """Override paint section to add filter indicator"""
137
+ super().paintSection(painter, rect, logical_index)
138
+
139
+ if logical_index in self.active_filters:
140
+ # Draw background highlight for filtered columns
141
+ highlight_color = QColor(52, 152, 219, 30) # Light blue background
142
+ painter.fillRect(rect, highlight_color)
143
+
144
+ # Make icon larger and more visible
145
+ icon_size = min(rect.height() - 8, 24) # Larger icon, but not too large
146
+ margin = 6
147
+ icon_rect = QRect(
148
+ rect.right() - icon_size - margin,
149
+ rect.top() + (rect.height() - icon_size) // 2,
150
+ icon_size,
151
+ icon_size
152
+ )
153
+
154
+ # Draw filter icon with improved visibility
155
+ painter.save()
156
+
157
+ # Set up the pen for better visibility
158
+ pen = painter.pen()
159
+ pen.setWidth(3) # Thicker lines
160
+ pen.setColor(self.filter_icon_color)
161
+ painter.setPen(pen)
162
+
163
+ # Calculate points for larger funnel shape
164
+ points = [
165
+ QPoint(icon_rect.left(), icon_rect.top()),
166
+ QPoint(icon_rect.right(), icon_rect.top()),
167
+ QPoint(icon_rect.center().x() + icon_size//3, icon_rect.center().y()),
168
+ QPoint(icon_rect.center().x() + icon_size//3, icon_rect.bottom()),
169
+ QPoint(icon_rect.center().x() - icon_size//3, icon_rect.bottom()),
170
+ QPoint(icon_rect.center().x() - icon_size//3, icon_rect.center().y()),
171
+ QPoint(icon_rect.left(), icon_rect.top())
172
+ ]
173
+
174
+ # Create and fill path
175
+ path = QPainterPath()
176
+ path.moveTo(float(points[0].x()), float(points[0].y()))
177
+ for point in points[1:]:
178
+ path.lineTo(float(point.x()), float(point.y()))
179
+
180
+ # Fill with semi-transparent blue
181
+ painter.fillPath(path, QBrush(QColor(52, 152, 219, 120))) # More opaque fill
182
+
183
+ # Draw outline
184
+ painter.drawPolyline(QPolygon(points))
185
+
186
+ # If multiple values are filtered, add a number
187
+ if len(self.active_filters[logical_index]) > 1:
188
+ # Draw number with better visibility
189
+ number_rect = QRect(icon_rect.left(), icon_rect.top(),
190
+ icon_rect.width(), icon_rect.height())
191
+ painter.setFont(QFont("Arial", icon_size//2, QFont.Weight.Bold))
192
+
193
+ # Draw text shadow for better contrast
194
+ painter.setPen(QColor("white"))
195
+ painter.drawText(number_rect.adjusted(1, 1, 1, 1),
196
+ Qt.AlignmentFlag.AlignCenter,
197
+ str(len(self.active_filters[logical_index])))
198
+
199
+ # Draw main text
200
+ painter.setPen(self.filter_icon_color)
201
+ painter.drawText(number_rect, Qt.AlignmentFlag.AlignCenter,
202
+ str(len(self.active_filters[logical_index])))
203
+
204
+ painter.restore()
205
+
206
+ # Draw a more visible indicator at the bottom of the header section
207
+ painter.save()
208
+ indicator_height = 3 # Thicker indicator line
209
+ indicator_rect = QRect(rect.left(), rect.bottom() - indicator_height,
210
+ rect.width(), indicator_height)
211
+ painter.fillRect(indicator_rect, self.filter_icon_color)
212
+ painter.restore()
213
+
214
+ def show_filter_menu(self, logical_index):
215
+ if not self.parent() or not isinstance(self.parent(), QTableWidget):
216
+ return
217
+
218
+ table = self.parent()
219
+ unique_values = set()
220
+
221
+ # Collect unique values from the column
222
+ for row in range(table.rowCount()):
223
+ item = table.item(row, logical_index)
224
+ if item and not table.isRowHidden(row):
225
+ unique_values.add(item.text())
226
+
227
+ # Create and show the filter menu
228
+ menu = QMenu(self)
229
+ menu.setStyleSheet("""
230
+ QMenu {
231
+ background-color: white;
232
+ border: 1px solid #BDC3C7;
233
+ padding: 5px;
234
+ }
235
+ QMenu::item {
236
+ padding: 5px 20px;
237
+ }
238
+ QMenu::item:selected {
239
+ background-color: #3498DB;
240
+ color: white;
241
+ }
242
+ QCheckBox {
243
+ padding: 5px;
244
+ }
245
+ QScrollArea {
246
+ border: none;
247
+ }
248
+ """)
249
+
250
+ # Add search box at the top
251
+ search_widget = QWidget(menu)
252
+ search_layout = QVBoxLayout(search_widget)
253
+ search_edit = QLineEdit(search_widget)
254
+ search_edit.setPlaceholderText("Search values...")
255
+ search_layout.addWidget(search_edit)
256
+
257
+ # Add action for search widget
258
+ search_action = QWidgetAction(menu)
259
+ search_action.setDefaultWidget(search_widget)
260
+ menu.addAction(search_action)
261
+ menu.addSeparator()
262
+
263
+ # Add "Select All" checkbox
264
+ select_all = QCheckBox("Select All", menu)
265
+ select_all.setChecked(True)
266
+ select_all_action = QWidgetAction(menu)
267
+ select_all_action.setDefaultWidget(select_all)
268
+ menu.addAction(select_all_action)
269
+ menu.addSeparator()
270
+
271
+ # Create scrollable area for checkboxes
272
+ scroll_widget = QWidget(menu)
273
+ scroll_layout = QVBoxLayout(scroll_widget)
274
+ scroll_layout.setSpacing(2)
275
+ scroll_layout.setContentsMargins(0, 0, 0, 0)
276
+
277
+ # Add checkboxes for unique values
278
+ value_checkboxes = {}
279
+ for value in sorted(unique_values):
280
+ checkbox = QCheckBox(str(value), scroll_widget)
281
+ # Set checked state based on active filters
282
+ checkbox.setChecked(logical_index not in self.active_filters or
283
+ value in self.active_filters[logical_index])
284
+ value_checkboxes[value] = checkbox
285
+ scroll_layout.addWidget(checkbox)
286
+
287
+ # Add scrollable area to menu
288
+ scroll_action = QWidgetAction(menu)
289
+ scroll_action.setDefaultWidget(scroll_widget)
290
+ menu.addAction(scroll_action)
291
+
292
+ # Connect search box to filter checkboxes
293
+ def filter_checkboxes(text):
294
+ for value, checkbox in value_checkboxes.items():
295
+ checkbox.setVisible(text.lower() in str(value).lower())
296
+
297
+ search_edit.textChanged.connect(filter_checkboxes)
298
+
299
+ # Connect select all to other checkboxes
300
+ def toggle_all(state):
301
+ for checkbox in value_checkboxes.values():
302
+ if not checkbox.isHidden(): # Only toggle visible checkboxes
303
+ checkbox.setChecked(state)
304
+
305
+ select_all.stateChanged.connect(toggle_all)
306
+
307
+ # Add Apply and Clear buttons
308
+ menu.addSeparator()
309
+ apply_button = QPushButton("Apply Filter", menu)
310
+ apply_button.setStyleSheet("""
311
+ QPushButton {
312
+ background-color: #2ECC71;
313
+ color: white;
314
+ border: none;
315
+ padding: 5px 15px;
316
+ border-radius: 3px;
317
+ }
318
+ QPushButton:hover {
319
+ background-color: #27AE60;
320
+ }
321
+ """)
322
+
323
+ clear_button = QPushButton("Clear Filter", menu)
324
+ clear_button.setStyleSheet("""
325
+ QPushButton {
326
+ background-color: #E74C3C;
327
+ color: white;
328
+ border: none;
329
+ padding: 5px 15px;
330
+ border-radius: 3px;
331
+ }
332
+ QPushButton:hover {
333
+ background-color: #C0392B;
334
+ }
335
+ """)
336
+
337
+ button_widget = QWidget(menu)
338
+ button_layout = QHBoxLayout(button_widget)
339
+ button_layout.addWidget(apply_button)
340
+ button_layout.addWidget(clear_button)
341
+
342
+ button_action = QWidgetAction(menu)
343
+ button_action.setDefaultWidget(button_widget)
344
+ menu.addAction(button_action)
345
+
346
+ def apply_filter():
347
+ # Get selected values
348
+ selected_values = {value for value, checkbox in value_checkboxes.items()
349
+ if checkbox.isChecked()}
350
+
351
+ if len(selected_values) < len(unique_values):
352
+ # Store active filter only if not all values are selected
353
+ self.active_filters[logical_index] = selected_values
354
+ else:
355
+ # Remove filter if all values are selected
356
+ self.active_filters.pop(logical_index, None)
357
+
358
+ # Apply all active filters
359
+ self.apply_all_filters(table)
360
+
361
+ menu.close()
362
+ self.updateSection(logical_index) # Redraw section to show/hide filter icon
363
+
364
+ def clear_filter():
365
+ # Remove filter for this column
366
+ if logical_index in self.active_filters:
367
+ del self.active_filters[logical_index]
368
+
369
+ # Apply remaining filters
370
+ self.apply_all_filters(table)
371
+
372
+ menu.close()
373
+ self.updateSection(logical_index) # Redraw section to hide filter icon
374
+
375
+ apply_button.clicked.connect(apply_filter)
376
+ clear_button.clicked.connect(clear_filter)
377
+
378
+ # Show menu under the header section
379
+ header_pos = self.mapToGlobal(self.geometry().bottomLeft())
380
+ header_pos.setX(header_pos.x() + self.sectionPosition(logical_index))
381
+ menu.exec(header_pos)
382
+
383
+ def apply_all_filters(self, table):
384
+ """Apply all active filters to the table"""
385
+ # Show all rows first
386
+ for row in range(table.rowCount()):
387
+ table.setRowHidden(row, False)
388
+
389
+ # Apply each active filter
390
+ for col_idx, allowed_values in self.active_filters.items():
391
+ for row in range(table.rowCount()):
392
+ item = table.item(row, col_idx)
393
+ if item and not table.isRowHidden(row):
394
+ table.setRowHidden(row, item.text() not in allowed_values)
395
+
396
+ # Update status bar with visible row count
397
+ if self.main_window:
398
+ visible_rows = sum(1 for row in range(table.rowCount())
399
+ if not table.isRowHidden(row))
400
+ total_filters = len(self.active_filters)
401
+ filter_text = f" ({total_filters} filter{'s' if total_filters != 1 else ''} active)" if total_filters > 0 else ""
402
+ self.main_window.statusBar().showMessage(
403
+ f"Showing {visible_rows:,} rows{filter_text}")
@@ -0,0 +1,122 @@
1
+ Metadata-Version: 2.4
2
+ Name: sqlshell
3
+ Version: 0.1.9
4
+ Summary: A powerful SQL shell with GUI interface for data analysis
5
+ Home-page: https://github.com/yourusername/sqlshell
6
+ Author: SQLShell Team
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/oyvinrog/SQLShell
9
+ Keywords: sql,data analysis,gui,duckdb
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.8
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Requires-Python: >=3.8
18
+ Description-Content-Type: text/markdown
19
+ Requires-Dist: pandas>=2.0.0
20
+ Requires-Dist: numpy>=1.24.0
21
+ Requires-Dist: PyQt6>=6.4.0
22
+ Requires-Dist: duckdb>=0.9.0
23
+ Requires-Dist: openpyxl>=3.1.0
24
+ Requires-Dist: pyarrow>=14.0.1
25
+ Requires-Dist: fastparquet>=2023.10.1
26
+ Requires-Dist: xlrd>=2.0.1
27
+ Dynamic: home-page
28
+ Dynamic: requires-python
29
+
30
+ # SQLShell
31
+
32
+ <div align="center">
33
+
34
+ <img src="sqlshell_logo.png" alt="SQLShell Logo" width="256" height="256">
35
+
36
+ **A modern SQL REPL interface for seamless querying of Excel, Parquet, and SQLite databases**
37
+
38
+ ![SQLShell Interface](sqlshell_demo.png)
39
+
40
+ </div>
41
+
42
+ ## 🚀 Key Features
43
+
44
+ - **Interactive SQL Interface** - Rich syntax highlighting for enhanced query writing
45
+ - **DuckDB Integration** - Built-in support for local DuckDB database (pool.db)
46
+ - **Multi-Format Support** - Import and query Excel (.xlsx, .xls), CSV, and Parquet files effortlessly
47
+ - **Modern UI** - Clean, tabular results display with intuitive controls
48
+ - **Productivity Tools** - Streamlined workflow with keyboard shortcuts (e.g., Ctrl+Enter for query execution)
49
+ - **Professional Design** - Human-readable interface with optimized graphics
50
+
51
+ ## 📦 Installation
52
+
53
+ ### Linux Setup with Virtual Environment
54
+
55
+ ```bash
56
+ # Create and activate virtual environment
57
+ python3 -m venv ~/.venv/sqlshell
58
+ source ~/.venv/sqlshell/bin/activate
59
+
60
+ # Install SQLShell
61
+ pip install sqlshell
62
+
63
+ # Configure shell alias
64
+ echo 'alias sqls="~/.venv/sqlshell/bin/sqls"' >> ~/.bashrc # or ~/.zshrc for Zsh
65
+ source ~/.bashrc # or source ~/.zshrc
66
+ ```
67
+
68
+ ### Windows Quick Start
69
+ SQLShell is immediately available via the `sqls` command after installation:
70
+ ```bash
71
+ pip install sqlshell
72
+ ```
73
+
74
+ ## 🎯 Getting Started
75
+
76
+ 1. **Launch the Application**
77
+ ```bash
78
+ sqls
79
+ ```
80
+
81
+ 2. **Database Connection**
82
+ - SQLShell automatically connects to a local DuckDB database named 'pool.db'
83
+
84
+ 3. **Working with Data Files**
85
+ - Click "Load Files" to select your Excel, CSV, or Parquet files
86
+ - File contents are loaded as queryable SQL tables
87
+ - Query using standard SQL syntax
88
+
89
+ 4. **Query Execution**
90
+ - Enter SQL in the editor
91
+ - Execute using Ctrl+Enter or the "Execute" button
92
+ - View results in the structured output panel
93
+
94
+ ## 📝 Query Examples
95
+
96
+ ### Basic Join Operation
97
+ ```sql
98
+ SELECT *
99
+ FROM sample_sales_data cd
100
+ INNER JOIN product_catalog pc ON pc.productid = cd.productid
101
+ LIMIT 3;
102
+ ```
103
+
104
+ ### Multi-Statement Queries
105
+ ```sql
106
+ -- Create a temporary view
107
+ CREATE OR REPLACE TEMPORARY VIEW test_v AS
108
+ SELECT *
109
+ FROM sample_sales_data cd
110
+ INNER JOIN product_catalog pc ON pc.productid = cd.productid;
111
+
112
+ -- Query the view
113
+ SELECT DISTINCT productid
114
+ FROM test_v;
115
+ ```
116
+
117
+ ## 💡 Pro Tips
118
+
119
+ - Use temporary views for complex query organization
120
+ - Leverage keyboard shortcuts for efficient workflow
121
+ - Explore the multi-format support for various data sources
122
+ - Create multiple tabs for parallel query development
@@ -0,0 +1,31 @@
1
+ sqlshell/__init__.py,sha256=GAZ3g4YsExb-aFyN0a77whBxRRk4XMGJYakvpeKbxdg,164
2
+ sqlshell/create_test_data.py,sha256=AzrEsKlZsR1H1Xlp7IKOzWQ2N6FsVISJbc6CerI8IJ0,1954
3
+ sqlshell/editor.py,sha256=LSUu1woAXXRNx-iquYY0_tjybOdaor-wSZfoHTEz5jk,36768
4
+ sqlshell/main.py,sha256=n6d5lYE0bfeWHB-9pbMpAm3GPz0t225EMqW1CYAqLp0,103613
5
+ sqlshell/query_tab.py,sha256=cvuaqPdwdhPo1O5jRTyyxYoCOJx0RpFClwBb7pv-Ivw,7095
6
+ sqlshell/setup.py,sha256=kaBlE81C38Sp7M76BinoBqbZ_XgbXc1fFFAvU6kZxVQ,1263
7
+ sqlshell/splash_screen.py,sha256=K0Ku_nXJWmWSnVEh2OttIthRZcnUoY_tmjIAWIWLm7Y,17604
8
+ sqlshell/sqlshell_demo.png,sha256=dPp9J1FVqQVfrh-gekosuha2Jw2p2--wxbOmt2kr7fg,133550
9
+ sqlshell/syntax_highlighter.py,sha256=mPwsD8N4XzAUx0IgwlelyfjUhe0xmH0Ug3UI9hTcHz0,5861
10
+ sqlshell/data/create_test_data.py,sha256=sUTcf50V8-bVwYV2VNTLK65c-iHiU4wb99By67I10zM,5404
11
+ sqlshell/db/__init__.py,sha256=AJGRkywFCnJliwfOBvtE_ISXjdESkRea7lBFM5KjuTU,152
12
+ sqlshell/db/database_manager.py,sha256=a3Uq8Lqxamvk4mikaZ3MNCY5Ft_Vv8v33cdToNzBLNk,29548
13
+ sqlshell/resources/__init__.py,sha256=VLTJ_5pUHhctRiV8UZDvG-jnsjgT6JQvW-ZPzIJqBIY,44
14
+ sqlshell/resources/create_icon.py,sha256=O7idVEKwmSXxLUsbeRn6zcYVQLPSdJi98nGamTgXiM4,4905
15
+ sqlshell/resources/create_splash.py,sha256=t1KK43Y0pHKGcdRkbnZgV6_y1c1C0THHQl5_fmpC2gQ,3347
16
+ sqlshell/resources/icon.png,sha256=l7MI1PWCED1XzsRgUjPR3A9pmbZ253tghd5s_0lJBMs,3173
17
+ sqlshell/resources/logo_large.png,sha256=pjLs6kXCy8gW8Iiq1gb6ZLnJEQ7_2GxtoJ_HDZ0_ERQ,31080
18
+ sqlshell/resources/logo_medium.png,sha256=brEV-YLgKS4RSxdZBgrwq_MvMA9zpsYvvvWgchUdjK4,14087
19
+ sqlshell/resources/logo_small.png,sha256=X4oQwj1k4OTbY785hWUIR12f1yAduV-USNzEu7aqkHs,6677
20
+ sqlshell/resources/splash_screen.gif,sha256=H24DQBdK1EsqQTWZkgInjM5ouOzY4cMesUoza10auNg,3070484
21
+ sqlshell/sqlshell/__init__.py,sha256=6Wp5nabfTzH5rkC-2jYo_ZjCuw8utmj21Jpy8vBuliI,100
22
+ sqlshell/sqlshell/create_test_data.py,sha256=TFXgWeK1l3l_c4Dg38yS8Df4sBUfOZcBucXngtpThvk,4624
23
+ sqlshell/sqlshell/create_test_databases.py,sha256=oqryFJJahqLFsAjBFM4r9Fe1ea7djDcRpT9U_aBf7PU,3573
24
+ sqlshell/ui/__init__.py,sha256=2CsTDAvRZJ99gkjs3-rdwkxyGVAKXX6ueOhPdP1VXQc,206
25
+ sqlshell/ui/bar_chart_delegate.py,sha256=tbtIt2ZqPIcYWNJzpONpYa0CYURkLdjkg23TI7TmOKY,1881
26
+ sqlshell/ui/filter_header.py,sha256=c4Mg1J1yTUfrnT9C-xDWHhcauRsgU3WNfvVInv1J814,16074
27
+ sqlshell-0.1.9.dist-info/METADATA,sha256=xiGeZnTbFrzPbG0wtCLgxQvqFZlya9gaxRs4yc9qDhg,3518
28
+ sqlshell-0.1.9.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
29
+ sqlshell-0.1.9.dist-info/entry_points.txt,sha256=Kd0fOvyOW7UiTgTVY7abVOmDIH2Y2nawGTp5kVadac4,44
30
+ sqlshell-0.1.9.dist-info/top_level.txt,sha256=ahwsMFhvAqI97ZkT2xvHL5iZCO1p13mNiUOFkdSFwms,9
31
+ sqlshell-0.1.9.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (76.0.0)
2
+ Generator: setuptools (78.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,92 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: sqlshell
3
- Version: 0.1.6
4
- Summary: A powerful SQL shell with GUI interface for data analysis
5
- Home-page: https://github.com/yourusername/sqlshell
6
- Author: SQLShell Team
7
- License: MIT
8
- Project-URL: Homepage, https://github.com/oyvinrog/SQLShell
9
- Keywords: sql,data analysis,gui,duckdb
10
- Classifier: Development Status :: 3 - Alpha
11
- Classifier: Intended Audience :: Developers
12
- Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.8
14
- Classifier: Programming Language :: Python :: 3.9
15
- Classifier: Programming Language :: Python :: 3.10
16
- Classifier: Programming Language :: Python :: 3.11
17
- Requires-Python: >=3.8
18
- Description-Content-Type: text/markdown
19
- Requires-Dist: pandas>=2.0.0
20
- Requires-Dist: numpy>=1.24.0
21
- Requires-Dist: PyQt6>=6.4.0
22
- Requires-Dist: duckdb>=0.9.0
23
- Requires-Dist: openpyxl>=3.1.0
24
- Requires-Dist: pyarrow>=14.0.1
25
- Requires-Dist: fastparquet>=2023.10.1
26
- Requires-Dist: xlrd>=2.0.1
27
- Dynamic: home-page
28
- Dynamic: requires-python
29
-
30
- # SQL Shell
31
-
32
- A GUI application that provides a SQL REPL interface for querying Excel and parquet files (more to come!)
33
-
34
-
35
- ![SQLShell Interface](sqlshell_demo.png)
36
-
37
- ## Features
38
-
39
- - SQL query interface with syntax highlighting
40
- - Support for querying local DuckDB database (pool.db)
41
- - Import and query Excel files (.xlsx, .xls) and CSV files
42
- - Results displayed in a clear, tabular format
43
- - Keyboard shortcuts (Ctrl+Enter to execute queries)
44
-
45
- ## Installation
46
-
47
- 1. Make sure you have Python 3.8 or newer installed
48
- 2. Install the required dependencies:
49
- ```bash
50
- pip install -r requirements.txt
51
- ```
52
-
53
- You can also do:
54
-
55
- ```bash
56
- pip install sqlshell
57
- ```
58
-
59
- ## Usage
60
-
61
- 1. Run the application:
62
- ```bash
63
- python sqls.py
64
- ```
65
-
66
- 2. The application will automatically connect to a local DuckDB database named 'pool.db'
67
-
68
- 3. To query Excel files:
69
- - Click the "Browse Excel" button
70
- - Select your Excel file
71
- - The file will be loaded as a table named 'imported_data'
72
- - Query the data using SQL commands (e.g., `SELECT * FROM imported_data`)
73
-
74
- 4. Enter SQL queries in the top text area
75
- - Press Ctrl+Enter or click "Execute" to run the query
76
- - Results will be displayed in the bottom panel
77
-
78
- ## Example Queries
79
-
80
- ```sql
81
- select * from sample_sales_data cd inner join product_catalog pc on pc.productid = cd.productid limit 3
82
- ```
83
-
84
- you can also do multiple statements, i.e:
85
-
86
- ```sql
87
- create or replace temporary view test_v as
88
- select * from sample_sales_data cd
89
- inner join product_catalog pc on pc.productid = cd.productid;
90
-
91
- select distinct productid from test_v ;
92
- ```
@@ -1,11 +0,0 @@
1
- sqlshell/__init__.py,sha256=OyPOfZIsEkW8eSHd0zAf6BT31-WwzDpONFBbeXV7kDc,129
2
- sqlshell/main.py,sha256=DuCJqWVxcRlOnPjV1h7LwC49yXZSRFcBdMsgldFG4Fc,60536
3
- sqlshell/setup.py,sha256=bAIXTpgAHhBRmPdT13Klzq16cjd4w4NOYSbyV_rxjlQ,1245
4
- sqlshell/sqlshell/__init__.py,sha256=6Wp5nabfTzH5rkC-2jYo_ZjCuw8utmj21Jpy8vBuliI,100
5
- sqlshell/sqlshell/create_test_data.py,sha256=sUTcf50V8-bVwYV2VNTLK65c-iHiU4wb99By67I10zM,5404
6
- sqlshell/sqlshell/create_test_databases.py,sha256=oqryFJJahqLFsAjBFM4r9Fe1ea7djDcRpT9U_aBf7PU,3573
7
- sqlshell-0.1.6.dist-info/METADATA,sha256=l0FXXswJr5NlZtD4YzzD345VAeYer8Mve8uhmcbana0,2559
8
- sqlshell-0.1.6.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
9
- sqlshell-0.1.6.dist-info/entry_points.txt,sha256=Kd0fOvyOW7UiTgTVY7abVOmDIH2Y2nawGTp5kVadac4,44
10
- sqlshell-0.1.6.dist-info/top_level.txt,sha256=ahwsMFhvAqI97ZkT2xvHL5iZCO1p13mNiUOFkdSFwms,9
11
- sqlshell-0.1.6.dist-info/RECORD,,