File: sorting.py

package info (click to toggle)
sphinx-gallery 0.19.0-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 2,340 kB
  • sloc: python: 10,346; makefile: 216; lisp: 15; sh: 11; cpp: 9
file content (186 lines) | stat: -rw-r--r-- 5,536 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
r"""Sorters for Sphinx-Gallery (sub)sections.

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

# Created: Sun May 21 20:38:59 2017
# Author: Óscar Nájera
# License: 3-clause BSD

import os
import types

from sphinx.errors import ConfigError

from .gen_rst import extract_intro_and_title
from .py_source_parser import split_code_and_text_blocks


class ExplicitOrder:
    """Sorting key for all gallery subsections.

    All subsections folders must be listed, otherwise an exception is raised.
    However, you can add '*' as a placeholder to the list. All not-listed
    subsection folders will be inserted at the given position and no
    exception is raised.

    Parameters
    ----------
    ordered_list : list, tuple, or :term:`python:generator`
        Hold the paths of each galleries' subsections.

    Raises
    ------
    ValueError
        Wrong input type or Subgallery path missing.
    """

    def __init__(self, ordered_list):
        if not isinstance(ordered_list, (list, tuple, types.GeneratorType)):
            raise ConfigError(
                "ExplicitOrder sorting key takes a list, "
                "tuple or Generator, which hold"
                "the paths of each gallery subfolder"
            )

        self.ordered_list = [
            "*" if path == "*" else os.path.normpath(path) for path in ordered_list
        ]
        try:
            i = ordered_list.index("*")
            self.has_wildcard = True
            self.ordered_list_start = self.ordered_list[:i]
            self.ordered_list_end = self.ordered_list[i + 1 :]
        except ValueError:  # from index("*")
            self.has_wildcard = False
            self.ordered_list_start = []
            self.ordered_list_end = self.ordered_list

    def __call__(self, item):
        """
        Return an integer suited for ordering the items.

        If the ordered_list contains a wildcard "*", items before "*" will return
        negative numbers, items after "*" will have positive numbers, and
        not-listed items will return 0.

        If there is no wildcard, all items with return positive numbers, and
        not-listed items will raise a ConfigError.
        """
        if item in self.ordered_list_start:
            return self.ordered_list_start.index(item) - len(self.ordered_list_start)
        elif item in self.ordered_list_end:
            return self.ordered_list_end.index(item) + 1
        else:
            if self.has_wildcard:
                return 0
            else:
                raise ConfigError(
                    "The subsection folder {!r} was not found in the "
                    "'subsection_order' config. If you use an explicit "
                    "'subsection_order', you must specify all subsection folders "
                    "or add '*' as a wildcard to collect all not-listed subsection "
                    "folders.".format(item)
                )

    def __repr__(self):
        return f"<{self.__class__.__name__} : {self.ordered_list}>"


class _SortKey:
    """Base class for section order key classes."""

    def __init__(self, src_dir):
        self.src_dir = src_dir

    def __repr__(self):
        return f"<{self.__class__.__name__}>"


class NumberOfCodeLinesSortKey(_SortKey):
    """Sort examples in src_dir by the number of code lines.

    Parameters
    ----------
    src_dir : str
        The source directory.
    """

    def __call__(self, filename):
        """Return number of code lines in `filename`."""
        src_file = os.path.normpath(os.path.join(self.src_dir, filename))
        file_conf, script_blocks = split_code_and_text_blocks(src_file)
        amount_of_code = sum(
            len(block.content) for block in script_blocks if block.type == "code"
        )
        return amount_of_code


class FileSizeSortKey(_SortKey):
    """Sort examples in src_dir by file size.

    Parameters
    ----------
    src_dir : str
        The source directory.
    """

    def __call__(self, filename):
        """Return file size."""
        src_file = os.path.normpath(os.path.join(self.src_dir, filename))
        return int(os.stat(src_file).st_size)


class FileNameSortKey(_SortKey):
    """Sort examples in src_dir by file name.

    Parameters
    ----------
    src_dir : str
        The source directory.
    """

    def __call__(self, filename):
        """Return `filename`."""
        return filename


class ExampleTitleSortKey(_SortKey):
    """Sort examples in src_dir by example title.

    Parameters
    ----------
    src_dir : str
        The source directory.
    """

    def __call__(self, filename):
        """Return title of example."""
        src_file = os.path.normpath(os.path.join(self.src_dir, filename))
        _, script_blocks = split_code_and_text_blocks(src_file)
        _, title = extract_intro_and_title(src_file, script_blocks[0].content)
        return title


class FunctionSortKey:
    """Sort examples using a function passed through to :py:func:`sorted`.

    Parameters
    ----------
    func : :external+python:term:`callable`
           sorting key function,
           can only take one argument, i.e. lambda func = arg: arg[0] * arg[1]
    r : str, None
        printable representation of object
    """

    def __init__(self, func, r=None):
        self.f = func
        self.r = r

    def __repr__(self):
        return self.r if self.r else "FunctionSortKey"

    def __call__(self, arg):
        """Return func(arg)."""
        return self.f(arg)