Skip to content

settings

NavEntry

Bases: NamedTuple

Source code in mkreports/settings.py
15
16
17
18
19
20
21
22
23
24
25
class NavEntry(NamedTuple):
    """
    An entry in the navigation tab.

    Args:
        hierarchy (Sequence[str]): List of navigation entries.
        file (Path): Path to the page, relative to report docs folder.
    """

    hierarchy: Sequence[str]
    loc: Union[Path, str]

ReportSettings

Bases: MutableMapping

Source code in mkreports/settings.py
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
class ReportSettings(MutableMapping):
    def __init__(self, file: Path):
        self._file = file
        self._dict = load_yaml(file)

    def __getitem__(self, key: Any) -> Any:
        return self._dict[key]

    def __setitem__(self, key: Any, value: Any):
        """Assign key to value, but also save to yaml-file."""
        self._dict[key] = value
        save_yaml(self._dict, self._file)

    def __delitem__(self, key: Any):
        del self._dict[key]

    def __iter__(self):
        return self._dict.__iter__()

    def __len__(self):
        return len(self._dict)

    @property
    def nav_list(self) -> List[NavEntry]:
        return mkdocs_to_navlist(self._dict["nav"])

    @nav_list.setter
    def nav_list(self, nav_list: List[NavEntry]):
        self["nav"] = navlist_to_mkdocs(nav_list)

    def append_nav_entry(
        self,
        nav_entry: Union[Path, NavEntry],
        nav_pref: Literal["S", "T"] = "T",
    ) -> None:
        if isinstance(nav_entry, Path):
            nav_entry = path_to_nav_entry(nav_entry)

        self.nav_list = _merge_nav_lists([nav_entry], self.nav_list, nav_pref=nav_pref)

    @property
    def dict(self):
        return self._dict

    @dict.setter
    def dict(self, value):
        self._dict = value
        save_yaml(self._dict, self._file)

    def merge(
        self,
        source: Union[Dict[str, Any], "ReportSettings"],
        nav_pref: Literal["S", "T"] = "T",
    ):
        if isinstance(source, self.__class__):
            source = source._dict

        # make a copy so we can manipulate it
        source = deepcopy(source)
        source_nav = source.get("nav", None)
        if "nav" in source:
            del source["nav"]

        # now we want to merge the content; but nav items have to be
        # treated differently
        merged_dict = merge_settings(self._dict, source)

        if source_nav is not None:
            # now we merge the navs; for this we access them as lists
            nav_list_target = self.nav_list
            nav_list_source = mkdocs_to_navlist(source_nav)

            combined_nav = _merge_nav_lists(
                nav_list_source=nav_list_source,
                nav_list_target=nav_list_target,
                nav_pref=nav_pref,
            )

            merged_dict["nav"] = combined_nav

        self.dict = merged_dict

__setitem__(key, value)

Assign key to value, but also save to yaml-file.

Source code in mkreports/settings.py
226
227
228
229
def __setitem__(self, key: Any, value: Any):
    """Assign key to value, but also save to yaml-file."""
    self._dict[key] = value
    save_yaml(self._dict, self._file)

add_nav_entry(mkdocs_settings, nav_entry)

Add an additional entry to the Nav in mkdocs.yml

Parameters:

Name Type Description Default
mkdocs_settings

The mkdocs settings to update.

required
nav_entry NavEntry

The NavEntry to add

required

Returns:

Type Description
Any

The updated mkdocs_settings

Source code in mkreports/settings.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
def add_nav_entry(mkdocs_settings, nav_entry: NavEntry) -> Any:
    """
    Add an additional entry to the Nav in mkdocs.yml

    Args:
        mkdocs_settings (): The mkdocs settings to update.
        nav_entry (NavEntry): The NavEntry to add

    Returns:
        The updated mkdocs_settings
    """
    mkdocs_settings = deepcopy(mkdocs_settings)
    nav = mkdocs_to_navlist(mkdocs_settings["nav"]) + [nav_entry]
    # we need to deduplicate
    nav = list(unique_everseen(nav))
    mkdocs_nav = navlist_to_mkdocs(nav)
    mkdocs_settings["nav"] = mkdocs_nav

    return mkdocs_settings

load_yaml(file)

Load a yaml file, return empty dict if not exists.

Parameters:

Name Type Description Default
file Path

File to load

required

Returns:

Type Description
Any

The value in the file, empty dict otherwise.

Source code in mkreports/settings.py
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
def load_yaml(file: Path) -> Any:
    """
    Load a yaml file, return empty dict if not exists.

    Args:
        file (Path): File to load

    Returns:
        The value in the file, empty dict otherwise.

    """
    if file.exists():
        with file.open("r") as f:
            res = yaml.load(f, Loader=yaml.Loader)
    else:
        res = {}

    return res

mkdocs_to_navlist(mkdocs_nav)

Convert an mkdocs nav to a list of NavEntry.

Parameters:

Name Type Description Default
mkdocs_nav MkdocsNav

