dataframe-textual 1.1.5__tar.gz → 1.3.9__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataframe-textual
3
- Version: 1.1.5
3
+ Version: 1.3.9
4
4
  Summary: Interactive terminal viewer/editor for tabular data
5
5
  Project-URL: Homepage, https://github.com/need47/dataframe-textual
6
6
  Project-URL: Repository, https://github.com/need47/dataframe-textual.git
@@ -29,7 +29,7 @@ Classifier: Topic :: Utilities
29
29
  Classifier: Typing :: Typed
30
30
  Requires-Python: >=3.11
31
31
  Requires-Dist: polars>=1.34.0
32
- Requires-Dist: textual>=6.5.0
32
+ Requires-Dist: textual[syntax]>=6.5.0
33
33
  Provides-Extra: dev
34
34
  Requires-Dist: textual-dev>=1.8.0; extra == 'dev'
35
35
  Provides-Extra: excel
@@ -45,11 +45,11 @@ A powerful, interactive terminal-based viewer/editor for CSV/TSV/Excel/Parquet/J
45
45
 
46
46
  ## Features
47
47
 
48
- ### Core Data Viewing
48
+ ### Data Viewing
49
49
  - 🚀 **Fast Loading** - Powered by Polars for efficient data handling
50
- - 🎨 **Rich Terminal UI** - Beautiful, color-coded columns with automatic type detection
50
+ - 🎨 **Rich Terminal UI** - Beautiful, color-coded columns with various data types (e.g., integer, float, string)
51
51
  - ⌨️ **Comprehensive Keyboard Navigation** - Intuitive controls for browsing, editing, and manipulating data
52
- - 📊 **Flexible Input** - Read from files or stdin (pipes/redirects)
52
+ - 📊 **Flexible Input** - Read from files and/or stdin (pipes/redirects)
53
53
  - 🔄 **Smart Pagination** - Lazy load rows on demand for handling large datasets
54
54
 
55
55
  ### Data Manipulation
@@ -60,7 +60,7 @@ A powerful, interactive terminal-based viewer/editor for CSV/TSV/Excel/Parquet/J
60
60
  - 💾 **Save & Undo** - Save edits back to file with full undo/redo support
61
61
 
62
62
  ### Advanced Features
63
- - 📂 **Multi-File Support** - Open multiple files in tabs for side-by-side comparison
63
+ - 📂 **Multi-File Support** - Open multiple files in separate tabs
64
64
  - 🔄 **Tab Management** - Seamlessly switch between open files with keyboard shortcuts
65
65
  - 📌 **Freeze Rows/Columns** - Keep important rows and columns visible while scrolling
66
66
  - 🎯 **Cursor Type Cycling** - Switch between cell, row, and column selection modes
@@ -161,7 +161,7 @@ When multiple files are opened:
161
161
  |-----|--------|
162
162
  | `Ctrl+O` | Open file in a new tab |
163
163
  | `Ctrl+W` | Close current tab |
164
- | `Ctrl+Shift+S` | Save all open tabs to Excel file |
164
+ | `Ctrl+A` | Save all open tabs to Excel file |
165
165
  | `>` or `b` | Move to next tab |
166
166
  | `<` | Move to previous tab |
167
167
  | `B` | Toggle tab bar visibility |
@@ -171,7 +171,7 @@ When multiple files are opened:
171
171
 
172
172
  | Key | Action |
173
173
  |-----|--------|
174
- | `Ctrl+H` | Toggle help panel |
174
+ | `F1` | Toggle help panel |
175
175
  | `k` | Cycle through themes |
176
176
 
177
177
  ---
@@ -206,17 +206,21 @@ When multiple files are opened:
206
206
  | Key | Action |
207
207
  |-----|--------|
208
208
  | `Double-click` | Edit cell or rename column header |
209
- | `X` | Clear current cell (set to NULL) |
209
+ | `delete` | Clear current cell (set to NULL) |
210
210
  | `e` | Edit current cell (respects data type) |
211
211
  | `E` | Edit entire column with expression |
212
212
  | `a` | Add empty column after current |
213
213
  | `A` | Add column with name and value/expression |
214
214
  | `-` (minus) | Delete current column |
