tksheet 7.4.4__py3-none-any.whl → 7.4.6__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 +1 -1
- tksheet/column_headers.py +84 -86
- tksheet/constants.py +4 -3
- tksheet/find_window.py +8 -8
- tksheet/formatters.py +58 -74
- tksheet/functions.py +65 -79
- tksheet/main_table.py +330 -448
- tksheet/other_classes.py +19 -25
- tksheet/row_index.py +114 -92
- tksheet/sheet.py +191 -208
- tksheet/sorting.py +23 -22
- tksheet/text_editor.py +18 -12
- tksheet/tksheet_types.py +187 -0
- tksheet/top_left_rectangle.py +18 -18
- {tksheet-7.4.4.dist-info → tksheet-7.4.6.dist-info}/METADATA +4 -2
- tksheet-7.4.6.dist-info/RECORD +22 -0
- {tksheet-7.4.4.dist-info → tksheet-7.4.6.dist-info}/WHEEL +1 -1
- tksheet-7.4.4.dist-info/RECORD +0 -22
- {tksheet-7.4.4.dist-info → tksheet-7.4.6.dist-info}/LICENSE.txt +0 -0
- {tksheet-7.4.4.dist-info → tksheet-7.4.6.dist-info}/top_level.txt +0 -0
tksheet/functions.py
CHANGED
@@ -10,7 +10,7 @@ from collections import deque
|
|
10
10
|
from collections.abc import Callable, Generator, Hashable, Iterable, Iterator, Sequence
|
11
11
|
from difflib import SequenceMatcher
|
12
12
|
from itertools import islice, repeat
|
13
|
-
from typing import Literal
|
13
|
+
from typing import Any, Literal
|
14
14
|
|
15
15
|
from .colors import color_map
|
16
16
|
from .constants import align_value_error, symbols_set
|
@@ -202,7 +202,7 @@ def recursive_bind(widget: tk.Misc, event: str, callback: Callable) -> None:
|
|
202
202
|
recursive_bind(child, event, callback)
|
203
203
|
|
204
204
|
|
205
|
-
def tksheet_type_error(kwarg: str, valid_types: list[str], not_type:
|
205
|
+
def tksheet_type_error(kwarg: str, valid_types: list[str], not_type: Any) -> str:
|
206
206
|
valid_types = ", ".join(f"{type_}" for type_ in valid_types)
|
207
207
|
return f"Argument '{kwarg}' must be one of the following types: {valid_types}, not {type(not_type)}."
|
208
208
|
|
@@ -213,7 +213,7 @@ def new_tk_event(keysym: str) -> tk.Event:
|
|
213
213
|
return event
|
214
214
|
|
215
215
|
|
216
|
-
def event_has_char_key(event:
|
216
|
+
def event_has_char_key(event: Any) -> bool:
|
217
217
|
return (
|
218
218
|
event and hasattr(event, "char") and (event.char.isalpha() or event.char.isdigit() or event.char in symbols_set)
|
219
219
|
)
|
@@ -232,7 +232,7 @@ def event_opens_dropdown_or_checkbox(event=None) -> bool:
|
|
232
232
|
)
|
233
233
|
|
234
234
|
|
235
|
-
def dropdown_search_function(search_for: str, data: Iterable[
|
235
|
+
def dropdown_search_function(search_for: str, data: Iterable[Any]) -> None | int:
|
236
236
|
search_for = search_for.lower()
|
237
237
|
search_len = len(search_for)
|
238
238
|
if not search_len:
|
@@ -281,16 +281,16 @@ def float_to_int(f: int | float) -> int | float:
|
|
281
281
|
|
282
282
|
def event_dict(
|
283
283
|
name: str = None,
|
284
|
-
sheet:
|
284
|
+
sheet: Any = None,
|
285
285
|
widget: tk.Canvas | None = None,
|
286
286
|
boxes: None | dict | tuple = None,
|
287
287
|
cells_table: None | dict = None,
|
288
288
|
cells_header: None | dict = None,
|
289
289
|
cells_index: None | dict = None,
|
290
290
|
selected: None | tuple = None,
|
291
|
-
data:
|
291
|
+
data: Any = None,
|
292
292
|
key: None | str = None,
|
293
|
-
value:
|
293
|
+
value: Any = None,
|
294
294
|
loc: None | int | tuple[int] = None,
|
295
295
|
row: None | int = None,
|
296
296
|
column: None | int = None,
|
@@ -331,12 +331,12 @@ def event_dict(
|
|
331
331
|
named_spans=DotDict() if named_spans is None else named_spans,
|
332
332
|
options=DotDict(),
|
333
333
|
selection_boxes={} if boxes is None else boxes,
|
334
|
-
selected=
|
335
|
-
being_selected=
|
334
|
+
selected=() if selected is None else selected,
|
335
|
+
being_selected=() if being_selected is None else being_selected,
|
336
336
|
data=[] if data is None else data,
|
337
337
|
key="" if key is None else key,
|
338
338
|
value=None if value is None else value,
|
339
|
-
loc=
|
339
|
+
loc=() if loc is None else loc,
|
340
340
|
row=row,
|
341
341
|
column=column,
|
342
342
|
resized=DotDict(
|
@@ -366,7 +366,8 @@ def stored_event_dict(d: DotDict) -> DotDict:
|
|
366
366
|
def len_to_idx(n: int) -> int:
|
367
367
|
if n < 1:
|
368
368
|
return 0
|
369
|
-
|
369
|
+
else:
|
370
|
+
return n - 1
|
370
371
|
|
371
372
|
|
372
373
|
def b_index(sorted_seq: Sequence[int], num_to_index: int) -> int:
|
@@ -376,13 +377,15 @@ def b_index(sorted_seq: Sequence[int], num_to_index: int) -> int:
|
|
376
377
|
"""
|
377
378
|
if (idx := bisect_left(sorted_seq, num_to_index)) == len(sorted_seq) or sorted_seq[idx] != num_to_index:
|
378
379
|
raise ValueError(f"{num_to_index} is not in Sequence")
|
379
|
-
|
380
|
+
else:
|
381
|
+
return idx
|
380
382
|
|
381
383
|
|
382
384
|
def try_b_index(sorted_seq: Sequence[int], num_to_index: int) -> int | None:
|
383
385
|
if (idx := bisect_left(sorted_seq, num_to_index)) == len(sorted_seq) or sorted_seq[idx] != num_to_index:
|
384
386
|
return None
|
385
|
-
|
387
|
+
else:
|
388
|
+
return idx
|
386
389
|
|
387
390
|
|
388
391
|
def bisect_in(sorted_seq: Sequence[int], num: int) -> bool:
|
@@ -399,27 +402,20 @@ def push_n(num: int, sorted_seq: Sequence[int]) -> int:
|
|
399
402
|
if num < sorted_seq[0]:
|
400
403
|
return num
|
401
404
|
else:
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
while lo < hi:
|
412
|
-
mid = (lo + hi) // 2
|
413
|
-
if sorted_seq[mid] < num + mid + 1:
|
414
|
-
lo = mid + 1
|
415
|
-
else:
|
416
|
-
hi = mid
|
417
|
-
return num + lo
|
405
|
+
hi = len(sorted_seq)
|
406
|
+
lo = 0
|
407
|
+
while lo < hi:
|
408
|
+
mid = (lo + hi) // 2
|
409
|
+
if sorted_seq[mid] < num + mid + 1:
|
410
|
+
lo = mid + 1
|
411
|
+
else:
|
412
|
+
hi = mid
|
413
|
+
return num + lo
|
418
414
|
|
419
415
|
|
420
416
|
def get_dropdown_kwargs(
|
421
|
-
values: list =
|
422
|
-
set_value:
|
417
|
+
values: list[Any] | None = None,
|
418
|
+
set_value: Any = None,
|
423
419
|
state: str = "normal",
|
424
420
|
redraw: bool = True,
|
425
421
|
selection_function: Callable | None = None,
|
@@ -429,7 +425,7 @@ def get_dropdown_kwargs(
|
|
429
425
|
text: None | str = None,
|
430
426
|
) -> dict:
|
431
427
|
return {
|
432
|
-
"values": values,
|
428
|
+
"values": [] if values is None else values,
|
433
429
|
"set_value": set_value,
|
434
430
|
"state": state,
|
435
431
|
"redraw": redraw,
|
@@ -477,7 +473,7 @@ def get_checkbox_dict(**kwargs) -> dict:
|
|
477
473
|
}
|
478
474
|
|
479
475
|
|
480
|
-
def is_iterable(o:
|
476
|
+
def is_iterable(o: Any) -> bool:
|
481
477
|
if isinstance(o, str):
|
482
478
|
return False
|
483
479
|
try:
|
@@ -499,7 +495,7 @@ def int_x_tuple(i: AnyIter[int] | int) -> tuple[int]:
|
|
499
495
|
return tuple(i)
|
500
496
|
|
501
497
|
|
502
|
-
def unpack(t: tuple[
|
498
|
+
def unpack(t: tuple[Any] | tuple[AnyIter[Any]]) -> tuple[Any]:
|
503
499
|
if not len(t):
|
504
500
|
return t
|
505
501
|
if is_iterable(t[0]) and len(t) == 1:
|
@@ -507,11 +503,11 @@ def unpack(t: tuple[object] | tuple[AnyIter[object]]) -> tuple[object]:
|
|
507
503
|
return t
|
508
504
|
|
509
505
|
|
510
|
-
def is_type_int(o:
|
506
|
+
def is_type_int(o: Any) -> bool:
|
511
507
|
return isinstance(o, int) and not isinstance(o, bool)
|
512
508
|
|
513
509
|
|
514
|
-
def force_bool(o:
|
510
|
+
def force_bool(o: Any) -> bool:
|
515
511
|
try:
|
516
512
|
return to_bool(o)
|
517
513
|
except Exception:
|
@@ -702,8 +698,8 @@ def cell_right_within_box(
|
|
702
698
|
|
703
699
|
|
704
700
|
def get_last(
|
705
|
-
it: AnyIter[
|
706
|
-
) ->
|
701
|
+
it: AnyIter[Any],
|
702
|
+
) -> Any:
|
707
703
|
if hasattr(it, "__reversed__"):
|
708
704
|
try:
|
709
705
|
return next(reversed(it))
|
@@ -716,7 +712,7 @@ def get_last(
|
|
716
712
|
return None
|
717
713
|
|
718
714
|
|
719
|
-
def index_exists(seq: Sequence[
|
715
|
+
def index_exists(seq: Sequence[Any], index: int) -> bool:
|
720
716
|
try:
|
721
717
|
seq[index]
|
722
718
|
return True
|
@@ -733,10 +729,10 @@ def add_to_displayed(displayed: list[int], to_add: Iterable[int]) -> list[int]:
|
|
733
729
|
|
734
730
|
|
735
731
|
def move_elements_by_mapping(
|
736
|
-
seq: list[
|
732
|
+
seq: list[Any],
|
737
733
|
new_idxs: dict[int, int],
|
738
734
|
old_idxs: dict[int, int] | None = None,
|
739
|
-
) -> list[
|
735
|
+
) -> list[Any]:
|
740
736
|
# move elements of a list around
|
741
737
|
# displacing other elements based on mapping
|
742
738
|
# new_idxs = {old index: new index, ...}
|
@@ -748,10 +744,10 @@ def move_elements_by_mapping(
|
|
748
744
|
|
749
745
|
|
750
746
|
def move_elements_by_mapping_gen(
|
751
|
-
seq: list[
|
747
|
+
seq: list[Any],
|
752
748
|
new_idxs: dict[int, int],
|
753
749
|
old_idxs: dict[int, int] | None = None,
|
754
|
-
) -> Generator[
|
750
|
+
) -> Generator[Any]:
|
755
751
|
if old_idxs is None:
|
756
752
|
old_idxs = dict(zip(new_idxs.values(), new_idxs))
|
757
753
|
remaining_values = (e for i, e in enumerate(seq) if i not in new_idxs)
|
@@ -759,10 +755,10 @@ def move_elements_by_mapping_gen(
|
|
759
755
|
|
760
756
|
|
761
757
|
def move_elements_to(
|
762
|
-
seq: list[
|
758
|
+
seq: list[Any],
|
763
759
|
move_to: int,
|
764
760
|
to_move: list[int],
|
765
|
-
) -> list[
|
761
|
+
) -> list[Any]:
|
766
762
|
return move_elements_by_mapping(
|
767
763
|
seq,
|
768
764
|
*get_new_indexes(
|
@@ -775,31 +771,30 @@ def move_elements_to(
|
|
775
771
|
|
776
772
|
def get_new_indexes(
|
777
773
|
move_to: int,
|
778
|
-
to_move:
|
774
|
+
to_move: Iterable[int],
|
779
775
|
get_inverse: bool = False,
|
780
|
-
) -> tuple[dict]:
|
776
|
+
) -> tuple[dict[int, int]] | dict[int, int]:
|
781
777
|
"""
|
782
778
|
move_to: A positive int, could possibly be the same as an element of to_move
|
783
|
-
to_move:
|
779
|
+
to_move: An iterable of ints, could be a dict, could be in any order
|
784
780
|
returns {old idx: new idx, ...}
|
785
781
|
"""
|
786
782
|
offset = sum(1 for i in to_move if i < move_to)
|
787
|
-
new_idxs = range(move_to - offset, move_to - offset + len(to_move))
|
788
|
-
new_idxs = {old: new for old, new in zip(to_move, new_idxs)}
|
783
|
+
new_idxs = dict(zip(to_move, range(move_to - offset, move_to - offset + len(to_move))))
|
789
784
|
if get_inverse:
|
790
785
|
return new_idxs, dict(zip(new_idxs.values(), new_idxs))
|
791
786
|
return new_idxs
|
792
787
|
|
793
788
|
|
794
789
|
def insert_items(
|
795
|
-
seq: list[
|
796
|
-
to_insert: dict[int,
|
790
|
+
seq: list[Any],
|
791
|
+
to_insert: dict[int, Any],
|
797
792
|
seq_len_func: Callable | None = None,
|
798
|
-
) -> list[
|
793
|
+
) -> list[Any]:
|
799
794
|
"""
|
800
|
-
seq: list[
|
795
|
+
seq: list[Any]
|
801
796
|
to_insert: keys are ints sorted in reverse, representing list indexes to insert items.
|
802
|
-
Values are any
|
797
|
+
Values are any, e.g. {1: 200, 0: 200}
|
803
798
|
"""
|
804
799
|
if to_insert:
|
805
800
|
if seq_len_func and next(iter(to_insert)) >= len(seq) + len(to_insert):
|
@@ -810,11 +805,11 @@ def insert_items(
|
|
810
805
|
|
811
806
|
|
812
807
|
def del_placeholder_dict_key(
|
813
|
-
d: dict[Hashable,
|
808
|
+
d: dict[Hashable, Any],
|
814
809
|
k: Hashable,
|
815
|
-
v:
|
816
|
-
p: tuple =
|
817
|
-
) -> dict[Hashable,
|
810
|
+
v: Any,
|
811
|
+
p: tuple = (),
|
812
|
+
) -> dict[Hashable, Any]:
|
818
813
|
if p in d:
|
819
814
|
del d[p]
|
820
815
|
d[k] = v
|
@@ -995,7 +990,7 @@ def is_last_cell(
|
|
995
990
|
return row == end_row - 1 and col == end_col - 1
|
996
991
|
|
997
992
|
|
998
|
-
def zip_fill_2nd_value(x: AnyIter[
|
993
|
+
def zip_fill_2nd_value(x: AnyIter[Any], o: Any) -> Generator[Any, Any]:
|
999
994
|
return zip(x, repeat(o))
|
1000
995
|
|
1001
996
|
|
@@ -1012,7 +1007,7 @@ def str_to_int(s: str) -> int | None:
|
|
1012
1007
|
|
1013
1008
|
def gen_formatted(
|
1014
1009
|
options: dict,
|
1015
|
-
formatter:
|
1010
|
+
formatter: Any = None,
|
1016
1011
|
) -> Generator[tuple[int, int]] | Generator[int]:
|
1017
1012
|
if formatter is None:
|
1018
1013
|
return (k for k, dct in options.items() if "format" in dct)
|
@@ -1061,7 +1056,7 @@ def span_dict(
|
|
1061
1056
|
convert: Callable | None = None,
|
1062
1057
|
undo: bool = False,
|
1063
1058
|
emit_event: bool = False,
|
1064
|
-
widget:
|
1059
|
+
widget: Any = None,
|
1065
1060
|
) -> Span:
|
1066
1061
|
d: Span = Span(
|
1067
1062
|
from_r=from_r,
|
@@ -1088,7 +1083,7 @@ def span_dict(
|
|
1088
1083
|
|
1089
1084
|
|
1090
1085
|
def coords_to_span(
|
1091
|
-
widget:
|
1086
|
+
widget: Any,
|
1092
1087
|
from_r: int | None = None,
|
1093
1088
|
from_c: int | None = None,
|
1094
1089
|
upto_r: int | None = None,
|
@@ -1123,7 +1118,7 @@ def key_to_span(
|
|
1123
1118
|
| Sequence[Sequence[int | None, int | None], Sequence[int | None, int | None]]
|
1124
1119
|
),
|
1125
1120
|
spans: dict[str, Span],
|
1126
|
-
widget:
|
1121
|
+
widget: Any = None,
|
1127
1122
|
) -> Span:
|
1128
1123
|
if isinstance(key, Span):
|
1129
1124
|
return key
|
@@ -1505,14 +1500,8 @@ def span_ranges(
|
|
1505
1500
|
) -> tuple[Generator[int], Generator[int]]:
|
1506
1501
|
rng_from_r = 0 if span.from_r is None else span.from_r
|
1507
1502
|
rng_from_c = 0 if span.from_c is None else span.from_c
|
1508
|
-
if span.upto_r is None
|
1509
|
-
|
1510
|
-
else:
|
1511
|
-
rng_upto_r = span.upto_r
|
1512
|
-
if span.upto_c is None:
|
1513
|
-
rng_upto_c = totalcols() if isinstance(totalcols, Callable) else totalcols
|
1514
|
-
else:
|
1515
|
-
rng_upto_c = span.upto_c
|
1503
|
+
rng_upto_r = (totalrows() if isinstance(totalrows, Callable) else totalrows) if span.upto_r is None else span.upto_r
|
1504
|
+
rng_upto_c = (totalcols() if isinstance(totalcols, Callable) else totalcols) if span.upto_c is None else span.upto_c
|
1516
1505
|
return range(rng_from_r, rng_upto_r), range(rng_from_c, rng_upto_c)
|
1517
1506
|
|
1518
1507
|
|
@@ -1630,7 +1619,7 @@ def add_to_options(
|
|
1630
1619
|
options: dict,
|
1631
1620
|
coords: int | tuple[int, int],
|
1632
1621
|
key: str,
|
1633
|
-
value:
|
1622
|
+
value: Any,
|
1634
1623
|
) -> dict:
|
1635
1624
|
if coords not in options:
|
1636
1625
|
options[coords] = {}
|
@@ -1674,10 +1663,7 @@ def span_idxs_post_move(
|
|
1674
1663
|
newupto_colrange = newupto
|
1675
1664
|
else:
|
1676
1665
|
oldfrom = int(span[f"from_{axis}"])
|
1677
|
-
if not oldfrom
|
1678
|
-
newfrom = 0
|
1679
|
-
else:
|
1680
|
-
newfrom = full_new_idxs[oldfrom]
|
1666
|
+
newfrom = 0 if not oldfrom else full_new_idxs[oldfrom]
|
1681
1667
|
newupto = None
|
1682
1668
|
oldupto_colrange = total
|
1683
1669
|
newupto_colrange = oldupto_colrange
|
@@ -1704,14 +1690,14 @@ def mod_span(
|
|
1704
1690
|
return to_set_to
|
1705
1691
|
|
1706
1692
|
|
1707
|
-
def mod_span_widget(span: Span, widget:
|
1693
|
+
def mod_span_widget(span: Span, widget: Any) -> Span:
|
1708
1694
|
span.widget = widget
|
1709
1695
|
return span
|
1710
1696
|
|
1711
1697
|
|
1712
1698
|
def mod_event_val(
|
1713
1699
|
event_data: EventDataDict,
|
1714
|
-
val:
|
1700
|
+
val: Any,
|
1715
1701
|
loc: Loc | None = None,
|
1716
1702
|
row: int | None = None,
|
1717
1703
|
column: int | None = None,
|