A python representation of the nav-entry in the mkdocs.yml file.

required
Source code in mkreports/settings.py
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
def mkdocs_to_navlist(mkdocs_nav: MkdocsNav) -> NavList:
    """
    Convert an mkdocs nav to a list of NavEntry.

    Args:
        mkdocs_nav: A python representation of the nav-entry
            in the mkdocs.yml file.
    """
    res = []
    for entry in mkdocs_nav:
        if isinstance(entry, str):
            res.append(NavEntry([], Path(entry)))
        elif isinstance(entry, Mapping):
            key, val = _check_length_one(entry)
            if isinstance(val, str):
                res.append(NavEntry([key], Path(val)))
            elif isinstance(val, List):
                res = res + [
                    NavEntry((key,) + tuple(h), p) for (h, p) in mkdocs_to_navlist(val)
                ]
            else:
                raise Exception("Not expected type")
        else:
            raise Exception("Not expected type")
    return res

navlist_to_mkdocs(nav_list)

Convert a list of nav-entries into mkdocs format.

Parameters:

Name Type Description Default
nav Nav

The list of NavEntry to convert to mkdocs.yml format

required

Returns:

Type Description
MkdocsNav

Python object of the mkdocs.yml nav entry.

Source code in mkreports/settings.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
def navlist_to_mkdocs(nav_list: NavList) -> MkdocsNav:
    """
    Convert a list of nav-entries into mkdocs format.

    Args:
        nav (Nav): The list of NavEntry to convert to mkdocs.yml format

    Returns:
        Python object of the mkdocs.yml nav entry.

    """
    split_nokey, split_keys = split_nav(nav_list)
    res: MkdocsNav = [str(p) for p in split_nokey]

    for key, val in split_keys.items():
        mkdocs_for_key = navlist_to_mkdocs(val)
        # if it is a list of length 1 with a string, treat it special
        if len(mkdocs_for_key) == 1 and isinstance(mkdocs_for_key[0], str):
            res.append({key: mkdocs_for_key[0]})
        else:
            res.append({key: mkdocs_for_key})

    return res

path_to_nav_entry(path)

Turn a file path into a NavEntry.

The path is split, each part of the path used as an element of the hierarchy. Snake-case are split into words with first letters capitalized.

Parameters:

Name Type Description Default
path Path

The path relative to the report docs folder to turn into a nav-entry.

required

Returns:

Name Type Description
NavEntry NavEntry

The NavEntry object representing the path and the hierarchy of navigation entries.

Source code in mkreports/settings.py
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
def path_to_nav_entry(path: Path) -> NavEntry:
    """
    Turn a file path into a NavEntry.

    The path is split, each part of the path used as an element of the
    hierarchy. Snake-case are split into words with first letters
    capitalized.

    Args:
        path (Path): The path relative to the report docs folder to turn
            into a nav-entry.

    Returns:
        NavEntry: The NavEntry object representing the path and
            the hierarchy of navigation entries.

    """
    return NavEntry(
        tuple(
            [snake_to_text(x) for x in path.parent.parts] + [snake_to_text(path.stem)]
        ),
        path,
    )

save_yaml(obj, file)

Save object to yaml file.

Parameters:

Name Type Description Default
obj Any

The object to save.

required
file Path

Filename to save it into.

required
Source code in mkreports/settings.py
184
185
186
187
188
189
190
191
192
193
def save_yaml(obj: Any, file: Path) -> None:
    """
    Save object to yaml file.

    Args:
        obj (Any): The object to save.
        file (Path): Filename to save it into.
    """
    with file.open("w") as f:
        yaml.dump(obj, f, default_flow_style=False)

split_nav(x)

Split the navigation entry into top level list of items and dict of Navs.

Given a nav-entry, each top-level item that is not a hierarchy itself is added to the return list. Every hierarchy will have its top level removed and entered into a dict, with the top-level hierarchy name as the key and the sub-nav as the value.

Parameters:

Name Type Description Default
x Nav

The list of NavEntry to process

required

Returns:

Type Description
Tuple[List[str], Dict[str, NavList]]

Tuple[List[str], Dict[str, Nav]]: Structure as explained above.

Source code in mkreports/settings.py
 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
def split_nav(x: NavList) -> Tuple[List[str], Dict[str, NavList]]:
    """
    Split the navigation entry into top level list of items and dict of Navs.

    Given a nav-entry, each top-level item that is not a hierarchy itself is
    added to the return list. Every hierarchy will have its top level
    removed and entered into a dict, with the top-level hierarchy name as the
    key and the sub-nav as the value.

    Args:
        x (Nav): The list of NavEntry to process

    Returns:
        Tuple[List[str], Dict[str, Nav]]: Structure as explained above.

    """
    res_nav = defaultdict(list)
    res_list = []
    for (h, p) in x:
        if len(h) == 0:
            res_list.append(p)
        else:
            res_nav[h[0]].append((h[1:], p))

    return (res_list, res_nav)