dataframe-textual 0.1.0__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dataframe-textual might be problematic. Click here for more details.
- dataframe_textual/__main__.py +65 -0
- dataframe_textual/common.py +340 -0
- {dataframe_viewer → dataframe_textual}/data_frame_help_panel.py +22 -4
- dataframe_textual/data_frame_table.py +2768 -0
- dataframe_textual/data_frame_viewer.py +472 -0
- dataframe_textual/table_screen.py +490 -0
- dataframe_textual/yes_no_screen.py +672 -0
- dataframe_textual-1.1.0.dist-info/METADATA +726 -0
- dataframe_textual-1.1.0.dist-info/RECORD +13 -0
- dataframe_textual-1.1.0.dist-info/entry_points.txt +2 -0
- dataframe_textual-0.1.0.dist-info/METADATA +0 -522
- dataframe_textual-0.1.0.dist-info/RECORD +0 -13
- dataframe_textual-0.1.0.dist-info/entry_points.txt +0 -2
- dataframe_viewer/__main__.py +0 -48
- dataframe_viewer/common.py +0 -204
- dataframe_viewer/data_frame_table.py +0 -1395
- dataframe_viewer/data_frame_viewer.py +0 -320
- dataframe_viewer/table_screen.py +0 -311
- dataframe_viewer/yes_no_screen.py +0 -409
- {dataframe_viewer → dataframe_textual}/__init__.py +0 -0
- {dataframe_textual-0.1.0.dist-info → dataframe_textual-1.1.0.dist-info}/WHEEL +0 -0
- {dataframe_textual-0.1.0.dist-info → dataframe_textual-1.1.0.dist-info}/licenses/LICENSE +0 -0
dataframe_viewer/common.py
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
"""Common utilities and constants for dataframe_viewer."""
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
from dataclasses import dataclass
|
|
5
|
-
from typing import Any
|
|
6
|
-
|
|
7
|
-
import polars as pl
|
|
8
|
-
from rich.text import Text
|
|
9
|
-
|
|
10
|
-
# Boolean string mappings
|
|
11
|
-
BOOLS = {
|
|
12
|
-
"true": True,
|
|
13
|
-
"t": True,
|
|
14
|
-
"yes": True,
|
|
15
|
-
"y": True,
|
|
16
|
-
"1": True,
|
|
17
|
-
"false": False,
|
|
18
|
-
"f": False,
|
|
19
|
-
"no": False,
|
|
20
|
-
"n": False,
|
|
21
|
-
"0": False,
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
# itype is used by Input widget for input validation
|
|
25
|
-
# fmt: off
|
|
26
|
-
STYLES = {
|
|
27
|
-
"Int64": {"style": "cyan", "justify": "right", "itype": "integer", "convert": int},
|
|
28
|
-
"Float64": {"style": "magenta", "justify": "right", "itype": "number", "convert": float},
|
|
29
|
-
"String": {"style": "green", "justify": "left", "itype": "text", "convert": str},
|
|
30
|
-
"Boolean": {"style": "blue", "justify": "center", "itype": "text", "convert": lambda x: BOOLS[x.lower()]},
|
|
31
|
-
"Date": {"style": "blue", "justify": "center", "itype": "text", "convert": str},
|
|
32
|
-
"Datetime": {"style": "blue", "justify": "center", "itype": "text", "convert": str},
|
|
33
|
-
}
|
|
34
|
-
# fmt: on
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
@dataclass
|
|
38
|
-
class DtypeConfig:
|
|
39
|
-
style: str
|
|
40
|
-
justify: str
|
|
41
|
-
itype: str
|
|
42
|
-
convert: Any
|
|
43
|
-
|
|
44
|
-
def __init__(self, dtype: pl.DataType):
|
|
45
|
-
dc = STYLES.get(
|
|
46
|
-
str(dtype), {"style": "", "justify": "", "itype": "text", "convert": str}
|
|
47
|
-
)
|
|
48
|
-
self.style = dc["style"]
|
|
49
|
-
self.justify = dc["justify"]
|
|
50
|
-
self.itype = dc["itype"]
|
|
51
|
-
self.convert = dc["convert"]
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
# Subscript digits mapping for sort indicators
|
|
55
|
-
SUBSCRIPT_DIGITS = {
|
|
56
|
-
0: "₀",
|
|
57
|
-
1: "₁",
|
|
58
|
-
2: "₂",
|
|
59
|
-
3: "₃",
|
|
60
|
-
4: "₄",
|
|
61
|
-
5: "₅",
|
|
62
|
-
6: "₆",
|
|
63
|
-
7: "₇",
|
|
64
|
-
8: "₈",
|
|
65
|
-
9: "₉",
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
# Cursor types ("none" removed)
|
|
69
|
-
CURSOR_TYPES = ["row", "column", "cell"]
|
|
70
|
-
|
|
71
|
-
# Pagination settings
|
|
72
|
-
INITIAL_BATCH_SIZE = 100 # Load this many rows initially
|
|
73
|
-
BATCH_SIZE = 50 # Load this many rows when scrolling
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def _format_row(vals, dtypes, apply_justify=True) -> list[Text]:
|
|
77
|
-
"""Format a single row with proper styling and justification.
|
|
78
|
-
|
|
79
|
-
Args:
|
|
80
|
-
vals: The list of values in the row.
|
|
81
|
-
dtypes: The list of data types corresponding to each value.
|
|
82
|
-
apply_justify: Whether to apply justification styling. Defaults to True.
|
|
83
|
-
"""
|
|
84
|
-
formatted_row = []
|
|
85
|
-
|
|
86
|
-
for val, dtype in zip(vals, dtypes, strict=True):
|
|
87
|
-
dc = DtypeConfig(dtype)
|
|
88
|
-
|
|
89
|
-
# Format the value
|
|
90
|
-
if val is None:
|
|
91
|
-
text_val = "-"
|
|
92
|
-
elif str(dtype).startswith("Float"):
|
|
93
|
-
text_val = f"{val:.4g}"
|
|
94
|
-
else:
|
|
95
|
-
text_val = str(val)
|
|
96
|
-
|
|
97
|
-
formatted_row.append(
|
|
98
|
-
Text(
|
|
99
|
-
text_val,
|
|
100
|
-
style=dc.style,
|
|
101
|
-
justify=dc.justify if apply_justify else "",
|
|
102
|
-
)
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
return formatted_row
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def _rindex(lst: list, value) -> int:
|
|
109
|
-
"""Return the last index of value in a list. Return -1 if not found."""
|
|
110
|
-
for i, item in enumerate(reversed(lst)):
|
|
111
|
-
if item == value:
|
|
112
|
-
return len(lst) - 1 - i
|
|
113
|
-
return -1
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
def _next(lst: list[Any], current, offset=1) -> Any:
|
|
117
|
-
"""Return the next item in the list after the current item, cycling if needed."""
|
|
118
|
-
if current not in lst:
|
|
119
|
-
raise ValueError("Current item not in list")
|
|
120
|
-
current_index = lst.index(current)
|
|
121
|
-
next_index = (current_index + offset) % len(lst)
|
|
122
|
-
return lst[next_index]
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def parse_filter_expression(
|
|
126
|
-
expression: str, df: pl.DataFrame, current_col_idx: int
|
|
127
|
-
) -> str:
|
|
128
|
-
"""Parse and convert a filter expression to Polars syntax.
|
|
129
|
-
|
|
130
|
-
Supports:
|
|
131
|
-
- $_ - Current selected column
|
|
132
|
-
- $1, $2, etc. - Column by 1-based index
|
|
133
|
-
- $col_name - Column by name
|
|
134
|
-
- Comparison operators: ==, !=, <, >, <=, >=
|
|
135
|
-
- Logical operators: &&, ||
|
|
136
|
-
- String literals: 'text', "text"
|
|
137
|
-
- Numeric literals: integers and floats
|
|
138
|
-
|
|
139
|
-
Examples:
|
|
140
|
-
- "$_ > 50" -> "pl.col('current_col') > 50"
|
|
141
|
-
- "$1 > 50" -> "pl.col('col0') > 50"
|
|
142
|
-
- "$name == 'Alex'" -> "pl.col('name') == 'Alex'"
|
|
143
|
-
- "$1 > 3 && $name == 'Alex'" -> "(pl.col('col0') > 3) & (pl.col('name') == 'Alex')"
|
|
144
|
-
- "$age < $salary" -> "pl.col('age') < pl.col('salary')"
|
|
145
|
-
|
|
146
|
-
Args:
|
|
147
|
-
expression: The filter expression as a string.
|
|
148
|
-
df: The DataFrame to validate column references.
|
|
149
|
-
current_col_idx: The index of the currently selected column (0-based). Used for $_ reference.
|
|
150
|
-
|
|
151
|
-
Returns:
|
|
152
|
-
A Python expression string that can be eval'd with Polars symbols.
|
|
153
|
-
|
|
154
|
-
Raises:
|
|
155
|
-
ValueError: If the expression contains invalid column references.
|
|
156
|
-
SyntaxError: If the expression has invalid syntax.
|
|
157
|
-
"""
|
|
158
|
-
# Tokenize the expression
|
|
159
|
-
# Pattern matches: $_, $index, $identifier, strings, operators, numbers, etc.
|
|
160
|
-
token_pattern = r'\$_|\$\d+|\$\w+|\'[^\']*\'|"[^"]*"|&&|\|\||<=|>=|!=|==|[+\-*/%<>=()]|\d+\.?\d*|\w+|.'
|
|
161
|
-
|
|
162
|
-
tokens = re.findall(token_pattern, expression)
|
|
163
|
-
|
|
164
|
-
if not tokens:
|
|
165
|
-
raise ValueError("Expression is empty")
|
|
166
|
-
|
|
167
|
-
# Convert tokens to Polars expression syntax
|
|
168
|
-
converted_tokens = []
|
|
169
|
-
for token in tokens:
|
|
170
|
-
if token.startswith("$"):
|
|
171
|
-
# Column reference
|
|
172
|
-
col_ref = token[1:]
|
|
173
|
-
|
|
174
|
-
# Special case: $_ refers to the current selected column
|
|
175
|
-
if col_ref == "_":
|
|
176
|
-
col_name = df.columns[current_col_idx]
|
|
177
|
-
# Check if it's a numeric index
|
|
178
|
-
elif col_ref.isdigit():
|
|
179
|
-
col_idx = int(col_ref) - 1 # Convert to 0-based index
|
|
180
|
-
if col_idx < 0 or col_idx >= len(df.columns):
|
|
181
|
-
raise ValueError(f"Column index out of range: ${col_ref}")
|
|
182
|
-
col_name = df.columns[col_idx]
|
|
183
|
-
else:
|
|
184
|
-
# It's a column name
|
|
185
|
-
if col_ref not in df.columns:
|
|
186
|
-
raise ValueError(f"Column not found: ${col_ref}")
|
|
187
|
-
col_name = col_ref
|
|
188
|
-
|
|
189
|
-
converted_tokens.append(f"pl.col('{col_name}')")
|
|
190
|
-
|
|
191
|
-
elif token in ("&&", "||"):
|
|
192
|
-
# Convert logical operators and wrap surrounding expressions in parentheses
|
|
193
|
-
if token == "&&":
|
|
194
|
-
converted_tokens.append(") & (")
|
|
195
|
-
else:
|
|
196
|
-
converted_tokens.append(") | (")
|
|
197
|
-
|
|
198
|
-
else:
|
|
199
|
-
# Keep as-is (operators, numbers, strings, parentheses)
|
|
200
|
-
converted_tokens.append(token)
|
|
201
|
-
|
|
202
|
-
# Join tokens with space to ensure proper separation
|
|
203
|
-
result = "(" + " ".join(converted_tokens) + ")"
|
|
204
|
-
return result
|