215
+ | `_` (underscore) | Delete current column and all columns after |
216
+ | `Ctrl+_` | Delete current column and all columns before |
215
217
  | `x` | Delete current row |
218
+ | `X` | Delete current row and all rows below |
219
+ | `Ctrl+X` | Delete current row and all rows above |
216
220
  | `d` | Duplicate current column (appends '_copy' suffix) |
217
221
  | `D` | Duplicate current row |
218
222
  | `h` | Hide current column |
219
- | `H` | Show all hidden columns |
223
+ | `H` | Show all hidden rows/columns |
220
224
 
221
225
  #### Searching & Filtering
222
226
 
@@ -237,6 +241,13 @@ When multiple files are opened:
237
241
  | `v` | View only rows by selected rows and/or matches or cursor value |
238
242
  | `V` | View only rows by expression |
239
243
 
244
+ #### SQL Interface
245
+
246
+ | Key | Action |
247
+ |-----|--------|
248
+ | `l` | Simple SQL interface (select columns & WHERE clause) |
249
+ | `L` | Advanced SQL interface (full SQL queries) |
250
+
240
251
  #### Find & Replace
241
252
 
242
253
  | Key | Action |
@@ -283,7 +294,8 @@ When multiple files are opened:
283
294
  | `Ctrl+R` | Copy row to clipboard (tab-separated) |
284
295
  | `Ctrl+S` | Save current tab to file |
285
296
  | `u` | Undo last action |
286
- | `U` | Reset to original data |
297
+ | `U` | Redo last undone action |
298
+ | `Ctrl+U` | Reset to initial state |
287
299
 
288
300
  ## Features in Detail
289
301
 
@@ -512,7 +524,7 @@ Press `F` to see how many times each value appears in the current column. The mo
512
524
  **In the Frequency Table**:
513
525
  - Press `[` and `]` to sort by any column (value, count, or percentage)
514
526
  - Press `v` to **filter** the main table to show only rows with the selected value
515
- - Press `"` to **highlight** all rows containing the selected value
527
+ - Press `"` to **exclude** all rows except those containing the selected value
516
528
  - Press `q` or `Escape` to close the frequency table
517
529
 
518
530
  This is useful for:
@@ -560,9 +572,25 @@ This is useful for:
560
572
  - Delete all selected rows (if any) at once
561
573
  - Or delete single row at cursor
562
574
 
575
+ **Delete Row and Below** (`X`):
576
+ - Deletes the current row and all rows below it
577
+ - Useful for removing trailing data or the end of a dataset
578
+
579
+ **Delete Row and Above** (`Ctrl+X`):
580
+ - Deletes the current row and all rows above it
581
+ - Useful for removing leading rows or the beginning of a dataset
582
+
563
583
  **Delete Column** (`-`):
564
584
  - Removes the entire column from view and dataframe
565
585
 
586
+ **Delete Column and After** (`_`):
587
+ - Deletes the current column and all columns to the right
588
+ - Useful for removing trailing columns or the end of a dataset
589
+
590
+ **Delete Column and Before** (`Ctrl+-`):
591
+ - Deletes the current column and all columns to the left
592
+ - Useful for removing leading columns or the beginning of a dataset
593
+
566
594
  ### 9. Hide & Show Columns
567
595
 
568
596
  **Hide Column** (`h`):
@@ -570,9 +598,8 @@ This is useful for:
570
598
  - Column data is preserved in the dataframe
571
599
  - Hidden columns are included in saves
572
600
 
573
- **Show Hidden Columns** (`H`):
574
- - Restores all previously hidden columns to the display
575
- - Returns table to full column view
601
+ **Show Hidden Rows/Columns** (`H`):
602
+ - Restores all previously hidden rows/columns to the display
576
603
 
577
604
  This is useful for:
578
605
  - Focusing on specific columns without deleting data
@@ -634,14 +661,23 @@ Press `Ctrl+S` to save:
634
661
  - Choose filename in modal dialog
635
662
  - Confirm if file already exists
636
663
 
637
- ### 15. Undo/Redo
664
+ ### 15. Undo/Redo/Reset
638
665
 
