Coverage for src\sql_organizer\sorter.py: 100%
26 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-25 09:55 +0300
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-25 09:55 +0300
1import re
2from abc import ABC, abstractmethod
3from collections.abc import Sequence
4from pathlib import Path
5from typing import Protocol
7NUMBERS_REGEX = re.compile(r"[0-9]+")
10class Comparable[CT: Comparable](Protocol):
11 def __lt__(self: CT, other: CT, /) -> bool: ...
14class SortStrategy[T: Comparable[int | str]](ABC):
15 @abstractmethod
16 def get_sort_order(self, path: Path) -> T: ...
19class FirstNumberSort(SortStrategy[int]):
20 def get_sort_order(self, path: Path) -> int:
21 matches = NUMBERS_REGEX.findall(path.stem)
22 return int(matches[0]) if len(matches) >= 1 else 0
25class LastNumberSort(SortStrategy[int]):
26 def get_sort_order(self, path: Path) -> int:
27 matches = NUMBERS_REGEX.findall(path.stem)
28 return int(matches[-1]) if len(matches) >= 1 else 0
31class LastFolderSort(SortStrategy[str]):
32 def get_sort_order(self, path: Path) -> str:
33 return path.parent.name
36SORTERS: dict[str, SortStrategy[str | int]] = {
37 "first_number": FirstNumberSort(),
38 "last_number": LastNumberSort(),
39 "folder": LastFolderSort(),
40}
43def sort_paths(
44 paths: Sequence[Path], sorting_strategies: Sequence[SortStrategy[int | str]]
45) -> list[Path]:
46 assert len(sorting_strategies) >= 1, (
47 "Sorting strategies should contain at least 1 value"
48 )
49 return sorted(
50 paths, key=lambda x: tuple(s.get_sort_order(x) for s in sorting_strategies)
51 )