tksheet 7.3.4__py3-none-any.whl → 7.4.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.
- tksheet/__init__.py +11 -11
- tksheet/column_headers.py +328 -239
- tksheet/constants.py +13 -0
- tksheet/functions.py +194 -11
- tksheet/main_table.py +926 -564
- tksheet/other_classes.py +12 -8
- tksheet/row_index.py +830 -259
- tksheet/sheet.py +465 -589
- tksheet/sheet_options.py +44 -1
- tksheet/sorting.py +369 -0
- tksheet/text_editor.py +2 -6
- tksheet/{types.py → tksheet_types.py} +10 -1
- {tksheet-7.3.4.dist-info → tksheet-7.4.0.dist-info}/METADATA +14 -14
- tksheet-7.4.0.dist-info/RECORD +22 -0
- tksheet-7.3.4.dist-info/RECORD +0 -21
- {tksheet-7.3.4.dist-info → tksheet-7.4.0.dist-info}/LICENSE.txt +0 -0
- {tksheet-7.3.4.dist-info → tksheet-7.4.0.dist-info}/WHEEL +0 -0
- {tksheet-7.3.4.dist-info → tksheet-7.4.0.dist-info}/top_level.txt +0 -0
tksheet/constants.py
CHANGED
@@ -9,6 +9,7 @@ symbols_set: set[str] = set("""!#$%&'()*+,-./:;"@[]^_`{|}~>?= \\""")
|
|
9
9
|
nonelike: set[object] = {None, "none", ""}
|
10
10
|
truthy: set[object] = {True, "true", "t", "yes", "y", "on", "1", 1, 1.0}
|
11
11
|
falsy: set[object] = {False, "false", "f", "no", "n", "off", "0", 0, 0.0}
|
12
|
+
_test_str: str = "aiW_-|"
|
12
13
|
|
13
14
|
val_modifying_options: set[str] = {"checkbox", "format", "dropdown"}
|
14
15
|
|
@@ -34,6 +35,18 @@ emitted_events: set[str] = {
|
|
34
35
|
"<<SelectAll>>",
|
35
36
|
}
|
36
37
|
|
38
|
+
align_helper: dict[str, str] = {
|
39
|
+
"w": "nw",
|
40
|
+
"e": "ne",
|
41
|
+
"center": "n",
|
42
|
+
"n": "center",
|
43
|
+
"nw": "left",
|
44
|
+
"ne": "right",
|
45
|
+
}
|
46
|
+
|
47
|
+
align_value_error: str = "Align must be one of the following values: c, center, w, nw, west, left, e, ne, east, right"
|
48
|
+
font_value_error: str = "Argument must be font, size and 'normal', 'bold' or'italic' e.g. ('Carlito',12,'normal')"
|
49
|
+
|
37
50
|
backwards_compatibility_keys: dict[str, str] = {
|
38
51
|
"font": "table_font",
|
39
52
|
}
|
tksheet/functions.py
CHANGED
@@ -12,12 +12,159 @@ from itertools import islice, repeat
|
|
12
12
|
from typing import Literal
|
13
13
|
|
14
14
|
from .colors import color_map
|
15
|
-
from .constants import symbols_set
|
15
|
+
from .constants import align_value_error, symbols_set
|
16
16
|
from .formatters import to_bool
|
17
17
|
from .other_classes import Box_nt, DotDict, EventDataDict, Highlight, Loc, Span
|
18
|
-
from .
|
18
|
+
from .tksheet_types import AnyIter
|
19
19
|
|
20
20
|
unpickle_obj = pickle.loads
|
21
|
+
lines_re = re.compile(r"[^\n]+")
|
22
|
+
|
23
|
+
|
24
|
+
def wrap_text(
|
25
|
+
text: str,
|
26
|
+
max_width: int,
|
27
|
+
max_lines: int,
|
28
|
+
char_width_fn: Callable,
|
29
|
+
widths: dict[str, int],
|
30
|
+
wrap: Literal["", "c", "w"] = "",
|
31
|
+
start_line: int = 0,
|
32
|
+
) -> Generator[str]:
|
33
|
+
lines = (match.group() for match in lines_re.finditer(text))
|
34
|
+
current_line = []
|
35
|
+
total_lines = 0
|
36
|
+
line_width = 0
|
37
|
+
|
38
|
+
if not wrap:
|
39
|
+
for line in lines:
|
40
|
+
line_width = 0
|
41
|
+
current_line = []
|
42
|
+
for char in line:
|
43
|
+
char_width = widths.get(char, char_width_fn(char))
|
44
|
+
line_width += char_width
|
45
|
+
if line_width >= max_width:
|
46
|
+
break
|
47
|
+
current_line.append(char)
|
48
|
+
|
49
|
+
if total_lines >= start_line:
|
50
|
+
yield "".join(current_line)
|
51
|
+
|
52
|
+
# Count the line whether it's empty or not
|
53
|
+
total_lines += 1
|
54
|
+
if total_lines >= max_lines:
|
55
|
+
return
|
56
|
+
|
57
|
+
elif wrap == "c":
|
58
|
+
for line in lines:
|
59
|
+
for char in line:
|
60
|
+
char_width = widths.get(char, char_width_fn(char))
|
61
|
+
|
62
|
+
# adding char to line would result in wrap
|
63
|
+
if line_width + char_width >= max_width:
|
64
|
+
if total_lines >= start_line:
|
65
|
+
yield "".join(current_line)
|
66
|
+
|
67
|
+
total_lines += 1
|
68
|
+
if total_lines >= max_lines:
|
69
|
+
return
|
70
|
+
current_line = []
|
71
|
+
line_width = 0
|
72
|
+
|
73
|
+
if char_width <= max_width:
|
74
|
+
current_line.append(char)
|
75
|
+
line_width = char_width
|
76
|
+
# adding char to line is okay
|
77
|
+
else:
|
78
|
+
current_line.append(char)
|
79
|
+
line_width += char_width
|
80
|
+
|
81
|
+
if total_lines >= start_line:
|
82
|
+
yield "".join(current_line)
|
83
|
+
|
84
|
+
total_lines += 1
|
85
|
+
if total_lines >= max_lines:
|
86
|
+
return
|
87
|
+
current_line = [] # Reset for next line
|
88
|
+
line_width = 0
|
89
|
+
|
90
|
+
elif wrap == "w":
|
91
|
+
space_width = widths.get(" ", char_width_fn(" "))
|
92
|
+
|
93
|
+
for line in lines:
|
94
|
+
words = line.split()
|
95
|
+
for i, word in enumerate(words):
|
96
|
+
# if we're going to next word and
|
97
|
+
# if a space fits on the end of the current line we add one
|
98
|
+
if i and line_width + space_width < max_width:
|
99
|
+
current_line.append(" ")
|
100
|
+
line_width += space_width
|
101
|
+
|
102
|
+
# check if word will fit
|
103
|
+
word_width = 0
|
104
|
+
word_char_widths = []
|
105
|
+
for char in word:
|
106
|
+
word_char_widths.append((w := widths.get(char, char_width_fn(char))))
|
107
|
+
word_width += w
|
108
|
+
|
109
|
+
# we only wrap by character if the whole word alone wont fit max width
|
110
|
+
# word won't fit at all we resort to char wrapping it
|
111
|
+
if word_width >= max_width:
|
112
|
+
# yield current line before char wrapping word
|
113
|
+
if current_line:
|
114
|
+
if total_lines >= start_line:
|
115
|
+
yield "".join(current_line)
|
116
|
+
|
117
|
+
total_lines += 1
|
118
|
+
if total_lines >= max_lines:
|
119
|
+
return
|
120
|
+
current_line = []
|
121
|
+
line_width = 0
|
122
|
+
|
123
|
+
for char, w in zip(word, word_char_widths):
|
124
|
+
# adding char to line would result in wrap
|
125
|
+
if line_width + w >= max_width:
|
126
|
+
if total_lines >= start_line:
|
127
|
+
yield "".join(current_line)
|
128
|
+
|
129
|
+
total_lines += 1
|
130
|
+
if total_lines >= max_lines:
|
131
|
+
return
|
132
|
+
current_line = []
|
133
|
+
line_width = 0
|
134
|
+
|
135
|
+
if w <= max_width:
|
136
|
+
current_line.append(char)
|
137
|
+
line_width = w
|
138
|
+
# adding char to line is okay
|
139
|
+
else:
|
140
|
+
current_line.append(char)
|
141
|
+
line_width += w
|
142
|
+
|
143
|
+
# word won't fit on current line but will fit on a newline
|
144
|
+
elif line_width + word_width >= max_width:
|
145
|
+
if total_lines >= start_line:
|
146
|
+
yield "".join(current_line)
|
147
|
+
|
148
|
+
total_lines += 1
|
149
|
+
if total_lines >= max_lines:
|
150
|
+
return
|
151
|
+
current_line = [word]
|
152
|
+
line_width = word_width
|
153
|
+
|
154
|
+
# word will fit we put it on the current line
|
155
|
+
else:
|
156
|
+
current_line.append(word)
|
157
|
+
line_width += word_width
|
158
|
+
|
159
|
+
if total_lines >= start_line:
|
160
|
+
yield "".join(current_line)
|
161
|
+
|
162
|
+
total_lines += 1
|
163
|
+
if total_lines >= max_lines:
|
164
|
+
return
|
165
|
+
|
166
|
+
current_line = [] # Reset for next line
|
167
|
+
line_width = 0
|
21
168
|
|
22
169
|
|
23
170
|
def get_csv_str_dialect(s: str, delimiters: str) -> csv.Dialect:
|
@@ -161,6 +308,8 @@ def event_dict(
|
|
161
308
|
# resized_header: None, dict] = None,
|
162
309
|
being_selected: None | tuple = None,
|
163
310
|
named_spans: None | dict = None,
|
311
|
+
sheet_state: None | dict = None,
|
312
|
+
treeview: None | dict = None,
|
164
313
|
**kwargs,
|
165
314
|
) -> EventDataDict:
|
166
315
|
return EventDataDict(
|
@@ -186,8 +335,6 @@ def event_dict(
|
|
186
335
|
index=DotDict(),
|
187
336
|
column_widths=DotDict(),
|
188
337
|
row_heights=DotDict(),
|
189
|
-
displayed_rows=None,
|
190
|
-
displayed_columns=None,
|
191
338
|
),
|
192
339
|
named_spans=DotDict() if named_spans is None else named_spans,
|
193
340
|
options=DotDict(),
|
@@ -209,6 +356,12 @@ def event_dict(
|
|
209
356
|
# "index": DotDict() if resized_index is None else resized_index,
|
210
357
|
),
|
211
358
|
widget=widget,
|
359
|
+
sheet_state=DotDict() if sheet_state is None else sheet_state,
|
360
|
+
treeview=DotDict(
|
361
|
+
nodes={},
|
362
|
+
)
|
363
|
+
if treeview is None
|
364
|
+
else treeview,
|
212
365
|
)
|
213
366
|
|
214
367
|
|
@@ -236,6 +389,12 @@ def b_index(sorted_seq: Sequence[int], num_to_index: int) -> int:
|
|
236
389
|
return idx
|
237
390
|
|
238
391
|
|
392
|
+
def try_b_index(sorted_seq: Sequence[int], num_to_index: int) -> int | None:
|
393
|
+
if (idx := bisect_left(sorted_seq, num_to_index)) == len(sorted_seq) or sorted_seq[idx] != num_to_index:
|
394
|
+
return None
|
395
|
+
return idx
|
396
|
+
|
397
|
+
|
239
398
|
def bisect_in(sorted_seq: Sequence[int], num: int) -> bool:
|
240
399
|
"""
|
241
400
|
Faster than 'num in sorted_seq'
|
@@ -246,6 +405,18 @@ def bisect_in(sorted_seq: Sequence[int], num: int) -> bool:
|
|
246
405
|
return False
|
247
406
|
|
248
407
|
|
408
|
+
def push_n(num: int, sorted_seq: Sequence[int]) -> int:
|
409
|
+
if num < sorted_seq[0]:
|
410
|
+
return num
|
411
|
+
else:
|
412
|
+
for e in sorted_seq:
|
413
|
+
if num >= e:
|
414
|
+
num += 1
|
415
|
+
else:
|
416
|
+
return num
|
417
|
+
return num
|
418
|
+
|
419
|
+
|
249
420
|
def get_dropdown_kwargs(
|
250
421
|
values: list = [],
|
251
422
|
set_value: object = None,
|
@@ -616,6 +787,18 @@ def insert_items(
|
|
616
787
|
return seq
|
617
788
|
|
618
789
|
|
790
|
+
def del_placeholder_dict_key(
|
791
|
+
d: dict[Hashable, object],
|
792
|
+
k: Hashable,
|
793
|
+
v: object,
|
794
|
+
p: tuple = tuple(),
|
795
|
+
) -> dict[Hashable, object]:
|
796
|
+
if p in d:
|
797
|
+
del d[p]
|
798
|
+
d[k] = v
|
799
|
+
return d
|
800
|
+
|
801
|
+
|
619
802
|
def data_to_displayed_idxs(
|
620
803
|
to_convert: list[int],
|
621
804
|
displayed: list[int],
|
@@ -1390,15 +1573,15 @@ def convert_align(align: str | None) -> str | None:
|
|
1390
1573
|
a = align.lower()
|
1391
1574
|
if a == "global":
|
1392
1575
|
return None
|
1393
|
-
elif a in ("c", "center", "centre"):
|
1394
|
-
return "
|
1395
|
-
elif a in ("w", "west", "left"):
|
1396
|
-
return "
|
1397
|
-
elif a in ("e", "east", "right"):
|
1398
|
-
return "
|
1576
|
+
elif a in ("c", "center", "centre", "n"):
|
1577
|
+
return "n"
|
1578
|
+
elif a in ("w", "west", "left", "nw"):
|
1579
|
+
return "nw"
|
1580
|
+
elif a in ("e", "east", "right", "ne"):
|
1581
|
+
return "ne"
|
1399
1582
|
elif align is None:
|
1400
1583
|
return None
|
1401
|
-
raise ValueError(
|
1584
|
+
raise ValueError(align_value_error)
|
1402
1585
|
|
1403
1586
|
|
1404
1587
|
def set_align(
|