639
- Press `u` to undo:
666
+ **Undo** (`u`):
640
667
  - Reverts last action with full state restoration
641
668
  - Works for edits, deletions, sorts, searches, etc.
642
669
  - Shows description of reverted action
643
670
 
644
- Press `U` to revert to when data was initially loaded
671
+ **Redo** (`U`):
672
+ - Reapplies the last undone action
673
+ - Restores the state before the undo was performed
674
+ - Useful for redoing actions you've undone by mistake
675
+ - Useful for alternating between two different states
676
+
677
+ **Reset** (`Ctrl+U`):
678
+ - Reverts all changes and returns to original data state when file was first loaded
679
+ - Clears all edits, deletions, selections, filters, and sorts
680
+ - Useful for starting fresh without reloading the file
645
681
 
646
682
  ### 16. Column Type Conversion
647
683
 
@@ -674,7 +710,40 @@ Press `@` to make URLs in the current column clickable:
674
710
  - **Scans** all cells in the current column for URLs starting with `http://` or `https://`
675
711
  - **Applies** link styling to make them clickable and dataframe remains unchanged
676
712
 
677
- ### 19. Clipboard Operations
713
+ ### 19. SQL Interface
714
+
715
+ The SQL interface provides two modes for querying your dataframe:
716
+
717
+ #### Simple SQL Interface (`l`)
718
+ Select specific columns and apply WHERE conditions without writing full SQL:
719
+ - Choose which columns to include in results
720
+ - Specify WHERE clause for filtering
721
+ - Ideal for quick filtering and column selection
722
+
723
+ #### Advanced SQL Interface (`L`)
724
+ Execute complete SQL queries for advanced data manipulation:
725
+ - Write full SQL queries with standard [SQL syntax](https://docs.pola.rs/api/python/stable/reference/sql/index.html)
726
+ - Support for JOINs, GROUP BY, aggregations, and more
727
+ - Access to all SQL capabilities for complex transformations
728
+ - Always use `self` as the table name
729
+
730
+ **Examples:**
731
+ ```sql
732
+ -- Filter and select specific rows and/or columns
733
+ SELECT name, age FROM self WHERE age > 30
734
+
735
+ -- Aggregate with GROUP BY
736
+ SELECT department, COUNT(*) as count, AVG(salary) as avg_salary
737
+ FROM self
738
+ GROUP BY department
739
+
740
+ -- Complex filtering with multiple conditions
741
+ SELECT *
742
+ FROM self
743
+ WHERE (age > 25 AND salary > 50000) OR department = 'Management'
744
+ ```
745
+
746
+ ### 20. Clipboard Operations
678
747
 
679
748
  Copies value to system clipboard with `pbcopy` on macOS and `xclip` on Linux
680
749
 
@@ -6,11 +6,11 @@ A powerful, interactive terminal-based viewer/editor for CSV/TSV/Excel/Parquet/J
6
6
 
7
7
  ## Features
8
8
 
9
- ### Core Data Viewing
9
+ ### Data Viewing
10
10
  - 🚀 **Fast Loading** - Powered by Polars for efficient data handling
11
- - 🎨 **Rich Terminal UI** - Beautiful, color-coded columns with automatic type detection
11
+ - 🎨 **Rich Terminal UI** - Beautiful, color-coded columns with various data types (e.g., integer, float, string)
12
12
  - ⌨️ **Comprehensive Keyboard Navigation** - Intuitive controls for browsing, editing, and manipulating data
13
- - 📊 **Flexible Input** - Read from files or stdin (pipes/redirects)
13
+ - 📊 **Flexible Input** - Read from files and/or stdin (pipes/redirects)
14
14
  - 🔄 **Smart Pagination** - Lazy load rows on demand for handling large datasets
15
15
 
16
16
  ### Data Manipulation
@@ -21,7 +21,7 @@ A powerful, interactive terminal-based viewer/editor for CSV/TSV/Excel/Parquet/J
21
21
  - 💾 **Save & Undo** - Save edits back to file with full undo/redo support
22
22
 
23
23
  ### Advanced Features
24
- - 📂 **Multi-File Support** - Open multiple files in tabs for side-by-side comparison
24
+ - 📂 **Multi-File Support** - Open multiple files in separate tabs
25
25
  - 🔄 **Tab Management** - Seamlessly switch between open files with keyboard shortcuts
26
26
  - 📌 **Freeze Rows/Columns** - Keep important rows and columns visible while scrolling
27
27
  - 🎯 **Cursor Type Cycling** - Switch between cell, row, and column selection modes
@@ -122,7 +122,7 @@ When multiple files are opened:
122
122
  |-----|--------|
123
123
  | `Ctrl+O` | Open file in a new tab |
124
124
  | `Ctrl+W` | Close current tab |
125
- | `Ctrl+Shift+S` | Save all open tabs to Excel file |
125
+ | `Ctrl+A` | Save all open tabs to Excel file |
126
126
  | `>` or `b` | Move to next tab |
127
127
  | `<` | Move to previous tab |
128
128
  | `B` | Toggle tab bar visibility |
@@ -132,7 +132,7 @@ When multiple files are opened:
132
132
 
133
133
  | Key | Action |
134
134
  |-----|--------|
135
- | `Ctrl+H` | Toggle help panel |
135
+ | `F1` | Toggle help panel |
136
136
  | `k` | Cycle through themes |
137
137
 
138
138
  ---
@@ -167,17 +167,21 @@ When multiple files are opened:
167
167
  | Key | Action |
168
168
  |-----|--------|
169
169
  | `Double-click` | Edit cell or rename column header |
170
- | `X` | Clear current cell (set to NULL) |
170
+ | `delete` | Clear current cell (set to NULL) |
171
171
  | `e` | Edit current cell (respects data type) |
172
172
  | `E` | Edit entire column with expression |
173
173
  | `a` | Add empty column after current |
174
174
  | `A` | Add column with name and value/expression |
175
175
  | `-` (minus) | Delete current column |
176
+ | `_` (underscore) | Delete current column and all columns after |
177
+ | `Ctrl+_` | Delete current column and all columns before |
176
178
  | `x` | Delete current row |
179
+ | `X` | Delete current row and all rows below |
180
+ | `Ctrl+X` | Delete current row and all rows above |
177
181
  | `d` | Duplicate current column (appends '_copy' suffix) |
178
182
  | `D` | Duplicate current row |
179
183
  | `h` | Hide current column |
180
- | `H` | Show all hidden columns |
184
+ | `H` | Show all hidden rows/columns |
181
185
 
182
186
  #### Searching & Filtering
183
187
 
@@ -198,6 +202,13 @@ When multiple files are opened:
198
202
  | `v` | View only rows by selected rows and/or matches or cursor value |
199
203
  | `V` | View only rows by expression |
200
204
 
205
+ #### SQL Interface
206
+
207
+ | Key | Action |
208
+ |-----|--------|
209
+ | `l` | Simple SQL interface (select columns & WHERE clause) |
210
+ | `L` | Advanced SQL interface (full SQL queries) |
211
+
201
212
  #### Find & Replace
202
213
 
203
214
  | Key | Action |
@@ -244,7 +255,8 @@ When multiple files are opened:
244
255
  | `Ctrl+R` | Copy row to clipboard (tab-separated) |
245
256
  | `Ctrl+S` | Save current tab to file |
246
257
  | `u` | Undo last action |
247
- | `U` | Reset to original data |
258
+ | `U` | Redo last undone action |
259
+ | `Ctrl+U` | Reset to initial state |
248
260
 
249
261
  ## Features in Detail
250
262
 
@@ -473,7 +485,7 @@ Press `F` to see how many times each value appears in the current column. The mo
473
485
  **In the Frequency Table**:
474
486
  - Press `[` and `]` to sort by any column (value, count, or percentage)
475
487
  - Press `v` to **filter** the main table to show only rows with the selected value
476
- - Press `"` to **highlight** all rows containing the selected value
488
+ - Press `"` to **exclude** all rows except those containing the selected value
477
489
  - Press `q` or `Escape` to close the frequency table
478
490
 
479
491
  This is useful for:
@@ -521,9 +533,25 @@ This is useful for:
521
533
  - Delete all selected rows (if any) at once
522
534
  - Or delete single row at cursor
523
535
 
536
+ **Delete Row and Below** (`X`):
537
+ - Deletes the current row and all rows below it
538
+ - Useful for removing trailing data or the end of a dataset
539
+
540
+ **Delete Row and Above** (`Ctrl+X`):
541
+ - Deletes the current row and all rows above it
542
+ - Useful for removing leading rows or the beginning of a dataset
543
+
524
544
  **Delete Column** (`-`):
525
545
  - Removes the entire column from view and dataframe
526
546
 
547
+ **Delete Column and After** (`_`):
548
+ - Deletes the current column and all columns to the right
549
+ - Useful for removing trailing columns or the end of a dataset
550
+
551
+ **Delete Column and Before** (`Ctrl+-`):
552
+ - Deletes the current column and all columns to the left
553
+ - Useful for removing leading columns or the beginning of a dataset
554
+
527
555
  ### 9. Hide & Show Columns
528
556
 
529
557
  **Hide Column** (`h`):
@@ -531,9 +559,8 @@ This is useful for:
531
559
  - Column data is preserved in the dataframe
532
560
  - Hidden columns are included in saves
533
561
 
534
- **Show Hidden Columns** (`H`):
535
- - Restores all previously hidden columns to the display
536
- - Returns table to full column view
562
+ **Show Hidden Rows/Columns** (`H`):
563
+ - Restores all previously hidden rows/columns to the display
537
564
 
538
565
  This is useful for:
539
566
  - Focusing on specific columns without deleting data
@@ -595,14 +622,23 @@ Press `Ctrl+S` to save:
595
622
  - Choose filename in modal dialog
596
623
  - Confirm if file already exists
597
624
 
598
- ### 15. Undo/Redo
625
+ ### 15. Undo/Redo/Reset
599
626
 
600
- Press `u` to undo:
627
+ **Undo** (`u`):
601
628
  - Reverts last action with full state restoration
602
629
  - Works for edits, deletions, sorts, searches, etc.
603
630
  - Shows description of reverted action
604
631
 
605
- Press `U` to revert to when data was initially loaded
632
+ **Redo** (`U`):
633
+ - Reapplies the last undone action
634
+ - Restores the state before the undo was performed
635
+ - Useful for redoing actions you've undone by mistake
636
+ - Useful for alternating between two different states
637
+
638
+ **Reset** (`Ctrl+U`):
639
+ - Reverts all changes and returns to original data state when file was first loaded
640
+ - Clears all edits, deletions, selections, filters, and sorts
641
+ - Useful for starting fresh without reloading the file
606
642
 
607
643
  ### 16. Column Type Conversion
608
644
 
@@ -635,7 +671,40 @@ Press `@` to make URLs in the current column clickable:
635
671
  - **Scans** all cells in the current column for URLs starting with `http://` or `https://`
636
672
  - **Applies** link styling to make them clickable and dataframe remains unchanged
637
673
 
638
- ### 19. Clipboard Operations
674
+ ### 19. SQL Interface
675
+
676
+ The SQL interface provides two modes for querying your dataframe:
677
+
678
+ #### Simple SQL Interface (`l`)
679
+ Select specific columns and apply WHERE conditions without writing full SQL:
680
+ - Choose which columns to include in results
681
+ - Specify WHERE clause for filtering
682
+ - Ideal for quick filtering and column selection
683
+
684
+ #### Advanced SQL Interface (`L`)
685
+ Execute complete SQL queries for advanced data manipulation:
686
+ - Write full SQL queries with standard [SQL syntax](https://docs.pola.rs/api/python/stable/reference/sql/index.html)
687
+ - Support for JOINs, GROUP BY, aggregations, and more
688
+ - Access to all SQL capabilities for complex transformations
689
+ - Always use `self` as the table name
690
+
691
+ **Examples:**
692
+ ```sql
693
+ -- Filter and select specific rows and/or columns
694
+ SELECT name, age FROM self WHERE age > 30
695
+
696
+ -- Aggregate with GROUP BY
697
+ SELECT department, COUNT(*) as count, AVG(salary) as avg_salary
698
+ FROM self
699
+ GROUP BY department
700
+
701
+ -- Complex filtering with multiple conditions
702
+ SELECT *
703
+ FROM self
704
+ WHERE (age > 25 AND salary > 50000) OR department = 'Management'
705
+ ```
706
+
707
+ ### 20. Clipboard Operations
639
708
 
640
709
  Copies value to system clipboard with `pbcopy` on macOS and `xclip` on Linux
641
710
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "dataframe-textual"
7
- version = "1.1.5"
7
+ version = "1.3.9"
8
8
  description = "Interactive terminal viewer/editor for tabular data"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -34,7 +34,7 @@ classifiers = [
34
34
  ]
35
35
  dependencies = [
36
36
  "polars>=1.34.0",
37
- "textual>=6.5.0",
37
+ "textual[syntax]>=6.5.0",
38
38
  ]
39
39
 
40
40
  [project.urls]
@@ -69,4 +69,5 @@ dev = [
69
69
  ]
70
70
 
71
71
  [project.scripts]
72
+ dataframe-textual = "dataframe_textual.__main__:main"
72
73
  dv = "dataframe_textual.__main__:main"
@@ -133,7 +133,7 @@ def format_float(value: float, thousand_separator: bool = False, precision: int
133
133
  return f"{value:,f}" if thousand_separator else str(value)
134
134
 
135
135
 
136
- def format_row(vals, dtypes, apply_justify=True, thousand_separator=False) -> list[Text]:
136
+ def format_row(vals, dtypes, styles=None, apply_justify=True, thousand_separator=False) -> list[Text]:
137
137
  """Format a single row with proper styling and justification.
138
138
 
139
139
  Converts raw row values to formatted Rich Text objects with appropriate
@@ -149,7 +149,7 @@ def format_row(vals, dtypes, apply_justify=True, thousand_separator=False) -> li
149
149
  """
150
150
  formatted_row = []
151
151
 
152
- for val, dtype in zip(vals, dtypes, strict=True):
152
+ for idx, (val, dtype) in enumerate(zip(vals, dtypes, strict=True)):
153
153
  dc = DtypeConfig(dtype)
154
154
 
155
155
  # Format the value
@@ -165,7 +165,7 @@ def format_row(vals, dtypes, apply_justify=True, thousand_separator=False) -> li
165
165
  formatted_row.append(
166
166
  Text(
167
167
  text_val,
168
- style=dc.style,
168
+ style=styles[idx] if styles and styles[idx] else dc.style,
169
169
  justify=dc.justify if apply_justify else "",
170
170
  )
171
171
  )
@@ -216,7 +216,7 @@ def get_next_item(lst: list[Any], current, offset=1) -> Any:
216
216
  return lst[next_index]
217
217
 
218
218
 
219
- def parse_polars_expression(expression: str, df: pl.DataFrame, current_col_idx: int) -> str:
219
+ def parse_polars_expression(expression: str, columns: list[str], current_col_idx: int) -> str:
220
220
  """Parse and convert an expression to Polars syntax.
221
221
 
222
222
  Replaces column references with Polars col() expressions:
@@ -234,7 +234,7 @@ def parse_polars_expression(expression: str, df: pl.DataFrame, current_col_idx:
234
234
 
235
235
  Args:
236
236
  expression: The input expression as a string.
237
- df: The DataFrame to validate column references.
237
+ columns: The list of column names in the DataFrame.
238
238
  current_col_idx: The index of the currently selected column (0-based). Used for $_ reference.
239
239
 
240
240
  Returns:
@@ -264,19 +264,19 @@ def parse_polars_expression(expression: str, df: pl.DataFrame, current_col_idx:
264
264
 
265
265
  if col_ref == "_":
266
266
  # Current selected column
267
- col_name = df.columns[current_col_idx]
267
+ col_name = columns[current_col_idx]
268
268
  elif col_ref == "#":
269
269
  # RIDX is used to store 0-based row index; add 1 for 1-based index
270
270
  return f"(pl.col('{RIDX}') + 1)"
271
271
  elif col_ref.isdigit():
272
272
  # Column by 1-based index
273
273
  col_idx = int(col_ref) - 1
274
- if col_idx < 0 or col_idx >= len(df.columns):
274
+ if col_idx < 0 or col_idx >= len(columns):
275
275
  raise ValueError(f"Column index out of range: ${col_ref}")
276
- col_name = df.columns[col_idx]
276
+ col_name = columns[col_idx]
277
277
  else:
278
278
  # Column by name
279
- if col_ref not in df.columns:
279
+ if col_ref not in columns:
280
280
  raise ValueError(f"Column not found: ${col_ref}")
281
281
  col_name = col_ref
282
282
 
@@ -305,7 +305,7 @@ def tentative_expr(term: str) -> bool:
305
305
  return False
306
306
 
307
307
 
308
- def validate_expr(term: str, df: pl.DataFrame, current_col_idx: int) -> pl.Expr | None:
308
+ def validate_expr(term: str, columns: list[str], current_col_idx: int) -> pl.Expr | None:
309
309
  """Validate and return the expression.
310
310
 
311
311
  Parses a user-provided expression string and validates it as a valid Polars expression.
@@ -313,7 +313,7 @@ def validate_expr(term: str, df: pl.DataFrame, current_col_idx: int) -> pl.Expr
313
313
 
314
314
  Args:
315
315
  term: The input expression as a string.
316
- df: The DataFrame to validate column references against.
316
+ columns: The list of column names in the DataFrame.
317
317
  current_col_idx: The index of the currently selected column (0-based). Used for $_ reference.
318
318
 
319
319
  Returns:
@@ -326,7 +326,7 @@ def validate_expr(term: str, df: pl.DataFrame, current_col_idx: int) -> pl.Expr
326
326
 
327
327
  try:
328
328
  # Parse the expression
329
- expr_str = parse_polars_expression(term, df, current_col_idx)
329
+ expr_str = parse_polars_expression(term, columns, current_col_idx)
330
330
 
331
331
  # Validate by evaluating it
332
332
  try:
@@ -440,6 +440,9 @@ def load_file(
440
440
  sources.append((lf, filename, filepath.stem))
441
441
  else:
442
442
  ext = filepath.suffix.lower()
443
+ if ext == ".gz" or ext == ".bz2" or ext == ".xz":
444
+ ext = filepath.with_suffix("").suffix.lower()
445
+
443
446
  if ext == ".csv":
444
447
  file_format = "csv"
445
448
  elif ext in (".xlsx", ".xls"):
@@ -459,3 +462,21 @@ def load_file(
459
462
  sources.extend(load_file(filename, first_sheet, prefix_sheet, file_format, has_header))
460
463
 
461
464
  return sources
465
+
466
+
467
+ def now() -> str:
468
+ """Get the current local time as a formatted string."""
469
+ import time
470
+
471
+ return time.strftime("%m/%d/%Y %H:%M:%S", time.localtime())
472
+
473
+
474
+ async def sleep_async(seconds: float) -> None:
475
+ """Async sleep to yield control back to the event loop.
476
+
477
+ Args:
478
+ seconds: The number of seconds to sleep.
479
+ """
480
+ import asyncio
481
+
482
+ await asyncio.sleep(seconds)
@@ -79,10 +79,12 @@ class DataFrameHelpPanel(Widget):
79
79
  None
80
80
  """
81
81
 
82
- def update_help(focused_widget: Widget | None):
83
- self.update_help(focused_widget)
82
+ # def update_help(focused_widget: Widget | None):
83
+ # self.update_help(focused_widget)
84
84
 
85
- self.watch(self.screen, "focused", update_help)
85
+ # self.watch(self.screen, "focused", update_help)
86
+
87
+ self.update_help(self.screen.focused)
86
88
 
87
89
  def update_help(self, focused_widget: Widget | None) -> None:
88
90
  """Update the help for the focused widget.
@@ -96,7 +98,7 @@ class DataFrameHelpPanel(Widget):
96
98
  return
97
99
  self.set_class(focused_widget is not None, "-show-help")
98
100
  if focused_widget is not None:
99
- help = self.app.HELP + "\n" + focused_widget.HELP or ""
101
+ help = (self.app.HELP or "") + "\n" + (focused_widget.HELP or "")
100
102
  if not help:
101
103
  self.remove_class("-show-help")
102
104
  try: