sqlshell 0.1.8__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.

sqlshell/query_tab.py ADDED
@@ -0,0 +1,172 @@
1
+ from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
2
+ QPushButton, QFrame, QHeaderView, QTableWidget, QSplitter, QApplication)
3
+ from PyQt6.QtCore import Qt
4
+ from PyQt6.QtGui import QIcon
5
+
6
+ from sqlshell.editor import SQLEditor
7
+ from sqlshell.syntax_highlighter import SQLSyntaxHighlighter
8
+ from sqlshell.ui import FilterHeader
9
+
10
+ class QueryTab(QWidget):
11
+ def __init__(self, parent, results_title="RESULTS"):
12
+ super().__init__()
13
+ self.parent = parent
14
+ self.current_df = None
15
+ self.filter_widgets = []
16
+ self.results_title_text = results_title
17
+ self.init_ui()
18
+
19
+ def init_ui(self):
20
+ """Initialize the tab's UI components"""
21
+ # Set main layout
22
+ main_layout = QVBoxLayout(self)
23
+ main_layout.setContentsMargins(0, 0, 0, 0)
24
+ main_layout.setSpacing(0)
25
+
26
+ # Create splitter for query and results
27
+ self.splitter = QSplitter(Qt.Orientation.Vertical)
28
+ self.splitter.setHandleWidth(8)
29
+ self.splitter.setChildrenCollapsible(False)
30
+
31
+ # Top part - Query section
32
+ query_widget = QFrame()
33
+ query_widget.setObjectName("content_panel")
34
+ query_layout = QVBoxLayout(query_widget)
35
+ query_layout.setContentsMargins(16, 16, 16, 16)
36
+ query_layout.setSpacing(12)
37
+
38
+ # Query input
39
+ self.query_edit = SQLEditor()
40
+ # Apply syntax highlighting to the query editor
41
+ self.sql_highlighter = SQLSyntaxHighlighter(self.query_edit.document())
42
+
43
+ # Ensure a default completer is available
44
+ if not self.query_edit.completer:
45
+ from PyQt6.QtCore import QStringListModel
46
+ from PyQt6.QtWidgets import QCompleter
47
+
48
+ # Create a basic completer with SQL keywords if one doesn't exist
49
+ if hasattr(self.query_edit, 'all_sql_keywords'):
50
+ model = QStringListModel(self.query_edit.all_sql_keywords)
51
+ completer = QCompleter()
52
+ completer.setModel(model)
53
+ self.query_edit.set_completer(completer)
54
+
55
+ query_layout.addWidget(self.query_edit)
56
+
57
+ # Button row
58
+ button_layout = QHBoxLayout()
59
+ button_layout.setSpacing(8)
60
+
61
+ self.execute_btn = QPushButton('Execute Query')
62
+ self.execute_btn.setObjectName("primary_button")
63
+ self.execute_btn.setIcon(QIcon.fromTheme("media-playback-start"))
64
+ self.execute_btn.clicked.connect(self.execute_query)
65
+
66
+ self.clear_btn = QPushButton('Clear')
67
+ self.clear_btn.clicked.connect(self.clear_query)
68
+
69
+ button_layout.addWidget(self.execute_btn)
70
+ button_layout.addWidget(self.clear_btn)
71
+ button_layout.addStretch()
72
+
73
+ self.export_excel_btn = QPushButton('Export to Excel')
74
+ self.export_excel_btn.setIcon(QIcon.fromTheme("x-office-spreadsheet"))
75
+ self.export_excel_btn.clicked.connect(self.export_to_excel)
76
+
77
+ self.export_parquet_btn = QPushButton('Export to Parquet')
78
+ self.export_parquet_btn.setIcon(QIcon.fromTheme("application-octet-stream"))
79
+ self.export_parquet_btn.clicked.connect(self.export_to_parquet)
80
+
81
+ button_layout.addWidget(self.export_excel_btn)
82
+ button_layout.addWidget(self.export_parquet_btn)
83
+
84
+ query_layout.addLayout(button_layout)
85
+
86
+ # Bottom part - Results section
87
+ results_widget = QWidget()
88
+ results_layout = QVBoxLayout(results_widget)
89
+ results_layout.setContentsMargins(16, 16, 16, 16)
90
+ results_layout.setSpacing(12)
91
+
92
+ # Results header with row count
93
+ header_layout = QHBoxLayout()
94
+ self.results_title = QLabel(self.results_title_text)
95
+ self.results_title.setObjectName("header_label")
96
+ header_layout.addWidget(self.results_title)
97
+
98
+ header_layout.addStretch()
99
+
100
+ self.row_count_label = QLabel("")
101
+ self.row_count_label.setStyleSheet("color: #7F8C8D; font-style: italic;")
102
+ header_layout.addWidget(self.row_count_label)
103
+
104
+ results_layout.addLayout(header_layout)
105
+
106
+ # Results table with customized header
107
+ self.results_table = QTableWidget()
108
+ self.results_table.setAlternatingRowColors(True)
109
+
110
+ # Use custom FilterHeader for filtering
111
+ header = FilterHeader(self.results_table)
112
+ header.set_main_window(self.parent) # Set reference to main window
113
+ self.results_table.setHorizontalHeader(header)
114
+
115
+ # Set table properties for better performance with large datasets
116
+ self.results_table.setShowGrid(True)
117
+ self.results_table.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers)
118
+ self.results_table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Interactive)
119
+ self.results_table.horizontalHeader().setStretchLastSection(True)
120
+ self.results_table.verticalHeader().setVisible(True)
121
+
122
+ results_layout.addWidget(self.results_table)
123
+
124
+ # Add widgets to splitter
125
+ self.splitter.addWidget(query_widget)
126
+ self.splitter.addWidget(results_widget)
127
+
128
+ # Set initial sizes - default 40% query, 60% results
129
+ # This will be better for most uses of the app
130
+ screen = QApplication.primaryScreen()
131
+ if screen:
132
+ # Get available screen height
133
+ available_height = screen.availableGeometry().height()
134
+ # Calculate reasonable query pane size (25-35% depending on screen size)
135
+ if available_height >= 1080: # Large screens
136
+ query_height = int(available_height * 0.3) # 30% for query area
137
+ self.splitter.setSizes([query_height, available_height - query_height])
138
+ else: # Smaller screens
139
+ self.splitter.setSizes([300, 500]) # Default values for smaller screens
140
+ else:
141
+ # Fallback to fixed values if screen detection fails
142
+ self.splitter.setSizes([300, 500])
143
+
144
+ main_layout.addWidget(self.splitter)
145
+
146
+ def get_query_text(self):
147
+ """Get the current query text"""
148
+ return self.query_edit.toPlainText()
149
+
150
+ def set_query_text(self, text):
151
+ """Set the query text"""
152
+ self.query_edit.setPlainText(text)
153
+
154
+ def execute_query(self):
155
+ """Execute the current query"""
156
+ if hasattr(self.parent, 'execute_query'):
157
+ self.parent.execute_query()
158
+
159
+ def clear_query(self):
160
+ """Clear the query editor"""
161
+ if hasattr(self.parent, 'clear_query'):
162
+ self.parent.clear_query()
163
+
164
+ def export_to_excel(self):
165
+ """Export results to Excel"""
166
+ if hasattr(self.parent, 'export_to_excel'):
167
+ self.parent.export_to_excel()
168
+
169
+ def export_to_parquet(self):
170
+ """Export results to Parquet"""
171
+ if hasattr(self.parent, 'export_to_parquet'):
172
+ self.parent.export_to_parquet()
@@ -1,53 +1,131 @@
1
1
  import os
