dataframe-textual 1.1.5__py3-none-any.whl → 1.3.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.
- dataframe_textual/common.py +33 -12
- dataframe_textual/data_frame_help_panel.py +6 -4
- dataframe_textual/data_frame_table.py +574 -309
- dataframe_textual/data_frame_viewer.py +19 -27
- dataframe_textual/sql_screen.py +202 -0
- dataframe_textual/table_screen.py +20 -18
- dataframe_textual/yes_no_screen.py +9 -5
- {dataframe_textual-1.1.5.dist-info → dataframe_textual-1.3.9.dist-info}/METADATA +88 -19
- dataframe_textual-1.3.9.dist-info/RECORD +14 -0
- {dataframe_textual-1.1.5.dist-info → dataframe_textual-1.3.9.dist-info}/entry_points.txt +1 -0
- dataframe_textual-1.1.5.dist-info/RECORD +0 -13
- {dataframe_textual-1.1.5.dist-info → dataframe_textual-1.3.9.dist-info}/WHEEL +0 -0
- {dataframe_textual-1.1.5.dist-info → dataframe_textual-1.3.9.dist-info}/licenses/LICENSE +0 -0
dataframe_textual/common.py
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
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 =
|
|
276
|
+
col_name = columns[col_idx]
|
|
277
277
|
else:
|
|
278
278
|
# Column by name
|
|
279
|
-
if col_ref not in
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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:
|