tksheet 7.3.3__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/colors.py +1 -1
- tksheet/column_headers.py +397 -366
- tksheet/constants.py +13 -0
- tksheet/find_window.py +4 -13
- tksheet/functions.py +198 -37
- tksheet/main_table.py +1109 -848
- tksheet/other_classes.py +13 -9
- tksheet/row_index.py +939 -437
- tksheet/sheet.py +470 -619
- tksheet/sheet_options.py +47 -12
- tksheet/sorting.py +369 -0
- tksheet/text_editor.py +4 -15
- tksheet/{types.py → tksheet_types.py} +12 -8
- {tksheet-7.3.3.dist-info → tksheet-7.4.0.dist-info}/METADATA +14 -14
- tksheet-7.4.0.dist-info/RECORD +22 -0
- tksheet-7.3.3.dist-info/RECORD +0 -21
- {tksheet-7.3.3.dist-info → tksheet-7.4.0.dist-info}/LICENSE.txt +0 -0
- {tksheet-7.3.3.dist-info → tksheet-7.4.0.dist-info}/WHEEL +0 -0
- {tksheet-7.3.3.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/find_window.py
CHANGED
@@ -1,21 +1,12 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import tkinter as tk
|
4
|
-
from collections.abc import
|
5
|
-
Callable,
|
6
|
-
)
|
4
|
+
from collections.abc import Callable
|
7
5
|
from typing import Literal
|
8
6
|
|
9
|
-
from .
|
10
|
-
|
11
|
-
|
12
|
-
from .constants import (
|
13
|
-
ctrl_key,
|
14
|
-
rc_binding,
|
15
|
-
)
|
16
|
-
from .functions import (
|
17
|
-
recursive_bind,
|
18
|
-
)
|
7
|
+
from .constants import ctrl_key, rc_binding
|
8
|
+
from .functions import recursive_bind
|
9
|
+
from .other_classes import DotDict
|
19
10
|
|
20
11
|
|
21
12
|
class FindWindowTkText(tk.Text):
|
tksheet/functions.py
CHANGED
@@ -5,41 +5,166 @@ import io
|
|
5
5
|
import pickle
|
6
6
|
import re
|
7
7
|
import tkinter as tk
|
8
|
-
from bisect import
|
9
|
-
bisect_left,
|
10
|
-
)
|
8
|
+
from bisect import bisect_left
|
11
9
|
from collections import deque
|
12
|
-
from collections.abc import
|
13
|
-
Callable,
|
14
|
-
Generator,
|
15
|
-
Hashable,
|
16
|
-
Iterable,
|
17
|
-
Iterator,
|
18
|
-
Sequence,
|
19
|
-
)
|
10
|
+
from collections.abc import Callable, Generator, Hashable, Iterable, Iterator, Sequence
|
20
11
|
from itertools import islice, repeat
|
21
12
|
from typing import Literal
|
22
13
|
|
23
14
|
from .colors import color_map
|
24
|
-
from .constants import
|
25
|
-
|
26
|
-
|
27
|
-
from .
|
28
|
-
to_bool,
|
29
|
-
)
|
30
|
-
from .other_classes import (
|
31
|
-
Box_nt,
|
32
|
-
DotDict,
|
33
|
-
EventDataDict,
|
34
|
-
Highlight,
|
35
|
-
Loc,
|
36
|
-
Span,
|
37
|
-
)
|
38
|
-
from .types import (
|
39
|
-
AnyIter,
|
40
|
-
)
|
15
|
+
from .constants import align_value_error, symbols_set
|
16
|
+
from .formatters import to_bool
|
17
|
+
from .other_classes import Box_nt, DotDict, EventDataDict, Highlight, Loc, Span
|
18
|
+
from .tksheet_types import AnyIter
|
41
19
|
|
42
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
|
43
168
|
|
44
169
|
|
45
170
|
def get_csv_str_dialect(s: str, delimiters: str) -> csv.Dialect:
|
@@ -183,6 +308,8 @@ def event_dict(
|
|
183
308
|
# resized_header: None, dict] = None,
|
184
309
|
being_selected: None | tuple = None,
|
185
310
|
named_spans: None | dict = None,
|
311
|
+
sheet_state: None | dict = None,
|
312
|
+
treeview: None | dict = None,
|
186
313
|
**kwargs,
|
187
314
|
) -> EventDataDict:
|
188
315
|
return EventDataDict(
|
@@ -208,8 +335,6 @@ def event_dict(
|
|
208
335
|
index=DotDict(),
|
209
336
|
column_widths=DotDict(),
|
210
337
|
row_heights=DotDict(),
|
211
|
-
displayed_rows=None,
|
212
|
-
displayed_columns=None,
|
213
338
|
),
|
214
339
|
named_spans=DotDict() if named_spans is None else named_spans,
|
215
340
|
options=DotDict(),
|
@@ -231,6 +356,12 @@ def event_dict(
|
|
231
356
|
# "index": DotDict() if resized_index is None else resized_index,
|
232
357
|
),
|
233
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,
|
234
365
|
)
|
235
366
|
|
236
367
|
|
@@ -258,6 +389,12 @@ def b_index(sorted_seq: Sequence[int], num_to_index: int) -> int:
|
|
258
389
|
return idx
|
259
390
|
|
260
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
|
+
|
261
398
|
def bisect_in(sorted_seq: Sequence[int], num: int) -> bool:
|
262
399
|
"""
|
263
400
|
Faster than 'num in sorted_seq'
|
@@ -268,6 +405,18 @@ def bisect_in(sorted_seq: Sequence[int], num: int) -> bool:
|
|
268
405
|
return False
|
269
406
|
|
270
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
|
+
|
271
420
|
def get_dropdown_kwargs(
|
272
421
|
values: list = [],
|
273
422
|
set_value: object = None,
|
@@ -638,6 +787,18 @@ def insert_items(
|
|
638
787
|
return seq
|
639
788
|
|
640
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
|
+
|
641
802
|
def data_to_displayed_idxs(
|
642
803
|
to_convert: list[int],
|
643
804
|
displayed: list[int],
|
@@ -1412,15 +1573,15 @@ def convert_align(align: str | None) -> str | None:
|
|
1412
1573
|
a = align.lower()
|
1413
1574
|
if a == "global":
|
1414
1575
|
return None
|
1415
|
-
elif a in ("c", "center", "centre"):
|
1416
|
-
return "
|
1417
|
-
elif a in ("w", "west", "left"):
|
1418
|
-
return "
|
1419
|
-
elif a in ("e", "east", "right"):
|
1420
|
-
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"
|
1421
1582
|
elif align is None:
|
1422
1583
|
return None
|
1423
|
-
raise ValueError(
|
1584
|
+
raise ValueError(align_value_error)
|
1424
1585
|
|
1425
1586
|
|
1426
1587
|
def set_align(
|