Coverage for src/mkdocs_gallery/sorting.py: 57%

58 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-09-30 08:26 +0000

1# Authors: Sylvain MARIE <sylvain.marie@se.com> 

2# + All contributors to <https://github.com/smarie/mkdocs-gallery> 

3# 

4# Original idea and code: sphinx-gallery, <https://sphinx-gallery.github.io> 

5# License: 3-clause BSD, <https://github.com/smarie/mkdocs-gallery/blob/master/LICENSE> 

6""" 

7Sorters for mkdocs-gallery (sub)sections 

8======================================== 

9 

10Sorting key functions for gallery subsection folders and section files. 

11""" 

12 

13from __future__ import absolute_import, division, print_function 

14 

15import os 

16import types 

17from enum import Enum 

18from pathlib import Path 

19from typing import Iterable, Type 

20 

21from .errors import ConfigError 

22from .gen_single import extract_intro_and_title 

23from .py_source_parser import split_code_and_text_blocks 

24 

25 

26class _SortKey(object): 

27 """Base class for section order key classes.""" 

28 

29 def __repr__(self): 

30 return "<%s>" % (self.__class__.__name__,) 

31 

32 

33class ExplicitOrder(_SortKey): 

34 """Sorting key for all gallery subsections. 

35 

36 This requires all folders to be listed otherwise an exception is raised. 

37 

38 Parameters 

39 ---------- 

40 ordered_list : list, tuple, or :term:`python:generator` 

41 Hold the paths of each galleries' subsections. 

42 

43 Raises 

44 ------ 

45 ValueError 

46 Wrong input type or Subgallery path missing. 

47 """ 

48 

49 def __init__(self, ordered_list: Iterable[str]): 

50 if not isinstance(ordered_list, (list, tuple, types.GeneratorType)): 

51 raise ConfigError( 

52 "ExplicitOrder sorting key takes a list, " 

53 "tuple or Generator, which hold" 

54 "the paths of each gallery subfolder" 

55 ) 

56 

57 self.ordered_list = list(os.path.normpath(path) for path in ordered_list) 

58 

59 def __call__(self, item: Path): 

60 if item.name in self.ordered_list: 

61 return self.ordered_list.index(item.name) 

62 else: 

63 raise ConfigError( 

64 "If you use an explicit folder ordering, you " 

65 "must specify all folders. Explicit order not " 

66 "found for {}".format(item.name) 

67 ) 

68 

69 def __repr__(self): 

70 return "<%s : %s>" % (self.__class__.__name__, self.ordered_list) 

71 

72 

73class NumberOfCodeLinesSortKey(_SortKey): 

74 """Sort examples by the number of code lines.""" 

75 

76 def __call__(self, file: Path): 

77 file_conf, script_blocks = split_code_and_text_blocks(file) 

78 amount_of_code = sum([len(bcontent) for blabel, bcontent, lineno in script_blocks if blabel == "code"]) 

79 return amount_of_code 

80 

81 

82class FileSizeSortKey(_SortKey): 

83 """Sort examples by file size.""" 

84 

85 def __call__(self, file: Path): 

86 # src_file = os.path.normpath(str(file)) 

87 # return int(os.stat(src_file).st_size) 

88 return file.stat().st_size 

89 

90 

91class FileNameSortKey(_SortKey): 

92 """Sort examples by file name.""" 

93 

94 def __call__(self, file: Path): 

95 return file.name 

96 

97 

98class ExampleTitleSortKey(_SortKey): 

99 """Sort examples by example title.""" 

100 

101 def __call__(self, file: Path): 

102 _, script_blocks = split_code_and_text_blocks(file) 

103 _, title = extract_intro_and_title(file, script_blocks[0][1]) 

104 return title 

105 

106 

107class SortingMethod(Enum): 

108 """ 

109 All known sorting methods. 

110 """ 

111 

112 ExplicitOrder = ExplicitOrder 

113 NumberOfCodeLinesSortKey = NumberOfCodeLinesSortKey 

114 FileSizeSortKey = FileSizeSortKey 

115 FileNameSortKey = FileNameSortKey 

116 ExampleTitleSortKey = ExampleTitleSortKey 

117 

118 def __call__(self, *args, **kwargs): 

119 """When enum member is called, return the class""" 

120 return self.value(*args, **kwargs) 

121 

122 @classmethod 

123 def all_names(cls): 

124 return [s.name for s in cls] 

125 

126 @classmethod 

127 def from_str(cls, name) -> "SortingMethod": 

128 try: 

129 return cls[name] 

130 except KeyError: 

131 raise ValueError(f"Unknown sorting method {name!r}. Available methods: {cls.all_names()}") 

132 

133 

134def str_to_sorting_method(name: str) -> Type: 

135 """Return the sorting method class associated with the fiven name.""" 

136 return SortingMethod.from_str(name).value