dataframe-textual 2.2.2__tar.gz → 2.11.0__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.
Files changed (19) hide show
  1. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/PKG-INFO +49 -38
  2. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/README.md +48 -37
  3. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/pyproject.toml +3 -1
  4. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/src/dataframe_textual/__main__.py +24 -4
  5. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/src/dataframe_textual/common.py +15 -10
  6. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/src/dataframe_textual/data_frame_table.py +306 -322
  7. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/src/dataframe_textual/data_frame_viewer.py +238 -78
  8. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/src/dataframe_textual/table_screen.py +94 -12
  9. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/src/dataframe_textual/yes_no_screen.py +1 -7
  10. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/uv.lock +1 -1
  11. dataframe_textual-2.2.2/1811.csv.gz +0 -0
  12. dataframe_textual-2.2.2/large_malformed.tsv.gz +0 -0
  13. dataframe_textual-2.2.2/x +0 -40532
  14. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/.gitignore +0 -0
  15. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/LICENSE +0 -0
  16. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/main.py +0 -0
  17. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/src/dataframe_textual/__init__.py +0 -0
  18. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/src/dataframe_textual/data_frame_help_panel.py +0 -0
  19. {dataframe_textual-2.2.2 → dataframe_textual-2.11.0}/src/dataframe_textual/sql_screen.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataframe-textual
3
- Version: 2.2.2
3
+ Version: 2.11.0
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
@@ -39,7 +39,7 @@ Description-Content-Type: text/markdown
39
39
 
40
40
  # DataFrame Textual
41
41
 
