1# Python Markdown 
    2 
    3# A Python implementation of John Gruber's Markdown. 
    4 
    5# Documentation: https://python-markdown.github.io/ 
    6# GitHub: https://github.com/Python-Markdown/markdown/ 
    7# PyPI: https://pypi.org/project/Markdown/ 
    8 
    9# Started by Manfred Stienstra (http://www.dwerg.net/). 
    10# Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org). 
    11# Currently maintained by Waylan Limberg (https://github.com/waylan), 
    12# Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). 
    13 
    14# Copyright 2007-2023 The Python Markdown Project (v. 1.7 and later) 
    15# Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) 
    16# Copyright 2004 Manfred Stienstra (the original version) 
    17 
    18# License: BSD (see LICENSE.md for details). 
    19 
    20""" 
    21Markdown accepts an [`Extension`][markdown.extensions.Extension] instance for each extension. Therefore, each extension 
    22must to define a class that extends [`Extension`][markdown.extensions.Extension] and over-rides the 
    23[`extendMarkdown`][markdown.extensions.Extension.extendMarkdown] method. Within this class one can manage configuration 
    24options for their extension and attach the various processors and patterns which make up an extension to the 
    25[`Markdown`][markdown.Markdown] instance. 
    26""" 
    27 
    28from __future__ import annotations 
    29 
    30from typing import TYPE_CHECKING, Any, Iterable, Mapping 
    31from ..util import parseBoolValue 
    32 
    33if TYPE_CHECKING:  # pragma: no cover 
    34    from markdown import Markdown 
    35 
    36 
    37class Extension: 
    38    """ Base class for extensions to subclass. """ 
    39 
    40    config: Mapping[str, list] = {} 
    41    """ 
    42    Default configuration for an extension. 
    43 
    44    This attribute is to be defined in a subclass and must be of the following format: 
    45 
    46    ``` python 
    47    config = { 
    48        'key': ['value', 'description'] 
    49    } 
    50    ``` 
    51 
    52    Note that [`setConfig`][markdown.extensions.Extension.setConfig] will raise a [`KeyError`][] 
    53    if a default is not set for each option. 
    54    """ 
    55 
    56    def __init__(self, **kwargs): 
    57        """ Initiate Extension and set up configs. """ 
    58        self.setConfigs(kwargs) 
    59 
    60    def getConfig(self, key: str, default: Any = '') -> Any: 
    61        """ 
    62        Return a single configuration option value. 
    63 
    64        Arguments: 
    65            key: The configuration option name. 
    66            default: Default value to return if key is not set. 
    67 
    68        Returns: 
    69            Value of stored configuration option. 
    70        """ 
    71        if key in self.config: 
    72            return self.config[key][0] 
    73        else: 
    74            return default 
    75 
    76    def getConfigs(self) -> dict[str, Any]: 
    77        """ 
    78        Return all configuration options. 
    79 
    80        Returns: 
    81            All configuration options. 
    82        """ 
    83        return {key: self.getConfig(key) for key in self.config.keys()} 
    84 
    85    def getConfigInfo(self) -> list[tuple[str, str]]: 
    86        """ 
    87        Return descriptions of all configuration options. 
    88 
    89        Returns: 
    90            All descriptions of configuration options. 
    91        """ 
    92        return [(key, self.config[key][1]) for key in self.config.keys()] 
    93 
    94    def setConfig(self, key: str, value: Any) -> None: 
    95        """ 
    96        Set a configuration option. 
    97 
    98        If the corresponding default value set in [`config`][markdown.extensions.Extension.config] 
    99        is a `bool` value or `None`, then `value` is passed through 
    100        [`parseBoolValue`][markdown.util.parseBoolValue] before being stored. 
    101 
    102        Arguments: 
    103            key: Name of configuration option to set. 
    104            value: Value to assign to option. 
    105 
    106        Raises: 
    107            KeyError: If `key` is not known. 
    108        """ 
    109        if isinstance(self.config[key][0], bool): 
    110            value = parseBoolValue(value) 
    111        if self.config[key][0] is None: 
    112            value = parseBoolValue(value, preserve_none=True) 
    113        self.config[key][0] = value 
    114 
    115    def setConfigs(self, items: Mapping[str, Any] | Iterable[tuple[str, Any]]) -> None: 
    116        """ 
    117        Loop through a collection of configuration options, passing each to 
    118        [`setConfig`][markdown.extensions.Extension.setConfig]. 
    119 
    120        Arguments: 
    121            items: Collection of configuration options. 
    122 
    123        Raises: 
    124            KeyError: for any unknown key. 
    125        """ 
    126        if hasattr(items, 'items'): 
    127            # it's a dict 
    128            items = items.items() 
    129        for key, value in items: 
    130            self.setConfig(key, value) 
    131 
    132    def extendMarkdown(self, md: Markdown) -> None: 
    133        """ 
    134        Add the various processors and patterns to the Markdown Instance. 
    135 
    136        This method must be overridden by every extension. 
    137 
    138        Arguments: 
    139            md: The Markdown instance. 
    140 
    141        """ 
    142        raise NotImplementedError( 
    143            'Extension "%s.%s" must define an "extendMarkdown"' 
    144            'method.' % (self.__class__.__module__, self.__class__.__name__) 
    145        )