dataframe-textual 1.2.0__tar.gz → 1.4.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.
- {dataframe_textual-1.2.0 → dataframe_textual-1.4.0}/PKG-INFO +149 -13
- {dataframe_textual-1.2.0 → dataframe_textual-1.4.0}/README.md +147 -11
- {dataframe_textual-1.2.0 → dataframe_textual-1.4.0}/pyproject.toml +3 -2
- dataframe_textual-1.4.0/src/dataframe_textual/__main__.py +90 -0
- {dataframe_textual-1.2.0 → dataframe_textual-1.4.0}/src/dataframe_textual/common.py +280 -72
- {dataframe_textual-1.2.0 → dataframe_textual-1.4.0}/src/dataframe_textual/data_frame_help_panel.py +6 -4
- {dataframe_textual-1.2.0 → dataframe_textual-1.4.0}/src/dataframe_textual/data_frame_table.py +633 -370
- {dataframe_textual-1.2.0 → dataframe_textual-1.4.0}/src/dataframe_textual/data_frame_viewer.py +24 -28
- dataframe_textual-1.4.0/src/dataframe_textual/sql_screen.py +202 -0
- {dataframe_textual-1.2.0 → dataframe_textual-1.4.0}/src/dataframe_textual/table_screen.py +31 -20
- {dataframe_textual-1.2.0 → dataframe_textual-1.4.0}/src/dataframe_textual/yes_no_screen.py +12 -8
- {dataframe_textual-1.2.0 → dataframe_textual-1.4.0}/uv.lock +292 -3
- dataframe_textual-1.2.0/.python-version +0 -1
- dataframe_textual-1.2.0/src/dataframe_textual/__main__.py +0 -68
- {dataframe_textual-1.2.0 → dataframe_textual-1.4.0}/.gitignore +0 -0
- {dataframe_textual-1.2.0 → dataframe_textual-1.4.0}/LICENSE +0 -0
- {dataframe_textual-1.2.0 → dataframe_textual-1.4.0}/main.py +0 -0
- {dataframe_textual-1.2.0 → dataframe_textual-1.4.0}/src/dataframe_textual/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dataframe-textual
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.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
|
|
@@ -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
|
|
@@ -129,6 +129,13 @@ uv run python main.py pokemon.csv
|
|
|
129
129
|
# Read from stdin (auto-detects format; defaults to TSV if not recognized)
|
|
130
130
|
cat data.tsv | dv
|
|
131
131
|
dv < data.tsv
|
|
132
|
+
|
|
133
|
+
# Gzipped files are supported
|
|
134
|
+
dv data.csv.gz
|
|
135
|
+
dv large_dataset.tsv.gz
|
|
136
|
+
|
|
137
|
+
# Specify format for gzipped stdin
|
|
138
|
+
zcat data.csv.gz | dv -f csv
|
|
132
139
|
```
|
|
133
140
|
|
|
134
141
|
### Multi-File Usage - Multiple Tabs
|
|
@@ -142,6 +149,9 @@ dv file.xlsx
|
|
|
142
149
|
|
|
143
150
|
# Mix files and stdin (read from stdin, then open file)
|
|
144
151
|
dv data1.tsv < data2.tsv
|
|
152
|
+
|
|
153
|
+
# Mix regular and gzipped files
|
|
154
|
+
dv data1.csv data2.csv.gz data3.tsv.gz
|
|
145
155
|
```
|
|
146
156
|
|
|
147
157
|
When multiple files are opened:
|
|
@@ -151,6 +161,67 @@ When multiple files are opened:
|
|
|
151
161
|
- Close the current tab with `Ctrl+W`
|
|
152
162
|
- Each file maintains its own state (edits, sort order, selections, history, etc.)
|
|
153
163
|
|
|
164
|
+
## Command Line Options
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
usage: dv [-h] [-f {csv,excel,tsv,parquet,json,ndjson}] [-H] [-I] [-L SKIP_LINES] [-K SKIP_ROWS_AFTER_HEADER] [-U NULL [NULL ...]] [files ...]
|
|
168
|
+
|
|
169
|
+
Interactive terminal based viewer/editor for tabular data (e.g., CSV/Excel).
|
|
170
|
+
|
|
171
|
+
positional arguments:
|
|
172
|
+
files Files to view (or read from stdin)
|
|
173
|
+
|
|
174
|
+
options:
|
|
175
|
+
-h, --help show this help message and exit
|
|
176
|
+
-f, --format {csv,excel,tsv,parquet,json,ndjson}
|
|
177
|
+
Specify the format of the input files
|
|
178
|
+
-H, --no-header Specify that input files have no header row
|
|
179
|
+
-I, --no-inferrence Do not infer data types when reading CSV/TSV
|
|
180
|
+
-L, --skip-lines SKIP_LINES
|
|
181
|
+
Skip lines when reading CSV/TSV (default: 0)
|
|
182
|
+
-K, --skip-rows-after-header SKIP_ROWS_AFTER_HEADER
|
|
183
|
+
Skip rows after header when reading CSV/TSV (default: 0)
|
|
184
|
+
-U, --null NULL [NULL ...]
|
|
185
|
+
Values to interpret as null values when reading CSV/TSV
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### CLI Examples
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# View CSV file without header row
|
|
192
|
+
dv -H data_no_header.csv
|
|
193
|
+
|
|
194
|
+
# Disable type inference for faster loading
|
|
195
|
+
dv -I large_data.csv
|
|
196
|
+
|
|
197
|
+
# Skip first 3 lines of file (e.g., comments, metadata)
|
|
198
|
+
dv -L 3 data_with_comments.csv
|
|
199
|
+
|
|
200
|
+
# Skip 1 row after header (e.g., units row)
|
|
201
|
+
dv -K 1 data_with_units.csv
|
|
202
|
+
|
|
203
|
+
# Treat specific values as null/missing (e.g., 'NA', 'N/A', '-')
|
|
204
|
+
dv -U NA N/A - data.csv
|
|
205
|
+
|
|
206
|
+
# Multiple null values with different formats
|
|
207
|
+
dv -U NULL NA "" "Not Available" messy_data.csv
|
|
208
|
+
|
|
209
|
+
# Complex CSV with comments and units row
|
|
210
|
+
dv -L 3 -K 1 -I messy_scientific_data.csv
|
|
211
|
+
|
|
212
|
+
# Combine all options: skip lines, skip after header, no header, no inference, gzipped
|
|
213
|
+
dv -L 2 -K 1 -H -I complex_data.csv.gz
|
|
214
|
+
|
|
215
|
+
# Process compressed data from stdin with line skipping
|
|
216
|
+
zcat compressed_data.csv.gz | dv -f csv -L 2
|
|
217
|
+
|
|
218
|
+
# CSV with custom null values and no header
|
|
219
|
+
dv -H -U NA "N/A" "-" raw_data.csv
|
|
220
|
+
|
|
221
|
+
# Skip lines, specify null values, and disable type inference
|
|
222
|
+
dv -L 5 -U NA "" data_with_metadata.csv
|
|
223
|
+
```
|
|
224
|
+
|
|
154
225
|
## Keyboard Shortcuts
|
|
155
226
|
|
|
156
227
|
### App-Level Controls
|
|
@@ -161,7 +232,7 @@ When multiple files are opened:
|
|
|
161
232
|
|-----|--------|
|
|
162
233
|
| `Ctrl+O` | Open file in a new tab |
|
|
163
234
|
| `Ctrl+W` | Close current tab |
|
|
164
|
-
| `Ctrl+
|
|
235
|
+
| `Ctrl+A` | Save all open tabs to Excel file |
|
|
165
236
|
| `>` or `b` | Move to next tab |
|
|
166
237
|
| `<` | Move to previous tab |
|
|
167
238
|
| `B` | Toggle tab bar visibility |
|
|
@@ -171,7 +242,7 @@ When multiple files are opened:
|
|
|
171
242
|
|
|
172
243
|
| Key | Action |
|
|
173
244
|
|-----|--------|
|
|
174
|
-
| `
|
|
245
|
+
| `F1` | Toggle help panel |
|
|
175
246
|
| `k` | Cycle through themes |
|
|
176
247
|
|
|
177
248
|
---
|
|
@@ -189,6 +260,8 @@ When multiple files are opened:
|
|
|
189
260
|
| `Home` / `End` | Jump to first/last column in current row |
|
|
190
261
|
| `Ctrl + Home` / `Ctrl + End` | Jump to top/bottom in current page |
|
|
191
262
|
| `PageDown` / `PageUp` | Scroll down/up one page |
|
|
263
|
+
| `Ctrl+F` | Page down |
|
|
264
|
+
| `Ctrl+B` | Page up |
|
|
192
265
|
|
|
193
266
|
#### Viewing & Display
|
|
194
267
|
|
|
@@ -200,6 +273,7 @@ When multiple files are opened:
|
|
|
200
273
|
| `S` | Show statistics for entire dataframe |
|
|
201
274
|
| `K` | Cycle cursor type: cell → row → column → cell |
|
|
202
275
|
| `~` | Toggle row labels |
|
|
276
|
+
| `_` (underscore) | Expand column to full width |
|
|
203
277
|
|
|
204
278
|
#### Data Editing
|
|
205
279
|
|
|
@@ -212,8 +286,6 @@ When multiple files are opened:
|
|
|
212
286
|
| `a` | Add empty column after current |
|
|
213
287
|
| `A` | Add column with name and value/expression |
|
|
214
288
|
| `-` (minus) | Delete current column |
|
|
215
|
-
| `_` (underscore) | Delete current column and all columns after |
|
|
216
|
-
| `Ctrl+-` | Delete current column and all columns before |
|
|
217
289
|
| `x` | Delete current row |
|
|
218
290
|
| `X` | Delete current row and all rows below |
|
|
219
291
|
| `Ctrl+X` | Delete current row and all rows above |
|
|
@@ -241,12 +313,19 @@ When multiple files are opened:
|
|
|
241
313
|
| `v` | View only rows by selected rows and/or matches or cursor value |
|
|
242
314
|
| `V` | View only rows by expression |
|
|
243
315
|
|
|
316
|
+
#### SQL Interface
|
|
317
|
+
|
|
318
|
+
| Key | Action |
|
|
319
|
+
|-----|--------|
|
|
320
|
+
| `l` | Simple SQL interface (select columns & WHERE clause) |
|
|
321
|
+
| `L` | Advanced SQL interface (full SQL queries) |
|
|
322
|
+
|
|
244
323
|
#### Find & Replace
|
|
245
324
|
|
|
246
325
|
| Key | Action |
|
|
247
326
|
|-----|--------|
|
|
248
|
-
|
|
|
249
|
-
|
|
|
327
|
+
| `;` | Find across all columns with cursor value |
|
|
328
|
+
| `:` | Find across all columns with expression |
|
|
250
329
|
| `r` | Find and replace in current column (interactive or replace all) |
|
|
251
330
|
| `R` | Find and replace across all columns (interactive or replace all) |
|
|
252
331
|
|
|
@@ -322,8 +401,8 @@ The application provides multiple search modes for different use cases:
|
|
|
322
401
|
**Find Operations** - Find by value/expression:
|
|
323
402
|
- **`/` - Column Find**: Find cursor value within current column
|
|
324
403
|
- **`?` - Column Expression Find**: Open dialog to search current column with expression
|
|
325
|
-
-
|
|
326
|
-
-
|
|
404
|
+
- **`;` - Global Find**: Find cursor value across all columns
|
|
405
|
+
- **`:` - Global Expression Find**: Open dialog to search all columns with expression
|
|
327
406
|
|
|
328
407
|
**Selection & Filtering**:
|
|
329
408
|
- **`'` - Toggle Row Selection**: Select/deselect current row (marks it for filtering)
|
|
@@ -703,7 +782,40 @@ Press `@` to make URLs in the current column clickable:
|
|
|
703
782
|
- **Scans** all cells in the current column for URLs starting with `http://` or `https://`
|
|
704
783
|
- **Applies** link styling to make them clickable and dataframe remains unchanged
|
|
705
784
|
|
|
706
|
-
### 19.
|
|
785
|
+
### 19. SQL Interface
|
|
786
|
+
|
|
787
|
+
The SQL interface provides two modes for querying your dataframe:
|
|
788
|
+
|
|
789
|
+
#### Simple SQL Interface (`l`)
|
|
790
|
+
Select specific columns and apply WHERE conditions without writing full SQL:
|
|
791
|
+
- Choose which columns to include in results
|
|
792
|
+
- Specify WHERE clause for filtering
|
|
793
|
+
- Ideal for quick filtering and column selection
|
|
794
|
+
|
|
795
|
+
#### Advanced SQL Interface (`L`)
|
|
796
|
+
Execute complete SQL queries for advanced data manipulation:
|
|
797
|
+
- Write full SQL queries with standard [SQL syntax](https://docs.pola.rs/api/python/stable/reference/sql/index.html)
|
|
798
|
+
- Support for JOINs, GROUP BY, aggregations, and more
|
|
799
|
+
- Access to all SQL capabilities for complex transformations
|
|
800
|
+
- Always use `self` as the table name
|
|
801
|
+
|
|
802
|
+
**Examples:**
|
|
803
|
+
```sql
|
|
804
|
+
-- Filter and select specific rows and/or columns
|
|
805
|
+
SELECT name, age FROM self WHERE age > 30
|
|
806
|
+
|
|
807
|
+
-- Aggregate with GROUP BY
|
|
808
|
+
SELECT department, COUNT(*) as count, AVG(salary) as avg_salary
|
|
809
|
+
FROM self
|
|
810
|
+
GROUP BY department
|
|
811
|
+
|
|
812
|
+
-- Complex filtering with multiple conditions
|
|
813
|
+
SELECT *
|
|
814
|
+
FROM self
|
|
815
|
+
WHERE (age > 25 AND salary > 50000) OR department = 'Management'
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
### 20. Clipboard Operations
|
|
707
819
|
|
|
708
820
|
Copies value to system clipboard with `pbcopy` on macOS and `xclip` on Linux
|
|
709
821
|
|
|
@@ -722,6 +834,30 @@ dv pokemon.csv
|
|
|
722
834
|
|
|
723
835
|
# Chain with other command and specify input file format
|
|
724
836
|
cut -d',' -f1,2,3 pokemon.csv | dv -f csv
|
|
837
|
+
|
|
838
|
+
# Work with gzipped files
|
|
839
|
+
dv large_dataset.csv.gz
|
|
840
|
+
|
|
841
|
+
# CSV file without header row
|
|
842
|
+
dv -H raw_data.csv
|
|
843
|
+
|
|
844
|
+
# Skip type inference for faster loading
|
|
845
|
+
dv -I huge_file.csv
|
|
846
|
+
|
|
847
|
+
# Skip first 5 lines (comments, metadata)
|
|
848
|
+
dv -L 5 data_with_metadata.csv
|
|
849
|
+
|
|
850
|
+
# Skip 1 row after header (units row)
|
|
851
|
+
dv -K 1 data_with_units.csv
|
|
852
|
+
|
|
853
|
+
# Complex CSV with comments and units row
|
|
854
|
+
dv -L 3 -K 1 -I messy_scientific_data.csv
|
|
855
|
+
|
|
856
|
+
# Combine all options: skip lines, skip after header, no header, no inference, gzipped
|
|
857
|
+
dv -L 2 -K 1 -H -I complex_data.csv.gz
|
|
858
|
+
|
|
859
|
+
# Process compressed data from stdin with line skipping
|
|
860
|
+
zcat compressed_data.csv.gz | dv -f csv -L 2
|
|
725
861
|
```
|
|
726
862
|
|
|
727
863
|
### Multi-File/Tab Examples
|
|
@@ -730,8 +866,8 @@ cut -d',' -f1,2,3 pokemon.csv | dv -f csv
|
|
|
730
866
|
# Open multiple sheets as tabs in a single Excel
|
|
731
867
|
dv sales.xlsx
|
|
732
868
|
|
|
733
|
-
# Open multiple files as tabs
|
|
734
|
-
dv pokemon.csv titanic.csv
|
|
869
|
+
# Open multiple files as tabs (including gzipped)
|
|
870
|
+
dv pokemon.csv titanic.csv large_data.csv.gz
|
|
735
871
|
|
|
736
872
|
# Start with one file, then open others using Ctrl+O
|
|
737
873
|
dv initial_data.csv
|
|
@@ -90,6 +90,13 @@ uv run python main.py pokemon.csv
|
|
|
90
90
|
# Read from stdin (auto-detects format; defaults to TSV if not recognized)
|
|
91
91
|
cat data.tsv | dv
|
|
92
92
|
dv < data.tsv
|
|
93
|
+
|
|
94
|
+
# Gzipped files are supported
|
|
95
|
+
dv data.csv.gz
|
|
96
|
+
dv large_dataset.tsv.gz
|
|
97
|
+
|
|
98
|
+
# Specify format for gzipped stdin
|
|
99
|
+
zcat data.csv.gz | dv -f csv
|
|
93
100
|
```
|
|
94
101
|
|
|
95
102
|
### Multi-File Usage - Multiple Tabs
|
|
@@ -103,6 +110,9 @@ dv file.xlsx
|
|
|
103
110
|
|
|
104
111
|
# Mix files and stdin (read from stdin, then open file)
|
|
105
112
|
dv data1.tsv < data2.tsv
|
|
113
|
+
|
|
114
|
+
# Mix regular and gzipped files
|
|
115
|
+
dv data1.csv data2.csv.gz data3.tsv.gz
|
|
106
116
|
```
|
|
107
117
|
|
|
108
118
|
When multiple files are opened:
|
|
@@ -112,6 +122,67 @@ When multiple files are opened:
|
|
|
112
122
|
- Close the current tab with `Ctrl+W`
|
|
113
123
|
- Each file maintains its own state (edits, sort order, selections, history, etc.)
|
|
114
124
|
|
|
125
|
+
## Command Line Options
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
usage: dv [-h] [-f {csv,excel,tsv,parquet,json,ndjson}] [-H] [-I] [-L SKIP_LINES] [-K SKIP_ROWS_AFTER_HEADER] [-U NULL [NULL ...]] [files ...]
|
|
129
|
+
|
|
130
|
+
Interactive terminal based viewer/editor for tabular data (e.g., CSV/Excel).
|
|
131
|
+
|
|
132
|
+
positional arguments:
|
|
133
|
+
files Files to view (or read from stdin)
|
|
134
|
+
|
|
135
|
+
options:
|
|
136
|
+
-h, --help show this help message and exit
|
|
137
|
+
-f, --format {csv,excel,tsv,parquet,json,ndjson}
|
|
138
|
+
Specify the format of the input files
|
|
139
|
+
-H, --no-header Specify that input files have no header row
|
|
140
|
+
-I, --no-inferrence Do not infer data types when reading CSV/TSV
|
|
141
|
+
-L, --skip-lines SKIP_LINES
|
|
142
|
+
Skip lines when reading CSV/TSV (default: 0)
|
|
143
|
+
-K, --skip-rows-after-header SKIP_ROWS_AFTER_HEADER
|
|
144
|
+
Skip rows after header when reading CSV/TSV (default: 0)
|
|
145
|
+
-U, --null NULL [NULL ...]
|
|
146
|
+
Values to interpret as null values when reading CSV/TSV
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### CLI Examples
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# View CSV file without header row
|
|
153
|
+
dv -H data_no_header.csv
|
|
154
|
+
|
|
155
|
+
# Disable type inference for faster loading
|
|
156
|
+
dv -I large_data.csv
|
|
157
|
+
|
|
158
|
+
# Skip first 3 lines of file (e.g., comments, metadata)
|
|
159
|
+
dv -L 3 data_with_comments.csv
|
|
160
|
+
|
|
161
|
+
# Skip 1 row after header (e.g., units row)
|
|
162
|
+
dv -K 1 data_with_units.csv
|
|
163
|
+
|
|
164
|
+
# Treat specific values as null/missing (e.g., 'NA', 'N/A', '-')
|
|
165
|
+
dv -U NA N/A - data.csv
|
|
166
|
+
|
|
167
|
+
# Multiple null values with different formats
|
|
168
|
+
dv -U NULL NA "" "Not Available" messy_data.csv
|
|
169
|
+
|
|
170
|
+
# Complex CSV with comments and units row
|
|
171
|
+
dv -L 3 -K 1 -I messy_scientific_data.csv
|
|
172
|
+
|
|
173
|
+
# Combine all options: skip lines, skip after header, no header, no inference, gzipped
|
|
174
|
+
dv -L 2 -K 1 -H -I complex_data.csv.gz
|
|
175
|
+
|
|
176
|
+
# Process compressed data from stdin with line skipping
|
|
177
|
+
zcat compressed_data.csv.gz | dv -f csv -L 2
|
|
178
|
+
|
|
179
|
+
# CSV with custom null values and no header
|
|
180
|
+
dv -H -U NA "N/A" "-" raw_data.csv
|
|
181
|
+
|
|
182
|
+
# Skip lines, specify null values, and disable type inference
|
|
183
|
+
dv -L 5 -U NA "" data_with_metadata.csv
|
|
184
|
+
```
|
|
185
|
+
|
|
115
186
|
## Keyboard Shortcuts
|
|
116
187
|
|
|
117
188
|
### App-Level Controls
|
|
@@ -122,7 +193,7 @@ When multiple files are opened:
|
|
|
122
193
|
|-----|--------|
|
|
123
194
|
| `Ctrl+O` | Open file in a new tab |
|
|
124
195
|
| `Ctrl+W` | Close current tab |
|
|
125
|
-
| `Ctrl+
|
|
196
|
+
| `Ctrl+A` | Save all open tabs to Excel file |
|
|
126
197
|
| `>` or `b` | Move to next tab |
|
|
127
198
|
| `<` | Move to previous tab |
|
|
128
199
|
| `B` | Toggle tab bar visibility |
|
|
@@ -132,7 +203,7 @@ When multiple files are opened:
|
|
|
132
203
|
|
|
133
204
|
| Key | Action |
|
|
134
205
|
|-----|--------|
|
|
135
|
-
| `
|
|
206
|
+
| `F1` | Toggle help panel |
|
|
136
207
|
| `k` | Cycle through themes |
|
|
137
208
|
|
|
138
209
|
---
|
|
@@ -150,6 +221,8 @@ When multiple files are opened:
|
|
|
150
221
|
| `Home` / `End` | Jump to first/last column in current row |
|
|
151
222
|
| `Ctrl + Home` / `Ctrl + End` | Jump to top/bottom in current page |
|
|
152
223
|
| `PageDown` / `PageUp` | Scroll down/up one page |
|
|
224
|
+
| `Ctrl+F` | Page down |
|
|
225
|
+
| `Ctrl+B` | Page up |
|
|
153
226
|
|
|
154
227
|
#### Viewing & Display
|
|
155
228
|
|
|
@@ -161,6 +234,7 @@ When multiple files are opened:
|
|
|
161
234
|
| `S` | Show statistics for entire dataframe |
|
|
162
235
|
| `K` | Cycle cursor type: cell → row → column → cell |
|
|
163
236
|
| `~` | Toggle row labels |
|
|
237
|
+
| `_` (underscore) | Expand column to full width |
|
|
164
238
|
|
|
165
239
|
#### Data Editing
|
|
166
240
|
|
|
@@ -173,8 +247,6 @@ When multiple files are opened:
|
|
|
173
247
|
| `a` | Add empty column after current |
|
|
174
248
|
| `A` | Add column with name and value/expression |
|
|
175
249
|
| `-` (minus) | Delete current column |
|
|
176
|
-
| `_` (underscore) | Delete current column and all columns after |
|
|
177
|
-
| `Ctrl+-` | Delete current column and all columns before |
|
|
178
250
|
| `x` | Delete current row |
|
|
179
251
|
| `X` | Delete current row and all rows below |
|
|
180
252
|
| `Ctrl+X` | Delete current row and all rows above |
|
|
@@ -202,12 +274,19 @@ When multiple files are opened:
|
|
|
202
274
|
| `v` | View only rows by selected rows and/or matches or cursor value |
|
|
203
275
|
| `V` | View only rows by expression |
|
|
204
276
|
|
|
277
|
+
#### SQL Interface
|
|
278
|
+
|
|
279
|
+
| Key | Action |
|
|
280
|
+
|-----|--------|
|
|
281
|
+
| `l` | Simple SQL interface (select columns & WHERE clause) |
|
|
282
|
+
| `L` | Advanced SQL interface (full SQL queries) |
|
|
283
|
+
|
|
205
284
|
#### Find & Replace
|
|
206
285
|
|
|
207
286
|
| Key | Action |
|
|
208
287
|
|-----|--------|
|
|
209
|
-
|
|
|
210
|
-
|
|
|
288
|
+
| `;` | Find across all columns with cursor value |
|
|
289
|
+
| `:` | Find across all columns with expression |
|
|
211
290
|
| `r` | Find and replace in current column (interactive or replace all) |
|
|
212
291
|
| `R` | Find and replace across all columns (interactive or replace all) |
|
|
213
292
|
|
|
@@ -283,8 +362,8 @@ The application provides multiple search modes for different use cases:
|
|
|
283
362
|
**Find Operations** - Find by value/expression:
|
|
284
363
|
- **`/` - Column Find**: Find cursor value within current column
|
|
285
364
|
- **`?` - Column Expression Find**: Open dialog to search current column with expression
|
|
286
|
-
-
|
|
287
|
-
-
|
|
365
|
+
- **`;` - Global Find**: Find cursor value across all columns
|
|
366
|
+
- **`:` - Global Expression Find**: Open dialog to search all columns with expression
|
|
288
367
|
|
|
289
368
|
**Selection & Filtering**:
|
|
290
369
|
- **`'` - Toggle Row Selection**: Select/deselect current row (marks it for filtering)
|
|
@@ -664,7 +743,40 @@ Press `@` to make URLs in the current column clickable:
|
|
|
664
743
|
- **Scans** all cells in the current column for URLs starting with `http://` or `https://`
|
|
665
744
|
- **Applies** link styling to make them clickable and dataframe remains unchanged
|
|
666
745
|
|
|
667
|
-
### 19.
|
|
746
|
+
### 19. SQL Interface
|
|
747
|
+
|
|
748
|
+
The SQL interface provides two modes for querying your dataframe:
|
|
749
|
+
|
|
750
|
+
#### Simple SQL Interface (`l`)
|
|
751
|
+
Select specific columns and apply WHERE conditions without writing full SQL:
|
|
752
|
+
- Choose which columns to include in results
|
|
753
|
+
- Specify WHERE clause for filtering
|
|
754
|
+
- Ideal for quick filtering and column selection
|
|
755
|
+
|
|
756
|
+
#### Advanced SQL Interface (`L`)
|
|
757
|
+
Execute complete SQL queries for advanced data manipulation:
|
|
758
|
+
- Write full SQL queries with standard [SQL syntax](https://docs.pola.rs/api/python/stable/reference/sql/index.html)
|
|
759
|
+
- Support for JOINs, GROUP BY, aggregations, and more
|
|
760
|
+
- Access to all SQL capabilities for complex transformations
|
|
761
|
+
- Always use `self` as the table name
|
|
762
|
+
|
|
763
|
+
**Examples:**
|
|
764
|
+
```sql
|
|
765
|
+
-- Filter and select specific rows and/or columns
|
|
766
|
+
SELECT name, age FROM self WHERE age > 30
|
|
767
|
+
|
|
768
|
+
-- Aggregate with GROUP BY
|
|
769
|
+
SELECT department, COUNT(*) as count, AVG(salary) as avg_salary
|
|
770
|
+
FROM self
|
|
771
|
+
GROUP BY department
|
|
772
|
+
|
|
773
|
+
-- Complex filtering with multiple conditions
|
|
774
|
+
SELECT *
|
|
775
|
+
FROM self
|
|
776
|
+
WHERE (age > 25 AND salary > 50000) OR department = 'Management'
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
### 20. Clipboard Operations
|
|
668
780
|
|
|
669
781
|
Copies value to system clipboard with `pbcopy` on macOS and `xclip` on Linux
|
|
670
782
|
|
|
@@ -683,6 +795,30 @@ dv pokemon.csv
|
|
|
683
795
|
|
|
684
796
|
# Chain with other command and specify input file format
|
|
685
797
|
cut -d',' -f1,2,3 pokemon.csv | dv -f csv
|
|
798
|
+
|
|
799
|
+
# Work with gzipped files
|
|
800
|
+
dv large_dataset.csv.gz
|
|
801
|
+
|
|
802
|
+
# CSV file without header row
|
|
803
|
+
dv -H raw_data.csv
|
|
804
|
+
|
|
805
|
+
# Skip type inference for faster loading
|
|
806
|
+
dv -I huge_file.csv
|
|
807
|
+
|
|
808
|
+
# Skip first 5 lines (comments, metadata)
|
|
809
|
+
dv -L 5 data_with_metadata.csv
|
|
810
|
+
|
|
811
|
+
# Skip 1 row after header (units row)
|
|
812
|
+
dv -K 1 data_with_units.csv
|
|
813
|
+
|
|
814
|
+
# Complex CSV with comments and units row
|
|
815
|
+
dv -L 3 -K 1 -I messy_scientific_data.csv
|
|
816
|
+
|
|
817
|
+
# Combine all options: skip lines, skip after header, no header, no inference, gzipped
|
|
818
|
+
dv -L 2 -K 1 -H -I complex_data.csv.gz
|
|
819
|
+
|
|
820
|
+
# Process compressed data from stdin with line skipping
|
|
821
|
+
zcat compressed_data.csv.gz | dv -f csv -L 2
|
|
686
822
|
```
|
|
687
823
|
|
|
688
824
|
### Multi-File/Tab Examples
|
|
@@ -691,8 +827,8 @@ cut -d',' -f1,2,3 pokemon.csv | dv -f csv
|
|
|
691
827
|
# Open multiple sheets as tabs in a single Excel
|
|
692
828
|
dv sales.xlsx
|
|
693
829
|
|
|
694
|
-
# Open multiple files as tabs
|
|
695
|
-
dv pokemon.csv titanic.csv
|
|
830
|
+
# Open multiple files as tabs (including gzipped)
|
|
831
|
+
dv pokemon.csv titanic.csv large_data.csv.gz
|
|
696
832
|
|
|
697
833
|
# Start with one file, then open others using Ctrl+O
|
|
698
834
|
dv initial_data.csv
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dataframe-textual"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.4.0"
|
|
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"
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Entry point for running DataFrameViewer as a module."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from .common import SUPPORTED_FORMATS, load_dataframe
|
|
8
|
+
from .data_frame_viewer import DataFrameViewer
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def cli() -> argparse.Namespace:
|
|
12
|
+
"""Parse command-line arguments.
|
|
13
|
+
|
|
14
|
+
Determines input files or stdin and validates file existence
|
|
15
|
+
"""
|
|
16
|
+
parser = argparse.ArgumentParser(
|
|
17
|
+
prog="dv",
|
|
18
|
+
description="Interactive terminal based viewer/editor for tabular data (e.g., CSV/Excel).",
|
|
19
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
20
|
+
epilog="Examples:\n"
|
|
21
|
+
" %(prog)s data.csv\n"
|
|
22
|
+
" %(prog)s file1.csv file2.csv file3.csv\n"
|
|
23
|
+
" %(prog)s data.xlsx (opens each sheet in separate tab)\n"
|
|
24
|
+
" cat data.csv | %(prog)s --format csv\n",
|
|
25
|
+
)
|
|
26
|
+
parser.add_argument("files", nargs="*", help="Files to view (or read from stdin)")
|
|
27
|
+
parser.add_argument(
|
|
28
|
+
"-f",
|
|
29
|
+
"--format",
|
|
30
|
+
choices=SUPPORTED_FORMATS,
|
|
31
|
+
help="Specify the format of the input files (csv, excel, tsv etc.)",
|
|
32
|
+
)
|
|
33
|
+
parser.add_argument(
|
|
34
|
+
"-H",
|
|
35
|
+
"--no-header",
|
|
36
|
+
action="store_true",
|
|
37
|
+
help="Specify that input files have no header row when reading CSV/TSV",
|
|
38
|
+
)
|
|
39
|
+
parser.add_argument(
|
|
40
|
+
"-I", "--no-inferrence", action="store_true", help="Do not infer data types when reading CSV/TSV"
|
|
41
|
+
)
|
|
42
|
+
parser.add_argument(
|
|
43
|
+
"-C", "--comment-prefix", nargs="?", const="#", help="Comment lines are skipped when reading CSV/TSV"
|
|
44
|
+
)
|
|
45
|
+
parser.add_argument("-L", "--skip-lines", type=int, default=0, help="Skip lines when reading CSV/TSV")
|
|
46
|
+
parser.add_argument(
|
|
47
|
+
"-K", "--skip-rows-after-header", type=int, default=0, help="Skip rows after header when reading CSV/TSV"
|
|
48
|
+
)
|
|
49
|
+
parser.add_argument("-U", "--null", nargs="+", help="Values to interpret as null values when reading CSV/TSV")
|
|
50
|
+
|
|
51
|
+
args = parser.parse_args()
|
|
52
|
+
if args.files is None:
|
|
53
|
+
args.files = []
|
|
54
|
+
|
|
55
|
+
# Check if reading from stdin (pipe or redirect)
|
|
56
|
+
if not sys.stdin.isatty():
|
|
57
|
+
args.files.append("-")
|
|
58
|
+
else:
|
|
59
|
+
# Validate all files exist
|
|
60
|
+
for filename in args.files:
|
|
61
|
+
if not Path(filename).exists():
|
|
62
|
+
print(f"File not found: {filename}")
|
|
63
|
+
sys.exit(1)
|
|
64
|
+
|
|
65
|
+
if not args.files:
|
|
66
|
+
parser.print_help()
|
|
67
|
+
sys.exit(1)
|
|
68
|
+
|
|
69
|
+
return args
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def main() -> None:
|
|
73
|
+
"""Run the DataFrame Viewer application."""
|
|
74
|
+
args = cli()
|
|
75
|
+
sources = load_dataframe(
|
|
76
|
+
args.files,
|
|
77
|
+
file_format=args.format,
|
|
78
|
+
has_header=not args.no_header,
|
|
79
|
+
infer_schema=not args.no_inferrence,
|
|
80
|
+
comment_prefix=args.comment_prefix,
|
|
81
|
+
skip_lines=args.skip_lines,
|
|
82
|
+
skip_rows_after_header=args.skip_rows_after_header,
|
|
83
|
+
null_values=args.null,
|
|
84
|
+
)
|
|
85
|
+
app = DataFrameViewer(*sources)
|
|
86
|
+
app.run()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
if __name__ == "__main__":
|
|
90
|
+
main()
|