tksheet 7.4.0__tar.gz → 7.4.1__tar.gz
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-7.4.0/tksheet.egg-info → tksheet-7.4.1}/PKG-INFO +1 -4
- {tksheet-7.4.0 → tksheet-7.4.1}/README.md +0 -3
- {tksheet-7.4.0 → tksheet-7.4.1}/pyproject.toml +1 -1
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/__init__.py +1 -1
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/main_table.py +40 -28
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/sorting.py +13 -95
- {tksheet-7.4.0 → tksheet-7.4.1/tksheet.egg-info}/PKG-INFO +1 -4
- {tksheet-7.4.0 → tksheet-7.4.1}/LICENSE.txt +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/setup.cfg +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/colors.py +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/column_headers.py +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/constants.py +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/find_window.py +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/formatters.py +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/functions.py +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/other_classes.py +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/row_index.py +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/sheet.py +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/sheet_options.py +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/text_editor.py +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/themes.py +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/tksheet_types.py +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet/top_left_rectangle.py +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet.egg-info/SOURCES.txt +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet.egg-info/dependency_links.txt +0 -0
- {tksheet-7.4.0 → tksheet-7.4.1}/tksheet.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: tksheet
|
3
|
-
Version: 7.4.
|
3
|
+
Version: 7.4.1
|
4
4
|
Summary: Tkinter table / sheet and treeview widget
|
5
5
|
Author-email: ragardner <github@ragardner.simplelogin.com>
|
6
6
|
License: Copyright (c) 2019 ragardner and open source contributors
|
@@ -82,8 +82,6 @@ License-File: LICENSE.txt
|
|
82
82
|
</tbody>
|
83
83
|
</table>
|
84
84
|
|
85
|
-
This library is maintained with the help of **[others](https://github.com/ragardner/tksheet/graphs/contributors)**. If you would like to contribute please read this [help section](https://github.com/ragardner/tksheet/wiki/Version-7#contributing).
|
86
|
-
|
87
85
|
## **Features**
|
88
86
|
|
89
87
|
- Smoothly display and modify tabular data
|
@@ -95,7 +93,6 @@ This library is maintained with the help of **[others](https://github.com/ragard
|
|
95
93
|
- [Expand row heights and column widths](https://github.com/ragardner/tksheet/wiki/Version-7#table-functionality-and-bindings)
|
96
94
|
- [Change fonts and font size (not for individual cells)](https://github.com/ragardner/tksheet/wiki/Version-7#text-font-and-alignment)
|
97
95
|
- [Change any colors in the sheet](https://github.com/ragardner/tksheet/wiki/Version-7#sheet-appearance)
|
98
|
-
|
99
96
|
- [Dropdown boxes](https://github.com/ragardner/tksheet/wiki/Version-7#dropdown-boxes)
|
100
97
|
- [Check boxes](https://github.com/ragardner/tksheet/wiki/Version-7#check-boxes)
|
101
98
|
- [Progress bars](https://github.com/ragardner/tksheet/wiki/Version-7#progress-bars)
|
@@ -39,8 +39,6 @@
|
|
39
39
|
</tbody>
|
40
40
|
</table>
|
41
41
|
|
42
|
-
This library is maintained with the help of **[others](https://github.com/ragardner/tksheet/graphs/contributors)**. If you would like to contribute please read this [help section](https://github.com/ragardner/tksheet/wiki/Version-7#contributing).
|
43
|
-
|
44
42
|
## **Features**
|
45
43
|
|
46
44
|
- Smoothly display and modify tabular data
|
@@ -52,7 +50,6 @@ This library is maintained with the help of **[others](https://github.com/ragard
|
|
52
50
|
- [Expand row heights and column widths](https://github.com/ragardner/tksheet/wiki/Version-7#table-functionality-and-bindings)
|
53
51
|
- [Change fonts and font size (not for individual cells)](https://github.com/ragardner/tksheet/wiki/Version-7#text-font-and-alignment)
|
54
52
|
- [Change any colors in the sheet](https://github.com/ragardner/tksheet/wiki/Version-7#sheet-appearance)
|
55
|
-
|
56
53
|
- [Dropdown boxes](https://github.com/ragardner/tksheet/wiki/Version-7#dropdown-boxes)
|
57
54
|
- [Check boxes](https://github.com/ragardner/tksheet/wiki/Version-7#check-boxes)
|
58
55
|
- [Progress bars](https://github.com/ragardner/tksheet/wiki/Version-7#progress-bars)
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
6
6
|
name = "tksheet"
|
7
7
|
description = "Tkinter table / sheet and treeview widget"
|
8
8
|
readme = "README.md"
|
9
|
-
version = "7.4.
|
9
|
+
version = "7.4.1"
|
10
10
|
authors = [{ name = "ragardner", email = "github@ragardner.simplelogin.com" }]
|
11
11
|
requires-python = ">=3.8"
|
12
12
|
license = {file = "LICENSE.txt"}
|
@@ -275,31 +275,21 @@ class MainTable(tk.Canvas):
|
|
275
275
|
self.all_columns_displayed = True
|
276
276
|
self.all_rows_displayed = True
|
277
277
|
self.align = kwargs["align"]
|
278
|
-
|
279
|
-
self.PAR.ops.table_font = [
|
278
|
+
self.PAR.ops.table_font = FontTuple(
|
280
279
|
self.PAR.ops.table_font[0],
|
281
|
-
int(self.PAR.ops.table_font[1] * kwargs["zoom"] / 100),
|
280
|
+
max(1, int(self.PAR.ops.table_font[1] * kwargs["zoom"] / 100)),
|
282
281
|
self.PAR.ops.table_font[2],
|
283
|
-
|
284
|
-
|
285
|
-
self.PAR.ops.index_font = [
|
282
|
+
)
|
283
|
+
self.PAR.ops.index_font = FontTuple(
|
286
284
|
self.PAR.ops.index_font[0],
|
287
|
-
int(self.PAR.ops.index_font[1] * kwargs["zoom"] / 100),
|
285
|
+
max(1, int(self.PAR.ops.index_font[1] * kwargs["zoom"] / 100)),
|
288
286
|
self.PAR.ops.index_font[2],
|
289
|
-
|
290
|
-
|
291
|
-
self.PAR.ops.header_font = [
|
287
|
+
)
|
288
|
+
self.PAR.ops.header_font = FontTuple(
|
292
289
|
self.PAR.ops.header_font[0],
|
293
|
-
int(self.PAR.ops.header_font[1] * kwargs["zoom"] / 100),
|
290
|
+
max(1, int(self.PAR.ops.header_font[1] * kwargs["zoom"] / 100)),
|
294
291
|
self.PAR.ops.header_font[2],
|
295
|
-
|
296
|
-
for fnt in (self.PAR.ops.table_font, self.PAR.ops.index_font, self.PAR.ops.header_font):
|
297
|
-
if fnt[1] < 1:
|
298
|
-
fnt[1] = 1
|
299
|
-
self.PAR.ops.table_font = FontTuple(*self.PAR.ops.table_font)
|
300
|
-
self.PAR.ops.index_font = FontTuple(*self.PAR.ops.index_font)
|
301
|
-
self.PAR.ops.header_font = FontTuple(*self.PAR.ops.header_font)
|
302
|
-
|
292
|
+
)
|
303
293
|
self.txt_measure_canvas = tk.Canvas(self)
|
304
294
|
self.txt_measure_canvas_text = self.txt_measure_canvas.create_text(0, 0, text="", font=self.PAR.ops.table_font)
|
305
295
|
|
@@ -1155,7 +1145,7 @@ class MainTable(tk.Canvas):
|
|
1155
1145
|
if ctr:
|
1156
1146
|
event_data = self.add_rows(
|
1157
1147
|
rows=rows,
|
1158
|
-
index=index,
|
1148
|
+
index=index if isinstance(self._row_index, list) and self._row_index else {},
|
1159
1149
|
row_heights=row_heights,
|
1160
1150
|
event_data=event_data,
|
1161
1151
|
mod_event_boxes=False,
|
@@ -1205,7 +1195,7 @@ class MainTable(tk.Canvas):
|
|
1205
1195
|
if ctr:
|
1206
1196
|
event_data = self.add_columns(
|
1207
1197
|
columns=columns,
|
1208
|
-
header=headers,
|
1198
|
+
header=headers if isinstance(self._headers, list) and self._headers else {},
|
1209
1199
|
column_widths=column_widths,
|
1210
1200
|
event_data=event_data,
|
1211
1201
|
mod_event_boxes=False,
|
@@ -5009,8 +4999,11 @@ class MainTable(tk.Canvas):
|
|
5009
4999
|
event_data = self.new_event_dict("add_columns", state=True)
|
5010
5000
|
if not try_binding(self.extra_begin_insert_cols_rc_func, event_data, "begin_add_columns"):
|
5011
5001
|
return
|
5002
|
+
columns, headers, widths = self.get_args_for_add_columns(data_ins_col, displayed_ins_col, numcols)
|
5012
5003
|
event_data = self.add_columns(
|
5013
|
-
|
5004
|
+
columns=columns,
|
5005
|
+
header=headers if isinstance(self._headers, list) and self._headers else {},
|
5006
|
+
column_widths=widths,
|
5014
5007
|
event_data=event_data,
|
5015
5008
|
)
|
5016
5009
|
if self.undo_enabled:
|
@@ -5138,8 +5131,11 @@ class MainTable(tk.Canvas):
|
|
5138
5131
|
event_data = self.new_event_dict("add_rows", state=True)
|
5139
5132
|
if not try_binding(self.extra_begin_insert_rows_rc_func, event_data, "begin_add_rows"):
|
5140
5133
|
return
|
5134
|
+
rows, index, heights = self.get_args_for_add_rows(data_ins_row, displayed_ins_row, numrows)
|
5141
5135
|
event_data = self.add_rows(
|
5142
|
-
|
5136
|
+
rows=rows,
|
5137
|
+
index=index if isinstance(self._row_index, list) and self._row_index else {},
|
5138
|
+
row_heights=heights,
|
5143
5139
|
event_data=event_data,
|
5144
5140
|
)
|
5145
5141
|
if self.undo_enabled:
|
@@ -5346,12 +5342,22 @@ class MainTable(tk.Canvas):
|
|
5346
5342
|
return event_data
|
5347
5343
|
if not ext and not try_binding(self.extra_begin_del_cols_rc_func, event_data, "begin_delete_columns"):
|
5348
5344
|
return
|
5345
|
+
if self.all_columns_displayed:
|
5346
|
+
data_columns = columns
|
5347
|
+
disp_columns = columns
|
5348
|
+
else:
|
5349
|
+
if data_indexes:
|
5350
|
+
data_columns = columns
|
5351
|
+
disp_columns = data_to_displayed_idxs(data_columns, self.displayed_columns)
|
5352
|
+
else:
|
5353
|
+
data_columns = [self.displayed_columns[c] for c in columns]
|
5354
|
+
disp_columns = columns
|
5349
5355
|
event_data = self.delete_columns_displayed(
|
5350
|
-
|
5356
|
+
disp_columns,
|
5351
5357
|
event_data,
|
5352
5358
|
)
|
5353
5359
|
event_data = self.delete_columns_data(
|
5354
|
-
|
5360
|
+
data_columns,
|
5355
5361
|
event_data,
|
5356
5362
|
)
|
5357
5363
|
if undo and self.undo_enabled:
|
@@ -5425,10 +5431,16 @@ class MainTable(tk.Canvas):
|
|
5425
5431
|
return
|
5426
5432
|
if not ext and not try_binding(self.extra_begin_del_rows_rc_func, event_data, "begin_delete_rows"):
|
5427
5433
|
return
|
5428
|
-
if
|
5434
|
+
if self.all_rows_displayed:
|
5429
5435
|
data_rows = rows
|
5436
|
+
disp_rows = rows
|
5430
5437
|
else:
|
5431
|
-
|
5438
|
+
if data_indexes:
|
5439
|
+
data_rows = rows
|
5440
|
+
disp_rows = data_to_displayed_idxs(data_rows, self.displayed_rows)
|
5441
|
+
else:
|
5442
|
+
data_rows = [self.displayed_rows[r] for r in rows]
|
5443
|
+
disp_rows = rows
|
5432
5444
|
if self.PAR.ops.treeview:
|
5433
5445
|
data_rows = sorted(
|
5434
5446
|
chain(
|
@@ -5441,7 +5453,7 @@ class MainTable(tk.Canvas):
|
|
5441
5453
|
)
|
5442
5454
|
)
|
5443
5455
|
event_data = self.delete_rows_displayed(
|
5444
|
-
|
5456
|
+
disp_rows,
|
5445
5457
|
event_data,
|
5446
5458
|
)
|
5447
5459
|
event_data = self.delete_rows_data(
|
@@ -1,9 +1,8 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
import re
|
4
|
-
import unittest
|
5
3
|
from collections.abc import Callable, Generator
|
6
4
|
from datetime import datetime
|
5
|
+
from re import finditer
|
7
6
|
|
8
7
|
from .other_classes import Node
|
9
8
|
from .tksheet_types import AnyIter
|
@@ -59,8 +58,6 @@ def natural_sort_key(item: object) -> tuple[int, object]:
|
|
59
58
|
- Strings with natural sorting for embedded numbers and dates
|
60
59
|
- Unknown types treated as strings or left at the end
|
61
60
|
|
62
|
-
With love from Grok ❤️
|
63
|
-
|
64
61
|
Args:
|
65
62
|
item: Any Python object to be sorted.
|
66
63
|
|
@@ -68,39 +65,42 @@ def natural_sort_key(item: object) -> tuple[int, object]:
|
|
68
65
|
A tuple or value that can be used for sorting.
|
69
66
|
"""
|
70
67
|
if item is None:
|
71
|
-
return (0,
|
68
|
+
return (0,)
|
72
69
|
|
73
70
|
elif isinstance(item, bool):
|
74
71
|
return (1, item)
|
75
72
|
|
76
73
|
elif isinstance(item, (int, float)):
|
77
|
-
return (2,
|
74
|
+
return (2, item)
|
78
75
|
|
79
76
|
elif isinstance(item, datetime):
|
80
77
|
return (3, item.timestamp())
|
81
78
|
|
82
79
|
elif isinstance(item, str):
|
83
|
-
# Check if the whole string is a date
|
84
80
|
for date_format in date_formats:
|
85
81
|
try:
|
86
|
-
# Use the same sort order as for datetime objects
|
87
82
|
return (3, datetime.strptime(item, date_format).timestamp())
|
88
83
|
except ValueError:
|
89
84
|
continue
|
90
85
|
|
91
|
-
# Check if the whole string is a number
|
92
86
|
try:
|
93
|
-
return (
|
87
|
+
return (2, float(item))
|
94
88
|
except Exception:
|
95
|
-
|
96
|
-
|
89
|
+
n = []
|
90
|
+
s = []
|
91
|
+
for match in finditer(r"\d+|[^\d\s]+", item):
|
92
|
+
if (m := match.group()).isdigit():
|
93
|
+
n.append(int(m))
|
94
|
+
else:
|
95
|
+
s.append(m.lower())
|
96
|
+
return (5, s, n)
|
97
97
|
|
98
98
|
else:
|
99
99
|
# For unknown types, attempt to convert to string, or place at end
|
100
100
|
try:
|
101
101
|
return (6, f"{item}".lower())
|
102
102
|
except Exception:
|
103
|
-
return (7, item)
|
103
|
+
return (7, item)
|
104
104
|
|
105
105
|
|
106
106
|
def sort_selection(
|
@@ -285,85 +285,3 @@ def sort_tree_view(
|
|
285
285
|
new_index += 1
|
286
286
|
|
287
287
|
return sorted_nodes, mapping
|
288
|
-
|
289
|
-
|
290
|
-
class TestNaturalSort(unittest.TestCase):
|
291
|
-
def test_none_first(self):
|
292
|
-
self.assertEqual(natural_sort_key(None), (0, ""))
|
293
|
-
|
294
|
-
def test_booleans_order(self):
|
295
|
-
self.assertLess(natural_sort_key(False), natural_sort_key(True))
|
296
|
-
|
297
|
-
def test_numbers_order(self):
|
298
|
-
self.assertLess(natural_sort_key(5), natural_sort_key(10))
|
299
|
-
self.assertLess(natural_sort_key(5.5), natural_sort_key(6))
|
300
|
-
|
301
|
-
def test_datetime_order(self):
|
302
|
-
dt1 = datetime(2023, 1, 1)
|
303
|
-
dt2 = datetime(2023, 1, 2)
|
304
|
-
self.assertLess(natural_sort_key(dt1), natural_sort_key(dt2))
|
305
|
-
|
306
|
-
def test_string_natural_sort(self):
|
307
|
-
items = ["item2", "item10", "item1"]
|
308
|
-
sorted_items = sorted(items, key=natural_sort_key)
|
309
|
-
self.assertEqual(sorted_items, ["item1", "item2", "item10"])
|
310
|
-
|
311
|
-
def test_date_string_recognition(self):
|
312
|
-
# Test various date formats
|
313
|
-
date_str1 = "01/01/2023"
|
314
|
-
date_str2 = "2023-01-01"
|
315
|
-
date_str3 = "Jan 1, 2023"
|
316
|
-
|
317
|
-
dt = datetime(2023, 1, 1)
|
318
|
-
|
319
|
-
self.assertEqual(natural_sort_key(date_str1)[0], 3)
|
320
|
-
self.assertEqual(natural_sort_key(date_str2)[0], 3)
|
321
|
-
self.assertEqual(natural_sort_key(date_str3)[0], 3)
|
322
|
-
self.assertEqual(natural_sort_key(date_str1)[1], natural_sort_key(dt)[1]) # Timestamps should match
|
323
|
-
|
324
|
-
def test_unknown_types(self):
|
325
|
-
# Here we use a custom class for testing unknown types
|
326
|
-
class Unknown:
|
327
|
-
pass
|
328
|
-
|
329
|
-
unknown = Unknown()
|
330
|
-
self.assertEqual(natural_sort_key(unknown)[0], 5) # Success case, string conversion works
|
331
|
-
|
332
|
-
def test_unknown_types_failure(self):
|
333
|
-
# Create an object where string conversion fails
|
334
|
-
class Unconvertible:
|
335
|
-
def __str__(self):
|
336
|
-
raise Exception("String conversion fails")
|
337
|
-
|
338
|
-
def __repr__(self):
|
339
|
-
raise Exception("String conversion fails")
|
340
|
-
|
341
|
-
unconvertible = Unconvertible()
|
342
|
-
self.assertEqual(natural_sort_key(unconvertible)[0], 6) # Failure case, string conversion fails
|
343
|
-
|
344
|
-
|
345
|
-
def test_sort_selection():
|
346
|
-
# Test case 1: Mixed types, no reverse
|
347
|
-
data1 = [[1, "b"], [3, "a"]]
|
348
|
-
sorted_data1 = sort_selection(data1)
|
349
|
-
print(f"Test 1 - No reverse: {data1} -> {sorted_data1}")
|
350
|
-
|
351
|
-
# Test case 2: Mixed types, with reverse
|
352
|
-
data2 = [[1, "b"], [3, "a"]]
|
353
|
-
sorted_data2 = sort_selection(data2, reverse=True)
|
354
|
-
print(f"Test 2 - With reverse: {data2} -> {sorted_data2}")
|
355
|
-
|
356
|
-
# Test case 3: All numbers
|
357
|
-
data3 = [[2, 1], [4, 3]]
|
358
|
-
sorted_data3 = sort_selection(data3)
|
359
|
-
print(f"Test 3 - All numbers: {data3} -> {sorted_data3}")
|
360
|
-
|
361
|
-
# Test case 4: With None values
|
362
|
-
data4 = [[None, "b"], ["a", None]]
|
363
|
-
sorted_data4 = sort_selection(data4)
|
364
|
-
print(f"Test 4 - With None: {data4} -> {sorted_data4}")
|
365
|
-
|
366
|
-
|
367
|
-
if __name__ == "__main__":
|
368
|
-
test_sort_selection()
|
369
|
-
unittest.main()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: tksheet
|
3
|
-
Version: 7.4.
|
3
|
+
Version: 7.4.1
|
4
4
|
Summary: Tkinter table / sheet and treeview widget
|
5
5
|
Author-email: ragardner <github@ragardner.simplelogin.com>
|
6
6
|
License: Copyright (c) 2019 ragardner and open source contributors
|
@@ -82,8 +82,6 @@ License-File: LICENSE.txt
|
|
82
82
|
</tbody>
|
83
83
|
</table>
|
84
84
|
|
85
|
-
This library is maintained with the help of **[others](https://github.com/ragardner/tksheet/graphs/contributors)**. If you would like to contribute please read this [help section](https://github.com/ragardner/tksheet/wiki/Version-7#contributing).
|
86
|
-
|
87
85
|
## **Features**
|
88
86
|
|
89
87
|
- Smoothly display and modify tabular data
|
@@ -95,7 +93,6 @@ This library is maintained with the help of **[others](https://github.com/ragard
|
|
95
93
|
- [Expand row heights and column widths](https://github.com/ragardner/tksheet/wiki/Version-7#table-functionality-and-bindings)
|
96
94
|
- [Change fonts and font size (not for individual cells)](https://github.com/ragardner/tksheet/wiki/Version-7#text-font-and-alignment)
|
97
95
|
- [Change any colors in the sheet](https://github.com/ragardner/tksheet/wiki/Version-7#sheet-appearance)
|
98
|
-
|
99
96
|
- [Dropdown boxes](https://github.com/ragardner/tksheet/wiki/Version-7#dropdown-boxes)
|
100
97
|
- [Check boxes](https://github.com/ragardner/tksheet/wiki/Version-7#check-boxes)
|
101
98
|
- [Progress bars](https://github.com/ragardner/tksheet/wiki/Version-7#progress-bars)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|