dataframe-textual 0.3.2__py3-none-any.whl → 1.5.0__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.
@@ -0,0 +1,202 @@
1
+ """Modal screens for Polars sql manipulation"""
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from .data_frame_table import DataFrameTable
7
+
8
+ import polars as pl
9
+ from textual.app import ComposeResult
10
+ from textual.containers import Container, Horizontal
11
+ from textual.screen import ModalScreen
12
+ from textual.widgets import Button, Input, Label, SelectionList, TextArea
13
+ from textual.widgets.selection_list import Selection
14
+
15
+
16
+ class SqlScreen(ModalScreen):
17
+ """Base class for modal screens handling SQL query."""
18
+
19
+ DEFAULT_CSS = """
20
+ SqlScreen {
21
+ align: center middle;
22
+ }
23
+
24
+ SqlScreen > Container {
25
+ width: auto;
26
+ height: auto;
27
+ border: heavy $accent;
28
+ border-title-color: $accent;
29
+ border-title-background: $panel;
30
+ border-title-style: bold;
31
+ background: $background;
32
+ padding: 1 2;
33
+ overflow: auto;
34
+ }
35
+
36
+ #button-container {
37
+ width: auto;
38
+ margin: 1 0 0 0;
39
+ height: 3;
40
+ align: center middle;
41
+ }
42
+
43
+ Button {
44
+ margin: 0 2;
45
+ }
46
+
47
+ """
48
+
49
+ def __init__(self, dftable: "DataFrameTable", on_yes_callback=None) -> None:
50
+ """Initialize the SQL screen."""
51
+ super().__init__()
52
+ self.dftable = dftable # DataFrameTable
53
+ self.df: pl.DataFrame = dftable.df # Polars DataFrame
54
+ self.on_yes_callback = on_yes_callback
55
+
56
+ def compose(self) -> ComposeResult:
57
+ """Compose the SQL screen widget structure."""
58
+ # Shared by subclasses
59
+ with Horizontal(id="button-container"):
60
+ yield Button("Apply", id="yes", variant="success")
61
+ yield Button("Cancel", id="no", variant="error")
62
+
63
+ def on_key(self, event) -> None:
64
+ """Handle key press events in the SQL screen"""
65
+ if event.key in ("q", "escape"):
66
+ self.app.pop_screen()
67
+ event.stop()
68
+ elif event.key == "enter":
69
+ self._handle_yes()
70
+ event.stop()
71
+ elif event.key == "escape":
72
+ self.dismiss(None)
73
+ event.stop()
74
+
75
+ def on_button_pressed(self, event: Button.Pressed) -> None:
76
+ """Handle button press events in the SQL screen."""
77
+ if event.button.id == "yes":
78
+ self._handle_yes()
79
+ elif event.button.id == "no":
80
+ self.dismiss(None)
81
+
82
+ def _handle_yes(self) -> None:
83
+ """Handle Yes button/Enter key press."""
84
+ if self.on_yes_callback:
85
+ result = self.on_yes_callback()
86
+ self.dismiss(result)
87
+ else:
88
+ self.dismiss(True)
89
+
90
+
91
+ class SimpleSqlScreen(SqlScreen):
92
+ """Simple SQL query screen."""
93
+
94
+ DEFAULT_CSS = SqlScreen.DEFAULT_CSS.replace("SqlScreen", "SimpleSqlScreen")
95
+
96
+ CSS = """
97
+ SimpleSqlScreen SelectionList {
98
+ width: auto;
99
+ min-width: 40;
100
+ margin: 1 0;
101
+ }
102
+
103
+ SimpleSqlScreen SelectionList:blur {
104
+ border: solid $secondary;
105
+ }
106
+
107
+ SimpleSqlScreen Label {
108
+ width: auto;
109
+ }
110
+
111
+ SimpleSqlScreen Input {
112
+ width: auto;
113
+ }
114
+
115
+ SimpleSqlScreen Input:blur {
116
+ border: solid $secondary;
117
+ }
118
+
119
+ #button-container {
120
+ min-width: 40;
121
+ }
122
+ """
123
+
124
+ def __init__(self, dftable: "DataFrameTable") -> None:
125
+ """Initialize the simple SQL screen.
126
+
127
+ Sets up the modal screen with reference to the main DataFrameTable widget
128
+ and stores the DataFrame for display.
129
+
130
+ Args:
131
+ dftable: Reference to the parent DataFrameTable widget.
132
+
133
+ Returns:
134
+ None
135
+ """
136
+ super().__init__(dftable, on_yes_callback=self._handle_simple)
137
+
138
+ def compose(self) -> ComposeResult:
139
+ """Compose the simple SQL screen widget structure."""
140
+ with Container(id="sql-container") as container:
141
+ container.border_title = "SQL Query"
142
+ yield Label("Select columns (default to all):", id="select-label")
143
+ yield SelectionList(*[Selection(col, col) for col in self.df.columns], id="column-selection")
144
+ yield Label("Where condition (optional)", id="where-label")
145
+ yield Input(placeholder="e.g., age > 30 and height < 180", id="where-input")
146
+ yield from super().compose()
147
+
148
+ def _handle_simple(self) -> None:
149
+ """Handle Yes button/Enter key press."""
150
+ selections = self.query_one(SelectionList).selected
151
+ columns = ", ".join(f"`{s}`" for s in selections) if selections else "*"
152
+ where = self.query_one(Input).value.strip()
153
+
154
+ return columns, where
155
+
156
+
157
+ class AdvancedSqlScreen(SqlScreen):
158
+ """Advanced SQL query screen."""
159
+
160
+ DEFAULT_CSS = SqlScreen.DEFAULT_CSS.replace("SqlScreen", "AdvancedSqlScreen")
161
+
162
+ CSS = """
163
+ AdvancedSqlScreen TextArea {
164
+ width: auto;
165
+ min-width: 60;
166
+ height: auto;
167
+ min-height: 10;
168
+ }
169
+
170
+ #button-container {
171
+ min-width: 60;
172
+ }
173
+ """
174
+
175
+ def __init__(self, dftable: "DataFrameTable") -> None:
176
+ """Initialize the simple SQL screen.
177
+
178
+ Sets up the modal screen with reference to the main DataFrameTable widget
179
+ and stores the DataFrame for display.
180
+
181
+ Args:
182
+ dftable: Reference to the parent DataFrameTable widget.
183
+
184
+ Returns:
185
+ None
186
+ """
187
+ super().__init__(dftable, on_yes_callback=self._handle_advanced)
188
+
189
+ def compose(self) -> ComposeResult:
190
+ """Compose the advanced SQL screen widget structure."""
191
+ with Container(id="sql-container") as container:
192
+ container.border_title = "Advanced SQL Query"
193
+ yield TextArea.code_editor(
194
+ placeholder="Enter SQL query (use `self` as the table name), e.g., \n\nSELECT * \nFROM self \nWHERE age > 30",
195
+ id="sql-textarea",
196
+ language="sql",
197
+ )
198
+ yield from super().compose()
199
+
200
+ def _handle_advanced(self) -> None:
201
+ """Handle Yes button/Enter key press."""
202
+ return self.query_one(TextArea).text.strip()