42
- A powerful, interactive terminal-based viewer/editor for CSV/TSV/Excel/Parquet/JSON/NDJSON built with Python, [Polars](https://pola.rs/), and [Textual](https://textual.textualize.io/). Inspired by [VisiData](https://www.visidata.org/), this tool provides smooth keyboard navigation, data manipulation, and a clean interface for exploring tabular data directly in terminal with multi-tab support for multiple files!
42
+ A powerful, interactive terminal-based viewer/editor for CSV/TSV/PSV/Excel/Parquet/JSON/NDJSON built with Python, [Polars](https://pola.rs/), and [Textual](https://textual.textualize.io/). Inspired by [VisiData](https://www.visidata.org/), this tool provides smooth keyboard navigation, data manipulation, and a clean interface for exploring tabular data directly in terminal with multi-tab support for multiple files!
43
43
 
44
44
  ![Screenshot](https://raw.githubusercontent.com/need47/dataframe-textual/refs/heads/main/screenshot.png)
45
45
 
@@ -167,28 +167,32 @@ When multiple files are opened:
167
167
  ## Command Line Options
168
168
 
169
169
  ```
170
- usage: dv [-h] [-f {csv,excel,tsv,parquet,json,ndjson}] [-H] [-I] [-E] [-c COMMENT_PREFIX] [-q QUOTE_CHAR] [-l SKIP_LINES] [-a SKIP_ROWS_AFTER_HEADER] [-n NULL [NULL ...]] [files ...]
170
+ usage: dv [-h] [-V] [-f {csv,json,xlsx,xls,ndjson,psv,parquet,tsv}] [-H] [-I] [-t] [-E] [-c [COMMENT_PREFIX]] [-q [QUOTE_CHAR]] [-l SKIP_LINES] [-a SKIP_ROWS_AFTER_HEADER] [-n NULL [NULL ...]] [files ...]
171
171
 
172
- Interactive terminal based viewer/editor for tabular data (e.g., CSV/TSV/Excel).
172
+ Interactive terminal based viewer/editor for tabular data (e.g., CSV/Excel).
173
173
 
174
174
  positional arguments:
175
- files Input files (or read from stdin)
175
+ files Files to view (or read from stdin)
176
176
 
177
177
  options:
178
178
  -h, --help show this help message and exit
179
- -f, --format {csv,excel,tsv,parquet,json,ndjson}
180
- Specify the format of the input files
181
- -H, --no-header Specify that input files have no header row
182
- -I, --no-inference Do not infer data types when reading CSV/TSV
179
+ -V, --version show program's version number and exit
180
+ -f, --format {csv,json,xlsx,xls,ndjson,psv,parquet,tsv}
181
+ Specify the format of the input files (csv, tsv etc.)
182
+ -H, --no-header Specify that input files have no header row when reading CSV/TSV
183
+ -I, --no-inference Do not infer data types when reading CSV/TSV
184
+ -t, --truncate-ragged-lines
185
+ Truncate ragged lines when reading CSV/TSV
183
186
  -E, --ignore-errors Ignore errors when reading CSV/TSV
184
- -c, --comment-prefix COMMENT_PREFIX
185
- Comment lines are skipped when reading CSV/TSV (default: skip none)
186
- -q, --quote-char QUOTE_CHAR
187
- Quote character for reading CSV/TSV (default: "; use -q without argument value to disable)
188
- -l, --skip-lines SKIP_LINES
189
- Skip lines when reading CSV/TSV (default: 0)
190
- -a, --skip-rows-after-header SKIP_ROWS_AFTER_HEADER
191
- Skip rows after header when reading CSV/TSV (default: 0)
187
+ -c, --comment-prefix [PREFIX]
188
+ Comment lines starting with `PREFIX` are skipped when reading CSV/TSV
189
+ -q, --quote-char [C]
190
+ Use `C` as quote character for reading CSV/TSV
191
+ -L, --skip-lines N
192
+ Skip first N lines when reading CSV/TSV
193
+ -A, --skip-rows-after-header N
194
+ Skip N rows after header when reading CSV/TSV
195
+ -N, --n-rows N Stop after reading N rows from CSV/TSV
192
196
  -n, --null NULL [NULL ...]
193
197
  Values to interpret as null values when reading CSV/TSV
194
198
  ```
@@ -243,11 +247,11 @@ zcat compressed_data.csv.gz | dv -f csv
243
247
  | `<` | Move to previous tab |
244
248
  | `b` | Cycle through tabs |
245
249
  | `B` | Toggle tab bar visibility |
246
- | `q` | Close current tab (prompts to save unsaved changes) |
247
- | `Q` | Close all tabs and app (prompts to save unsaved changes) |
250
+ | `q` | Quit current tab (prompts to save unsaved changes) |
251
+ | `Q` | Quit all tabs and app (prompts to save unsaved changes) |
248
252
  | `Ctrl+Q` | Force to quit app (regardless of unsaved changes) |
249
253
  | `Ctrl+T` | Save current tab to file |
250
- | `Ctrl+A` | Save all tabs to a Excel file |
254
+ | `Ctrl+S` | Save all tabs to file |
251
255
  | `w` | Save current tab to file (overwrite without prompt) |
252
256
  | `W` | Save all tabs to file (overwrite without prompt) |
253
257
  | `Ctrl+D` | Duplicate current tab |
@@ -302,15 +306,17 @@ zcat compressed_data.csv.gz | dv -f csv
302
306
  | `_` (underscore) | Toggle column full width |
303
307
  | `z` | Freeze rows and columns |
304
308
  | `,` | Toggle thousand separator for numeric display |
309
+ | `&` | Set current row as the new header row |
305
310
  | `h` | Hide current column |
306
- | `H` | Show all hidden rows/columns |
311
+ | `H` | Show all hidden columns |
307
312
 
308
- #### Data Editing
313
+ #### Editing
309
314
 
310
315
  | Key | Action |
311
316
  |-----|--------|
312
317
  | `Double-click` | Edit cell or rename column header |
313
- | `delete` | Clear current cell (set to NULL) |
318
+ | `Delete` | Clear current cell (set to NULL) |
319
+ | `Shift+Delete` | Clear current column (set matching cells to NULL) |
314
320
  | `e` | Edit current cell (respects data type) |
315
321
  | `E` | Edit entire column with value/expression |
316
322
  | `a` | Add empty column after current |
@@ -352,16 +358,10 @@ zcat compressed_data.csv.gz | dv -f csv
352
358
  | Key | Action |
353
359
  |-----|--------|
354
360
  | `"` (quote) | Filter selected rows (others removed) |
361
+ | `.` | View rows with non-null values in current column (others hidden) |
355
362
  | `v` | View selected rows (others hidden) |
356
363
  | `V` | View selected by expression (others hidden) |
357
364
 
358
- #### SQL Interface
359
-
360
- | Key | Action |
361
- |-----|--------|
362
- | `l` | Simple SQL interface (select columns & where clause) |
363
- | `L` | Advanced SQL interface (full SQL query with syntax highlight) |
364
-
365
365
  #### Sorting (supporting multiple columns)
366
366
 
367
367
  | Key | Action |
@@ -387,14 +387,20 @@ zcat compressed_data.csv.gz | dv -f csv
387
387
  | `!` | Cast current column to boolean |
388
388
  | `$` | Cast current column to string |
389
389
 
390
- #### Copy & Save
390
+ #### Copy
391
391
 
392
392
  | Key | Action |
393
393
  |-----|--------|
394
394
  | `c` | Copy current cell to clipboard |
395
395
  | `Ctrl+C` | Copy column to clipboard |
396
396
  | `Ctrl+R` | Copy row to clipboard (tab-separated) |
397
- | `Ctrl+S` | Save to file |
397
+
398
+ #### SQL Interface
399
+
400
+ | Key | Action |
401
+ |-----|--------|
402
+ | `l` | Simple SQL interface (select columns & where clause) |
403
+ | `L` | Advanced SQL interface (full SQL query with syntax highlight) |
398
404
 
399
405
  ## Features in Detail
400
406
 
@@ -417,6 +423,8 @@ Useful for examining wide datasets where columns don't fit well on screen.
417
423
  - Press `"` to **filter** all rows containing the selected column value (others removed)
418
424
  - Press `{` to move to the previous row
419
425
  - Press `}` to move to the next row
426
+ - Press `F` to show the frequency table for the selected column
427
+ - Press `s` to show the statistics table for the selected column
420
428
  - Press `q` or `Escape` to close the modal
421
429
 
422
430
  ### 3. Row Selection
@@ -442,7 +450,6 @@ These options work with plain text searches. Use Polars regex patterns in expres
442
450
  **Quick Tips:**
443
451
  - Search results highlight matching rows in **red**
444
452
  - Use expression for advanced selection (e.g., $attack > $defense)
445
- - Multiple searches **accumulate** - each new search adds to the selections or matches
446
453
  - Type-aware matching automatically converts values. Resort to string comparison if conversion fails
447
454
  - Use `u` to undo any search or filter
448
455
 
@@ -492,7 +499,7 @@ Both operations show selected rows but with fundamentally different effects:
492
499
  **When to use View** (`v` or `V`):
493
500
  - Exploring or analyzing data safely
494
501
  - Switching between different perspectives
495
- - Press `H` to restore hidden rows (and hidden columns)
502
+ - Press `q` to return to main table
496
503
 
497
504
  **When to use Filter** (`"`):
498
505
  - Cleaning data (removing unwanted rows)
@@ -582,6 +589,10 @@ View quick metadata about your dataframe and columns to understand their structu
582
589
  - **Name** - Column name
583
590
  - **Type** - Data type (e.g., Int64, String, Float64, Boolean)
584
591
 
592
+ **In the Column Metadata Table**
593
+ - Press `F` to show the frequency table for the selected column
594
+ - Press `s` to show the statistics table for the selected column
595
+
585
596
  **In Metadata Modals**:
586
597
  - Press `q` or `Escape` to close
587
598
 
@@ -621,7 +632,7 @@ This is useful for:
621
632
  - Quick statistical summaries without external tools
622
633
  - Comparing statistics across columns
623
634
 
624
- ### 11. Data Editing
635
+ ### 11. Editing
625
636
 
626
637
  **Edit Cell** (`e` or **Double-click**):
627
638
  - Opens modal for editing current cell
@@ -667,7 +678,7 @@ This is useful for:
667
678
 
668
679
  **Hide/Show Columns** (`h` / `H`):
669
680
  - `h` - Temporarily hide current column (data preserved)
670
- - `H` - Restore all hidden columns and rows
681
+ - `H` - Restore all hidden columns
671
682
 
672
683
  ### 12. Column & Row Reordering
673
684
 
@@ -696,7 +707,7 @@ Press `,` to toggle thousand separator formatting for numeric data:
696
707
 
697
708
  ### 15. Save File
698
709
 
699
- Press `Ctrl+S` to save filtered, edited, or sorted data back to file
710
+ Press `Ctrl+S` to save filtered, edited, or sorted data back to file. The output format is automatically determined by the file extension, making it easy to convert between different formats (e.g., CSV to TSV).
700
711
 
701
712
  ### 16. Undo/Redo/Reset
702
713
 
@@ -816,7 +827,7 @@ Manage multiple files and dataframes simultaneously with tabs.
816
827
  - **`Double-click`** - Rename the tab
817
828
  - **`Ctrl+D`** - Duplicate current tab (creates a copy with same data and state)
818
829
  - **`Ctrl+T`** - Save current tab to file
819
- - **`Ctrl+A`** - Save all tabs in a single Excel file
830
+ - **`Ctrl+S`** - Save all tabs to file
820
831
  - **`w`** - Save current tab to file (overwrite without prompt)
821
832
  - **`W`** - Save all tabs to file (overwrite without prompt)
822
833
  - **`q`** - Close current tab (closes tab, prompts to save if unsaved changes)
@@ -1,6 +1,6 @@
1
1
  # DataFrame Textual
2
2
 
3
- A powerful, interactive terminal-based viewer/editor for CSV/TSV/Excel/Parquet/JSON/NDJSON built with Python, [Polars](https://pola.rs/), and [Textual](https://textual.textualize.io/). Inspired by [VisiData](https://www.visidata.org/), this tool provides smooth keyboard navigation, data manipulation, and a clean interface for exploring tabular data directly in terminal with multi-tab support for multiple files!
3
+ A powerful, interactive terminal-based viewer/editor for CSV/TSV/PSV/Excel/Parquet/JSON/NDJSON built with Python, [Polars](https://pola.rs/), and [Textual](https://textual.textualize.io/). Inspired by [VisiData](https://www.visidata.org/), this tool provides smooth keyboard navigation, data manipulation, and a clean interface for exploring tabular data directly in terminal with multi-tab support for multiple files!
4
4
 
5
5
  ![Screenshot](https://raw.githubusercontent.com/need47/dataframe-textual/refs/heads/main/screenshot.png)
6
6
 
@@ -128,28 +128,32 @@ When multiple files are opened:
128
128
  ## Command Line Options
129
129
 
130
130
  ```
131
- usage: dv [-h] [-f {csv,excel,tsv,parquet,json,ndjson}] [-H] [-I] [-E] [-c COMMENT_PREFIX] [-q QUOTE_CHAR] [-l SKIP_LINES] [-a SKIP_ROWS_AFTER_HEADER] [-n NULL [NULL ...]] [files ...]
131
+ usage: dv [-h] [-V] [-f {csv,json,xlsx,xls,ndjson,psv,parquet,tsv}] [-H] [-I] [-t] [-E] [-c [COMMENT_PREFIX]] [-q [QUOTE_CHAR]] [-l SKIP_LINES] [-a SKIP_ROWS_AFTER_HEADER] [-n NULL [NULL ...]] [files ...]
132
132
 
133
- Interactive terminal based viewer/editor for tabular data (e.g., CSV/TSV/Excel).
133
+ Interactive terminal based viewer/editor for tabular data (e.g., CSV/Excel).
134
134
 
135
135
  positional arguments:
136
- files Input files (or read from stdin)
136
+ files Files to view (or read from stdin)
137
137
 
138
138
  options:
139
139
  -h, --help show this help message and exit
140
- -f, --format {csv,excel,tsv,parquet,json,ndjson}
141
- Specify the format of the input files
142
- -H, --no-header Specify that input files have no header row
143
- -I, --no-inference Do not infer data types when reading CSV/TSV
140
+ -V, --version show program's version number and exit
141
+ -f, --format {csv,json,xlsx,xls,ndjson,psv,parquet,tsv}
142
+ Specify the format of the input files (csv, tsv etc.)
143
+ -H, --no-header Specify that input files have no header row when reading CSV/TSV
144
+ -I, --no-inference Do not infer data types when reading CSV/TSV
145
+ -t, --truncate-ragged-lines
146
+ Truncate ragged lines when reading CSV/TSV
144
147
  -E, --ignore-errors Ignore errors when reading CSV/TSV
145
- -c, --comment-prefix COMMENT_PREFIX
146
- Comment lines are skipped when reading CSV/TSV (default: skip none)
147
- -q, --quote-char QUOTE_CHAR
148
- Quote character for reading CSV/TSV (default: "; use -q without argument value to disable)
149
- -l, --skip-lines SKIP_LINES
150
- Skip lines when reading CSV/TSV (default: 0)
151
- -a, --skip-rows-after-header SKIP_ROWS_AFTER_HEADER
152
- Skip rows after header when reading CSV/TSV (default: 0)
148
+ -c, --comment-prefix [PREFIX]
149
+ Comment lines starting with `PREFIX` are skipped when reading CSV/TSV
150
+ -q, --quote-char [C]
151
+ Use `C` as quote character for reading CSV/TSV
152
+ -L, --skip-lines N
153
+ Skip first N lines when reading CSV/TSV
154
+ -A, --skip-rows-after-header N
155
+ Skip N rows after header when reading CSV/TSV
156
+ -N, --n-rows N Stop after reading N rows from CSV/TSV
153
157
  -n, --null NULL [NULL ...]
154
158
  Values to interpret as null values when reading CSV/TSV
155
159
  ```
@@ -204,11 +208,11 @@ zcat compressed_data.csv.gz | dv -f csv
204
208
  | `<` | Move to previous tab |
205
209
  | `b` | Cycle through tabs |
206
210
  | `B` | Toggle tab bar visibility |
207
- | `q` | Close current tab (prompts to save unsaved changes) |
208
- | `Q` | Close all tabs and app (prompts to save unsaved changes) |
211
+ | `q` | Quit current tab (prompts to save unsaved changes) |
212
+ | `Q` | Quit all tabs and app (prompts to save unsaved changes) |
209
213
  | `Ctrl+Q` | Force to quit app (regardless of unsaved changes) |
210
214
  | `Ctrl+T` | Save current tab to file |
211
- | `Ctrl+A` | Save all tabs to a Excel file |
215
+ | `Ctrl+S` | Save all tabs to file |
212
216
  | `w` | Save current tab to file (overwrite without prompt) |
213
217
  | `W` | Save all tabs to file (overwrite without prompt) |
214
218
  | `Ctrl+D` | Duplicate current tab |
@@ -263,15 +267,17 @@ zcat compressed_data.csv.gz | dv -f csv
263
267
  | `_` (underscore) | Toggle column full width |
264
268
  | `z` | Freeze rows and columns |
265
269
  | `,` | Toggle thousand separator for numeric display |
270
+ | `&` | Set current row as the new header row |
266
271
  | `h` | Hide current column |
267
- | `H` | Show all hidden rows/columns |
272
+ | `H` | Show all hidden columns |
268
273
 
269
- #### Data Editing
274
+ #### Editing
270
275
 
271
276
  | Key | Action |
272
277
  |-----|--------|
273
278
  | `Double-click` | Edit cell or rename column header |
274
- | `delete` | Clear current cell (set to NULL) |
279
+ | `Delete` | Clear current cell (set to NULL) |
280
+ | `Shift+Delete` | Clear current column (set matching cells to NULL) |
275
281
  | `e` | Edit current cell (respects data type) |
276
282
  | `E` | Edit entire column with value/expression |
277
283
  | `a` | Add empty column after current |
@@ -313,16 +319,10 @@ zcat compressed_data.csv.gz | dv -f csv
313
319
  | Key | Action |
314
320
  |-----|--------|
315
321
  | `"` (quote) | Filter selected rows (others removed) |
322
+ | `.` | View rows with non-null values in current column (others hidden) |
316
323
  | `v` | View selected rows (others hidden) |
317
324
  | `V` | View selected by expression (others hidden) |
318
325
 
319
- #### SQL Interface
320
-
321
- | Key | Action |
322
- |-----|--------|
323
- | `l` | Simple SQL interface (select columns & where clause) |
324
- | `L` | Advanced SQL interface (full SQL query with syntax highlight) |
325
-
326
326
  #### Sorting (supporting multiple columns)
327
327
 
328
328
  | Key | Action |
@@ -348,14 +348,20 @@ zcat compressed_data.csv.gz | dv -f csv
348
348
  | `!` | Cast current column to boolean |
349
349
  | `$` | Cast current column to string |
350
350
 
351
- #### Copy & Save
351
+ #### Copy
352
352
 
353
353
  | Key | Action |
354
354
  |-----|--------|
355
355
  | `c` | Copy current cell to clipboard |
356
356
  | `Ctrl+C` | Copy column to clipboard |
357
357
  | `Ctrl+R` | Copy row to clipboard (tab-separated) |
358
- | `Ctrl+S` | Save to file |
358
+
359
+ #### SQL Interface
360
+
361
+ | Key | Action |
362
+ |-----|--------|
363
+ | `l` | Simple SQL interface (select columns & where clause) |
364
+ | `L` | Advanced SQL interface (full SQL query with syntax highlight) |
359
365
 
360
366
  ## Features in Detail
361
367
 
@@ -378,6 +384,8 @@ Useful for examining wide datasets where columns don't fit well on screen.
378
384
  - Press `"` to **filter** all rows containing the selected column value (others removed)
379
385
  - Press `{` to move to the previous row
380
386
  - Press `}` to move to the next row
387
+ - Press `F` to show the frequency table for the selected column
388
+ - Press `s` to show the statistics table for the selected column
381
389
  - Press `q` or `Escape` to close the modal
382
390
 
383
391
  ### 3. Row Selection
@@ -403,7 +411,6 @@ These options work with plain text searches. Use Polars regex patterns in expres
403
411
  **Quick Tips:**
404
412
  - Search results highlight matching rows in **red**
405
413
  - Use expression for advanced selection (e.g., $attack > $defense)
406
- - Multiple searches **accumulate** - each new search adds to the selections or matches
407
414
  - Type-aware matching automatically converts values. Resort to string comparison if conversion fails
408
415
  - Use `u` to undo any search or filter
409
416
 
@@ -453,7 +460,7 @@ Both operations show selected rows but with fundamentally different effects:
453
460
  **When to use View** (`v` or `V`):
454
461
  - Exploring or analyzing data safely
455
462
  - Switching between different perspectives
456
- - Press `H` to restore hidden rows (and hidden columns)
463
+ - Press `q` to return to main table
457
464
 
458
465
  **When to use Filter** (`"`):
459
466
  - Cleaning data (removing unwanted rows)
@@ -543,6 +550,10 @@ View quick metadata about your dataframe and columns to understand their structu
543
550
  - **Name** - Column name
544
551
  - **Type** - Data type (e.g., Int64, String, Float64, Boolean)
545
552
 
553
+ **In the Column Metadata Table**
554
+ - Press `F` to show the frequency table for the selected column
555
+ - Press `s` to show the statistics table for the selected column
556
+
546
557
  **In Metadata Modals**:
547
558
  - Press `q` or `Escape` to close
548
559
 
@@ -582,7 +593,7 @@ This is useful for:
582
593
  - Quick statistical summaries without external tools
583
594
  - Comparing statistics across columns
584
595
 
585
- ### 11. Data Editing
596
+ ### 11. Editing
586
597
 
587
598
  **Edit Cell** (`e` or **Double-click**):
588
599
  - Opens modal for editing current cell
@@ -628,7 +639,7 @@ This is useful for:
628
639
 
629
640
  **Hide/Show Columns** (`h` / `H`):
630
641
  - `h` - Temporarily hide current column (data preserved)
631
- - `H` - Restore all hidden columns and rows
642
+ - `H` - Restore all hidden columns
632
643
 
633
644
  ### 12. Column & Row Reordering
634
645
 
@@ -657,7 +668,7 @@ Press `,` to toggle thousand separator formatting for numeric data:
657
668
 
658
669
  ### 15. Save File
659
670
 
660
- Press `Ctrl+S` to save filtered, edited, or sorted data back to file
671
+ Press `Ctrl+S` to save filtered, edited, or sorted data back to file. The output format is automatically determined by the file extension, making it easy to convert between different formats (e.g., CSV to TSV).
661
672
 
662
673
  ### 16. Undo/Redo/Reset
663
674
 
@@ -777,7 +788,7 @@ Manage multiple files and dataframes simultaneously with tabs.
777
788
  - **`Double-click`** - Rename the tab
778
789
  - **`Ctrl+D`** - Duplicate current tab (creates a copy with same data and state)
779
790
  - **`Ctrl+T`** - Save current tab to file
780
- - **`Ctrl+A`** - Save all tabs in a single Excel file
791
+ - **`Ctrl+S`** - Save all tabs to file
781
792
  - **`w`** - Save current tab to file (overwrite without prompt)
782
793
  - **`W`** - Save all tabs to file (overwrite without prompt)
783
794
  - **`q`** - Close current tab (closes tab, prompts to save if unsaved changes)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "dataframe-textual"
7
- version = "2.2.2"
7
+ version = "2.11.0"
8
8
  description = "Interactive terminal viewer/editor for tabular data"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -56,11 +56,13 @@ dev = [
56
56
  packages = ["src/dataframe_textual"]
57
57
  exclude = [
58
58
  "*.png",
59
+ "*.gz",
59
60
  ]
60
61
 
61
62
  [tool.hatch.build.targets.sdist]
62
63
  exclude = [
63
64
  "*.png",
65
+ "*.gz",
64
66
  ]
65
67
 
66
68
  [dependency-groups]
@@ -51,15 +51,34 @@ def cli() -> argparse.Namespace:
51
51
  )
52
52
  parser.add_argument("-E", "--ignore-errors", action="store_true", help="Ignore errors when reading CSV/TSV")
53
53
  parser.add_argument(
54
- "-c", "--comment-prefix", nargs="?", const="#", help="Comment lines are skipped when reading CSV/TSV"
54
+ "-c",
55
+ "--comment-prefix",
56
+ metavar="PREFIX",
57
+ nargs="?",
58
+ const="#",
59
+ help="Comment lines starting with `PREFIX` are skipped when reading CSV/TSV",
55
60
  )
56
61
  parser.add_argument(
57
- "-q", "--quote-char", nargs="?", const=None, default='"', help="Quote character for reading CSV/TSV"
62
+ "-q",
63
+ "--quote-char",
64
+ metavar="C",
65
+ nargs="?",
66
+ const=None,
67
+ default='"',
68
+ help="Use `C` as quote character for reading CSV/TSV",
58
69
  )
59
- parser.add_argument("-l", "--skip-lines", type=int, default=0, help="Skip lines when reading CSV/TSV")
60
70
  parser.add_argument(
61
- "-a", "--skip-rows-after-header", type=int, default=0, help="Skip rows after header when reading CSV/TSV"
71
+ "-L", "--skip-lines", metavar="N", type=int, default=0, help="Skip first N lines when reading CSV/TSV"
62
72
  )
73
+ parser.add_argument(
74
+ "-A",
75
+ "--skip-rows-after-header",
76
+ metavar="N",
77
+ type=int,
78
+ default=0,
79
+ help="Skip N rows after header when reading CSV/TSV",
80
+ )
81
+ parser.add_argument("-N", "--n-rows", metavar="N", type=int, help="Stop after reading N rows from CSV/TSV")
63
82
  parser.add_argument("-n", "--null", nargs="+", help="Values to interpret as null values when reading CSV/TSV")
64
83
 
65
84
  args = parser.parse_args()
@@ -98,6 +117,7 @@ def main() -> None:
98
117
  null_values=args.null,
99
118
  ignore_errors=args.ignore_errors,
100
119
  truncate_ragged_lines=args.truncate_ragged_lines,
120
+ n_rows=args.n_rows,
101
121
  )
102
122
  app = DataFrameViewer(*sources)
103
123
  app.run()
@@ -12,7 +12,7 @@ import polars as pl
12
12
  from rich.text import Text
13
13
 
14
14
  # Supported file formats
15
- SUPPORTED_FORMATS = {"tsv", "tab", "csv", "excel", "xlsx", "xls", "parquet", "json", "ndjson"}
15
+ SUPPORTED_FORMATS = ["tsv", "csv", "psv", "xlsx", "xls", "parquet", "json", "ndjson"]
16
16
 
17
17
 
18
18
  # Boolean string mappings
@@ -485,6 +485,7 @@ def load_dataframe(
485
485
  null_values: list[str] | None = None,
486
486
  ignore_errors: bool = False,
487
487
  truncate_ragged_lines: bool = False,
488
+ n_rows: int | None = None,
488
489
  ) -> list[Source]:
489
490
  """Load DataFrames from file specifications.
490
491
 
@@ -502,6 +503,8 @@ def load_dataframe(
502
503
  skip_rows_after_header: Number of rows to skip after header. Defaults to 0.
503
504
  null_values: List of values to interpret as null when reading CSV/TSV files. Defaults to None.
504
505
  ignore_errors: Whether to ignore errors when reading CSV/TSV files. Defaults to False.
506
+ truncate_ragged_lines: Whether to truncate ragged lines when reading CSV/TSV files. Defaults to False.
507
+ n_rows: Number of rows to read from CSV/TSV files. Defaults to None (read all rows).
505
508
 
506
509
  Returns:
507
510
  List of `Source` objects.
@@ -529,6 +532,7 @@ def load_dataframe(
529
532
  ext = Path(filename).suffix.lower()
530
533
  if ext == ".gz":
531
534
  ext = Path(filename).with_suffix("").suffix.lower()
535
+
532
536
  fmt = ext.removeprefix(".")
533
537
 
534
538
  # Default to TSV
@@ -550,6 +554,7 @@ def load_dataframe(
550
554
  null_values=null_values,
551
555
  ignore_errors=ignore_errors,
552
556
  truncate_ragged_lines=truncate_ragged_lines,
557
+ n_rows=n_rows,
553
558
  )
554
559
  )
555
560
 
@@ -634,6 +639,7 @@ def load_file(
634
639
  null_values: list[str] | None = None,
635
640
  ignore_errors: bool = False,
636
641
  truncate_ragged_lines: bool = False,
642
+ n_rows: int | None = None,
637
643
  ) -> list[Source]:
638
644
  """Load a single file.
639
645
 
@@ -659,6 +665,8 @@ def load_file(
659
665
  schema_overrides: Optional dictionary of column name to Polars data type to override inferred schema.
660
666
  null_values: List of values to interpret as null when reading CSV/TSV files. Defaults to None.
661
667
  ignore_errors: Whether to ignore errors when reading CSV/TSV files.
668
+ truncate_ragged_lines: Whether to truncate ragged lines when reading CSV/TSV files. Defaults to False.
669
+ n_rows: Number of rows to read from CSV/TSV files. Defaults to None (read all rows).
662
670
 
663
671
  Returns:
664
672
  List of `Source` objects.
@@ -668,17 +676,11 @@ def load_file(
668
676
  filename = f"stdin.{file_format}" if isinstance(source, StringIO) else source
669
677
  filepath = Path(filename)
670
678
 
671
- if not file_format:
672
- ext = filepath.suffix.lower()
673
- if ext == ".gz":
674
- ext = Path(filename).with_suffix("").suffix.lower()
675
- file_format = ext.removeprefix(".")
676
-
677
679
  # Load based on file format
678
- if file_format in ("csv", "tsv"):
680
+ if file_format in ("csv", "tsv", "psv"):
679
681
  lf = pl.scan_csv(
680
682
  source,
681
- separator="\t" if file_format == "tsv" else ",",
683
+ separator="\t" if file_format == "tsv" else ("|" if file_format == "psv" else ","),
682
684
  has_header=has_header,
683
685
  infer_schema=infer_schema,
684
686
  comment_prefix=comment_prefix,
@@ -689,9 +691,10 @@ def load_file(
689
691
  null_values=null_values,
690
692
  ignore_errors=ignore_errors,
691
693
  truncate_ragged_lines=truncate_ragged_lines,
694
+ n_rows=n_rows,
692
695
  )
693
696
  data.append(Source(lf, filename, filepath.stem))
694
- elif file_format in ("xlsx", "xls", "excel"):
697
+ elif file_format in ("xlsx", "xls"):
695
698
  if first_sheet:
696
699
  # Read only the first sheet for multiple files
697
700
  lf = pl.read_excel(source).lazy()
@@ -745,6 +748,8 @@ def load_file(
745
748
  schema_overrides=schema_overrides,
746
749
  null_values=null_values,
747
750
  ignore_errors=ignore_errors,
751
+ truncate_ragged_lines=truncate_ragged_lines,
752
+ n_rows=n_rows,
748
753
  )
749
754
 
750
755
  return data