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

1import re 

2from abc import ABC, abstractmethod 

3from collections.abc import Sequence 

4from pathlib import Path 

5from typing import Protocol 

6 

7NUMBERS_REGEX = re.compile(r"[0-9]+") 

8 

9 

10class Comparable[CT: Comparable](Protocol): 

11 def __lt__(self: CT, other: CT, /) -> bool: ... 

12 

13 

14class SortStrategy[T: Comparable[int | str]](ABC): 

15 @abstractmethod 

16 def get_sort_order(self, path: Path) -> T: ... 

17 

18 

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 

23 

24 

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 

29 

30 

31class LastFolderSort(SortStrategy[str]): 

32 def get_sort_order(self, path: Path) -> str: 

33 return path.parent.name 

34 

35 

36SORTERS: dict[str, SortStrategy[str | int]] = { 

37 "first_number": FirstNumberSort(), 

38 "last_number": LastNumberSort(), 

39 "folder": LastFolderSort(), 

40} 

41 

42 

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 )