File size: 4,822 Bytes
122d3ff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# Python Markdown

# A Python implementation of John Gruber's Markdown.

# Documentation: https://python-markdown.github.io/
# GitHub: https://github.com/Python-Markdown/markdown/
# PyPI: https://pypi.org/project/Markdown/

# Started by Manfred Stienstra (http://www.dwerg.net/).
# Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
# Currently maintained by Waylan Limberg (https://github.com/waylan),
# Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).

# Copyright 2007-2023 The Python Markdown Project (v. 1.7 and later)
# Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
# Copyright 2004 Manfred Stienstra (the original version)

# License: BSD (see LICENSE.md for details).

"""
Markdown accepts an [`Extension`][markdown.extensions.Extension] instance for each extension. Therefore, each extension
must to define a class that extends [`Extension`][markdown.extensions.Extension] and over-rides the
[`extendMarkdown`][markdown.extensions.Extension.extendMarkdown] method. Within this class one can manage configuration
options for their extension and attach the various processors and patterns which make up an extension to the
[`Markdown`][markdown.Markdown] instance.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, Iterable, Mapping
from ..util import parseBoolValue

if TYPE_CHECKING:  # pragma: no cover
    from markdown import Markdown


class Extension:
    """ Base class for extensions to subclass. """

    config: Mapping[str, list] = {}
    """
    Default configuration for an extension.

    This attribute is to be defined in a subclass and must be of the following format:

    ``` python
    config = {
        'key': ['value', 'description']
    }
    ```

    Note that [`setConfig`][markdown.extensions.Extension.setConfig] will raise a [`KeyError`][]
    if a default is not set for each option.
    """

    def __init__(self, **kwargs):
        """ Initiate Extension and set up configs. """
        self.setConfigs(kwargs)

    def getConfig(self, key: str, default: Any = '') -> Any:
        """
        Return a single configuration option value.

        Arguments:
            key: The configuration option name.
            default: Default value to return if key is not set.

        Returns:
            Value of stored configuration option.
        """
        if key in self.config:
            return self.config[key][0]
        else:
            return default

    def getConfigs(self) -> dict[str, Any]:
        """
        Return all configuration options.

        Returns:
            All configuration options.
        """
        return {key: self.getConfig(key) for key in self.config.keys()}

    def getConfigInfo(self) -> list[tuple[str, str]]:
        """
        Return descriptions of all configuration options.

        Returns:
            All descriptions of configuration options.
        """
        return [(key, self.config[key][1]) for key in self.config.keys()]

    def setConfig(self, key: str, value: Any) -> None:
        """
        Set a configuration option.

        If the corresponding default value set in [`config`][markdown.extensions.Extension.config]
        is a `bool` value or `None`, then `value` is passed through
        [`parseBoolValue`][markdown.util.parseBoolValue] before being stored.

        Arguments:
            key: Name of configuration option to set.
            value: Value to assign to option.

        Raises:
            KeyError: If `key` is not known.
        """
        if isinstance(self.config[key][0], bool):
            value = parseBoolValue(value)
        if self.config[key][0] is None:
            value = parseBoolValue(value, preserve_none=True)
        self.config[key][0] = value

    def setConfigs(self, items: Mapping[str, Any] | Iterable[tuple[str, Any]]) -> None:
        """
        Loop through a collection of configuration options, passing each to
        [`setConfig`][markdown.extensions.Extension.setConfig].

        Arguments:
            items: Collection of configuration options.

        Raises:
            KeyError: for any unknown key.
        """
        if hasattr(items, 'items'):
            # it's a dict
            items = items.items()
        for key, value in items:
            self.setConfig(key, value)

    def extendMarkdown(self, md: Markdown) -> None:
        """
        Add the various processors and patterns to the Markdown Instance.

        This method must be overridden by every extension.

        Arguments:
            md: The Markdown instance.

        """
        raise NotImplementedError(
            'Extension "%s.%s" must define an "extendMarkdown"'
            'method.' % (self.__class__.__module__, self.__class__.__name__)
        )