Skip to content

Commit 6ef4142

Browse files
committed
fix: natural_sort_key improper sorting of some integers
`natural_sort_key` improperly treating some integers as dates, leading to incorrect sorting of numbers. `natural_sort_key` no longer sorts strings that are integer style dates, e.g. `"20251030"` use `date_sort_key` for those.
1 parent dfd84b9 commit 6ef4142

4 files changed

Lines changed: 130 additions & 2 deletions

File tree

docs/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
### Version 7.6.0
2+
#### Fixed:
3+
- `natural_sort_key` improperly treating some integers as dates, leading to incorrect sorting of numbers.
4+
25
#### Changed:
36
- Copying cells to clipboard which are `None` now copies an empty string `""`, previously copied `"None"` to clipboard.
7+
- `natural_sort_key` no longer sorts strings that are integer style dates, e.g. `"20251030"` use `date_sort_key` for those.
8+
9+
#### Added:
10+
- `date_sort_key` to emulate previous behavior of `natural_sort_key` where for strings, a date conversion is attempted before a float and integer style dates are handled. This may cause errors in some edge cases though [#316](https://github.com/ragardner/tksheet/issues/316).
411

512
### Version 7.5.19
613
#### Addressed:

docs/DOCUMENTATION.html

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@
408408
<li><a href="#natural_sort_key">natural_sort_key</a></li>
409409
<li><a href="#version_sort_key">version_sort_key</a></li>
410410
<li><a href="#fast_sort_key">fast_sort_key</a></li>
411+
<li><a href="#date_sort_key">date_sort_key</a></li>
411412
<li><a href="#setting-the-default-sorting-key">Setting the default sorting key</a></li>
412413
<li><a href="#sorting-cells">Sorting cells</a></li>
413414
<li><a href="#sorting-row-values">Sorting row values</a></li>
@@ -4365,6 +4366,7 @@ <h4 id="natural_sort_key"><strong>natural_sort_key</strong></h4>
43654366
<ul>
43664367
<li>Won't sort string version numbers.</li>
43674368
<li>Will convert strings to floats.</li>
4369+
<li>Will try to convert strings to floats before it tries to convert them to dates.</li>
43684370
<li>Will sort strings that are file paths.</li>
43694371
</ul>
43704372
<p>Order:</p>
@@ -4414,6 +4416,28 @@ <h4 id="fast_sort_key"><strong>fast_sort_key</strong></h4>
44144416
<li>strings (including paths as POSIX strings) &amp; unknown objects with <strong>str</strong></li>
44154417
<li>unknown objects</li>
44164418
</ul>
4419+
<h4 id="date_sort_key"><strong>date_sort_key</strong></h4>
4420+
<p>A key for sorting with an emphasis on dates over numbers. This used to be <code>natural_sort_key</code> in tksheet versions prior to <code>7.6.0</code>.</p>
4421+
<ul>
4422+
<li>Won't sort string version numbers</li>
4423+
<li>Will try to convert strings to dates before it tries floats<ul>
4424+
<li>This may result in errors in integer date edge cases</li>
4425+
</ul>
4426+
</li>
4427+
<li>Will convert strings to floats</li>
4428+
<li>
4429+
<p>Will sort strings that are file paths</p>
4430+
</li>
4431+
<li>
4432+
<p>None</p>
4433+
</li>
4434+
<li>Empty strings</li>
4435+
<li>bool</li>
4436+
<li>int, float (inc. strings that are numbers)</li>
4437+
<li>datetime (inc. strings that are dates)</li>
4438+
<li>strings (including string file paths and paths as POSIX strings) &amp; unknown objects with <strong>str</strong></li>
4439+
<li>unknown objects</li>
4440+
</ul>
44174441
<h4 id="setting-the-default-sorting-key"><strong>Setting the default sorting key</strong></h4>
44184442
<p>Setting the sorting key at initialization:</p>
44194443
<pre><code class="language-python">from tksheet import Sheet, natural_sort_key

docs/DOCUMENTATION.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3976,6 +3976,7 @@ This is the **default** sorting key for natural sorting of various Python types:
39763976

39773977
- Won't sort string version numbers.
39783978
- Will convert strings to floats.
3979+
- Will try to convert strings to floats before it tries to convert them to dates.
39793980
- Will sort strings that are file paths.
39803981

39813982
Order:
@@ -4021,6 +4022,24 @@ A faster key for natural sorting of various Python types. This key should probab
40214022
5. strings (including paths as POSIX strings) & unknown objects with __str__
40224023
6. unknown objects
40234024

4025+
#### **date_sort_key**
4026+
4027+
A key for sorting with an emphasis on dates over numbers. This used to be `natural_sort_key` in tksheet versions prior to `7.6.0`.
4028+
4029+
- Won't sort string version numbers
4030+
- Will try to convert strings to dates before it tries floats
4031+
- This may result in errors in integer date edge cases
4032+
- Will convert strings to floats
4033+
- Will sort strings that are file paths
4034+
4035+
0. None
4036+
1. Empty strings
4037+
2. bool
4038+
3. int, float (inc. strings that are numbers)
4039+
4. datetime (inc. strings that are dates)
4040+
5. strings (including string file paths and paths as POSIX strings) & unknown objects with __str__
4041+
6. unknown objects
4042+
40244043
#### **Setting the default sorting key**
40254044

40264045
Setting the sorting key at initialization:

tksheet/sorting.py

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,85 @@ def natural_sort_key(item: Any) -> tuple[int, ...]:
151151
- Will convert strings to floats
152152
- Will sort strings that are file paths
153153
154+
0. None
155+
1. Empty strings
156+
2. bool
157+
3. int, float (inc. strings that are numbers)
158+
4. datetime (inc. strings that are dates, except for pure integer dates)
159+
5. strings (including string file paths and paths as POSIX strings) & unknown objects with __str__
160+
6. unknown objects
161+
"""
162+
if isinstance(item, str):
163+
if item:
164+
try:
165+
return (3, float(item))
166+
except ValueError:
167+
for date_format in date_formats:
168+
try:
169+
return (4, datetime.strptime(item, date_format).timestamp())
170+
except ValueError:
171+
continue
172+
# the same as _string_fallback
173+
components = split(r"[/\\]", item)
174+
if components[-1]:
175+
return (
176+
5,
177+
len(components),
178+
tuple(
179+
int(e) if e.isdigit() else e.lower()
180+
for comp in components[:-1]
181+
for e in split(r"(\d+)", comp)
182+
if e
183+
),
184+
tuple(int(e) if e.isdigit() else e.lower() for e in split(r"(\d+)", components[-1])),
185+
)
186+
else:
187+
return (
188+
5,
189+
len(components),
190+
tuple(
191+
int(e) if e.isdigit() else e.lower()
192+
for comp in components[:-1]
193+
for e in split(r"(\d+)", comp)
194+
if e
195+
),
196+
(),
197+
)
198+
else:
199+
return (1, item)
200+
201+
elif item is None:
202+
return (0,)
203+
204+
elif isinstance(item, bool):
205+
return (2, item)
206+
207+
elif isinstance(item, (int, float)):
208+
return (3, item)
209+
210+
elif isinstance(item, datetime):
211+
return (4, item.timestamp())
212+
213+
elif isinstance(item, Path):
214+
return _string_fallback(item.as_posix())
215+
216+
else:
217+
try:
218+
return _string_fallback(f"{item}")
219+
except Exception:
220+
return (6, item)
221+
222+
223+
def date_sort_key(item: Any) -> tuple[int, ...]:
224+
"""
225+
A key for sorting with an emphasis on dates over numbers.
226+
227+
- Won't sort string version numbers
228+
- Will try to convert strings to dates before it tries floats
229+
- This may result in errors in integer date edge cases
230+
- Will convert strings to floats
231+
- Will sort strings that are file paths
232+
154233
0. None
155234
1. Empty strings
156235
2. bool
@@ -166,7 +245,6 @@ def natural_sort_key(item: Any) -> tuple[int, ...]:
166245
return (4, datetime.strptime(item, date_format).timestamp())
167246
except ValueError:
168247
continue
169-
170248
try:
171249
return (3, float(item))
172250
except ValueError:
@@ -423,7 +501,7 @@ def sort_tree_rows_by_column(
423501
return [], {}
424502

425503
if key is None:
426-
key = natural_sort_key # Assuming natural_sort_key is defined elsewhere
504+
key = natural_sort_key
427505

428506
# Define the sort_reverse parameter to avoid unnecessary reversals
429507
sort_reverse = not reverse

0 commit comments

Comments
 (0)