2
+ import sys
2
3
  from PIL import Image, ImageDraw, ImageFont
3
4
 
4
5
  def create_sql_icon(output_path, size=256):
5
- """Create a simple SQL icon"""
6
+ """Create a professional SQL icon with improved readability"""
6
7
  # Create a new image with a transparent background
7
8
  img = Image.new('RGBA', (size, size), (0, 0, 0, 0))
8
9
  draw = ImageDraw.Draw(img)
9
10
 
10
11
  # Define colors
11
- primary_color = (44, 62, 80, 255) # Dark blue-gray
12
+ primary_color = (44, 62, 80, 255) # Dark blue-gray
12
13
  secondary_color = (52, 152, 219, 255) # Bright blue
13
- accent_color = (26, 188, 156, 255) # Teal
14
+ text_color = (236, 240, 241, 255) # Light gray for better readability
15
+ accent_color = (26, 188, 156, 255) # Teal
14
16
 
15
17
  # Draw a rounded rectangle background
16
- radius = size // 10
17
- rect = [(size//8, size//8), (size - size//8, size - size//8)]
18
+ radius = size // 8
19
+ rect = [(size//12, size//12), (size - size//12, size - size//12)]
18
20
  draw.rounded_rectangle(rect, radius, fill=primary_color)
19
21
 
20
- # Try to load a font, fall back to default if not available
21
- try:
22
- font_size = size // 3
23
- font = ImageFont.truetype("arial.ttf", font_size)
24
- except IOError:
22
+ # Try to load fonts in order of preference
23
+ font_size = size // 4 # Slightly smaller for better readability
24
+ font = None
25
+
26
+ # Common fonts list to try
27
+ font_options = [
28
+ "Arial Bold", "Arial", "Helvetica Bold", "Helvetica",
29
+ "DejaVuSans-Bold.ttf", "DejaVuSans.ttf",
30
+ "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
31
+ "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
32
+ ]
33
+
34
+ for font_name in font_options:
25
35
  try:
26
- font = ImageFont.truetype("DejaVuSans.ttf", font_size)
36
+ font = ImageFont.truetype(font_name, font_size)
37
+ break
27
38
  except IOError:
28
- font = ImageFont.load_default()
39
+ continue
29
40
 
30
- # Draw SQL text
41
+ if font is None:
42
+ font = ImageFont.load_default()
43
+ font_size = size // 5 # Adjust size for default font
44
+
45
+ # Draw "SQL" text with improved visibility
31
46
  text = "SQL"
32
- text_width, text_height = draw.textsize(text, font=font) if hasattr(draw, 'textsize') else font.getsize(text)
33
- position = ((size - text_width) // 2, (size - text_height) // 2)
34
- draw.text(position, text, fill=accent_color, font=font)
47
+
48
+ # Handle different PIL versions for text size calculation
49
+ if hasattr(draw, 'textsize'):
50
+ text_width, text_height = draw.textsize(text, font=font)
51
+ elif hasattr(font, 'getsize'):
52
+ text_width, text_height = font.getsize(text)
53
+ else:
54
+ # Fallback for newer PIL versions
55
+ try:
56
+ text_width, text_height = font.getbbox(text)[2:]
57
+ except:
58
+ text_width, text_height = font_size * 3, font_size
59
+
60
+ # Position text slightly higher
61
+ position = ((size - text_width) // 2, (size - text_height) // 2 - size//12)
62
+
63
+ # Draw text with subtle shadow for better readability
64
+ shadow_offset = max(1, size // 64)
65
+ draw.text((position[0] + shadow_offset, position[1] + shadow_offset),
66
+ text, fill=(0, 0, 0, 100), font=font)
67
+ draw.text(position, text, fill=text_color, font=font)
35
68
 
36
69
  # Draw a small database icon
37
- db_size = size // 4
70
+ db_size = size // 3
38
71
  db_x = size // 2 - db_size // 2
39
- db_y = size // 2 + text_height // 2 + db_size // 2
72
+ db_y = size // 2 + text_height // 2 + db_size // 4
73
+
74
+ # Draw database cylinder with improved shape
75
+ # Top ellipse
76
+ draw.ellipse([(db_x, db_y - db_size//4), (db_x + db_size, db_y)],
77
+ fill=secondary_color)
78
+ # Bottom ellipse
79
+ draw.ellipse([(db_x, db_y + db_size//2), (db_x + db_size, db_y + db_size//1.5)],
80
+ fill=secondary_color)
81
+ # Rectangle body
82
+ draw.rectangle([(db_x, db_y), (db_x + db_size, db_y + db_size//2)],
83
+ fill=secondary_color)
40
84
 
41
- # Draw database cylinder
42
- draw.ellipse([(db_x, db_y - db_size//3), (db_x + db_size, db_y)], fill=secondary_color)
43
- draw.ellipse([(db_x, db_y + db_size//3), (db_x + db_size, db_y + db_size//1.5)], fill=secondary_color)
44
- draw.rectangle([(db_x, db_y), (db_x + db_size, db_y + db_size//3)], fill=secondary_color)
85
+ # Add subtle details to database
86
+ highlight_color = (72, 172, 240, 150) # Lighter blue for highlight
87
+ # Database line details
88
+ line_y1 = db_y + db_size//6
89
+ line_y2 = db_y + db_size//3
90
+ draw.line([(db_x + db_size//6, line_y1), (db_x + db_size - db_size//6, line_y1)],
91
+ fill=highlight_color, width=max(1, size//128))
92
+ draw.line([(db_x + db_size//6, line_y2), (db_x + db_size - db_size//6, line_y2)],
93
+ fill=highlight_color, width=max(1, size//128))
45
94
 
46
- # Save the image
47
- img.save(output_path)
48
- print(f"Icon created at {output_path}")
95
+ # Save the image with compression
96
+ img.save(output_path, optimize=True)
97
+ print(f"Professional SQL icon created at {output_path}")
98
+ return img
49
99
 
50
- if __name__ == "__main__":
100
+ def create_logo(size=512):
101
+ """Create a properly sized logo for different uses"""
51
102
  output_dir = os.path.dirname(os.path.abspath(__file__))
52
- output_path = os.path.join(output_dir, "icon.png")
53
- create_sql_icon(output_path)
103
+ project_dir = os.path.abspath(os.path.join(output_dir, '..', '..'))
104
+
105
+ # Create different sizes
106
+ sizes = {
107
+ 'icon': 128, # For app icon
108
+ 'logo_small': 256, # For UI elements
109
+ 'logo_medium': 512, # For documentation
110
+ 'logo_large': 1024 # For high-res displays
111
+ }
112
+
113
+ for name, icon_size in sizes.items():
114
+ output_path = os.path.join(output_dir, f"{name}.png")
115
+ create_sql_icon(output_path, icon_size)
116
+
117
+ # Create the main logo file at the root directory
118
+ main_logo_path = os.path.join(project_dir, "sqlshell_logo.png")
119
+ logo = create_sql_icon(main_logo_path, size)
120
+ print(f"Main logo created at {main_logo_path}")
121
+
122
+ if __name__ == "__main__":
123
+ # Default size is 512 if no argument provided
124
+ size = 512
125
+ if len(sys.argv) > 1:
126
+ try:
127
+ size = int(sys.argv[1])
128
+ except ValueError:
129
+ print(f"Invalid size argument: {sys.argv[1]}. Using default size {size}.")
130
+
131
+ create_logo(size)
@@ -2,7 +2,7 @@ from PIL import Image, ImageDraw, ImageFont
2
2
  import os
3
3
  import math
4
4
 
5
- def create_frame(size, progress, text=None): # We won't use text parameter anymore
5
+ def create_frame(size, progress, text=None):
6
6
  # Create a new image with a dark background
7
7
  img = Image.new('RGBA', size, (44, 62, 80, 255)) # Dark blue-gray background
8
8
  draw = ImageDraw.Draw(img)
@@ -12,12 +12,31 @@ def create_frame(size, progress, text=None): # We won't use text parameter anym
12
12
  center_x = width // 2
13
13
  center_y = height // 2
14
14
 
15
- # Create a subtle circular pattern
16
- radius = 60
15
+ # Create a more visible circular pattern
16
+ radius = 80 # Larger radius
17
17
  num_dots = 12
18
- dot_size = 4
19
- trail_length = 6
18
+ dot_size = 6 # Larger dots
19
+ trail_length = 8 # Longer trail
20
20
 
21
+ # Add a subtle gradient background
22
+ for y in range(height):
23
+ # Create a vertical gradient
24
+ gradient_factor = y / height
25
+ r = int(44 + (52 - 44) * gradient_factor)
26
+ g = int(62 + (152 - 62) * gradient_factor)
27
+ b = int(80 + (219 - 80) * gradient_factor)
28
+ draw.line([(0, y), (width, y)], fill=(r, g, b, 255))
29
+
30
+ # Draw a pulsing circle
31
+ pulse_size = 40 + 15 * math.sin(progress * 2 * math.pi)
32
+ draw.ellipse(
33
+ (center_x - pulse_size, center_y - pulse_size,
34
+ center_x + pulse_size, center_y + pulse_size),
35
+ outline=(52, 152, 219, 100),
36
+ width=2
37
+ )
38
+
39
+ # Draw orbiting dots with trails
21
40
  for i in range(num_dots):
22
41
  # Calculate dot position
23
42
  angle = (progress * 360 - i * (360 / num_dots)) % 360
@@ -32,21 +51,32 @@ def create_frame(size, progress, text=None): # We won't use text parameter anym
32
51
  for size_mult in [1.0, 0.8, 0.6]:
33
52
  current_size = int(dot_size * size_mult)
34
53
  current_opacity = int(opacity * size_mult)
54
+
55
+ # Use more vibrant color for dots
35
56
  draw.ellipse(
36
57
  (x - current_size, y - current_size,
37
58
  x + current_size, y + current_size),
38
- fill=(52, 152, 219, current_opacity) # Bright blue with fading opacity
59
+ fill=(41, 128, 185, current_opacity) # Brighter blue with fading opacity
39
60
  )
40
61
 
62
+ # Add a subtle glow effect in the center
63
+ glow_radius = 60 + 10 * math.sin(progress * 4 * math.pi)
64
+ for r in range(int(glow_radius), 0, -5):
65
+ opacity = int(100 * (r / glow_radius))
66
+ draw.ellipse(
67
+ (center_x - r, center_y - r, center_x + r, center_y + r),
68
+ fill=(52, 152, 219, opacity // 8) # Very transparent blue
69
+ )
70
+
41
71
  return img
42
72
 
43
73
  def create_splash_gif():
44
74
  size = (400, 300)
45
75
  frames = []
46
76
 
47
- # Create 60 frames for smooth animation
48
- for i in range(60):
49
- progress = i / 60
77
+ # Create 30 frames for smooth animation (reduced from 60 for smaller file size)
78
+ for i in range(30):
79
+ progress = i / 30
50
80
  frame = create_frame(size, progress)
51
81
  frames.append(frame)
52
82
 
@@ -56,9 +86,9 @@ def create_splash_gif():
56
86
  output_path,
57
87
  save_all=True,
58
88
  append_images=frames[1:],
59
- duration=50, # 50ms per frame = 20fps
89
+ duration=66, # 66ms per frame = ~15fps (reduced from 20fps for smaller file size)
60
90
  loop=0,
61
- optimize=False
91
+ optimize=True # Enable optimization
62
92
  )
63
93
  print(f"Created splash screen GIF at: {output_path}")
64
94
 
Binary file
Binary file
Binary file
Binary file
sqlshell/setup.py CHANGED
@@ -21,7 +21,7 @@ setup(
21
21
  },
22
22
  author="SQLShell Team",
23
23
  description="A powerful SQL shell with GUI interface for data analysis",
24
- long_description=open('README.md').read(),
24
+ long_description=open('README.md', encoding='utf-8').read(),
25
25
  long_description_content_type="text/markdown",
26
26
  keywords="sql, data analysis, gui, duckdb",
27
27
  url="https://github.com/yourusername/sqlshell",