From 9fad090be28a40fe9db174eb0b1cd2d5749f8174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Wed, 23 Aug 2023 01:39:24 +0200 Subject: [PATCH 01/61] Create API docs --- .gitignore | 1 + docs/extensions/api.md | 2 +- docs/mkdocstrings.css | 26 ++++++++++ markdown/blockparser.py | 34 ++++++++++-- markdown/core.py | 71 ++++++++++++------------- markdown/extensions/__init__.py | 12 +++-- markdown/extensions/codehilite.py | 33 +++++------- markdown/extensions/footnotes.py | 5 +- markdown/inlinepatterns.py | 47 ++++++++--------- markdown/treeprocessors.py | 86 +++++++++++++++---------------- markdown/util.py | 22 ++++---- mkdocs.yml | 35 +++++++++++++ pyproject.toml | 6 ++- scripts/gen_ref_nav.py | 34 ++++++++++++ 14 files changed, 270 insertions(+), 144 deletions(-) create mode 100644 docs/mkdocstrings.css create mode 100755 scripts/gen_ref_nav.py diff --git a/.gitignore b/.gitignore index 6de88e389..456d05c3c 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,7 @@ target/ .python-version # virtualenv +.venv/ venv/ ENV/ diff --git a/docs/extensions/api.md b/docs/extensions/api.md index d7eb6896d..951496eb8 100644 --- a/docs/extensions/api.md +++ b/docs/extensions/api.md @@ -845,7 +845,7 @@ assert someitem in registry : Add an item to the registry with the given name and priority. - Parameters: + Arguments: * `item`: The item being registered. * `name`: A string used to reference the item. diff --git a/docs/mkdocstrings.css b/docs/mkdocstrings.css new file mode 100644 index 000000000..762746e10 --- /dev/null +++ b/docs/mkdocstrings.css @@ -0,0 +1,26 @@ +/* Indentation. */ +div.doc-contents:not(.first) { + padding-left: 25px; + border-left: .05rem solid #d0d0d0; +} + +/* Mark external links as such. */ +a.external::after, +a.autorefs-external::after { + /* https://primer.style/octicons/arrow-up-right-24 */ + mask-image: url('data:image/svg+xml,'); + content: ' '; + + display: inline-block; + vertical-align: middle; + position: relative; + + height: 1em; + width: 1em; + background-color: #005b81; +} + +a.external:hover::after, +a.autorefs-external:hover::after { + background-color: #e32e00; +} \ No newline at end of file diff --git a/markdown/blockparser.py b/markdown/blockparser.py index 501965ecd..65fdf5b99 100644 --- a/markdown/blockparser.py +++ b/markdown/blockparser.py @@ -19,9 +19,15 @@ License: BSD (see LICENSE.md for details). """ +from __future__ import annotations + import xml.etree.ElementTree as etree +from typing import TYPE_CHECKING, Sequence from . import util +if TYPE_CHECKING: + from markdown import Markdown + class State(list): """ Track the current and nested state of the parser. @@ -62,14 +68,21 @@ class BlockParser: A wrapper class that stitches the various `BlockProcessors` together, looping through them and creating an `ElementTree` object. + """ - def __init__(self, md): + def __init__(self, md: Markdown): + """ Initialize the block parser. + + Arguments: + md: A Markdown instance. + + """ self.blockprocessors = util.Registry() self.state = State() self.md = md - def parseDocument(self, lines): + def parseDocument(self, lines: Sequence[str]) -> etree.ElementTree: """ Parse a markdown document into an ElementTree. Given a list of lines, an ElementTree object (not just a parent @@ -78,13 +91,18 @@ def parseDocument(self, lines): This should only be called on an entire document, not pieces. + Arguments: + lines: A list of lines (strings). + + Returns: + An element tree. """ # Create an `ElementTree` from the lines self.root = etree.Element(self.md.doc_tag) self.parseChunk(self.root, '\n'.join(lines)) return etree.ElementTree(self.root) - def parseChunk(self, parent, text): + def parseChunk(self, parent: etree.Element, text: str): """ Parse a chunk of markdown text and attach to given `etree` node. While the `text` argument is generally assumed to contain multiple @@ -95,10 +113,14 @@ def parseChunk(self, parent, text): The `parent` `etree` Element passed in is altered in place. Nothing is returned. + Arguments: + parent: The parent element. + text: The text to parse. + """ self.parseBlocks(parent, text.split('\n\n')) - def parseBlocks(self, parent, blocks): + def parseBlocks(self, parent: etree.Element, blocks: Sequence[str]): """ Process blocks of markdown text and attach to given `etree` node. Given a list of `blocks`, each `blockprocessor` is stepped through @@ -110,6 +132,10 @@ def parseBlocks(self, parent, blocks): additional `BlockProcessors` which call this method to recursively parse a nested block. + Arguments: + parent: The parent element. + blocks: The blocks of text to parse. + """ while blocks: for processor in self.blockprocessors: diff --git a/markdown/core.py b/markdown/core.py index 77cd2d7ad..98ae499e5 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -19,10 +19,13 @@ License: BSD (see LICENSE.md for details). """ +from __future__ import annotations + import codecs import sys import logging import importlib +from typing import Any, TextIO from . import util from .preprocessors import build_preprocessors from .blockprocessors import build_block_parser @@ -54,17 +57,16 @@ def __init__(self, **kwargs): Creates a new Markdown instance. Keyword arguments: - - * `extensions`: A list of extensions. - If an item is an instance of a subclass of `markdown.extension.Extension`, the instance will be used - as-is. If an item is of type string, first an entry point will be loaded. If that fails, the string is - assumed to use Python dot notation (`path.to.module:ClassName`) to load a `markdown.Extension` subclass. If - no class is specified, then a `makeExtension` function is called within the specified module. - * `extension_configs`: Configuration settings for extensions. - * `output_format`: Format of output. Supported formats are: - * `xhtml`: Outputs XHTML style tags. Default. - * `html`: Outputs HTML style tags. - * `tab_length`: Length of tabs in the source. Default: 4 + extensions (list[str | Extension]): A list of extensions. + If an item is an instance of a subclass of `markdown.extension.Extension`, the instance will be used + as-is. If an item is of type string, first an entry point will be loaded. If that fails, the string is + assumed to use Python dot notation (`path.to.module:ClassName`) to load a `markdown.Extension` subclass. + If no class is specified, then a `makeExtension` function is called within the specified module. + extension_configs (dict[str, dict[str, Any]]): Configuration settings for extensions. + output_format (str): Format of output. Supported formats are: + * `xhtml`: Outputs XHTML style tags. Default. + * `html`: Outputs HTML style tags. + tab_length (int): Length of tabs in the source. Default: 4 """ @@ -97,15 +99,13 @@ def build_parser(self): self.postprocessors = build_postprocessors(self) return self - def registerExtensions(self, extensions, configs): + def registerExtensions(self, extensions: list[str | Extension], configs: dict[str, dict[str, Any]]) -> Markdown: """ Register extensions with this instance of Markdown. - Keyword arguments: - - * `extensions`: A list of extensions, which can either - be strings or objects. - * `configs`: A dictionary mapping extension names to `configs` options. + Arguments: + extensions: A list of extensions, which can either be strings or objects. + configs: A dictionary mapping extension names to `configs` options. """ for ext in extensions: @@ -212,13 +212,12 @@ def is_block_level(self, tag): # Some ElementTree tags are not strings, so return False. return False - def convert(self, source): + def convert(self, source: str): """ Convert markdown to serialized XHTML or HTML. - Keyword arguments: - - * `source`: Source text as a Unicode string. + Arguments: + source: Source text as a Unicode string. Markdown processing takes place in five steps: @@ -282,7 +281,7 @@ def convert(self, source): return output.strip() - def convertFile(self, input=None, output=None, encoding=None): + def convertFile(self, input: str | TextIO | None = None, output: str | TextIO | None = None, encoding: str | None = None): """Converts a markdown file and returns the HTML as a Unicode string. Decodes the file using the provided encoding (defaults to `utf-8`), @@ -295,11 +294,10 @@ def convertFile(self, input=None, output=None, encoding=None): takes place in Python-Markdown. (All other code is Unicode-in / Unicode-out.) - Keyword arguments: - - * `input`: File object or path. Reads from `stdin` if `None`. - * `output`: File object or path. Writes to `stdout` if `None`. - * `encoding`: Encoding of input and output files. Defaults to `utf-8`. + Arguments: + input: File object or path. Reads from `stdin` if `None`. + output: File object or path. Writes to `stdout` if `None`. + encoding: Encoding of input and output files. Defaults to `utf-8`. """ @@ -358,7 +356,7 @@ def convertFile(self, input=None, output=None, encoding=None): """ -def markdown(text, **kwargs): +def markdown(text, **kwargs) -> str: """Convert a markdown string to HTML and return HTML as a Unicode string. This is a shortcut function for `Markdown` class to cover the most @@ -366,11 +364,11 @@ def markdown(text, **kwargs): necessary extensions and runs the parser on the given text. Keyword arguments: + text (str): Markdown formatted text as Unicode or ASCII string. + **other (Any): Any arguments accepted by the Markdown class. - * `text`: Markdown formatted text as Unicode or ASCII string. - * Any arguments accepted by the Markdown class. - - Returns: An HTML document as a string. + Returns: + An HTML document as a string. """ md = Markdown(**kwargs) @@ -384,11 +382,10 @@ def markdownFromFile(**kwargs): and calls the `convertFile` method rather than `convert`. Keyword arguments: - - * `input`: a file name or readable object. - * `output`: a file name or writable object. - * `encoding`: Encoding of input and output. - * Any arguments accepted by the `Markdown` class. + input (str | TextIO): A file name or readable object. + output (str | TextIO): A file name or writable object. + encoding (str): Encoding of input and output. + **other (Any): Any arguments accepted by the `Markdown` class. """ md = Markdown(**kwargs) diff --git a/markdown/extensions/__init__.py b/markdown/extensions/__init__.py index 7a32e1c52..c420e1ba3 100644 --- a/markdown/extensions/__init__.py +++ b/markdown/extensions/__init__.py @@ -19,8 +19,13 @@ License: BSD (see LICENSE.md for details). """ +from __future__ import annotations + +from typing import TYPE_CHECKING from ..util import parseBoolValue +if TYPE_CHECKING: + from markdown import Markdown class Extension: """ Base class for extensions to subclass. """ @@ -69,15 +74,14 @@ def setConfigs(self, items): for key, value in items: self.setConfig(key, value) - def extendMarkdown(self, md): + def extendMarkdown(self, md: Markdown): """ Add the various processors and patterns to the Markdown Instance. This method must be overridden by every extension. - Keyword arguments: - - * md: The Markdown instance. + Arguments: + md: The Markdown instance. """ raise NotImplementedError( diff --git a/markdown/extensions/codehilite.py b/markdown/extensions/codehilite.py index 1941ce288..8dec2ccee 100644 --- a/markdown/extensions/codehilite.py +++ b/markdown/extensions/codehilite.py @@ -54,24 +54,19 @@ class CodeHilite: html = code.hilite() Arguments: - * `src`: Source string or any object with a `.readline` attribute. - - * `lang`: String name of Pygments lexer to use for highlighting. Default: `None`. - - * `guess_lang`: Auto-detect which lexer to use. Ignored if `lang` is set to a valid - value. Default: `True`. - - * `use_pygments`: Pass code to Pygments for code highlighting. If `False`, the code is - instead wrapped for highlighting by a JavaScript library. Default: `True`. - - * `pygments_formatter`: The name of a Pygments formatter or a formatter class used for - highlighting the code blocks. Default: `html`. - - * `linenums`: An alias to Pygments `linenos` formatter option. Default: `None`. - - * `css_class`: An alias to Pygments `cssclass` formatter option. Default: 'codehilite'. - - * `lang_prefix`: Prefix prepended to the language. Default: "language-". + src: Source string or any object with a `.readline` attribute. + + Keyword arguments: + lang (str): String name of Pygments lexer to use for highlighting. Default: `None`. + guess_lang (bool): Auto-detect which lexer to use. + Ignored if `lang` is set to a valid value. Default: `True`. + use_pygments (bool): Pass code to Pygments for code highlighting. If `False`, the code is + instead wrapped for highlighting by a JavaScript library. Default: `True`. + pygments_formatter (str): The name of a Pygments formatter or a formatter class used for + highlighting the code blocks. Default: `html`. + linenums (bool): An alias to Pygments `linenos` formatter option. Default: `None`. + css_class (str): An alias to Pygments `cssclass` formatter option. Default: 'codehilite'. + lang_prefix (str): Prefix prepended to the language. Default: "language-". Other Options: Any other options are accepted and passed on to the lexer and formatter. Therefore, @@ -100,7 +95,7 @@ class CodeHilite: """ - def __init__(self, src, **options): + def __init__(self, src: str, **options): self.src = src self.lang = options.pop('lang', None) self.guess_lang = options.pop('guess_lang', True) diff --git a/markdown/extensions/footnotes.py b/markdown/extensions/footnotes.py index 41074c050..6c8c28465 100644 --- a/markdown/extensions/footnotes.py +++ b/markdown/extensions/footnotes.py @@ -255,10 +255,11 @@ def run(self, parent, blocks): blocks.insert(0, block) return False - def detectTabbed(self, blocks): + def detectTabbed(self, blocks) -> list[str]: """ Find indented text and remove indent before further processing. - Returns: a list of blocks with indentation removed. + Returns: + A list of blocks with indentation removed. """ fn_blocks = [] while blocks: diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py index ee7722e9c..9244194af 100644 --- a/markdown/inlinepatterns.py +++ b/markdown/inlinepatterns.py @@ -60,8 +60,11 @@ * finally we apply strong and emphasis """ +from __future__ import annotations + from . import util from collections import namedtuple +from typing import TYPE_CHECKING, Match import re import xml.etree.ElementTree as etree try: # pragma: no cover @@ -69,6 +72,9 @@ except ImportError: # pragma: no cover import htmlentitydefs as entities +if TYPE_CHECKING: + from markdown import Markdown + def build_inlinepatterns(md, **kwargs): """ Build the default set of inline patterns for Markdown. """ @@ -196,13 +202,12 @@ class Pattern: # pragma: no cover ANCESTOR_EXCLUDES = tuple() - def __init__(self, pattern, md=None): + def __init__(self, pattern: str, md: Markdown | None = None): """ Create an instant of an inline pattern. - Keyword arguments: - - * pattern: A regular expression that matches a pattern + Arguments: + pattern: A regular expression that matches a pattern. """ self.pattern = pattern @@ -215,14 +220,13 @@ def getCompiledRegExp(self): """ Return a compiled regular expression. """ return self.compiled_re - def handleMatch(self, m): + def handleMatch(self, m: Match): """Return a ElementTree element from the given match. Subclasses should override this method. - Keyword arguments: - - * m: A re match object containing a match of the pattern. + Arguments: + m: A match object containing a match of the pattern. """ pass # pragma: no cover @@ -258,13 +262,12 @@ class InlineProcessor(Pattern): efficient and flexible search approach. """ - def __init__(self, pattern, md=None): + def __init__(self, pattern: str, md: Markdown | None = None): """ Create an instant of an inline pattern. - Keyword arguments: - - * pattern: A regular expression that matches a pattern + Arguments: + pattern: A regular expression that matches a pattern. """ self.pattern = pattern @@ -274,7 +277,7 @@ def __init__(self, pattern, md=None): self.safe_mode = False self.md = md - def handleMatch(self, m, data): + def handleMatch(self, m: Match, data: str) -> tuple[etree.ElementTree | str | None, int | None, int | None]: """Return a ElementTree element from the given match and the start and end index of the matched text. @@ -283,16 +286,14 @@ def handleMatch(self, m, data): Subclasses should override this method. - Keyword arguments: - - * m: A re match object containing a match of the pattern. - * data: The buffer current under analysis + Arguments: + m: A re match object containing a match of the pattern. + data: The buffer current under analysis. Returns: - - * el: The ElementTree element, text or None. - * start: The start of the region that has been matched or None. - * end: The end of the region that has been matched or None. + el: The ElementTree element, text or None. + start: The start of the region that has been matched or None. + end: The end of the region that has been matched or None. """ pass # pragma: no cover @@ -809,9 +810,9 @@ def handleMatch(self, m, data): def evalId(self, data, index, text): """ - Evaluate the id portion of [ref][id]. + Evaluate the id portion of `[ref][id]`. - If [ref][] use [ref]. + If `[ref][]` use `[ref]`. """ m = self.RE_LINK.match(data, pos=index) if not m: diff --git a/markdown/treeprocessors.py b/markdown/treeprocessors.py index c779d4d7b..d99eb337b 100644 --- a/markdown/treeprocessors.py +++ b/markdown/treeprocessors.py @@ -19,8 +19,11 @@ License: BSD (see LICENSE.md for details). """ +from __future__ import annotations + import re import xml.etree.ElementTree as etree +from typing import TYPE_CHECKING, Sequence from . import util from . import inlinepatterns @@ -83,16 +86,16 @@ def __makePlaceholder(self, type): hash = util.INLINE_PLACEHOLDER % id return hash, id - def __findPlaceholder(self, data, index): + def __findPlaceholder(self, data: str, index: int) -> tuple[str | None, int]: """ - Extract id from data string, start from index - - Keyword arguments: + Extract id from data string, start from index. - * `data`: string - * `index`: index, from which we start search + Arguments: + data: String. + index: Index, from which we start search. - Returns: placeholder id and string index, after the found placeholder. + Returns: + Placeholder id and string index, after the found placeholder. """ m = self.__placeholder_re.search(data, index) @@ -102,22 +105,21 @@ def __findPlaceholder(self, data, index): return None, index + 1 def __stashNode(self, node, type): - """ Add node to stash """ + """ Add node to stash. """ placeholder, id = self.__makePlaceholder(type) self.stashed_nodes[id] = node return placeholder - def __handleInline(self, data, patternIndex=0): + def __handleInline(self, data: str, patternIndex: int = 0) -> str: """ - Process string with inline patterns and replace it - with placeholders - - Keyword arguments: + Process string with inline patterns and replace it with placeholders. - * `data`: A line of Markdown text - * `patternIndex`: The index of the `inlinePattern` to start with + Arguments: + data: A line of Markdown text. + patternIndex: The index of the `inlinePattern` to start with. - Returns: String with placeholders. + Returns: + String with placeholders. """ if not isinstance(data, util.AtomicString): @@ -131,18 +133,15 @@ def __handleInline(self, data, patternIndex=0): patternIndex += 1 return data - def __processElementText(self, node, subnode, isText=True): + def __processElementText(self, node: etree.Element, subnode: etree.Element, isText: bool = True): """ Process placeholders in `Element.text` or `Element.tail` of Elements popped from `self.stashed_nodes`. - Keywords arguments: - - * `node`: parent node - * `subnode`: processing node - * `isText`: boolean variable, True - it's text, False - it's a tail - - Returns: None + Arguments: + node: Parent node. + subnode: Processing node. + isText: Boolean variable, True - it's text, False - it's a tail. """ if isText: @@ -163,16 +162,17 @@ def __processElementText(self, node, subnode, isText=True): for newChild in childResult: node.insert(pos, newChild[0]) - def __processPlaceholders(self, data, parent, isText=True): + def __processPlaceholders(self, data: str, parent: etree.Element, isText: bool = True) -> list[etree.ElementTree]: """ Process string with placeholders and generate `ElementTree` tree. - Keyword arguments: - - * `data`: string with placeholders instead of `ElementTree` elements. - * `parent`: Element, which contains processing inline data + Arguments: + data: String with placeholders instead of `ElementTree` elements. + parent: Element, which contains processing inline data. + isText: Boolean variable, True - it's text, False - it's a tail. - Returns: list with `ElementTree` elements with applied inline patterns. + Returns: + List with `ElementTree` elements with applied inline patterns. """ def linkText(text): @@ -238,19 +238,19 @@ def linkText(text): return result - def __applyPattern(self, pattern, data, patternIndex, startIndex=0): + def __applyPattern(self, pattern: str, data: srt, patternIndex: int, startIndex: int = 0) -> tuple[str, bool, int]: """ Check if the line fits the pattern, create the necessary elements, add it to `stashed_nodes`. - Keyword arguments: - - * `data`: the text to be processed - * `pattern`: the pattern to be checked - * `patternIndex`: index of current pattern - * `startIndex`: string index, from which we start searching + Arguments: + data: The text to be processed. + pattern: The pattern to be checked. + patternIndex: Index of current pattern. + startIndex: String index, from which we start searching. - Returns: String with placeholders instead of `ElementTree` elements. + Returns: + String with placeholders instead of `ElementTree` elements. """ new_style = isinstance(pattern, inlinepatterns.InlineProcessor) @@ -322,7 +322,7 @@ def __build_ancestors(self, parent, parents): ancestors.reverse() parents.extend(ancestors) - def run(self, tree, ancestors=None): + def run(self, tree: etree.ElementTree, ancestors: Sequence[str] | None = None) -> etree.ElementTree: """Apply inline patterns to a parsed Markdown tree. Iterate over `ElementTree`, find elements with inline tag, apply inline @@ -333,11 +333,11 @@ def run(self, tree, ancestors=None): node.text = markdown.AtomicString("This will not be processed.") Arguments: + tree: `ElementTree` object, representing Markdown tree. + ancestors: List of parent tag names that precede the tree node (if needed). - * `tree`: `ElementTree` object, representing Markdown tree. - * `ancestors`: List of parent tag names that precede the tree node (if needed). - - Returns: `ElementTree` object with applied inline patterns. + Returns: + An element tree object with applied inline patterns. """ self.stashed_nodes = {} diff --git a/markdown/util.py b/markdown/util.py index 09b8cf619..281f7e71e 100644 --- a/markdown/util.py +++ b/markdown/util.py @@ -19,12 +19,15 @@ License: BSD (see LICENSE.md for details). """ +from __future__ import annotations + import re import sys import warnings from collections import namedtuple from functools import wraps, lru_cache from itertools import count +from typing import Any """ @@ -185,17 +188,17 @@ def __init__(self): self.tag_counter = 0 self.tag_data = [] # list of dictionaries in the order tags appear - def store(self, html): + def store(self, html: str) -> str: """ Saves an HTML segment for later reinsertion. Returns a placeholder string that needs to be inserted into the document. Keyword arguments: + html: An html segment. - * `html`: an html segment - - Returns : a placeholder string + Returns: + A placeholder string. """ self.rawHtmlBlocks.append(html) @@ -310,15 +313,14 @@ def get_index_for_name(self, name): ) raise ValueError('No item named "{}" exists.'.format(name)) - def register(self, item, name, priority): + def register(self, item: Any, name: str, priority: int): """ Add an item to the registry with the given name and priority. - Parameters: - - * `item`: The item being registered. - * `name`: A string used to reference the item. - * `priority`: An integer or float used to sort against all items. + Arguments: + item: The item being registered. + name: A string used to reference the item. + priority: An integer or float used to sort against all items. If an item is registered with a "name" which already exists, the existing item is replaced with the new item. Treat carefully as the diff --git a/mkdocs.yml b/mkdocs.yml index 9cb1511d6..b65a26f94 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,6 +5,7 @@ site_author: "The Python-Markdown Project" copyright: "Copyright © 2010-2023" use_directory_urls: true +watch: [markdown] theme: name: nature @@ -14,6 +15,7 @@ theme: extra_css: - custom.css + - mkdocstrings.css nav: - Python-Markdown: index.md @@ -21,6 +23,7 @@ nav: - Library Reference: reference.md - Command Line: cli.md - Extensions: extensions/index.md + - API Reference: reference/ - Officially Supported Extensions: - Abbreviations: extensions/abbreviations.md - Admonition: extensions/admonition.md @@ -59,3 +62,35 @@ markdown_extensions: - mdx_gh_links: user: Python-Markdown repo: markdown + +plugins: +- gen-files: + scripts: + - scripts/gen_ref_nav.py +- literate-nav: + nav_file: SUMMARY.md +- section-index +- mkdocstrings: + handlers: + python: + import: + - https://docs.python.org/3/objects.inv + options: + annotations_path: brief + docstring_options: + ignore_init_summary: true + docstring_style: google + docstring_section_style: list + filters: ["!^_"] + heading_level: 1 + inherited_members: true + merge_init_into_class: true + separate_signature: true + show_root_heading: true + show_object_full_path: true + show_signature_annotations: true + show_source: false + show_symbol_type_heading: true + show_symbol_type_toc: true + signature_crossrefs: true + summary: true diff --git a/pyproject.toml b/pyproject.toml index c75a0edb2..87930852f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,11 @@ testing = [ docs = [ 'mkdocs>=1.5', 'mkdocs-nature>=0.5', - 'mdx_gh_links>=0.2' + 'mdx_gh_links>=0.2', + "mkdocstrings[python]", + "mkdocs-gen-files", + "mkdocs-section-index", + "mkdocs-literate-nav", ] [project.urls] diff --git a/scripts/gen_ref_nav.py b/scripts/gen_ref_nav.py new file mode 100755 index 000000000..75e7c91fc --- /dev/null +++ b/scripts/gen_ref_nav.py @@ -0,0 +1,34 @@ +"""Generate the code reference pages and navigation.""" + +from pathlib import Path + +import mkdocs_gen_files + +nav = mkdocs_gen_files.Nav() +mod_symbol = '' + +for path in sorted(Path("markdown").rglob("*.py")): + module_path = path.with_suffix("") + doc_path = path.with_suffix(".md") + full_doc_path = Path("reference", doc_path) + + parts = tuple(module_path.parts) + + if parts[-1] == "__init__": + parts = parts[:-1] + doc_path = doc_path.with_name("index.md") + full_doc_path = full_doc_path.with_name("index.md") + elif parts[-1].startswith("_"): + continue + + nav_parts = [f"{mod_symbol} {part}" for part in parts] + nav[tuple(nav_parts)] = doc_path.as_posix() + + with mkdocs_gen_files.open(full_doc_path, "w") as fd: + ident = ".".join(parts) + fd.write(f"::: {ident}") + + mkdocs_gen_files.set_edit_path(full_doc_path, ".." / path) + +with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file: + nav_file.writelines(nav.build_literate_nav()) From 8e406cd240f1e018fa5150c383b35894348df056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Thu, 24 Aug 2023 12:02:15 +0200 Subject: [PATCH 02/61] fixup! Create API docs --- docs/mkdocstrings.css | 1 - markdown/__init__.py | 10 ++--- markdown/__main__.py | 28 ++++++------- markdown/__meta__.py | 28 ++++++------- markdown/blockparser.py | 28 ++++++------- markdown/blockprocessors.py | 28 ++++++------- markdown/core.py | 42 ++++++++++--------- markdown/extensions/__init__.py | 28 ++++++------- markdown/extensions/abbr.py | 18 ++++---- markdown/extensions/admonition.py | 2 +- markdown/extensions/attr_list.py | 2 +- markdown/extensions/codehilite.py | 2 +- markdown/extensions/def_list.py | 2 +- markdown/extensions/extra.py | 2 +- markdown/extensions/fenced_code.py | 3 +- markdown/extensions/footnotes.py | 2 +- markdown/extensions/legacy_attrs.py | 28 ++++++------- markdown/extensions/legacy_em.py | 4 +- markdown/extensions/md_in_html.py | 2 +- markdown/extensions/meta.py | 2 +- markdown/extensions/nl2br.py | 2 +- markdown/extensions/sane_lists.py | 2 +- markdown/extensions/smarty.py | 6 +-- markdown/extensions/tables.py | 2 +- markdown/extensions/toc.py | 8 ++-- markdown/extensions/wikilinks.py | 6 +-- markdown/htmlparser.py | 28 ++++++------- markdown/inlinepatterns.py | 28 ++++++------- markdown/postprocessors.py | 28 ++++++------- markdown/preprocessors.py | 28 ++++++------- markdown/test_tools.py | 28 ++++++------- markdown/treeprocessors.py | 28 ++++++------- markdown/util.py | 28 ++++++------- mkdocs.yml | 2 +- scripts/gen_ref_nav.py | 4 +- .../test_syntax/extensions/test_md_in_html.py | 2 +- 36 files changed, 237 insertions(+), 255 deletions(-) diff --git a/docs/mkdocstrings.css b/docs/mkdocstrings.css index 762746e10..645a19fbf 100644 --- a/docs/mkdocstrings.css +++ b/docs/mkdocstrings.css @@ -1,7 +1,6 @@ /* Indentation. */ div.doc-contents:not(.first) { padding-left: 25px; - border-left: .05rem solid #d0d0d0; } /* Mark external links as such. */ diff --git a/markdown/__init__.py b/markdown/__init__.py index d88b1e974..7c1f29ec7 100644 --- a/markdown/__init__.py +++ b/markdown/__init__.py @@ -3,17 +3,17 @@ 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/ +- 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-2018 The Python Markdown Project (v. 1.7 and later) -Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) +Copyright 2007-2018 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). diff --git a/markdown/__main__.py b/markdown/__main__.py index 230ba3435..cba51bd80 100644 --- a/markdown/__main__.py +++ b/markdown/__main__.py @@ -1,23 +1,21 @@ -""" -Python Markdown +# Python Markdown -A Python implementation of John Gruber's 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/ +# 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). +# 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-2018 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) +# Copyright 2007-2018 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). -""" +# License: BSD (see LICENSE.md for details). import sys import optparse diff --git a/markdown/__meta__.py b/markdown/__meta__.py index 7d593844e..a2452ba31 100644 --- a/markdown/__meta__.py +++ b/markdown/__meta__.py @@ -1,23 +1,21 @@ -""" -Python Markdown +# Python Markdown -A Python implementation of John Gruber's 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/ +# 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). +# 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-2018 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) +# Copyright 2007-2018 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). -""" +# License: BSD (see LICENSE.md for details). # __version_info__ format: # (major, minor, patch, dev/alpha/beta/rc/final, #) diff --git a/markdown/blockparser.py b/markdown/blockparser.py index 65fdf5b99..cb69b23ed 100644 --- a/markdown/blockparser.py +++ b/markdown/blockparser.py @@ -1,23 +1,21 @@ -""" -Python Markdown +# Python Markdown -A Python implementation of John Gruber's 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/ +# 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). +# 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-2018 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) +# Copyright 2007-2018 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). -""" +# License: BSD (see LICENSE.md for details). from __future__ import annotations diff --git a/markdown/blockprocessors.py b/markdown/blockprocessors.py index e679e743e..a1a42ad9a 100644 --- a/markdown/blockprocessors.py +++ b/markdown/blockprocessors.py @@ -1,23 +1,23 @@ -""" -Python Markdown +# Python Markdown -A Python implementation of John Gruber's 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/ +# 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). +# 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-2018 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) +# Copyright 2007-2018 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). +# License: BSD (see LICENSE.md for details). +""" CORE MARKDOWN BLOCKPARSER =========================================================================== diff --git a/markdown/core.py b/markdown/core.py index 98ae499e5..feb38783a 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -1,23 +1,21 @@ -""" -Python Markdown +# Python Markdown -A Python implementation of John Gruber's 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/ +# 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). +# 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-2018 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) +# Copyright 2007-2018 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). -""" +# License: BSD (see LICENSE.md for details). from __future__ import annotations @@ -356,16 +354,18 @@ def convertFile(self, input: str | TextIO | None = None, output: str | TextIO | """ -def markdown(text, **kwargs) -> str: +def markdown(text: str, **kwargs: Any) -> str: """Convert a markdown string to HTML and return HTML as a Unicode string. This is a shortcut function for `Markdown` class to cover the most basic use case. It initializes an instance of `Markdown`, loads the necessary extensions and runs the parser on the given text. + Arguments: + text: Markdown formatted text as Unicode or ASCII string. + Keyword arguments: - text (str): Markdown formatted text as Unicode or ASCII string. - **other (Any): Any arguments accepted by the Markdown class. + **kwargs: Any arguments accepted by the Markdown class. Returns: An HTML document as a string. @@ -375,7 +375,7 @@ def markdown(text, **kwargs) -> str: return md.convert(text) -def markdownFromFile(**kwargs): +def markdownFromFile(**kwargs: Any): """Read markdown code from a file and write it to a file or a stream. This is a shortcut function which initializes an instance of `Markdown`, @@ -385,7 +385,9 @@ def markdownFromFile(**kwargs): input (str | TextIO): A file name or readable object. output (str | TextIO): A file name or writable object. encoding (str): Encoding of input and output. - **other (Any): Any arguments accepted by the `Markdown` class. + + Arguments: + **kwargs: Any arguments accepted by the `Markdown` class. """ md = Markdown(**kwargs) diff --git a/markdown/extensions/__init__.py b/markdown/extensions/__init__.py index c420e1ba3..87ffe5926 100644 --- a/markdown/extensions/__init__.py +++ b/markdown/extensions/__init__.py @@ -1,23 +1,21 @@ -""" -Python Markdown +# Python Markdown -A Python implementation of John Gruber's 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/ +# 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). +# 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-2018 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) +# Copyright 2007-2018 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). -""" +# License: BSD (see LICENSE.md for details). from __future__ import annotations diff --git a/markdown/extensions/abbr.py b/markdown/extensions/abbr.py index 064987047..1bdbfc5f5 100644 --- a/markdown/extensions/abbr.py +++ b/markdown/extensions/abbr.py @@ -1,20 +1,20 @@ -''' +""" Abbreviation Extension for Python-Markdown ========================================== This extension adds abbreviation handling to Python-Markdown. -See +See https://Python-Markdown.github.io/extensions/abbreviations for documentation. -Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/) and - [Seemant Kulleen](http://www.kulleen.org/) +Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/) +and [Seemant Kulleen](http://www.kulleen.org/) All changes Copyright 2008-2014 The Python Markdown Project License: [BSD](https://opensource.org/licenses/bsd-license.php) -''' +""" from . import Extension from ..blockprocessors import BlockProcessor @@ -41,11 +41,11 @@ def test(self, parent, block): return True def run(self, parent, blocks): - ''' + """ Find and remove all Abbreviation references from the text. Each reference is set as a new `AbbrPattern` in the markdown instance. - ''' + """ block = blocks.pop(0) m = self.RE.search(block) if m: @@ -66,7 +66,7 @@ def run(self, parent, blocks): return False def _generate_pattern(self, text): - ''' + """ Given a string, returns an regex pattern to match that string. 'HTML' -> r'(?P[H][T][M][L])' @@ -74,7 +74,7 @@ def _generate_pattern(self, text): Note: we force each char as a literal match (in brackets) as we don't know what they will be beforehand. - ''' + """ chars = list(text) for i in range(len(chars)): chars[i] = r'[%s]' % chars[i] diff --git a/markdown/extensions/admonition.py b/markdown/extensions/admonition.py index ce8492f4a..9c541bc97 100644 --- a/markdown/extensions/admonition.py +++ b/markdown/extensions/admonition.py @@ -6,7 +6,7 @@ [rST]: http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-admonitions -See +See https://Python-Markdown.github.io/extensions/admonition for documentation. Original code Copyright [Tiago Serafim](https://www.tiagoserafim.com/). diff --git a/markdown/extensions/attr_list.py b/markdown/extensions/attr_list.py index bc06786d3..ad171eb1b 100644 --- a/markdown/extensions/attr_list.py +++ b/markdown/extensions/attr_list.py @@ -6,7 +6,7 @@ [Maruku](http://maruku.rubyforge.org/proposal.html#attribute_lists)'s feature of the same name. -See +See https://Python-Markdown.github.io/extensions/attr_list for documentation. Original code Copyright 2011 [Waylan Limberg](http://achinghead.com/). diff --git a/markdown/extensions/codehilite.py b/markdown/extensions/codehilite.py index 8dec2ccee..4b9990aff 100644 --- a/markdown/extensions/codehilite.py +++ b/markdown/extensions/codehilite.py @@ -4,7 +4,7 @@ Adds code/syntax highlighting to standard Python-Markdown code blocks. -See +See https://Python-Markdown.github.io/extensions/code_hilite for documentation. Original code Copyright 2006-2008 [Waylan Limberg](http://achinghead.com/). diff --git a/markdown/extensions/def_list.py b/markdown/extensions/def_list.py index c2f23a694..cc0f0cd05 100644 --- a/markdown/extensions/def_list.py +++ b/markdown/extensions/def_list.py @@ -4,7 +4,7 @@ Adds parsing of Definition Lists to Python-Markdown. -See +See https://Python-Markdown.github.io/extensions/definition_lists for documentation. Original code Copyright 2008 [Waylan Limberg](http://achinghead.com) diff --git a/markdown/extensions/extra.py b/markdown/extensions/extra.py index 8f73806e1..dc8d6bab7 100644 --- a/markdown/extensions/extra.py +++ b/markdown/extensions/extra.py @@ -20,7 +20,7 @@ variable defined below, but be aware that such changes may be lost when you upgrade to any future version of Python-Markdown. -See +See https://Python-Markdown.github.io/extensions/extra for documentation. Copyright The Python Markdown Project diff --git a/markdown/extensions/fenced_code.py b/markdown/extensions/fenced_code.py index a0874d28b..f570e891c 100644 --- a/markdown/extensions/fenced_code.py +++ b/markdown/extensions/fenced_code.py @@ -4,12 +4,11 @@ This extension adds Fenced Code Blocks to Python-Markdown. -See +See https://Python-Markdown.github.io/extensions/fenced_code_blocks for documentation. Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/). - All changes Copyright 2008-2014 The Python Markdown Project License: [BSD](https://opensource.org/licenses/bsd-license.php) diff --git a/markdown/extensions/footnotes.py b/markdown/extensions/footnotes.py index 6c8c28465..ac4a8e3d0 100644 --- a/markdown/extensions/footnotes.py +++ b/markdown/extensions/footnotes.py @@ -4,7 +4,7 @@ Adds footnote handling to Python-Markdown. -See +See https://Python-Markdown.github.io/extensions/footnotes for documentation. Copyright The Python Markdown Project diff --git a/markdown/extensions/legacy_attrs.py b/markdown/extensions/legacy_attrs.py index 6e05e7677..89b0e8854 100644 --- a/markdown/extensions/legacy_attrs.py +++ b/markdown/extensions/legacy_attrs.py @@ -1,23 +1,23 @@ -""" -Python Markdown +# Python Markdown -A Python implementation of John Gruber's 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/ +# 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). +# 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-2018 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) +# Copyright 2007-2018 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). +# License: BSD (see LICENSE.md for details). +""" Legacy Attributes Extension =========================== diff --git a/markdown/extensions/legacy_em.py b/markdown/extensions/legacy_em.py index bc147a69c..3105c4f68 100644 --- a/markdown/extensions/legacy_em.py +++ b/markdown/extensions/legacy_em.py @@ -1,4 +1,4 @@ -''' +""" Legacy Em Extension for Python-Markdown ======================================= @@ -8,7 +8,7 @@ License: [BSD](https://opensource.org/licenses/bsd-license.php) -''' +""" from . import Extension from ..inlinepatterns import UnderscoreProcessor, EmStrongItem, EM_STRONG2_RE, STRONG_EM2_RE diff --git a/markdown/extensions/md_in_html.py b/markdown/extensions/md_in_html.py index 92afecfee..965297600 100644 --- a/markdown/extensions/md_in_html.py +++ b/markdown/extensions/md_in_html.py @@ -5,7 +5,7 @@ An implementation of [PHP Markdown Extra](http://michelf.com/projects/php-markdown/extra/)'s parsing of Markdown syntax in raw HTML. -See +See https://Python-Markdown.github.io/extensions/raw_html for documentation. Copyright The Python Markdown Project diff --git a/markdown/extensions/meta.py b/markdown/extensions/meta.py index 8a9386366..993193d8a 100644 --- a/markdown/extensions/meta.py +++ b/markdown/extensions/meta.py @@ -4,7 +4,7 @@ This extension adds Meta Data handling to markdown. -See +See https://Python-Markdown.github.io/extensions/meta_data for documentation. Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com). diff --git a/markdown/extensions/nl2br.py b/markdown/extensions/nl2br.py index 23d56034a..466737c32 100644 --- a/markdown/extensions/nl2br.py +++ b/markdown/extensions/nl2br.py @@ -5,7 +5,7 @@ A Python-Markdown extension to treat newlines as hard breaks; like GitHub-flavored Markdown does. -See +See https://Python-Markdown.github.io/extensions/nl2br for documentation. Original code Copyright 2011 [Brian Neal](https://deathofagremmie.com/) diff --git a/markdown/extensions/sane_lists.py b/markdown/extensions/sane_lists.py index e27eb1803..2c96cdb5f 100644 --- a/markdown/extensions/sane_lists.py +++ b/markdown/extensions/sane_lists.py @@ -4,7 +4,7 @@ Modify the behavior of Lists in Python-Markdown to act in a sane manor. -See +See https://Python-Markdown.github.io/extensions/sane_lists for documentation. Original code Copyright 2011 [Waylan Limberg](http://achinghead.com) diff --git a/markdown/extensions/smarty.py b/markdown/extensions/smarty.py index f03169e00..8c9eb0fe7 100644 --- a/markdown/extensions/smarty.py +++ b/markdown/extensions/smarty.py @@ -1,11 +1,11 @@ -''' +""" Smarty extension for Python-Markdown ==================================== Adds conversion of ASCII dashes, quotes and ellipses to their HTML entity equivalents. -See +See https://Python-Markdown.github.io/extensions/smarty for documentation. Author: 2013, Dmitry Shachnev @@ -77,7 +77,7 @@ (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. -''' +""" from . import Extension diff --git a/markdown/extensions/tables.py b/markdown/extensions/tables.py index a72103f5c..e78131cb9 100644 --- a/markdown/extensions/tables.py +++ b/markdown/extensions/tables.py @@ -4,7 +4,7 @@ Added parsing of tables to Python-Markdown. -See +See https://Python-Markdown.github.io/extensions/tables for documentation. Original code Copyright 2009 [Waylan Limberg](http://achinghead.com) diff --git a/markdown/extensions/toc.py b/markdown/extensions/toc.py index 6d080deb7..aa1c59b89 100644 --- a/markdown/extensions/toc.py +++ b/markdown/extensions/toc.py @@ -2,7 +2,7 @@ Table of Contents Extension for Python-Markdown =============================================== -See +See https://Python-Markdown.github.io/extensions/toc for documentation. Original code Copyright 2008 [Jack Miller](https://codezen.org/) @@ -178,7 +178,7 @@ def __init__(self, md, config): self.toc_bottom = int(config["toc_depth"]) def iterparent(self, node): - ''' Iterator wrapper to get allowed parent and child all at once. ''' + """ Iterator wrapper to get allowed parent and child all at once. """ # We do not allow the marker inside a header as that # would causes an endless loop of placing a new TOC @@ -189,7 +189,7 @@ def iterparent(self, node): yield from self.iterparent(child) def replace_marker(self, root, elem): - ''' Replace marker with elem. ''' + """ Replace marker with elem. """ for (p, c) in self.iterparent(root): text = ''.join(c.itertext()).strip() if not text: @@ -210,7 +210,7 @@ def replace_marker(self, root, elem): break def set_level(self, elem): - ''' Adjust header level according to base level. ''' + """ Adjust header level according to base level. """ level = int(elem.tag[-1]) + self.base_level if level > 6: level = 6 diff --git a/markdown/extensions/wikilinks.py b/markdown/extensions/wikilinks.py index d32d9122c..e6d1e3943 100644 --- a/markdown/extensions/wikilinks.py +++ b/markdown/extensions/wikilinks.py @@ -1,10 +1,10 @@ -''' +""" WikiLinks Extension for Python-Markdown ====================================== Converts [[WikiLinks]] to relative links. -See +See https://Python-Markdown.github.io/extensions/wikilinks for documentation. Original code Copyright [Waylan Limberg](http://achinghead.com/). @@ -13,7 +13,7 @@ License: [BSD](https://opensource.org/licenses/bsd-license.php) -''' +""" from . import Extension from ..inlinepatterns import InlineProcessor diff --git a/markdown/htmlparser.py b/markdown/htmlparser.py index 78ac9588a..8ff2b0050 100644 --- a/markdown/htmlparser.py +++ b/markdown/htmlparser.py @@ -1,23 +1,21 @@ -""" -Python Markdown +# Python Markdown -A Python implementation of John Gruber's 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/ +# 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). +# 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-2020 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) +# Copyright 2007-2018 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). -""" +# License: BSD (see LICENSE.md for details). import re import importlib.util diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py index 9244194af..fdd9a2bc1 100644 --- a/markdown/inlinepatterns.py +++ b/markdown/inlinepatterns.py @@ -1,23 +1,23 @@ -""" -Python Markdown +# Python Markdown -A Python implementation of John Gruber's 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/ +# 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). +# 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-2018 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) +# Copyright 2007-2018 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). +# License: BSD (see LICENSE.md for details). +""" INLINE PATTERNS ============================================================================= diff --git a/markdown/postprocessors.py b/markdown/postprocessors.py index 0e89d406f..fa76dfba2 100644 --- a/markdown/postprocessors.py +++ b/markdown/postprocessors.py @@ -1,23 +1,23 @@ -""" -Python Markdown +# Python Markdown -A Python implementation of John Gruber's 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/ +# 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). +# 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-2018 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) +# Copyright 2007-2018 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). +# License: BSD (see LICENSE.md for details). +""" POST-PROCESSORS ============================================================================= diff --git a/markdown/preprocessors.py b/markdown/preprocessors.py index e1023c59a..e32a33970 100644 --- a/markdown/preprocessors.py +++ b/markdown/preprocessors.py @@ -1,23 +1,23 @@ -""" -Python Markdown +# Python Markdown -A Python implementation of John Gruber's 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/ +# 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). +# 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-2018 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) +# Copyright 2007-2018 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). +# License: BSD (see LICENSE.md for details). +""" PRE-PROCESSORS ============================================================================= diff --git a/markdown/test_tools.py b/markdown/test_tools.py index c4db6b22c..edca31876 100644 --- a/markdown/test_tools.py +++ b/markdown/test_tools.py @@ -1,23 +1,21 @@ -""" -Python Markdown +# Python Markdown -A Python implementation of John Gruber's 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/ +# 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). +# 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-2018 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) +# Copyright 2007-2018 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). -""" +# License: BSD (see LICENSE.md for details). import os import sys diff --git a/markdown/treeprocessors.py b/markdown/treeprocessors.py index d99eb337b..bfb3d9110 100644 --- a/markdown/treeprocessors.py +++ b/markdown/treeprocessors.py @@ -1,23 +1,21 @@ -""" -Python Markdown +# Python Markdown -A Python implementation of John Gruber's 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/ +# 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). +# 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-2018 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) +# Copyright 2007-2018 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). -""" +# License: BSD (see LICENSE.md for details). from __future__ import annotations diff --git a/markdown/util.py b/markdown/util.py index 281f7e71e..7ca52b303 100644 --- a/markdown/util.py +++ b/markdown/util.py @@ -1,23 +1,21 @@ -""" -Python Markdown +# Python Markdown -A Python implementation of John Gruber's 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/ +# 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). +# 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-2018 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) +# Copyright 2007-2018 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). -""" +# License: BSD (see LICENSE.md for details). from __future__ import annotations diff --git a/mkdocs.yml b/mkdocs.yml index b65a26f94..1fe94ddff 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -23,7 +23,6 @@ nav: - Library Reference: reference.md - Command Line: cli.md - Extensions: extensions/index.md - - API Reference: reference/ - Officially Supported Extensions: - Abbreviations: extensions/abbreviations.md - Admonition: extensions/admonition.md @@ -45,6 +44,7 @@ nav: - WikiLinks: extensions/wikilinks.md - Extension API: extensions/api.md - Test Tools: test_tools.md + - API Reference: reference/ - Contributing to Python-Markdown: contributing.md - Changelog: changelog.md - Authors: authors.md diff --git a/scripts/gen_ref_nav.py b/scripts/gen_ref_nav.py index 75e7c91fc..b8411bb58 100755 --- a/scripts/gen_ref_nav.py +++ b/scripts/gen_ref_nav.py @@ -5,7 +5,6 @@ import mkdocs_gen_files nav = mkdocs_gen_files.Nav() -mod_symbol = '' for path in sorted(Path("markdown").rglob("*.py")): module_path = path.with_suffix("") @@ -21,8 +20,7 @@ elif parts[-1].startswith("_"): continue - nav_parts = [f"{mod_symbol} {part}" for part in parts] - nav[tuple(nav_parts)] = doc_path.as_posix() + nav[tuple(parts)] = doc_path.as_posix() with mkdocs_gen_files.open(full_doc_path, "w") as fd: ident = ".".join(parts) diff --git a/tests/test_syntax/extensions/test_md_in_html.py b/tests/test_syntax/extensions/test_md_in_html.py index 3de49b072..45bb3ad42 100644 --- a/tests/test_syntax/extensions/test_md_in_html.py +++ b/tests/test_syntax/extensions/test_md_in_html.py @@ -1208,7 +1208,7 @@ def test_md1_nested_footnote_ref(self): def load_tests(loader, tests, pattern): - ''' Ensure `TestHTMLBlocks` doesn't get run twice by excluding it here. ''' + """ Ensure `TestHTMLBlocks` doesn't get run twice by excluding it here. """ suite = TestSuite() for test_class in [TestDefaultwMdInHTML, TestMdInHTML, TestMarkdownInHTMLPostProcessor]: tests = loader.loadTestsFromTestCase(test_class) From 5c510cb34e4f21c159f742df07812494447bddc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Thu, 24 Aug 2023 15:24:54 +0200 Subject: [PATCH 03/61] fixup! Create API docs --- docs/mkdocstrings.css | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/mkdocstrings.css b/docs/mkdocstrings.css index 645a19fbf..a36e89164 100644 --- a/docs/mkdocstrings.css +++ b/docs/mkdocstrings.css @@ -8,6 +8,7 @@ a.external::after, a.autorefs-external::after { /* https://primer.style/octicons/arrow-up-right-24 */ mask-image: url('data:image/svg+xml,'); + -webkit-mask-image: url('data:image/svg+xml,'); content: ' '; display: inline-block; From 7af5634e95e8cd702a16d5d77ec4d1e092b3e1cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Thu, 24 Aug 2023 17:14:48 +0200 Subject: [PATCH 04/61] fixup! Create API docs --- markdown/__init__.py | 14 ++++++++++++++ mkdocs.yml | 4 ++-- scripts/gen_ref_nav.py | 9 +++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/markdown/__init__.py b/markdown/__init__.py index 7c1f29ec7..485a58e96 100644 --- a/markdown/__init__.py +++ b/markdown/__init__.py @@ -17,6 +17,20 @@ Copyright 2004 Manfred Stienstra (the original version) License: BSD (see LICENSE.md for details). + +Modules: + core: Core functionality. + preprocessors: Pre-processors. + blockparser: Core Markdown block parser. + blockprocessors: Block processors. + treeprocessors: Tree processors. + inlinepatterns: Inline patterns. + postprocessors: Post-processors. + serializers: Serializers. + util: Utility functions. + htmlparser: HTML parser. + test_tools: Testing utilities. + extensions: Markdown extensions. """ from .core import Markdown, markdown, markdownFromFile diff --git a/mkdocs.yml b/mkdocs.yml index 1fe94ddff..43fe0903c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -85,12 +85,12 @@ plugins: heading_level: 1 inherited_members: true merge_init_into_class: true - separate_signature: true + separate_signature: false show_root_heading: true show_object_full_path: true show_signature_annotations: true show_source: false show_symbol_type_heading: true show_symbol_type_toc: true - signature_crossrefs: true + signature_crossrefs: false summary: true diff --git a/scripts/gen_ref_nav.py b/scripts/gen_ref_nav.py index b8411bb58..dbd01a11d 100755 --- a/scripts/gen_ref_nav.py +++ b/scripts/gen_ref_nav.py @@ -1,11 +1,17 @@ """Generate the code reference pages and navigation.""" +import textwrap +import yaml from pathlib import Path import mkdocs_gen_files nav = mkdocs_gen_files.Nav() +per_module_options = { + "markdown": {"summary": {"attributes": True, "functions": True, "classes": True}} +} + for path in sorted(Path("markdown").rglob("*.py")): module_path = path.with_suffix("") doc_path = path.with_suffix(".md") @@ -25,6 +31,9 @@ with mkdocs_gen_files.open(full_doc_path, "w") as fd: ident = ".".join(parts) fd.write(f"::: {ident}") + if ident in per_module_options: + yaml_options = yaml.dump({"options": per_module_options[ident]}) + fd.write(f"\n{textwrap.indent(yaml_options, prefix=' ')}") mkdocs_gen_files.set_edit_path(full_doc_path, ".." / path) From 42cec09fca4e6ab072ec92df2b5a485ddf81f23d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Thu, 24 Aug 2023 18:57:55 +0200 Subject: [PATCH 05/61] fixup! Create API docs --- docs/mkdocstrings.css | 5 +++++ mkdocs.yml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/mkdocstrings.css b/docs/mkdocstrings.css index a36e89164..361c911bb 100644 --- a/docs/mkdocstrings.css +++ b/docs/mkdocstrings.css @@ -23,4 +23,9 @@ a.autorefs-external::after { a.external:hover::after, a.autorefs-external:hover::after { background-color: #e32e00; +} + +/* Cancel codehilite background in headings. */ +.doc-heading .codehilite { + background: unset; } \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 43fe0903c..20c17c7fb 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -88,7 +88,7 @@ plugins: separate_signature: false show_root_heading: true show_object_full_path: true - show_signature_annotations: true + show_signature_annotations: false show_source: false show_symbol_type_heading: true show_symbol_type_toc: true From 4166503db543f958d5b2175c0b63fa62030c6f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Thu, 24 Aug 2023 20:45:08 +0200 Subject: [PATCH 06/61] fixup! Create API docs --- docs/mkdocstrings.css | 21 +++++++++++++++++++++ mkdocs.yml | 2 +- scripts/gen_ref_nav.py | 18 +++++++++++++++++- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/docs/mkdocstrings.css b/docs/mkdocstrings.css index 361c911bb..18bb39fdf 100644 --- a/docs/mkdocstrings.css +++ b/docs/mkdocstrings.css @@ -28,4 +28,25 @@ a.autorefs-external:hover::after { /* Cancel codehilite background in headings. */ .doc-heading .codehilite { background: unset; +} + +/* Customize symbol names. */ +code.doc-symbol-attribute::after { + content: "Attr"; +} + +code.doc-symbol-function::after { + content: "Func"; +} + +code.doc-symbol-method::after { + content: "Method"; +} + +code.doc-symbol-class::after { + content: "Class"; +} + +code.doc-symbol-module::after { + content: "Module"; } \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 20c17c7fb..43fe0903c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -88,7 +88,7 @@ plugins: separate_signature: false show_root_heading: true show_object_full_path: true - show_signature_annotations: false + show_signature_annotations: true show_source: false show_symbol_type_heading: true show_symbol_type_toc: true diff --git a/scripts/gen_ref_nav.py b/scripts/gen_ref_nav.py index dbd01a11d..501c893bd 100755 --- a/scripts/gen_ref_nav.py +++ b/scripts/gen_ref_nav.py @@ -12,7 +12,23 @@ "markdown": {"summary": {"attributes": True, "functions": True, "classes": True}} } -for path in sorted(Path("markdown").rglob("*.py")): +modules = [ + Path("markdown", "__init__.py"), + Path("markdown", "core.py"), + Path("markdown", "preprocessors.py"), + Path("markdown", "blockparser.py"), + Path("markdown", "blockprocessors.py"), + Path("markdown", "treeprocessors.py"), + Path("markdown", "inlinepatterns.py"), + Path("markdown", "postprocessors.py"), + Path("markdown", "serializers.py"), + Path("markdown", "util.py"), + Path("markdown", "htmlparser.py"), + Path("markdown", "test_tools.py"), + *sorted(Path("markdown", "extensions").rglob("*.py")), +] + +for path in modules: module_path = path.with_suffix("") doc_path = path.with_suffix(".md") full_doc_path = Path("reference", doc_path) From d388012ea83914328f75969aae30f877af132716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Fri, 8 Sep 2023 15:03:21 +0200 Subject: [PATCH 07/61] fixup! Create API docs --- docs/mkdocstrings.css | 5 ----- markdown/__init__.py | 8 +++++--- markdown/__main__.py | 4 +++- markdown/__meta__.py | 6 +++++- markdown/blockparser.py | 4 ++-- markdown/blockprocessors.py | 4 +++- markdown/core.py | 18 +++++++++++++----- markdown/extensions/__init__.py | 3 ++- markdown/extensions/abbr.py | 2 ++ markdown/extensions/admonition.py | 2 ++ markdown/extensions/attr_list.py | 2 ++ markdown/extensions/codehilite.py | 2 ++ markdown/extensions/def_list.py | 2 ++ markdown/extensions/extra.py | 2 ++ markdown/extensions/fenced_code.py | 1 + markdown/extensions/footnotes.py | 2 ++ markdown/extensions/legacy_attrs.py | 4 +++- markdown/extensions/legacy_em.py | 2 ++ markdown/extensions/md_in_html.py | 2 ++ markdown/extensions/meta.py | 2 ++ markdown/extensions/nl2br.py | 2 ++ markdown/extensions/sane_lists.py | 2 ++ markdown/extensions/smarty.py | 1 + markdown/extensions/tables.py | 2 ++ markdown/extensions/toc.py | 2 ++ markdown/extensions/wikilinks.py | 2 ++ markdown/htmlparser.py | 4 +++- markdown/inlinepatterns.py | 2 +- markdown/postprocessors.py | 4 +++- markdown/preprocessors.py | 4 +++- markdown/serializers.py | 2 ++ markdown/test_tools.py | 4 +++- markdown/treeprocessors.py | 6 +++--- markdown/util.py | 2 +- tests/__init__.py | 2 +- tests/test_apis.py | 2 +- tests/test_extensions.py | 2 +- tests/test_legacy.py | 2 +- tests/test_syntax/__init__.py | 2 +- tests/test_syntax/blocks/__init__.py | 2 +- tests/test_syntax/blocks/test_blockquotes.py | 2 +- tests/test_syntax/blocks/test_code_blocks.py | 2 +- tests/test_syntax/blocks/test_headers.py | 2 +- tests/test_syntax/blocks/test_hr.py | 2 +- tests/test_syntax/blocks/test_html_blocks.py | 2 +- tests/test_syntax/blocks/test_paragraphs.py | 2 +- tests/test_syntax/extensions/__init__.py | 2 +- tests/test_syntax/extensions/test_abbr.py | 2 +- tests/test_syntax/extensions/test_attr_list.py | 2 +- tests/test_syntax/extensions/test_footnotes.py | 2 +- .../extensions/test_legacy_attrs.py | 2 +- tests/test_syntax/extensions/test_legacy_em.py | 2 +- .../test_syntax/extensions/test_md_in_html.py | 2 +- tests/test_syntax/extensions/test_tables.py | 2 +- tests/test_syntax/inline/__init__.py | 2 +- tests/test_syntax/inline/test_entities.py | 2 +- tests/test_syntax/inline/test_images.py | 2 +- tests/test_syntax/inline/test_links.py | 2 +- tests/test_syntax/inline/test_raw_html.py | 2 +- 59 files changed, 112 insertions(+), 54 deletions(-) diff --git a/docs/mkdocstrings.css b/docs/mkdocstrings.css index 18bb39fdf..40fdf7852 100644 --- a/docs/mkdocstrings.css +++ b/docs/mkdocstrings.css @@ -25,11 +25,6 @@ a.autorefs-external:hover::after { background-color: #e32e00; } -/* Cancel codehilite background in headings. */ -.doc-heading .codehilite { - background: unset; -} - /* Customize symbol names. */ code.doc-symbol-attribute::after { content: "Attr"; diff --git a/markdown/__init__.py b/markdown/__init__.py index 485a58e96..b3335f3c2 100644 --- a/markdown/__init__.py +++ b/markdown/__init__.py @@ -12,9 +12,9 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 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) +- 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). @@ -33,6 +33,8 @@ extensions: Markdown extensions. """ +from __future__ import annotations + from .core import Markdown, markdown, markdownFromFile from .__meta__ import __version__, __version_info__ # noqa diff --git a/markdown/__main__.py b/markdown/__main__.py index cba51bd80..c323aaac4 100644 --- a/markdown/__main__.py +++ b/markdown/__main__.py @@ -11,12 +11,14 @@ # Currently maintained by Waylan Limberg (https://github.com/waylan), # Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -# Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +# 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). +from __future__ import annotations + import sys import optparse import codecs diff --git a/markdown/__meta__.py b/markdown/__meta__.py index a2452ba31..aa7770ce3 100644 --- a/markdown/__meta__.py +++ b/markdown/__meta__.py @@ -11,7 +11,7 @@ # Currently maintained by Waylan Limberg (https://github.com/waylan), # Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -# Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +# 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) @@ -24,6 +24,10 @@ # (1, 2, 0, 'beta', 2) => "1.2b2" # (1, 2, 0, 'rc', 4) => "1.2rc4" # (1, 2, 0, 'final', 0) => "1.2" + +from __future__ import annotations + + __version_info__ = (3, 4, 4, 'final', 0) diff --git a/markdown/blockparser.py b/markdown/blockparser.py index cb69b23ed..1f437ae20 100644 --- a/markdown/blockparser.py +++ b/markdown/blockparser.py @@ -11,7 +11,7 @@ # Currently maintained by Waylan Limberg (https://github.com/waylan), # Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -# Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +# 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) @@ -71,7 +71,7 @@ class BlockParser: def __init__(self, md: Markdown): """ Initialize the block parser. - + Arguments: md: A Markdown instance. diff --git a/markdown/blockprocessors.py b/markdown/blockprocessors.py index a1a42ad9a..6e9b39e88 100644 --- a/markdown/blockprocessors.py +++ b/markdown/blockprocessors.py @@ -11,7 +11,7 @@ # Currently maintained by Waylan Limberg (https://github.com/waylan), # Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -# Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +# 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) @@ -30,6 +30,8 @@ as they need to alter how markdown blocks are parsed. """ +from __future__ import annotations + import logging import re import xml.etree.ElementTree as etree diff --git a/markdown/core.py b/markdown/core.py index feb38783a..e7b083b47 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -11,7 +11,7 @@ # Currently maintained by Waylan Limberg (https://github.com/waylan), # Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -# Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +# 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) @@ -56,12 +56,15 @@ def __init__(self, **kwargs): Keyword arguments: extensions (list[str | Extension]): A list of extensions. - If an item is an instance of a subclass of `markdown.extension.Extension`, the instance will be used - as-is. If an item is of type string, first an entry point will be loaded. If that fails, the string is - assumed to use Python dot notation (`path.to.module:ClassName`) to load a `markdown.Extension` subclass. + If an item is an instance of a subclass of `markdown.extension.Extension`, + the instance will be used as-is. + If an item is of type string, first an entry point will be loaded. + If that fails, the string is assumed to use Python dot notation (`path.to.module:ClassName`) + to load a `markdown.Extension` subclass. If no class is specified, then a `makeExtension` function is called within the specified module. extension_configs (dict[str, dict[str, Any]]): Configuration settings for extensions. output_format (str): Format of output. Supported formats are: + * `xhtml`: Outputs XHTML style tags. Default. * `html`: Outputs HTML style tags. tab_length (int): Length of tabs in the source. Default: 4 @@ -279,7 +282,12 @@ def convert(self, source: str): return output.strip() - def convertFile(self, input: str | TextIO | None = None, output: str | TextIO | None = None, encoding: str | None = None): + def convertFile( + self, + input: str | TextIO | None = None, + output: str | TextIO | None = None, + encoding: str | None = None, + ): """Converts a markdown file and returns the HTML as a Unicode string. Decodes the file using the provided encoding (defaults to `utf-8`), diff --git a/markdown/extensions/__init__.py b/markdown/extensions/__init__.py index 87ffe5926..e0d2e790a 100644 --- a/markdown/extensions/__init__.py +++ b/markdown/extensions/__init__.py @@ -11,7 +11,7 @@ # Currently maintained by Waylan Limberg (https://github.com/waylan), # Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -# Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +# 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) @@ -25,6 +25,7 @@ if TYPE_CHECKING: from markdown import Markdown + class Extension: """ Base class for extensions to subclass. """ diff --git a/markdown/extensions/abbr.py b/markdown/extensions/abbr.py index 1bdbfc5f5..678ac9b2c 100644 --- a/markdown/extensions/abbr.py +++ b/markdown/extensions/abbr.py @@ -16,6 +16,8 @@ """ +from __future__ import annotations + from . import Extension from ..blockprocessors import BlockProcessor from ..inlinepatterns import InlineProcessor diff --git a/markdown/extensions/admonition.py b/markdown/extensions/admonition.py index 9c541bc97..92c744ae2 100644 --- a/markdown/extensions/admonition.py +++ b/markdown/extensions/admonition.py @@ -17,6 +17,8 @@ """ +from __future__ import annotations + from . import Extension from ..blockprocessors import BlockProcessor import xml.etree.ElementTree as etree diff --git a/markdown/extensions/attr_list.py b/markdown/extensions/attr_list.py index ad171eb1b..b0ca1ccc2 100644 --- a/markdown/extensions/attr_list.py +++ b/markdown/extensions/attr_list.py @@ -17,6 +17,8 @@ """ +from __future__ import annotations + from . import Extension from ..treeprocessors import Treeprocessor import re diff --git a/markdown/extensions/codehilite.py b/markdown/extensions/codehilite.py index 4b9990aff..bceac2f26 100644 --- a/markdown/extensions/codehilite.py +++ b/markdown/extensions/codehilite.py @@ -15,6 +15,8 @@ """ +from __future__ import annotations + from . import Extension from ..treeprocessors import Treeprocessor from ..util import parseBoolValue diff --git a/markdown/extensions/def_list.py b/markdown/extensions/def_list.py index cc0f0cd05..76a2367ef 100644 --- a/markdown/extensions/def_list.py +++ b/markdown/extensions/def_list.py @@ -15,6 +15,8 @@ """ +from __future__ import annotations + from . import Extension from ..blockprocessors import BlockProcessor, ListIndentProcessor import xml.etree.ElementTree as etree diff --git a/markdown/extensions/extra.py b/markdown/extensions/extra.py index dc8d6bab7..407a50ef3 100644 --- a/markdown/extensions/extra.py +++ b/markdown/extensions/extra.py @@ -29,6 +29,8 @@ """ +from __future__ import annotations + from . import Extension extensions = [ diff --git a/markdown/extensions/fenced_code.py b/markdown/extensions/fenced_code.py index f570e891c..35a087c6d 100644 --- a/markdown/extensions/fenced_code.py +++ b/markdown/extensions/fenced_code.py @@ -14,6 +14,7 @@ License: [BSD](https://opensource.org/licenses/bsd-license.php) """ +from __future__ import annotations from textwrap import dedent from . import Extension diff --git a/markdown/extensions/footnotes.py b/markdown/extensions/footnotes.py index ac4a8e3d0..52ed31df4 100644 --- a/markdown/extensions/footnotes.py +++ b/markdown/extensions/footnotes.py @@ -13,6 +13,8 @@ """ +from __future__ import annotations + from . import Extension from ..blockprocessors import BlockProcessor from ..inlinepatterns import InlineProcessor diff --git a/markdown/extensions/legacy_attrs.py b/markdown/extensions/legacy_attrs.py index 89b0e8854..500022ab1 100644 --- a/markdown/extensions/legacy_attrs.py +++ b/markdown/extensions/legacy_attrs.py @@ -11,7 +11,7 @@ # Currently maintained by Waylan Limberg (https://github.com/waylan), # Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -# Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +# 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) @@ -31,6 +31,8 @@ years. This extension can be used to continue to render those documents correctly. """ +from __future__ import annotations + import re from markdown.treeprocessors import Treeprocessor, isString from markdown.extensions import Extension diff --git a/markdown/extensions/legacy_em.py b/markdown/extensions/legacy_em.py index 3105c4f68..5aa0ae64e 100644 --- a/markdown/extensions/legacy_em.py +++ b/markdown/extensions/legacy_em.py @@ -10,6 +10,8 @@ """ +from __future__ import annotations + from . import Extension from ..inlinepatterns import UnderscoreProcessor, EmStrongItem, EM_STRONG2_RE, STRONG_EM2_RE import re diff --git a/markdown/extensions/md_in_html.py b/markdown/extensions/md_in_html.py index 965297600..7446ba4c8 100644 --- a/markdown/extensions/md_in_html.py +++ b/markdown/extensions/md_in_html.py @@ -14,6 +14,8 @@ """ +from __future__ import annotations + from . import Extension from ..blockprocessors import BlockProcessor from ..preprocessors import Preprocessor diff --git a/markdown/extensions/meta.py b/markdown/extensions/meta.py index 993193d8a..ff6700e96 100644 --- a/markdown/extensions/meta.py +++ b/markdown/extensions/meta.py @@ -15,6 +15,8 @@ """ +from __future__ import annotations + from . import Extension from ..preprocessors import Preprocessor import re diff --git a/markdown/extensions/nl2br.py b/markdown/extensions/nl2br.py index 466737c32..43417c4d8 100644 --- a/markdown/extensions/nl2br.py +++ b/markdown/extensions/nl2br.py @@ -16,6 +16,8 @@ """ +from __future__ import annotations + from . import Extension from ..inlinepatterns import SubstituteTagInlineProcessor diff --git a/markdown/extensions/sane_lists.py b/markdown/extensions/sane_lists.py index 2c96cdb5f..aab3fbb84 100644 --- a/markdown/extensions/sane_lists.py +++ b/markdown/extensions/sane_lists.py @@ -15,6 +15,8 @@ """ +from __future__ import annotations + from . import Extension from ..blockprocessors import OListProcessor, UListProcessor import re diff --git a/markdown/extensions/smarty.py b/markdown/extensions/smarty.py index 8c9eb0fe7..7d7be491d 100644 --- a/markdown/extensions/smarty.py +++ b/markdown/extensions/smarty.py @@ -79,6 +79,7 @@ """ +from __future__ import annotations from . import Extension from ..inlinepatterns import HtmlInlineProcessor, HTML_RE diff --git a/markdown/extensions/tables.py b/markdown/extensions/tables.py index e78131cb9..1deb68608 100644 --- a/markdown/extensions/tables.py +++ b/markdown/extensions/tables.py @@ -15,6 +15,8 @@ """ +from __future__ import annotations + from . import Extension from ..blockprocessors import BlockProcessor import xml.etree.ElementTree as etree diff --git a/markdown/extensions/toc.py b/markdown/extensions/toc.py index aa1c59b89..36f1287d1 100644 --- a/markdown/extensions/toc.py +++ b/markdown/extensions/toc.py @@ -13,6 +13,8 @@ """ +from __future__ import annotations + from . import Extension from ..treeprocessors import Treeprocessor from ..util import code_escape, parseBoolValue, AMP_SUBSTITUTE, HTML_PLACEHOLDER_RE, AtomicString diff --git a/markdown/extensions/wikilinks.py b/markdown/extensions/wikilinks.py index e6d1e3943..30cf02c1e 100644 --- a/markdown/extensions/wikilinks.py +++ b/markdown/extensions/wikilinks.py @@ -15,6 +15,8 @@ """ +from __future__ import annotations + from . import Extension from ..inlinepatterns import InlineProcessor import xml.etree.ElementTree as etree diff --git a/markdown/htmlparser.py b/markdown/htmlparser.py index 8ff2b0050..9d15fca7b 100644 --- a/markdown/htmlparser.py +++ b/markdown/htmlparser.py @@ -11,12 +11,14 @@ # Currently maintained by Waylan Limberg (https://github.com/waylan), # Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -# Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +# 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). +from __future__ import annotations + import re import importlib.util import sys diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py index fdd9a2bc1..e15e7634c 100644 --- a/markdown/inlinepatterns.py +++ b/markdown/inlinepatterns.py @@ -11,7 +11,7 @@ # Currently maintained by Waylan Limberg (https://github.com/waylan), # Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -# Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +# 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) diff --git a/markdown/postprocessors.py b/markdown/postprocessors.py index fa76dfba2..de97525b8 100644 --- a/markdown/postprocessors.py +++ b/markdown/postprocessors.py @@ -11,7 +11,7 @@ # Currently maintained by Waylan Limberg (https://github.com/waylan), # Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -# Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +# 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) @@ -27,6 +27,8 @@ """ +from __future__ import annotations + from collections import OrderedDict from . import util import re diff --git a/markdown/preprocessors.py b/markdown/preprocessors.py index e32a33970..fe572b791 100644 --- a/markdown/preprocessors.py +++ b/markdown/preprocessors.py @@ -11,7 +11,7 @@ # Currently maintained by Waylan Limberg (https://github.com/waylan), # Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -# Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +# 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) @@ -25,6 +25,8 @@ complicated. """ +from __future__ import annotations + from . import util from .htmlparser import HTMLExtractor import re diff --git a/markdown/serializers.py b/markdown/serializers.py index b5dcd11d0..e21de0d3b 100644 --- a/markdown/serializers.py +++ b/markdown/serializers.py @@ -34,6 +34,8 @@ # OF THIS SOFTWARE. # -------------------------------------------------------------------- +from __future__ import annotations + from xml.etree.ElementTree import ProcessingInstruction from xml.etree.ElementTree import Comment, ElementTree, QName, HTML_EMPTY import re diff --git a/markdown/test_tools.py b/markdown/test_tools.py index edca31876..f26e5c94e 100644 --- a/markdown/test_tools.py +++ b/markdown/test_tools.py @@ -11,12 +11,14 @@ # Currently maintained by Waylan Limberg (https://github.com/waylan), # Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -# Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +# 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). +from __future__ import annotations + import os import sys import unittest diff --git a/markdown/treeprocessors.py b/markdown/treeprocessors.py index bfb3d9110..b0b653ca5 100644 --- a/markdown/treeprocessors.py +++ b/markdown/treeprocessors.py @@ -11,7 +11,7 @@ # Currently maintained by Waylan Limberg (https://github.com/waylan), # Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -# Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +# 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) @@ -21,7 +21,7 @@ import re import xml.etree.ElementTree as etree -from typing import TYPE_CHECKING, Sequence +from typing import Sequence from . import util from . import inlinepatterns @@ -236,7 +236,7 @@ def linkText(text): return result - def __applyPattern(self, pattern: str, data: srt, patternIndex: int, startIndex: int = 0) -> tuple[str, bool, int]: + def __applyPattern(self, pattern: str, data: str, patternIndex: int, startIndex: int = 0) -> tuple[str, bool, int]: """ Check if the line fits the pattern, create the necessary elements, add it to `stashed_nodes`. diff --git a/markdown/util.py b/markdown/util.py index 7ca52b303..b911f20b1 100644 --- a/markdown/util.py +++ b/markdown/util.py @@ -11,7 +11,7 @@ # Currently maintained by Waylan Limberg (https://github.com/waylan), # Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -# Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +# 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) diff --git a/tests/__init__.py b/tests/__init__.py index 564ba3be4..19aa92b87 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_apis.py b/tests/test_apis.py index 82bc3b8c5..1305c5476 100644 --- a/tests/test_apis.py +++ b/tests/test_apis.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_extensions.py b/tests/test_extensions.py index 305ea8347..a9e789f19 100644 --- a/tests/test_extensions.py +++ b/tests/test_extensions.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_legacy.py b/tests/test_legacy.py index 295588b0a..df4da4d71 100644 --- a/tests/test_legacy.py +++ b/tests/test_legacy.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/__init__.py b/tests/test_syntax/__init__.py index 564ba3be4..19aa92b87 100644 --- a/tests/test_syntax/__init__.py +++ b/tests/test_syntax/__init__.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/blocks/__init__.py b/tests/test_syntax/blocks/__init__.py index 564ba3be4..19aa92b87 100644 --- a/tests/test_syntax/blocks/__init__.py +++ b/tests/test_syntax/blocks/__init__.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/blocks/test_blockquotes.py b/tests/test_syntax/blocks/test_blockquotes.py index 3422f9f76..9a114644a 100644 --- a/tests/test_syntax/blocks/test_blockquotes.py +++ b/tests/test_syntax/blocks/test_blockquotes.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2020 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/blocks/test_code_blocks.py b/tests/test_syntax/blocks/test_code_blocks.py index 54b686069..dbbb9c79a 100644 --- a/tests/test_syntax/blocks/test_code_blocks.py +++ b/tests/test_syntax/blocks/test_code_blocks.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/blocks/test_headers.py b/tests/test_syntax/blocks/test_headers.py index ca065a56c..da2ca14ff 100644 --- a/tests/test_syntax/blocks/test_headers.py +++ b/tests/test_syntax/blocks/test_headers.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/blocks/test_hr.py b/tests/test_syntax/blocks/test_hr.py index 85a51b32f..a8753977b 100644 --- a/tests/test_syntax/blocks/test_hr.py +++ b/tests/test_syntax/blocks/test_hr.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/blocks/test_html_blocks.py b/tests/test_syntax/blocks/test_html_blocks.py index 8623b3085..22b949834 100644 --- a/tests/test_syntax/blocks/test_html_blocks.py +++ b/tests/test_syntax/blocks/test_html_blocks.py @@ -13,7 +13,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/blocks/test_paragraphs.py b/tests/test_syntax/blocks/test_paragraphs.py index 9b7ba0357..f09731e72 100644 --- a/tests/test_syntax/blocks/test_paragraphs.py +++ b/tests/test_syntax/blocks/test_paragraphs.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/extensions/__init__.py b/tests/test_syntax/extensions/__init__.py index 564ba3be4..19aa92b87 100644 --- a/tests/test_syntax/extensions/__init__.py +++ b/tests/test_syntax/extensions/__init__.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/extensions/test_abbr.py b/tests/test_syntax/extensions/test_abbr.py index 64388c2d8..fbb25ffb2 100644 --- a/tests/test_syntax/extensions/test_abbr.py +++ b/tests/test_syntax/extensions/test_abbr.py @@ -13,7 +13,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/extensions/test_attr_list.py b/tests/test_syntax/extensions/test_attr_list.py index f6a4fe65b..ba8b23693 100644 --- a/tests/test_syntax/extensions/test_attr_list.py +++ b/tests/test_syntax/extensions/test_attr_list.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2020 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/extensions/test_footnotes.py b/tests/test_syntax/extensions/test_footnotes.py index 9fe786bad..6f504e39c 100644 --- a/tests/test_syntax/extensions/test_footnotes.py +++ b/tests/test_syntax/extensions/test_footnotes.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/extensions/test_legacy_attrs.py b/tests/test_syntax/extensions/test_legacy_attrs.py index b4ba5e715..44e8a6159 100644 --- a/tests/test_syntax/extensions/test_legacy_attrs.py +++ b/tests/test_syntax/extensions/test_legacy_attrs.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/extensions/test_legacy_em.py b/tests/test_syntax/extensions/test_legacy_em.py index c5daf1cf8..ad2862e5e 100644 --- a/tests/test_syntax/extensions/test_legacy_em.py +++ b/tests/test_syntax/extensions/test_legacy_em.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/extensions/test_md_in_html.py b/tests/test_syntax/extensions/test_md_in_html.py index 45bb3ad42..c439a03b2 100644 --- a/tests/test_syntax/extensions/test_md_in_html.py +++ b/tests/test_syntax/extensions/test_md_in_html.py @@ -13,7 +13,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/extensions/test_tables.py b/tests/test_syntax/extensions/test_tables.py index 6a1a0d4fc..4e33d1aa3 100644 --- a/tests/test_syntax/extensions/test_tables.py +++ b/tests/test_syntax/extensions/test_tables.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/inline/__init__.py b/tests/test_syntax/inline/__init__.py index 564ba3be4..19aa92b87 100644 --- a/tests/test_syntax/inline/__init__.py +++ b/tests/test_syntax/inline/__init__.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/inline/test_entities.py b/tests/test_syntax/inline/test_entities.py index 34cc2e725..4262bce1b 100644 --- a/tests/test_syntax/inline/test_entities.py +++ b/tests/test_syntax/inline/test_entities.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/inline/test_images.py b/tests/test_syntax/inline/test_images.py index c9c7cb88d..379cc597a 100644 --- a/tests/test_syntax/inline/test_images.py +++ b/tests/test_syntax/inline/test_images.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/inline/test_links.py b/tests/test_syntax/inline/test_links.py index 04587560d..702756894 100644 --- a/tests/test_syntax/inline/test_links.py +++ b/tests/test_syntax/inline/test_links.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) diff --git a/tests/test_syntax/inline/test_raw_html.py b/tests/test_syntax/inline/test_raw_html.py index f75a616d6..f165f750a 100644 --- a/tests/test_syntax/inline/test_raw_html.py +++ b/tests/test_syntax/inline/test_raw_html.py @@ -12,7 +12,7 @@ Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). -Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later) +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) From 2e064837b01fc538b93535ab2919580d1d90606a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Wed, 13 Sep 2023 14:47:22 +0200 Subject: [PATCH 08/61] fixup! Create API docs --- markdown/__meta__.py | 2 +- markdown/blockparser.py | 12 ++++----- markdown/blockprocessors.py | 43 ++++++++++++++----------------- markdown/extensions/codehilite.py | 6 +++-- markdown/inlinepatterns.py | 2 +- scripts/gen_ref_nav.py | 3 ++- 6 files changed, 34 insertions(+), 34 deletions(-) diff --git a/markdown/__meta__.py b/markdown/__meta__.py index aa7770ce3..082bfa0fa 100644 --- a/markdown/__meta__.py +++ b/markdown/__meta__.py @@ -32,7 +32,7 @@ def _get_version(version_info): - " Returns a PEP 440-compliant version number from version_info. " + " Returns a PEP 440-compliant version number from `version_info`. " assert len(version_info) == 5 assert version_info[3] in ('dev', 'alpha', 'beta', 'rc', 'final') diff --git a/markdown/blockparser.py b/markdown/blockparser.py index 1f437ae20..9b2696014 100644 --- a/markdown/blockparser.py +++ b/markdown/blockparser.py @@ -81,11 +81,11 @@ def __init__(self, md: Markdown): self.md = md def parseDocument(self, lines: Sequence[str]) -> etree.ElementTree: - """ Parse a markdown document into an ElementTree. + """ Parse a Markdown document into an `ElementTree`. - Given a list of lines, an ElementTree object (not just a parent - Element) is created and the root element is passed to the parser - as the parent. The ElementTree object is returned. + Given a list of lines, an `ElementTree` object (not just a parent + `Element`) is created and the root element is passed to the parser + as the parent. The `ElementTree` object is returned. This should only be called on an entire document, not pieces. @@ -101,7 +101,7 @@ def parseDocument(self, lines: Sequence[str]) -> etree.ElementTree: return etree.ElementTree(self.root) def parseChunk(self, parent: etree.Element, text: str): - """ Parse a chunk of markdown text and attach to given `etree` node. + """ Parse a chunk of Markdown text and attach to given `etree` node. While the `text` argument is generally assumed to contain multiple blocks which will be split on blank lines, it could contain only one @@ -119,7 +119,7 @@ def parseChunk(self, parent: etree.Element, text: str): self.parseBlocks(parent, text.split('\n\n')) def parseBlocks(self, parent: etree.Element, blocks: Sequence[str]): - """ Process blocks of markdown text and attach to given `etree` node. + """ Process blocks of Markdown text and attach to given `etree` node. Given a list of `blocks`, each `blockprocessor` is stepped through until there are no blocks left. While an extension could potentially diff --git a/markdown/blockprocessors.py b/markdown/blockprocessors.py index 6e9b39e88..093563655 100644 --- a/markdown/blockprocessors.py +++ b/markdown/blockprocessors.py @@ -18,7 +18,7 @@ # License: BSD (see LICENSE.md for details). """ -CORE MARKDOWN BLOCKPARSER +CORE MARKDOWN BLOCK PARSER =========================================================================== This parser handles basic parsing of Markdown blocks. It doesn't concern @@ -27,7 +27,7 @@ The `BlockParser` is made up of a bunch of `BlockProcessors`, each handling a different type of block. Extensions may add/replace/remove `BlockProcessors` -as they need to alter how markdown blocks are parsed. +as they need to alter how Markdown blocks are parsed. """ from __future__ import annotations @@ -103,7 +103,7 @@ def looseDetab(self, text, level=1): lines[i] = lines[i][self.tab_length*level:] return '\n'.join(lines) - def test(self, parent, block): + def test(self, parent: etree.Element, block: list[str]): """ Test for block type. Must be overridden by subclasses. As the parser loops through processors, it will call the `test` @@ -115,35 +115,32 @@ def test(self, parent, block): depending on the parent of the block (i.e. inside a list), the parent `etree` element is also provided and may be used as part of the test. - Keywords: - - * ``parent``: An `etree` element which will be the parent of the block. - * ``block``: A block of text from the source which has been split at - blank lines. + Keyword arguments: + parent: An `etree` element which will be the parent of the block. + block: A block of text from the source which has been split at blank lines. """ pass # pragma: no cover - def run(self, parent, blocks): + def run(self, parent: etree.Element, blocks: list[str]): """ Run processor. Must be overridden by subclasses. When the parser determines the appropriate type of a block, the parser - will call the corresponding processor's ``run`` method. This method + will call the corresponding processor's `run` method. This method should parse the individual lines of the block and append them to the `etree`. - Note that both the ``parent`` and ``etree`` keywords are pointers + Note that both the `parent` and `etree` keywords are pointers to instances of the objects which should be edited in place. Each processor must make changes to the existing objects as there is no mechanism to return new/different objects to replace them. This means that this method should be adding `SubElements` or adding text - to the parent, and should remove (``pop``) or add (``insert``) items to + to the parent, and should remove (`pop`) or add (`insert`) items to the list of blocks. - Keywords: - - * ``parent``: An `etree` element which is the parent of the current block. - * ``blocks``: A list of all remaining blocks of the document. + Keyword arguments: + parent: An `etree` element which is the parent of the current block. + blocks: A list of all remaining blocks of the document. """ pass # pragma: no cover @@ -194,7 +191,7 @@ def run(self, parent, blocks): # The sibling is a `li`. Use it as parent. self.parser.parseBlocks(sibling, [block]) elif len(sibling) and sibling[-1].tag in self.ITEM_TYPES: - # The parent is a list (``ol`` or ``ul``) which has children. + # The parent is a list (`ol` or `ul`) which has children. # Assume the last child `li` is the parent of this block. if sibling[-1].text: # If the parent `li` has text, that text needs to be moved to a `p` @@ -215,7 +212,7 @@ def create_item(self, parent, block): self.parser.parseBlocks(li, [block]) def get_level(self, parent, block): - """ Get level of indent based on list level. """ + """ Get level of indentation based on list level. """ # Get indent level m = self.INDENT_RE.match(block) if m: @@ -290,7 +287,7 @@ def run(self, parent, blocks): before = block[:m.start()] # Lines before blockquote # Pass lines before blockquote in recursively for parsing first. self.parser.parseBlocks(parent, [before]) - # Remove ``> `` from beginning of each line. + # Remove `> ` from beginning of each line. block = '\n'.join( [self.clean(line) for line in block[m.start():].split('\n')] ) @@ -308,7 +305,7 @@ def run(self, parent, blocks): self.parser.state.reset() def clean(self, line): - """ Remove ``>`` from beginning of a line. """ + """ Remove `>` from beginning of a line. """ m = self.RE.match(line) if line.strip() == ">": return "" @@ -333,7 +330,7 @@ class OListProcessor(BlockProcessor): def __init__(self, parser): super().__init__(parser) - # Detect an item (``1. item``). ``group(1)`` contains contents of item. + # Detect an item (`1. item`). `group(1)` contains contents of item. self.RE = re.compile(r'^[ ]{0,%d}\d+\.[ ]+(.*)' % (self.tab_length - 1)) # Detect items on secondary lines. they can be of either list type. self.CHILD_RE = re.compile(r'^[ ]{0,%d}((\d+\.)|[*+-])[ ]+(.*)' % @@ -438,7 +435,7 @@ class UListProcessor(OListProcessor): def __init__(self, parser): super().__init__(parser) - # Detect an item (``1. item``). ``group(1)`` contains contents of item. + # Detect an item (`1. item`). `group(1)` contains contents of item. self.RE = re.compile(r'^[ ]{0,%d}[*+-][ ]+(.*)' % (self.tab_length - 1)) @@ -484,7 +481,7 @@ def test(self, parent, block): def run(self, parent, blocks): lines = blocks.pop(0).split('\n') - # Determine level. ``=`` is 1 and ``-`` is 2. + # Determine level. `=` is 1 and `-` is 2. if lines[1].startswith('='): level = 1 else: diff --git a/markdown/extensions/codehilite.py b/markdown/extensions/codehilite.py index bceac2f26..681041f63 100644 --- a/markdown/extensions/codehilite.py +++ b/markdown/extensions/codehilite.py @@ -34,8 +34,8 @@ def parse_hl_lines(expr): """Support our syntax for emphasizing certain lines of code. - expr should be like '1 2' to emphasize lines 1 and 2 of a code block. - Returns a list of ints, the line numbers to emphasize. + `expr` should be like '1 2' to emphasize lines 1 and 2 of a code block. + Returns a list of integers, the line numbers to emphasize. """ if not expr: return [] @@ -52,6 +52,7 @@ class CodeHilite: Determine language of source code, and pass it on to the Pygments highlighter. Usage: + code = CodeHilite(src=some_code, lang='python') html = code.hilite() @@ -85,6 +86,7 @@ class CodeHilite: This option has no effect to the Pygments' builtin formatters. Advanced Usage: + code = CodeHilite( src = some_code, lang = 'php', diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py index e15e7634c..16d41e66a 100644 --- a/markdown/inlinepatterns.py +++ b/markdown/inlinepatterns.py @@ -111,7 +111,7 @@ def build_inlinepatterns(md, **kwargs): NOIMG = r'(?{part}" for part in parts] + nav[nav_parts] = doc_path.as_posix() with mkdocs_gen_files.open(full_doc_path, "w") as fd: ident = ".".join(parts) From cb70465486b79f6ef6e51fa94564dc8ba63eb5dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Thu, 14 Sep 2023 14:34:34 +0200 Subject: [PATCH 09/61] fixup! Create API docs --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 87930852f..8c9e9bcfe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,7 +54,7 @@ testing = [ ] docs = [ 'mkdocs>=1.5', - 'mkdocs-nature>=0.5', + 'mkdocs-nature>=0.6', 'mdx_gh_links>=0.2', "mkdocstrings[python]", "mkdocs-gen-files", From 1140876c64efd73b6fa26eb30fa8128f82dbee1c Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Thu, 14 Sep 2023 15:06:54 -0400 Subject: [PATCH 10/61] 100% covergae of patch --- markdown/blockparser.py | 2 +- markdown/extensions/__init__.py | 2 +- markdown/inlinepatterns.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/markdown/blockparser.py b/markdown/blockparser.py index 9b2696014..0e632e140 100644 --- a/markdown/blockparser.py +++ b/markdown/blockparser.py @@ -23,7 +23,7 @@ from typing import TYPE_CHECKING, Sequence from . import util -if TYPE_CHECKING: +if TYPE_CHECKING: # pragma: no cover from markdown import Markdown diff --git a/markdown/extensions/__init__.py b/markdown/extensions/__init__.py index e0d2e790a..23d07c78f 100644 --- a/markdown/extensions/__init__.py +++ b/markdown/extensions/__init__.py @@ -22,7 +22,7 @@ from typing import TYPE_CHECKING from ..util import parseBoolValue -if TYPE_CHECKING: +if TYPE_CHECKING: # pragma: no cover from markdown import Markdown diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py index 16d41e66a..7bf14f3dc 100644 --- a/markdown/inlinepatterns.py +++ b/markdown/inlinepatterns.py @@ -72,7 +72,7 @@ except ImportError: # pragma: no cover import htmlentitydefs as entities -if TYPE_CHECKING: +if TYPE_CHECKING: # pragma: no cover from markdown import Markdown From c78dacfe8c5bc0c80a533e291221facd20390756 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Fri, 15 Sep 2023 11:03:09 -0400 Subject: [PATCH 11/61] remove core.py from documented modules it is repeated --- scripts/gen_ref_nav.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/gen_ref_nav.py b/scripts/gen_ref_nav.py index b75e096f6..5e388aa16 100755 --- a/scripts/gen_ref_nav.py +++ b/scripts/gen_ref_nav.py @@ -14,7 +14,6 @@ modules = [ Path("markdown", "__init__.py"), - Path("markdown", "core.py"), Path("markdown", "preprocessors.py"), Path("markdown", "blockparser.py"), Path("markdown", "blockprocessors.py"), From 69477444c3d7eed7dca0965371e8540a507dfddf Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Fri, 15 Sep 2023 11:03:52 -0400 Subject: [PATCH 12/61] refactor doc strings in core.py --- markdown/__init__.py | 32 ++++++------ markdown/core.py | 114 +++++++++++++++++++++++++++++++------------ 2 files changed, 102 insertions(+), 44 deletions(-) diff --git a/markdown/__init__.py b/markdown/__init__.py index b3335f3c2..48fe54f34 100644 --- a/markdown/__init__.py +++ b/markdown/__init__.py @@ -1,22 +1,26 @@ -""" -Python Markdown +# Python Markdown + +# A Python implementation of John Gruber's 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/ -- 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). -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) -- 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). -License: BSD (see LICENSE.md for details). +""" +Python-Markdown provides two public functions (`markdown.markdown` and `markdown.markdownFromFile`) both of which wrap +the public class `markdown.Markdown`. All submodules support these public functions and class and/or provide extension +support. Modules: core: Core functionality. diff --git a/markdown/core.py b/markdown/core.py index e7b083b47..9f4c766c9 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -41,7 +41,7 @@ class Markdown: - """Convert Markdown to HTML.""" + """A parser which converts Markdown to HTML.""" doc_tag = "div" # Element used to wrap document - later removed @@ -54,14 +54,16 @@ def __init__(self, **kwargs): """ Creates a new Markdown instance. - Keyword arguments: - extensions (list[str | Extension]): A list of extensions. + Keyword Arguments: + extensions (list[Extension | str]): A list of extensions. + If an item is an instance of a subclass of `markdown.extension.Extension`, the instance will be used as-is. - If an item is of type string, first an entry point will be loaded. + If an item is of type `str`, first an entry point of that name will be loaded. If that fails, the string is assumed to use Python dot notation (`path.to.module:ClassName`) - to load a `markdown.Extension` subclass. - If no class is specified, then a `makeExtension` function is called within the specified module. + which points to a `markdown.Extension` subclass. + If no class is specified (`path.to.module`), then a `makeExtension` function is called within + the specified module. extension_configs (dict[str, dict[str, Any]]): Configuration settings for extensions. output_format (str): Format of output. Supported formats are: @@ -91,8 +93,22 @@ def __init__(self, **kwargs): self.set_output_format(kwargs.get('output_format', 'xhtml')) self.reset() - def build_parser(self): - """ Build the parser from the various parts. """ + def build_parser(self) -> Markdown: + """ + Build the parser from the various parts. + + Assigns a value to each of the following attributes on the class instance: + + * `Markdown.preprocessors` (`markdown.util.Registry`) + * `Markdown.parser` (`markdown.blockparser.BlockParser`) + * `Markdown.inlinePatterns` (`markdown.util.Registry`) + * `Markdown.treeprocessors` (`markdown.util.Registry`) + * `Markdown.postprocessors` (`markdown.util.Registry`) + + This method could be redefined in a subclass to build a custom parser which is made up of a different + combination of processors and patterns. + + """ self.preprocessors = build_preprocessors(self) self.parser = build_block_parser(self) self.inlinePatterns = build_inlinepatterns(self) @@ -100,9 +116,9 @@ def build_parser(self): self.postprocessors = build_postprocessors(self) return self - def registerExtensions(self, extensions: list[str | Extension], configs: dict[str, dict[str, Any]]) -> Markdown: + def registerExtensions(self, extensions: list[Extension | str], configs: dict[str, dict[str, Any]]) -> Markdown: """ - Register extensions with this instance of Markdown. + Load a list of extensions with this instance of the `Markdown` class. Arguments: extensions: A list of extensions, which can either be strings or objects. @@ -127,9 +143,16 @@ def registerExtensions(self, extensions: list[str | Extension], configs: dict[st ) return self - def build_extension(self, ext_name, configs): + def build_extension(self, ext_name: str, configs: dict[str, Any]) -> Extension: """ - Build extension from a string name, then return an instance. + Build extension from a string name, then return an instance using the given `configs`. + + Arguments: + ext_name: Name of extension as a string. + configs: Configuration settings for extension. + + Returns: + An instance of the extension with the given configuration settings. First attempt to load an entry point. The string name must be registered as an entry point in the `markdown.extensions` group which points to a subclass of the `markdown.extensions.Extension` class. @@ -173,14 +196,27 @@ def build_extension(self, ext_name, configs): e.args = (message,) + e.args[1:] raise - def registerExtension(self, extension): - """ This gets called by the extension """ + def registerExtension(self, extension: Extension) -> Markdown: + """ + Register an extension as having a resettable state. + + Arguments: + extension: An instance of the extension to register. + + This should get called once by an extension during setup. A "registered" extension's + `reset` method is called by `Markdown.reset()`. Not all extensions have or need a + resettable state, and so it should not be assumed that all extensions are "registered." + + """ self.registeredExtensions.append(extension) return self - def reset(self): + def reset(self) -> Markdown: """ - Resets all state variables so that we can start with a new text. + Resets all state variables to prepare the parser instance for new input. + + Called once upon creation of a class instance. Should be called manually between calls + to `Markdown.convert`. """ self.htmlStash.reset() self.references.clear() @@ -191,8 +227,14 @@ def reset(self): return self - def set_output_format(self, format): - """ Set the output format for the class instance. """ + def set_output_format(self, format: str) -> Markdown: + """ + Set the output format for the class instance. + + Arguments: + format (str): Must be a known value in `Markdown.output_formats`. + + """ self.output_format = format.lower().rstrip('145') # ignore number try: self.serializer = self.output_formats[self.output_format] @@ -206,19 +248,30 @@ def set_output_format(self, format): raise return self - def is_block_level(self, tag): - """Check if the tag is a block level HTML tag.""" + # Note: the `tag` argument is not type annotated as ElementTree uses many various objects as tags. + # As there is no standardization in ElementTree, the type of a given tag is unpredictable. + def is_block_level(self, tag) -> bool: + """ + Check if the given tag is a block level HTML tag. + + Returns `True` for any string listed in `Markdown.block_level_elements`. A `tag` which is + not a string always returns `False`. + + """ if isinstance(tag, str): return tag.lower().rstrip('/') in self.block_level_elements # Some ElementTree tags are not strings, so return False. return False - def convert(self, source: str): + def convert(self, source: str) -> str: """ - Convert markdown to serialized XHTML or HTML. + Convert a Markdown string to a string in the specified output format. Arguments: - source: Source text as a Unicode string. + source: Markdown formatted text as Unicode or ASCII string. + + Returns: + A string in the specified output format. Markdown processing takes place in five steps: @@ -287,8 +340,9 @@ def convertFile( input: str | TextIO | None = None, output: str | TextIO | None = None, encoding: str | None = None, - ): - """Converts a markdown file and returns the HTML as a Unicode string. + ) -> Markdown: + """ + Converts a Markdown file and returns the HTML as a Unicode string. Decodes the file using the provided encoding (defaults to `utf-8`), passes the file content to markdown, and outputs the html to either @@ -363,7 +417,8 @@ def convertFile( def markdown(text: str, **kwargs: Any) -> str: - """Convert a markdown string to HTML and return HTML as a Unicode string. + """ + Convert a markdown string to HTML and return HTML as a Unicode string. This is a shortcut function for `Markdown` class to cover the most basic use case. It initializes an instance of `Markdown`, loads the @@ -376,7 +431,7 @@ def markdown(text: str, **kwargs: Any) -> str: **kwargs: Any arguments accepted by the Markdown class. Returns: - An HTML document as a string. + A string in the specified output format. """ md = Markdown(**kwargs) @@ -384,7 +439,8 @@ def markdown(text: str, **kwargs: Any) -> str: def markdownFromFile(**kwargs: Any): - """Read markdown code from a file and write it to a file or a stream. + """ + Read Markdown text from a file and write output to a file or a stream. This is a shortcut function which initializes an instance of `Markdown`, and calls the `convertFile` method rather than `convert`. @@ -393,8 +449,6 @@ def markdownFromFile(**kwargs: Any): input (str | TextIO): A file name or readable object. output (str | TextIO): A file name or writable object. encoding (str): Encoding of input and output. - - Arguments: **kwargs: Any arguments accepted by the `Markdown` class. """ From 236ecd27da3e54a2cb20d0bc3ac607891da0ac75 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Fri, 15 Sep 2023 11:08:30 -0400 Subject: [PATCH 13/61] update spelling dictionary --- .spell-dict | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.spell-dict b/.spell-dict index 91cd7bd10..e3944f1c0 100644 --- a/.spell-dict +++ b/.spell-dict @@ -102,6 +102,7 @@ refactor refactored refactors registerExtension +resettable richeland RSS rST @@ -126,6 +127,7 @@ stdout Stelios Stienstra subclasses +submodules SuperFences svn Swartz From 26383c207911f8a63cddb253ce3f88c6f008d04d Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Fri, 15 Sep 2023 11:29:41 -0400 Subject: [PATCH 14/61] Normalize docs of extension argument --- markdown/core.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/markdown/core.py b/markdown/core.py index 9f4c766c9..c283097f1 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -58,12 +58,9 @@ def __init__(self, **kwargs): extensions (list[Extension | str]): A list of extensions. If an item is an instance of a subclass of `markdown.extension.Extension`, - the instance will be used as-is. - If an item is of type `str`, first an entry point of that name will be loaded. - If that fails, the string is assumed to use Python dot notation (`path.to.module:ClassName`) - which points to a `markdown.Extension` subclass. - If no class is specified (`path.to.module`), then a `makeExtension` function is called within - the specified module. + the instance will be used as-is. If an item is of type `str`, it is passed + to `Markdown.build_extension` with its corresponding `extension_configs` and + the returned instance of `markdown.extension.Extension` is used. extension_configs (dict[str, dict[str, Any]]): Configuration settings for extensions. output_format (str): Format of output. Supported formats are: @@ -118,11 +115,16 @@ def build_parser(self) -> Markdown: def registerExtensions(self, extensions: list[Extension | str], configs: dict[str, dict[str, Any]]) -> Markdown: """ - Load a list of extensions with this instance of the `Markdown` class. + Load a list of extensions into an instance of the `Markdown` class. Arguments: - extensions: A list of extensions, which can either be strings or objects. - configs: A dictionary mapping extension names to `configs` options. + extensions (list[Extension | str]): A list of extensions. + + If an item is an instance of a subclass of `markdown.extension.Extension`, + the instance will be used as-is. If an item is of type `str`, it is passed + to `Markdown.build_extension` with its corresponding `configs` and the + returned instance of `markdown.extension.Extension` is used. + configs (dict[str, dict[str, Any]]): Configuration settings for extensions. """ for ext in extensions: From 6b4810a3e891dbdd808526b185cdcd86d0c520e8 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Mon, 18 Sep 2023 10:10:05 -0400 Subject: [PATCH 15/61] cleanup --- markdown/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/markdown/core.py b/markdown/core.py index c283097f1..15203bc2e 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -234,7 +234,7 @@ def set_output_format(self, format: str) -> Markdown: Set the output format for the class instance. Arguments: - format (str): Must be a known value in `Markdown.output_formats`. + format: Must be a known value in `Markdown.output_formats`. """ self.output_format = format.lower().rstrip('145') # ignore number From e40bd431b1f0b506911b218d3f9d9d2174e01715 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Mon, 18 Sep 2023 11:23:37 -0400 Subject: [PATCH 16/61] Added a bunch of internal links --- markdown/__init__.py | 4 +-- markdown/core.py | 67 +++++++++++++++++++++++--------------------- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/markdown/__init__.py b/markdown/__init__.py index 48fe54f34..4391b984b 100644 --- a/markdown/__init__.py +++ b/markdown/__init__.py @@ -18,8 +18,8 @@ # License: BSD (see LICENSE.md for details). """ -Python-Markdown provides two public functions (`markdown.markdown` and `markdown.markdownFromFile`) both of which wrap -the public class `markdown.Markdown`. All submodules support these public functions and class and/or provide extension +Python-Markdown provides two public functions ([`markdown.markdown`][] and [`markdown.markdownFromFile`][]) both of which wrap +the public class [`markdown.Markdown`][]. All submodules support these public functions and class and/or provide extension support. Modules: diff --git a/markdown/core.py b/markdown/core.py index 15203bc2e..318c28b90 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -57,10 +57,10 @@ def __init__(self, **kwargs): Keyword Arguments: extensions (list[Extension | str]): A list of extensions. - If an item is an instance of a subclass of `markdown.extension.Extension`, + If an item is an instance of a subclass of [`markdown.extensions.Extension`][], the instance will be used as-is. If an item is of type `str`, it is passed - to `Markdown.build_extension` with its corresponding `extension_configs` and - the returned instance of `markdown.extension.Extension` is used. + to [`build_extension`][markdown.Markdown.build_extension] with its corresponding `extension_configs` and + the returned instance of [`markdown.extensions.Extension`][] is used. extension_configs (dict[str, dict[str, Any]]): Configuration settings for extensions. output_format (str): Format of output. Supported formats are: @@ -96,11 +96,11 @@ def build_parser(self) -> Markdown: Assigns a value to each of the following attributes on the class instance: - * `Markdown.preprocessors` (`markdown.util.Registry`) - * `Markdown.parser` (`markdown.blockparser.BlockParser`) - * `Markdown.inlinePatterns` (`markdown.util.Registry`) - * `Markdown.treeprocessors` (`markdown.util.Registry`) - * `Markdown.postprocessors` (`markdown.util.Registry`) + * `Markdown.preprocessors` ([`markdown.util.Registry`][]) + * `Markdown.parser` ([`markdown.blockparser.BlockParser`][]) + * `Markdown.inlinePatterns` ([`markdown.util.Registry`][]) + * `Markdown.treeprocessors` ([`markdown.util.Registry`][]) + * `Markdown.postprocessors` ([`markdown.util.Registry`][]) This method could be redefined in a subclass to build a custom parser which is made up of a different combination of processors and patterns. @@ -120,10 +120,10 @@ def registerExtensions(self, extensions: list[Extension | str], configs: dict[st Arguments: extensions (list[Extension | str]): A list of extensions. - If an item is an instance of a subclass of `markdown.extension.Extension`, + If an item is an instance of a subclass of [`markdown.extensions.Extension`][], the instance will be used as-is. If an item is of type `str`, it is passed - to `Markdown.build_extension` with its corresponding `configs` and the - returned instance of `markdown.extension.Extension` is used. + to [`build_extension`][markdown.Markdown.build_extension] with its corresponding `configs` and the + returned instance of [`markdown.extensions.Extension`][] is used. configs (dict[str, dict[str, Any]]): Configuration settings for extensions. """ @@ -157,12 +157,12 @@ def build_extension(self, ext_name: str, configs: dict[str, Any]) -> Extension: An instance of the extension with the given configuration settings. First attempt to load an entry point. The string name must be registered as an entry point in the - `markdown.extensions` group which points to a subclass of the `markdown.extensions.Extension` class. + `markdown.extensions` group which points to a subclass of the [`markdown.extensions.Extension`][] class. If multiple distributions have registered the same name, the first one found is returned. If no entry point is found, assume dot notation (`path.to.module:ClassName`). Load the specified class and return an instance. If no class is specified, import the module and call a `makeExtension` function and return - the `Extension` instance returned by that function. + the [`markdown.extensions.Extension`][] instance returned by that function. """ configs = dict(configs) @@ -206,7 +206,7 @@ def registerExtension(self, extension: Extension) -> Markdown: extension: An instance of the extension to register. This should get called once by an extension during setup. A "registered" extension's - `reset` method is called by `Markdown.reset()`. Not all extensions have or need a + `reset` method is called by [`Markdown.reset()`][markdown.Markdown.reset]. Not all extensions have or need a resettable state, and so it should not be assumed that all extensions are "registered." """ @@ -218,7 +218,7 @@ def reset(self) -> Markdown: Resets all state variables to prepare the parser instance for new input. Called once upon creation of a class instance. Should be called manually between calls - to `Markdown.convert`. + to [`Markdown.convert`][markdown.Markdown.convert]. """ self.htmlStash.reset() self.references.clear() @@ -275,17 +275,18 @@ def convert(self, source: str) -> str: Returns: A string in the specified output format. - Markdown processing takes place in five steps: + Markdown parsing takes place in five steps: - 1. A bunch of `preprocessors` munge the input text. - 2. `BlockParser()` parses the high-level structural elements of the - pre-processed text into an `ElementTree`. - 3. A bunch of `treeprocessors` are run against the `ElementTree`. One - such `treeprocessor` runs `InlinePatterns` against the `ElementTree`, - detecting inline markup. - 4. Some post-processors are run against the text after the `ElementTree` - has been serialized into text. - 5. The output is written to a string. + 1. A bunch of [`preprocessors`][markdown.preprocessors] munge the input text. + 2. A [`BlockParser`][markdown.blockparser.BlockParser] parses the high-level structural elements of the + pre-processed text into an [`ElementTree`][xml.etree.ElementTree.ElementTree] object. + 3. A bunch of [`treeprocessors`][markdown.treeprocessors] are run against the + [`ElementTree`][xml.etree.ElementTree.ElementTree] object. One such `treeprocessor` + ([`markdown.treeprocessors.InlineProcessor`][]) runs [`inlinepatterns`][markdown.inlinepatterns] + against the [`ElementTree`][xml.etree.ElementTree.ElementTree] object, parsing inline markup. + 4. Some post-processors are run against the text after the [`ElementTree`][xml.etree.ElementTree.ElementTree] + object has been serialized into text. + 5. The output is returned as a string. """ @@ -347,10 +348,11 @@ def convertFile( Converts a Markdown file and returns the HTML as a Unicode string. Decodes the file using the provided encoding (defaults to `utf-8`), - passes the file content to markdown, and outputs the html to either + passes the file content to markdown, and outputs the HTML to either the provided stream or the file with provided name, using the same - encoding as the source file. The `xmlcharrefreplace` error handler is - used when encoding the output. + encoding as the source file. The + [`xmlcharrefreplace`](https://docs.python.org/3/library/codecs.html#error-handlers) + error handler is used when encoding the output. **Note:** This is the only place that decoding and encoding of Unicode takes place in Python-Markdown. (All other code is Unicode-in / @@ -422,8 +424,8 @@ def markdown(text: str, **kwargs: Any) -> str: """ Convert a markdown string to HTML and return HTML as a Unicode string. - This is a shortcut function for `Markdown` class to cover the most - basic use case. It initializes an instance of `Markdown`, loads the + This is a shortcut function for [`Markdown`][markdown.Markdown] class to cover the most + basic use case. It initializes an instance of [`Markdown`][markdown.Markdown], loads the necessary extensions and runs the parser on the given text. Arguments: @@ -444,8 +446,9 @@ def markdownFromFile(**kwargs: Any): """ Read Markdown text from a file and write output to a file or a stream. - This is a shortcut function which initializes an instance of `Markdown`, - and calls the `convertFile` method rather than `convert`. + This is a shortcut function which initializes an instance of [`Markdown`][markdown.Markdown], + and calls the [`convertFile`][markdown.Markdown.convertFile] method rather than + [`convert`][markdown.Markdown.convert]. Keyword arguments: input (str | TextIO): A file name or readable object. From fc8dc2d51115483faacf91c10769c8dcc43dec4a Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Mon, 18 Sep 2023 11:30:21 -0400 Subject: [PATCH 17/61] fix line length --- markdown/__init__.py | 6 +++--- markdown/core.py | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/markdown/__init__.py b/markdown/__init__.py index 4391b984b..9674d6e06 100644 --- a/markdown/__init__.py +++ b/markdown/__init__.py @@ -18,9 +18,9 @@ # License: BSD (see LICENSE.md for details). """ -Python-Markdown provides two public functions ([`markdown.markdown`][] and [`markdown.markdownFromFile`][]) both of which wrap -the public class [`markdown.Markdown`][]. All submodules support these public functions and class and/or provide extension -support. +Python-Markdown provides two public functions ([`markdown.markdown`][] and [`markdown.markdownFromFile`][]) +both of which wrap the public class [`markdown.Markdown`][]. All submodules support these public functions +and class and/or provide extension support. Modules: core: Core functionality. diff --git a/markdown/core.py b/markdown/core.py index 318c28b90..b64eba72a 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -59,8 +59,9 @@ def __init__(self, **kwargs): If an item is an instance of a subclass of [`markdown.extensions.Extension`][], the instance will be used as-is. If an item is of type `str`, it is passed - to [`build_extension`][markdown.Markdown.build_extension] with its corresponding `extension_configs` and - the returned instance of [`markdown.extensions.Extension`][] is used. + to [`build_extension`][markdown.Markdown.build_extension] with its corresponding + `extension_configs` and the returned instance of [`markdown.extensions.Extension`][] + is used. extension_configs (dict[str, dict[str, Any]]): Configuration settings for extensions. output_format (str): Format of output. Supported formats are: From eb5c5969cb734a73f06bb138b14dcdd76c26b6f2 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Mon, 18 Sep 2023 14:49:04 -0400 Subject: [PATCH 18/61] document attributes on markdown.Markdown. --- markdown/core.py | 47 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/markdown/core.py b/markdown/core.py index b64eba72a..73b9e005b 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -41,7 +41,29 @@ class Markdown: - """A parser which converts Markdown to HTML.""" + """ + A parser which converts Markdown to HTML. + + Attributes: + Markdown.tab_length (int): The number of spaces which correspond to a single tab. Default: `4` + Markdown.ESCAPED_CHARS (list[str]): List of characters which get the backslash escape treatment. + Markdown.block_level_elements (list[str]): List of HTML tags which get treated as block-level elements. + Markdown.registeredExtensions (list[Extension]): List of extensions which have called + [`markdown.Markdown.registerExtension`][]. + Markdown.doc_tag (str): Element used to wrap document. Default: `div`. + Markdown.stripTopLevelTags (bool): Indicates whether the `doc_tag` should be removed. Default: 'True'. + Markdown.references: A list of references found in a parsed document. + Markdown.htmlStash (util.HtmlStash): The instance of the `HtmlStash` used by an instance of this class. + Markdown.output_formats (dict[str, Callable[xml.etree.ElementTree.Element]]): A `dict` of known output + formats and their respective serializers. Each serializer must be a callable which accepts an + [`Element`][xml.etree.ElementTree.Element] and returns a `str`. + Markdown.preprocessors (util.Registry): A collection of [`preprocessors`][markdown.preprocessors]. + Markdown.parser (blockparser.BlockParser): A collection of [`blockprocessors`][markdown.blockprocessors]. + Markdown.inlinePatterns (util.Registry): A collection of [`inlinepatterns`][markdown.inlinepatterns]. + Markdown.treeprocessors (util.Registry): A collection of [`treeprocessors`][markdown.treeprocessors]. + Markdown.postprocessors (util.Registry): A collection of [`postprocessors`][markdown.postprocessors]. + + """ doc_tag = "div" # Element used to wrap document - later removed @@ -67,7 +89,7 @@ def __init__(self, **kwargs): * `xhtml`: Outputs XHTML style tags. Default. * `html`: Outputs HTML style tags. - tab_length (int): Length of tabs in the source. Default: 4 + tab_length (int): Length of tabs in the source. Default: `4` """ @@ -79,7 +101,7 @@ def __init__(self, **kwargs): self.block_level_elements = BLOCK_LEVEL_ELEMENTS.copy() self.registeredExtensions = [] - self.docType = "" + self.docType = "" # TODO: Maybe delete this. It does not appear to be used anymore. self.stripTopLevelTags = True self.build_parser() @@ -97,11 +119,16 @@ def build_parser(self) -> Markdown: Assigns a value to each of the following attributes on the class instance: - * `Markdown.preprocessors` ([`markdown.util.Registry`][]) - * `Markdown.parser` ([`markdown.blockparser.BlockParser`][]) - * `Markdown.inlinePatterns` ([`markdown.util.Registry`][]) - * `Markdown.treeprocessors` ([`markdown.util.Registry`][]) - * `Markdown.postprocessors` ([`markdown.util.Registry`][]) + * **`Markdown.preprocessors`** ([`Registry`][markdown.util.Registry]) -- A collection of + [`preprocessors`][markdown.preprocessors]. + * **`Markdown.parser`** ([`BlockParser`][markdown.blockparser.BlockParser]) -- A collection of + [`blockprocessors`][markdown.blockprocessors]. + * **`Markdown.inlinePatterns`** ([`Registry`][markdown.util.Registry]) -- A collection of + [`inlinepatterns`][markdown.inlinepatterns]. + * **`Markdown.treeprocessors`** ([`Registry`][markdown.util.Registry]) -- A collection of + [`treeprocessors`][markdown.treeprocessors]. + * **`Markdown.postprocessors`** ([`Registry`][markdown.util.Registry]) -- A collection of + [`postprocessors`][markdown.postprocessors]. This method could be redefined in a subclass to build a custom parser which is made up of a different combination of processors and patterns. @@ -285,8 +312,8 @@ def convert(self, source: str) -> str: [`ElementTree`][xml.etree.ElementTree.ElementTree] object. One such `treeprocessor` ([`markdown.treeprocessors.InlineProcessor`][]) runs [`inlinepatterns`][markdown.inlinepatterns] against the [`ElementTree`][xml.etree.ElementTree.ElementTree] object, parsing inline markup. - 4. Some post-processors are run against the text after the [`ElementTree`][xml.etree.ElementTree.ElementTree] - object has been serialized into text. + 4. Some [`postprocessors`][markdown.postprocessors] are run against the text after the + [`ElementTree`][xml.etree.ElementTree.ElementTree] object has been serialized into text. 5. The output is returned as a string. """ From 3757ed8addfe2345d7e32734091f62521ef788c4 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Mon, 18 Sep 2023 15:32:04 -0400 Subject: [PATCH 19/61] cleanup Markdown.references attribute --- markdown/core.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/markdown/core.py b/markdown/core.py index 73b9e005b..b2c7f47f8 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -52,7 +52,8 @@ class Markdown: [`markdown.Markdown.registerExtension`][]. Markdown.doc_tag (str): Element used to wrap document. Default: `div`. Markdown.stripTopLevelTags (bool): Indicates whether the `doc_tag` should be removed. Default: 'True'. - Markdown.references: A list of references found in a parsed document. + Markdown.references (dict[str, tuple[str, str]]): A `dict` of link references found in a parsed document + where the key is the reference name and the value is a tuple of the URL and title. Markdown.htmlStash (util.HtmlStash): The instance of the `HtmlStash` used by an instance of this class. Markdown.output_formats (dict[str, Callable[xml.etree.ElementTree.Element]]): A `dict` of known output formats and their respective serializers. Each serializer must be a callable which accepts an From d25f0adc2c5245430a297896429cea785e27c78b Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Wed, 20 Sep 2023 11:37:56 -0400 Subject: [PATCH 20/61] add output_format attribute --- markdown/core.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/markdown/core.py b/markdown/core.py index b2c7f47f8..0781bae28 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -49,7 +49,7 @@ class Markdown: Markdown.ESCAPED_CHARS (list[str]): List of characters which get the backslash escape treatment. Markdown.block_level_elements (list[str]): List of HTML tags which get treated as block-level elements. Markdown.registeredExtensions (list[Extension]): List of extensions which have called - [`markdown.Markdown.registerExtension`][]. + [`markdown.Markdown.registerExtension`][] during setup. Markdown.doc_tag (str): Element used to wrap document. Default: `div`. Markdown.stripTopLevelTags (bool): Indicates whether the `doc_tag` should be removed. Default: 'True'. Markdown.references (dict[str, tuple[str, str]]): A `dict` of link references found in a parsed document @@ -58,6 +58,8 @@ class Markdown: Markdown.output_formats (dict[str, Callable[xml.etree.ElementTree.Element]]): A `dict` of known output formats and their respective serializers. Each serializer must be a callable which accepts an [`Element`][xml.etree.ElementTree.Element] and returns a `str`. + Markdown.output_format (str): The output format for this instance of the class. Must correspond to one of + the keys in `Markdown.output_formats`. Default: `xhtml`. Markdown.preprocessors (util.Registry): A collection of [`preprocessors`][markdown.preprocessors]. Markdown.parser (blockparser.BlockParser): A collection of [`blockprocessors`][markdown.blockprocessors]. Markdown.inlinePatterns (util.Registry): A collection of [`inlinepatterns`][markdown.inlinepatterns]. From 6757ed7f23f47e83d0544cc41231e7dba9da2689 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Wed, 20 Sep 2023 15:59:50 -0400 Subject: [PATCH 21/61] add serializer attribute --- markdown/core.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/markdown/core.py b/markdown/core.py index 0781bae28..dbdff8953 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -55,11 +55,15 @@ class Markdown: Markdown.references (dict[str, tuple[str, str]]): A `dict` of link references found in a parsed document where the key is the reference name and the value is a tuple of the URL and title. Markdown.htmlStash (util.HtmlStash): The instance of the `HtmlStash` used by an instance of this class. - Markdown.output_formats (dict[str, Callable[xml.etree.ElementTree.Element]]): A `dict` of known output - formats and their respective serializers. Each serializer must be a callable which accepts an + Markdown.output_formats (dict[str, Callable[xml.etree.ElementTree.Element]]): A mapping of known output + formats by name and their respective serializers. Each serializer must be a callable which accepts an [`Element`][xml.etree.ElementTree.Element] and returns a `str`. - Markdown.output_format (str): The output format for this instance of the class. Must correspond to one of - the keys in `Markdown.output_formats`. Default: `xhtml`. + Markdown.output_format (str): The output format chosen for this instance of the class. It is set by + [`set_output_format`][markdown.Markdown.set_output_format] and must match one of the keys in + `output_formats`. Default: `xhtml`. + Markdown.serializer (Callable[xml.etree.ElementTree.Element]): The serializer chosen for this instance of the + class. It is set by [`set_output_format`][markdown.Markdown.set_output_format] and corresponds to the + chosen `output_format`. Markdown.preprocessors (util.Registry): A collection of [`preprocessors`][markdown.preprocessors]. Markdown.parser (blockparser.BlockParser): A collection of [`blockprocessors`][markdown.blockprocessors]. Markdown.inlinePatterns (util.Registry): A collection of [`inlinepatterns`][markdown.inlinepatterns]. From 14823e6f879484319fd0db1178c2a527ab7226e1 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Wed, 20 Sep 2023 16:25:15 -0400 Subject: [PATCH 22/61] CLean up autoref link styles for consistency --- docs/mkdocstrings.css | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/mkdocstrings.css b/docs/mkdocstrings.css index 40fdf7852..c1a1d7d45 100644 --- a/docs/mkdocstrings.css +++ b/docs/mkdocstrings.css @@ -25,6 +25,17 @@ a.autorefs-external:hover::after { background-color: #e32e00; } +/* Customize custom links. */ +a.autorefs code { + background-color: #ecf0f3; + font-weight: normal; + color: #005B81; +} + +a.autorefs:hover code { + color: #E32E00; +} + /* Customize symbol names. */ code.doc-symbol-attribute::after { content: "Attr"; @@ -44,4 +55,4 @@ code.doc-symbol-class::after { code.doc-symbol-module::after { content: "Module"; -} \ No newline at end of file +} From dfa6944a86c93bbd5aa94c8c4480952ff13c550d Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Thu, 21 Sep 2023 09:40:44 -0400 Subject: [PATCH 23/61] some text cleanup --- markdown/core.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/markdown/core.py b/markdown/core.py index dbdff8953..e1a3a3a6a 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -49,21 +49,19 @@ class Markdown: Markdown.ESCAPED_CHARS (list[str]): List of characters which get the backslash escape treatment. Markdown.block_level_elements (list[str]): List of HTML tags which get treated as block-level elements. Markdown.registeredExtensions (list[Extension]): List of extensions which have called - [`markdown.Markdown.registerExtension`][] during setup. + [`registerExtension`][markdown.Markdown.registerExtension] during setup. Markdown.doc_tag (str): Element used to wrap document. Default: `div`. Markdown.stripTopLevelTags (bool): Indicates whether the `doc_tag` should be removed. Default: 'True'. - Markdown.references (dict[str, tuple[str, str]]): A `dict` of link references found in a parsed document + Markdown.references (dict[str, tuple[str, str]]): A mapping of link references found in a parsed document where the key is the reference name and the value is a tuple of the URL and title. Markdown.htmlStash (util.HtmlStash): The instance of the `HtmlStash` used by an instance of this class. Markdown.output_formats (dict[str, Callable[xml.etree.ElementTree.Element]]): A mapping of known output formats by name and their respective serializers. Each serializer must be a callable which accepts an [`Element`][xml.etree.ElementTree.Element] and returns a `str`. - Markdown.output_format (str): The output format chosen for this instance of the class. It is set by - [`set_output_format`][markdown.Markdown.set_output_format] and must match one of the keys in - `output_formats`. Default: `xhtml`. - Markdown.serializer (Callable[xml.etree.ElementTree.Element]): The serializer chosen for this instance of the - class. It is set by [`set_output_format`][markdown.Markdown.set_output_format] and corresponds to the - chosen `output_format`. + Markdown.output_format (str): The output format set by + [`set_output_format`][markdown.Markdown.set_output_format]. + Markdown.serializer (Callable[xml.etree.ElementTree.Element]): The serializer set by + [`set_output_format`][markdown.Markdown.set_output_format]. Markdown.preprocessors (util.Registry): A collection of [`preprocessors`][markdown.preprocessors]. Markdown.parser (blockparser.BlockParser): A collection of [`blockprocessors`][markdown.blockprocessors]. Markdown.inlinePatterns (util.Registry): A collection of [`inlinepatterns`][markdown.inlinepatterns]. From f7b06d5e7ca911191d0ce927998fbf41780c6ef8 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Thu, 21 Sep 2023 11:27:17 -0400 Subject: [PATCH 24/61] Update pre/tree/postprocessors --- markdown/core.py | 6 +++--- markdown/postprocessors.py | 35 ++++++++++++++++++++------------- markdown/preprocessors.py | 30 +++++++++++++++------------- markdown/treeprocessors.py | 40 ++++++++++++++++++++++---------------- markdown/util.py | 11 ++++++++++- 5 files changed, 73 insertions(+), 49 deletions(-) diff --git a/markdown/core.py b/markdown/core.py index e1a3a3a6a..0940b1096 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -283,11 +283,11 @@ def set_output_format(self, format: str) -> Markdown: raise return self - # Note: the `tag` argument is not type annotated as ElementTree uses many various objects as tags. + # Note: the `tag` argument is type annotated `Any` as ElementTree uses many various objects as tags. # As there is no standardization in ElementTree, the type of a given tag is unpredictable. - def is_block_level(self, tag) -> bool: + def is_block_level(self, tag: Any) -> bool: """ - Check if the given tag is a block level HTML tag. + Check if the given `tag` is a block level HTML tag. Returns `True` for any string listed in `Markdown.block_level_elements`. A `tag` which is not a string always returns `False`. diff --git a/markdown/postprocessors.py b/markdown/postprocessors.py index de97525b8..eaccc3870 100644 --- a/markdown/postprocessors.py +++ b/markdown/postprocessors.py @@ -18,12 +18,11 @@ # License: BSD (see LICENSE.md for details). """ -POST-PROCESSORS -============================================================================= -Markdown also allows post-processors, which are similar to preprocessors in -that they need to implement a "run" method. However, they are run after core -processing. +Post-processors run on the text of the entire document after is has been serialized into a string. +Postprocessors should be used to work with the text just before output. Usually, they are used add +back sections that were extracted in a preprocessor, fix up outgoing encodings, or wrap the whole +document. """ @@ -34,7 +33,7 @@ import re -def build_postprocessors(md, **kwargs): +def build_postprocessors(md: Markdown, **kwargs: Any) -> util.Registry: """ Build the default postprocessors for Markdown. """ postprocessors = util.Registry() postprocessors.register(RawHtmlPostprocessor(md), 'raw_html', 30) @@ -46,16 +45,16 @@ class Postprocessor(util.Processor): """ Postprocessors are run after the ElementTree it converted back into text. - Each Postprocessor implements a "run" method that takes a pointer to a + Each Postprocessor implements a `run` method that takes a pointer to a text string, modifies it as necessary and returns a text string. - Postprocessors must extend markdown.Postprocessor. + Postprocessors must extend `Postprocessor`. """ - def run(self, text): + def run(self, text: str) -> str: """ - Subclasses of Postprocessor should implement a `run` method, which + Subclasses of `Postprocessor` should implement a `run` method, which takes the html document as a single text string and returns a (possibly modified) string. @@ -68,7 +67,7 @@ class RawHtmlPostprocessor(Postprocessor): BLOCK_LEVEL_REGEX = re.compile(r'^\<\/?([^ >]+)') - def run(self, text): + def run(self, text: str): """ Iterate over html stash and restore html. """ replacements = OrderedDict() for i in range(self.md.htmlStash.html_counter): @@ -101,7 +100,8 @@ def substitute_match(m): else: return self.run(processed_text) - def isblocklevel(self, html): + def isblocklevel(self, html: str) -> bool: + """ Check is block of HTML is block-level. """ m = self.BLOCK_LEVEL_REGEX.match(html) if m: if m.group(1)[0] in ('!', '?', '@', '%'): @@ -110,7 +110,7 @@ def isblocklevel(self, html): return self.md.is_block_level(m.group(1)) return False - def stash_to_string(self, text): + def stash_to_string(self, text: str) -> str: """ Convert a stashed object to a string. """ return str(text) @@ -128,7 +128,14 @@ def run(self, text): "use 'treeprocessors.UnescapeTreeprocessor' instead." ) class UnescapePostprocessor(Postprocessor): - """ Restore escaped chars """ + """ + Restore escaped chars. + + !!! warning "Deprecated" + + This class is deprecated and will be removed in the future; use + [`UnescapeTreeprocessor`][markdown.treeprocessors.UnescapeTreeprocessor] instead. + """ RE = re.compile(r'{}(\d+){}'.format(util.STX, util.ETX)) diff --git a/markdown/preprocessors.py b/markdown/preprocessors.py index fe572b791..b7059b031 100644 --- a/markdown/preprocessors.py +++ b/markdown/preprocessors.py @@ -18,11 +18,9 @@ # License: BSD (see LICENSE.md for details). """ -PRE-PROCESSORS -============================================================================= - -Preprocessors work on source text before we start doing anything too -complicated. +Preprocessors work on source text before it is broken down into its individual parts. +This is an excellent place to clean up bad characters or to extract portions for later +processing that the parser may otherwise choke on. """ from __future__ import annotations @@ -32,8 +30,8 @@ import re -def build_preprocessors(md, **kwargs): - """ Build the default set of preprocessors used by Markdown. """ +def build_preprocessors(md: Markdown, **kwargs: Any) -> util.Registry: + """ Build and return the default set of preprocessors used by Markdown. """ preprocessors = util.Registry() preprocessors.register(NormalizeWhitespace(md), 'normalize_whitespace', 30) preprocessors.register(HtmlBlockPreprocessor(md), 'html_block', 20) @@ -44,16 +42,16 @@ class Preprocessor(util.Processor): """ Preprocessors are run after the text is broken into lines. - Each preprocessor implements a "run" method that takes a pointer to a + Each preprocessor implements a `run` method that takes a pointer to a list of lines of the document, modifies it as necessary and returns either the same pointer or a pointer to a new list. - Preprocessors must extend markdown.Preprocessor. + Preprocessors must extend `Preprocessor`. """ - def run(self, lines): + def run(self, lines: list[str]) -> list[str]: """ - Each subclass of Preprocessor should override the `run` method, which + Each subclass of `Preprocessor` should override the `run` method, which takes the document as a list of strings split by newlines and returns the (possibly modified) list of lines. @@ -64,7 +62,7 @@ def run(self, lines): class NormalizeWhitespace(Preprocessor): """ Normalize whitespace for consistent parsing. """ - def run(self, lines): + def run(self, lines: list[str]) -> list[str]: source = '\n'.join(lines) source = source.replace(util.STX, "").replace(util.ETX, "") source = source.replace("\r\n", "\n").replace("\r", "\n") + "\n\n" @@ -74,9 +72,13 @@ def run(self, lines): class HtmlBlockPreprocessor(Preprocessor): - """Remove html blocks from the text and store them for later retrieval.""" + """ + Remove html blocks from the text and store them for later retrieval. + + The raw HTML is stored in the [`htmlStash`][markdown.util.HtmlStash] of the [`Markdown`][markdown.Markdown] instance. + """ - def run(self, lines): + def run(self, lines: list[str]) -> list[str]: source = '\n'.join(lines) parser = HTMLExtractor(self.md) parser.feed(source) diff --git a/markdown/treeprocessors.py b/markdown/treeprocessors.py index b0b653ca5..6ab865443 100644 --- a/markdown/treeprocessors.py +++ b/markdown/treeprocessors.py @@ -17,6 +17,13 @@ # License: BSD (see LICENSE.md for details). +""" +Tree processors manipulate the tree created by block processors. They can even create an entirely +new `ElementTree` object. This is an excellent place for creating summaries, adding collected +references, or last minute adjustments. + +""" + from __future__ import annotations import re @@ -26,7 +33,7 @@ from . import inlinepatterns -def build_treeprocessors(md, **kwargs): +def build_treeprocessors(md: Markdown, **kwargs: Any) -> util.Registry: """ Build the default `treeprocessors` for Markdown. """ treeprocessors = util.Registry() treeprocessors.register(InlineProcessor(md), 'inline', 20) @@ -35,8 +42,8 @@ def build_treeprocessors(md, **kwargs): return treeprocessors -def isString(s): - """ Check if it's string """ +def isString(s: Any) -> bool: + """ Return `True` if object is a string but not an [`AtomicString`][markdown.util.AtomicString]. """ if not isinstance(s, util.AtomicString): return isinstance(s, str) return False @@ -47,17 +54,16 @@ class Treeprocessor(util.Processor): `Treeprocessor`s are run on the `ElementTree` object before serialization. Each `Treeprocessor` implements a `run` method that takes a pointer to an - `ElementTree`, modifies it as necessary and returns an `ElementTree` - object. + `Element` and modifies it as necessary. `Treeprocessors` must extend `markdown.Treeprocessor`. """ - def run(self, root): + def run(self, root: etree.Element) -> etree.Element | None: """ Subclasses of `Treeprocessor` should implement a `run` method, which - takes a root `ElementTree`. This method can return another `ElementTree` - object, and the existing root `ElementTree `will be replaced, or it can + takes a root `Element`. This method can return another `Element` + object, and the existing root `Element` will be replaced, or it can modify the current tree and return `None`. """ pass # pragma: no cover @@ -320,18 +326,18 @@ def __build_ancestors(self, parent, parents): ancestors.reverse() parents.extend(ancestors) - def run(self, tree: etree.ElementTree, ancestors: Sequence[str] | None = None) -> etree.ElementTree: + def run(self, tree: etree.Element, ancestors: Sequence[str] | None = None) -> etree.Element: """Apply inline patterns to a parsed Markdown tree. - Iterate over `ElementTree`, find elements with inline tag, apply inline - patterns and append newly created Elements to tree. If you don't - want to process your data with inline patterns, instead of normal - string, use subclass `AtomicString`: + Iterate over `Element`, find elements with inline tag, apply inline + patterns and append newly created Elements to tree. To avoid further + processing of string with inline patterns, instead of normal string, + use subclass [`AtomicString`][markdown.util.AtomicString]: - node.text = markdown.AtomicString("This will not be processed.") + node.text = markdown.util.AtomicString("This will not be processed.") Arguments: - tree: `ElementTree` object, representing Markdown tree. + tree: `Element` object, representing Markdown tree. ancestors: List of parent tag names that precede the tree node (if needed). Returns: @@ -409,8 +415,8 @@ def _prettifyETree(self, elem): if not elem.tail or not elem.tail.strip(): elem.tail = i - def run(self, root): - """ Add line breaks to `ElementTree` root object. """ + def run(self, root: etree.Element) -> None: + """ Add line breaks to `Element` object and its children. """ self._prettifyETree(root) # Do `
`'s separately as they are often in the middle of diff --git a/markdown/util.py b/markdown/util.py index b911f20b1..4edf626b7 100644 --- a/markdown/util.py +++ b/markdown/util.py @@ -169,7 +169,16 @@ class AtomicString(str): class Processor: - def __init__(self, md=None): + """ The base class for all processors. + + Attributes: + Processor.md: The `Markdown` instance passed in an initialization. + + Arguments: + md: The `Markdown` instance this processor is a part of. + + """ + def __init__(self, md: Markdown=None): self.md = md From d040b249b2024744456ab707cd951285347105a5 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Thu, 21 Sep 2023 13:37:12 -0400 Subject: [PATCH 25/61] Update blockparser --- markdown/blockparser.py | 20 ++++++++- markdown/blockprocessors.py | 82 ++++++++++++++++++++++++++----------- 2 files changed, 76 insertions(+), 26 deletions(-) diff --git a/markdown/blockparser.py b/markdown/blockparser.py index 0e632e140..86c9d9948 100644 --- a/markdown/blockparser.py +++ b/markdown/blockparser.py @@ -17,6 +17,16 @@ # License: BSD (see LICENSE.md for details). +""" +The block parser handles basic parsing of Markdown blocks. It doesn't concern +itself with inline elements such as `**bold**` or `*italics*`, but rather just +catches blocks, lists, quotes, etc. + +The `BlockParser` is made up of a bunch of `BlockProcessors`, each handling a +different type of block. Extensions may add/replace/remove `BlockProcessors` +as they need to alter how Markdown blocks are parsed. +""" + from __future__ import annotations import xml.etree.ElementTree as etree @@ -45,7 +55,7 @@ class State(list): """ - def set(self, state): + def set(self, state:Any): """ Set a new state. """ self.append(state) @@ -53,7 +63,7 @@ def reset(self): """ Step back one step in nested state. """ self.pop() - def isstate(self, state): + def isstate(self, state:Any) -> bool: """ Test that top (current) level is of given state. """ if len(self): return self[-1] == state @@ -75,6 +85,12 @@ def __init__(self, md: Markdown): Arguments: md: A Markdown instance. + Attributes: + BlockParser.md (Markdown): A Markdown instance. + BlockParser.state (State): Tracks the nesting level of current location in document being parsed. + BlockParser.blockprocessors (util.Registry): A collection of + [`blockprocessors`][markdown.blockprocessors]. + """ self.blockprocessors = util.Registry() self.state = State() diff --git a/markdown/blockprocessors.py b/markdown/blockprocessors.py index 093563655..e41580c68 100644 --- a/markdown/blockprocessors.py +++ b/markdown/blockprocessors.py @@ -18,16 +18,10 @@ # License: BSD (see LICENSE.md for details). """ -CORE MARKDOWN BLOCK PARSER -=========================================================================== - -This parser handles basic parsing of Markdown blocks. It doesn't concern -itself with inline elements such as **bold** or *italics*, but rather just -catches blocks, lists, quotes, etc. - -The `BlockParser` is made up of a bunch of `BlockProcessors`, each handling a -different type of block. Extensions may add/replace/remove `BlockProcessors` -as they need to alter how Markdown blocks are parsed. +A block processor parses blocks of text and adds new elements to the ElementTree. Blocks of text, +separated from other text by blank lines, may have a different syntax and produce a differently +structured tree than other Markdown. Block processors excel at handling code formatting, equation +layouts, tables, etc. """ from __future__ import annotations @@ -41,7 +35,7 @@ logger = logging.getLogger('MARKDOWN') -def build_block_parser(md, **kwargs): +def build_block_parser(md: Markdown, **kwargs: Any) -> util.Registry: """ Build the default block parser used by Markdown. """ parser = BlockParser(md) parser.blockprocessors.register(EmptyBlockProcessor(parser), 'empty', 100) @@ -67,20 +61,24 @@ class BlockProcessor: whether the current block should be processed by this processor. If the test passes, the parser will call the processors `run` method. + Attributes: + BlockProcessor.parser (BlockParser): The `BlockParser` instance this is attached to. + BlockProcessor.tab_length (int): The tab length set on the `Markdown` instance. + """ - def __init__(self, parser): + def __init__(self, parser: BlockParser): self.parser = parser self.tab_length = parser.md.tab_length - def lastChild(self, parent): + def lastChild(self, parent: etree.Element) -> etree.Element | None: """ Return the last child of an `etree` element. """ if len(parent): return parent[-1] else: return None - def detab(self, text, length=None): + def detab(self, text: str, length: int=None) -> str: """ Remove a tab from the front of each line of the given text. """ if length is None: length = self.tab_length @@ -95,7 +93,7 @@ def detab(self, text, length=None): break return '\n'.join(newtext), '\n'.join(lines[len(newtext):]) - def looseDetab(self, text, level=1): + def looseDetab(self, text: str, level: int=1) -> str: """ Remove a tab from front of lines but allowing dedented lines. """ lines = text.split('\n') for i in range(len(lines)): @@ -103,7 +101,7 @@ def looseDetab(self, text, level=1): lines[i] = lines[i][self.tab_length*level:] return '\n'.join(lines) - def test(self, parent: etree.Element, block: list[str]): + def test(self, parent: etree.Element, block: list[str]) -> bool: """ Test for block type. Must be overridden by subclasses. As the parser loops through processors, it will call the `test` @@ -121,7 +119,7 @@ def test(self, parent: etree.Element, block: list[str]): """ pass # pragma: no cover - def run(self, parent: etree.Element, blocks: list[str]): + def run(self, parent: etree.Element, blocks: list[str]) -> bool | None: """ Run processor. Must be overridden by subclasses. When the parser determines the appropriate type of a block, the parser @@ -138,6 +136,9 @@ def run(self, parent: etree.Element, blocks: list[str]): to the parent, and should remove (`pop`) or add (`insert`) items to the list of blocks. + If `False` is retured, this will have the same effect as returning `False` + from the `test` method. + Keyword arguments: parent: An `etree` element which is the parent of the current block. blocks: A list of all remaining blocks of the document. @@ -148,12 +149,18 @@ def run(self, parent: etree.Element, blocks: list[str]): class ListIndentProcessor(BlockProcessor): """ Process children of list items. - Example: + Example + * a list item process this part or this part + Attributes: + ListIndentProcessor.ITEM_TYPES (list[str]): List of tags used for list items. Default: `['li']`. + ListIndentProcessor.LIST_TYPES (list[str]): Types of lists this processor can operate on. + Default: `['ul', 'ol']`. + """ ITEM_TYPES = ['li'] @@ -206,12 +213,12 @@ def run(self, parent, blocks): self.create_item(sibling, block) self.parser.state.reset() - def create_item(self, parent, block): + def create_item(self, parent: etree.Element, block: str): """ Create a new `li` and parse the block with it as the parent. """ li = etree.SubElement(parent, 'li') self.parser.parseBlocks(li, [block]) - def get_level(self, parent, block): + def get_level(self, parent: etree.Element, block: str) -> Tuple[int, etree.Element]: """ Get level of indentation based on list level. """ # Get indent level m = self.INDENT_RE.match(block) @@ -274,6 +281,7 @@ def run(self, parent, blocks): class BlockQuoteProcessor(BlockProcessor): + """ Process blockquotes. """ RE = re.compile(r'(^|\n)[ ]{0,3}>[ ]?(.*)') @@ -304,7 +312,7 @@ def run(self, parent, blocks): self.parser.parseChunk(quote, block) self.parser.state.reset() - def clean(self, line): + def clean(self, line: str) -> str: """ Remove `>` from beginning of a line. """ m = self.RE.match(line) if line.strip() == ">": @@ -316,7 +324,20 @@ def clean(self, line): class OListProcessor(BlockProcessor): - """ Process ordered list blocks. """ + """ + Process ordered list blocks. + + Attributes: + OListProcessor.TAG (str): The tag used for the the wrapping element. Default: `ol`. + OListProcessor.STARTSWITH (str): The integer (as a string ) with which the list starts. + For example, if a list is initialized as `3. Item`, then the `ol` tag will be + assigned an HTML attribute of `starts="3"`. Default: `"1"`. + OListProcessor.LAZY_OL (bool): Ignore STARTSWITH is `True`. Default: `True`. + OListProcessor.SIBLING_TAGS (list[str]): Markdown does not require the type of a new list + item match the previous list item type. This is the list of types which can be mixed. + Default: `['ol', 'ul']`. + + """ TAG = 'ol' # The integer (python string) with which the lists starts (default=1) @@ -401,7 +422,7 @@ def run(self, parent, blocks): self.parser.parseBlocks(li, [item]) self.parser.state.reset() - def get_items(self, block): + def get_items(self, block: str) -> list[str]: """ Break a block into list items. """ items = [] for line in block.split('\n'): @@ -429,7 +450,20 @@ def get_items(self, block): class UListProcessor(OListProcessor): - """ Process unordered list blocks. """ + """ + Process unordered list blocks. + + Attributes: + UListProcessor.TAG (str): The tag used for the the wrapping element. Default: `ul`. + UListProcessor.STARTSWITH (str): The integer (as a string ) with which the list starts. + For example, if a list is initialized as `3. Item`, then the `ol` tag will be + assigned an HTML attribute of `starts="3"`. Default: `"1"`. + UListProcessor.LAZY_OL (bool): Ignore STARTSWITH is `True`. Default: `True`. + UListProcessor.SIBLING_TAGS (list[str]): Markdown does not require the type of a new list + item match the previous list item type. This is the list of types which can be mixed. + Default: `['ol', 'ul']`. + + """ TAG = 'ul' From f53c5518a1fe3ab6c2d59a2eb281921f48cf4d7d Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Thu, 21 Sep 2023 14:21:21 -0400 Subject: [PATCH 26/61] Update util --- markdown/core.py | 1 + markdown/util.py | 67 ++++++++++++++++++++++++++++++------------------ 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/markdown/core.py b/markdown/core.py index 0940b1096..f4bcfaacc 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -48,6 +48,7 @@ class Markdown: Markdown.tab_length (int): The number of spaces which correspond to a single tab. Default: `4` Markdown.ESCAPED_CHARS (list[str]): List of characters which get the backslash escape treatment. Markdown.block_level_elements (list[str]): List of HTML tags which get treated as block-level elements. + See [`markdown.util.BLOCK_LEVEL_ELEMENTS`][] for the full list of elements. Markdown.registeredExtensions (list[Extension]): List of extensions which have called [`registerExtension`][markdown.Markdown.registerExtension] during setup. Markdown.doc_tag (str): Element used to wrap document. Default: `div`. diff --git a/markdown/util.py b/markdown/util.py index 4edf626b7..36e6716f8 100644 --- a/markdown/util.py +++ b/markdown/util.py @@ -17,6 +17,11 @@ # License: BSD (see LICENSE.md for details). +""" +This module contains various contacts, classes and functions which get referenced and used +throughout the code base. +""" + from __future__ import annotations import re @@ -46,23 +51,32 @@ 'math', 'map', 'noscript', 'output', 'object', 'option', 'progress', 'script', 'style', 'summary', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'tr', 'video' ] +""" +List of HTML tags which get treated as block-level elements. Same as the `block_level_elements` +attribute of the [`Markdown`][markdown.Markdown] class. Generally one should use the +attribute on the class. This remains for compatability with older extensions. +""" # Placeholders STX = '\u0002' # Use `STX` ("Start of text") for start-of-placeholder ETX = '\u0003' # Use `ETX` ("End of text") for end-of-placeholder INLINE_PLACEHOLDER_PREFIX = STX+"klzzwxh:" INLINE_PLACEHOLDER = INLINE_PLACEHOLDER_PREFIX + "%s" + ETX +""" Placeholder template for stashed inline text. """ INLINE_PLACEHOLDER_RE = re.compile(INLINE_PLACEHOLDER % r'([0-9]+)') +""" Regular Expression which matches inline placeholders. """ AMP_SUBSTITUTE = STX+"amp"+ETX +""" Placeholder template for HTML entities. """ HTML_PLACEHOLDER = STX + "wzxhzdk:%s" + ETX +""" Placeholder template for raw HTML. """ HTML_PLACEHOLDER_RE = re.compile(HTML_PLACEHOLDER % r'([0-9]+)') +""" Regular expression which matches HTML placeholders. """ TAG_PLACEHOLDER = STX + "hzzhzkh:%s" + ETX +""" Placeholder template for tags. """ -""" -Constants you probably do not need to change ------------------------------------------------------------------------------ -""" +# Constants you probably do not need to change +# ----------------------------------------------------------------------------- RTL_BIDI_RANGES = ( ('\u0590', '\u07FF'), @@ -73,14 +87,14 @@ ) -""" -AUXILIARY GLOBAL FUNCTIONS -============================================================================= -""" +# AUXILIARY GLOBAL FUNCTIONS +# ============================================================================= + @lru_cache(maxsize=None) -def get_installed_extensions(): +def get_installed_extensions() -> metadata.entry_points: + """ Return all entry_points in the `markdown.extensions` group. """ if sys.version_info >= (3, 10): from importlib import metadata else: # ` bool | None: + """Parses a string representing a boolean value. If parsing was successful, + returns `True` or `False`. If `preserve_none=True`, returns `True`, `False`, or `None`. If parsing was not successful, raises `ValueError`, or, if `fail_on_errors=False`, returns `None`.""" if not isinstance(value, str): @@ -130,8 +147,8 @@ def parseBoolValue(value, fail_on_errors=True, preserve_none=False): raise ValueError('Cannot parse bool value: %r' % value) -def code_escape(text): - """Escape code.""" +def code_escape(text: str) -> str: + """HTML escape a string of code.""" if "&" in text: text = text.replace("&", "&") if "<" in text: @@ -157,10 +174,9 @@ def nearing_recursion_limit(): return sys.getrecursionlimit() - _get_stack_depth() < 100 -""" -MISC AUXILIARY CLASSES -============================================================================= -""" +# MISC AUXILIARY CLASSES +# ============================================================================= + class AtomicString(str): @@ -214,13 +230,14 @@ def store(self, html: str) -> str: return placeholder def reset(self): + """ Clear the stash. """ self.html_counter = 0 self.rawHtmlBlocks = [] def get_placeholder(self, key): return HTML_PLACEHOLDER % key - def store_tag(self, tag, attrs, left_index, right_index): + def store_tag(self, tag, attrs, left_index, right_index) -> str: """Store tag data and return a placeholder.""" self.tag_data.append({'tag': tag, 'attrs': attrs, 'left_index': left_index, @@ -309,7 +326,7 @@ def __len__(self): def __repr__(self): return '<{}({})>'.format(self.__class__.__name__, list(self)) - def get_index_for_name(self, name): + def get_index_for_name(self, name) -> int: """ Return the index of the given name. """ @@ -346,7 +363,7 @@ def deregister(self, name, strict=True): """ Remove an item from the registry. - Set `strict=False` to fail silently. + Set `strict=False` to fail silently. Otherwise a [`ValueError`][] is raised for an unknown `name`. """ try: index = self.get_index_for_name(name) From 14e3850ebbd6e7bad03792a6e5ade4dac19987ea Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Thu, 21 Sep 2023 14:46:17 -0400 Subject: [PATCH 27/61] update test_tools --- markdown/htmlparser.py | 47 ++++++++++++++++++++++++------------------ markdown/test_tools.py | 30 ++++++++++++++------------- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/markdown/htmlparser.py b/markdown/htmlparser.py index 9d15fca7b..d662c2186 100644 --- a/markdown/htmlparser.py +++ b/markdown/htmlparser.py @@ -17,6 +17,12 @@ # License: BSD (see LICENSE.md for details). +""" +This module imports a copy of [`html.parser.HTMLParser`][] and modifies it heavly through monkeypathes. +A copy is imported rather than the module being directly imported as this ensures that the user can import +and use the unmodified library for their own needs. +""" + from __future__ import annotations import re @@ -65,8 +71,9 @@ class HTMLExtractor(htmlparser.HTMLParser): """ Extract raw HTML from text. - The raw HTML is stored in the `htmlStash` of the Markdown instance passed - to `md` and the remaining text is stored in `cleandoc` as a list of strings. + The raw HTML is stored in the [`htmlStash`][markdown.util.HtmlStash] of the + [`Markdown`][markdown.Markdown] instance passed to `md` and the remaining text + is stored in `cleandoc` as a list of strings. """ def __init__(self, md, *args, **kwargs): @@ -105,7 +112,7 @@ def close(self): self._cache = [] @property - def line_offset(self): + def line_offset(self) -> int: """Returns char index in `self.rawdata` for the start of the current line. """ if self.lineno > 1 and '\n' in self.rawdata: m = re.match(r'([^\n]*\n){{{}}}'.format(self.lineno-1), self.rawdata) @@ -117,7 +124,7 @@ def line_offset(self): return self.rawdata.rfind('\n') return 0 - def at_line_start(self): + def at_line_start(self) -> bool: """ Returns True if current position is at start of line. @@ -130,7 +137,7 @@ def at_line_start(self): # Confirm up to first 3 chars are whitespace return self.rawdata[self.line_offset:self.line_offset + self.offset].strip() == '' - def get_endtag_text(self, tag): + def get_endtag_text(self, tag: str) -> str: """ Returns the text of the end tag. @@ -145,7 +152,7 @@ def get_endtag_text(self, tag): # Failed to extract from raw data. Assume well formed and lowercase. return ''.format(tag) - def handle_starttag(self, tag, attrs): + def handle_starttag(self, tag: str, attrs: dict[str, str]): # Handle tags that should always be empty and do not specify a closing tag if tag in self.empty_tags: self.handle_startendtag(tag, attrs) @@ -166,7 +173,7 @@ def handle_starttag(self, tag, attrs): # This is presumably a standalone tag in a code span (see #1036). self.clear_cdata_mode() - def handle_endtag(self, tag): + def handle_endtag(self, tag: str): text = self.get_endtag_text(tag) if self.inraw: @@ -193,7 +200,7 @@ def handle_endtag(self, tag): else: self.cleandoc.append(text) - def handle_data(self, data): + def handle_data(self, data: str): if self.intail and '\n' in data: self.intail = False if self.inraw: @@ -201,7 +208,7 @@ def handle_data(self, data): else: self.cleandoc.append(data) - def handle_empty_tag(self, data, is_block): + def handle_empty_tag(self, data: str, is_block: bool): """ Handle empty tags (``). """ if self.inraw or self.intail: # Append this to the existing raw block @@ -224,29 +231,29 @@ def handle_empty_tag(self, data, is_block): else: self.cleandoc.append(data) - def handle_startendtag(self, tag, attrs): + def handle_startendtag(self, tag: str, attrs: dict[str, str]): self.handle_empty_tag(self.get_starttag_text(), is_block=self.md.is_block_level(tag)) - def handle_charref(self, name): + def handle_charref(self, name: str): self.handle_empty_tag('&#{};'.format(name), is_block=False) - def handle_entityref(self, name): + def handle_entityref(self, name: str): self.handle_empty_tag('&{};'.format(name), is_block=False) - def handle_comment(self, data): + def handle_comment(self, data: str): self.handle_empty_tag(''.format(data), is_block=True) - def handle_decl(self, data): + def handle_decl(self, data: str): self.handle_empty_tag(''.format(data), is_block=True) - def handle_pi(self, data): + def handle_pi(self, data: str): self.handle_empty_tag(''.format(data), is_block=True) - def unknown_decl(self, data): + def unknown_decl(self, data: str): end = ']]>' if data.startswith('CDATA[') else ']>' self.handle_empty_tag(' int: if self.at_line_start() or self.intail: return super().parse_pi(i) # This is not the beginning of a raw block so treat as plain data @@ -254,7 +261,7 @@ def parse_pi(self, i): self.handle_data(' int: if self.at_line_start() or self.intail: return super().parse_html_declaration(i) # This is not the beginning of a raw block so treat as plain data @@ -268,11 +275,11 @@ def parse_html_declaration(self, i): # can override `cdata_mode` in certain situations (in a code span). __starttag_text = None - def get_starttag_text(self): + def get_starttag_text(self) -> str: """Return full source of start tag: `<...>`.""" return self.__starttag_text - def parse_starttag(self, i): # pragma: no cover + def parse_starttag(self, i: int) -> int: # pragma: no cover self.__starttag_text = None endpos = self.check_for_whole_start_tag(i) if endpos < 0: diff --git a/markdown/test_tools.py b/markdown/test_tools.py index f26e5c94e..15be9c2f8 100644 --- a/markdown/test_tools.py +++ b/markdown/test_tools.py @@ -17,6 +17,8 @@ # License: BSD (see LICENSE.md for details). +""" A collection of tools for testing the Markdown codebase and extensions. """ + from __future__ import annotations import os @@ -35,7 +37,7 @@ class TestCase(unittest.TestCase): """ - A `unittest.TestCase` subclass with helpers for testing Markdown output. + A [`unittest.TestCase`][] subclass with helpers for testing Markdown output. Define `default_kwargs` as a dict of keywords to pass to Markdown for each test. The defaults can be overridden on individual tests. @@ -93,8 +95,10 @@ class recursionlimit: Example usage: - with recursionlimit(20): - # test code here + ``` python + with recursionlimit(20): + # test code here + ``` See https://stackoverflow.com/a/50120316/866026 """ @@ -189,22 +193,20 @@ def test(self): class LegacyTestCase(unittest.TestCase, metaclass=LegacyTestMeta): """ - A `unittest.TestCase` subclass for running Markdown's legacy file-based tests. + A [`unittest.TestCase`][] subclass for running Markdown's legacy file-based tests. A subclass should define various properties which point to a directory of text-based test files and define various behaviors/defaults for those tests. The following properties are supported: - `location`: A path to the directory of test files. An absolute path is preferred. - `exclude`: A list of tests to exclude. Each test name should comprise the filename - without an extension. - `normalize`: A boolean value indicating if the HTML should be normalized. - Default: `False`. - `input_ext`: A string containing the file extension of input files. Default: `.txt`. - `output_ext`: A string containing the file extension of expected output files. - Default: `html`. - `default_kwargs`: A `Kwargs` instance which stores the default set of keyword - arguments for all test files in the directory. + Attributes: + location (str): A path to the directory of test files. An absolute path is preferred. + exclude (list[str]): A list of tests to exclude. Each test name should comprise the filename + without an extension. + normalize (bool): A boolean value indicating if the HTML should be normalized. Default: `False`. + input_ext (str): A string containing the file extension of input files. Default: `.txt`. + output_ext (str): A string containing the file extension of expected output files. Default: `html`. + default_kwargs (Kwargs[str, Any]): The default set of keyword arguments for all test files in the directory. In addition, properties can be defined for each individual set of test files within the directory. The property should be given the name of the file without the file From 58f2e205a6f9d4cd474af6d1fcda5cb65b9f04ee Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Thu, 21 Sep 2023 16:20:40 -0400 Subject: [PATCH 28/61] Cleanup --- markdown/blockparser.py | 6 +++--- markdown/blockprocessors.py | 16 ++++++++-------- markdown/htmlparser.py | 2 +- markdown/postprocessors.py | 4 ++++ markdown/preprocessors.py | 7 ++++++- markdown/test_tools.py | 12 ++++++------ markdown/treeprocessors.py | 5 ++++- markdown/util.py | 15 ++++++++------- 8 files changed, 40 insertions(+), 27 deletions(-) diff --git a/markdown/blockparser.py b/markdown/blockparser.py index 86c9d9948..0e5616130 100644 --- a/markdown/blockparser.py +++ b/markdown/blockparser.py @@ -30,7 +30,7 @@ from __future__ import annotations import xml.etree.ElementTree as etree -from typing import TYPE_CHECKING, Sequence +from typing import TYPE_CHECKING, Sequence, Any from . import util if TYPE_CHECKING: # pragma: no cover @@ -55,7 +55,7 @@ class State(list): """ - def set(self, state:Any): + def set(self, state: Any): """ Set a new state. """ self.append(state) @@ -63,7 +63,7 @@ def reset(self): """ Step back one step in nested state. """ self.pop() - def isstate(self, state:Any) -> bool: + def isstate(self, state: Any) -> bool: """ Test that top (current) level is of given state. """ if len(self): return self[-1] == state diff --git a/markdown/blockprocessors.py b/markdown/blockprocessors.py index e41580c68..5f13769f1 100644 --- a/markdown/blockprocessors.py +++ b/markdown/blockprocessors.py @@ -29,9 +29,13 @@ import logging import re import xml.etree.ElementTree as etree +from typing import TYPE_CHECKING, Tuple from . import util from .blockparser import BlockParser +if TYPE_CHECKING: # pragma: no cover + from markdown import Markdown + logger = logging.getLogger('MARKDOWN') @@ -78,7 +82,7 @@ def lastChild(self, parent: etree.Element) -> etree.Element | None: else: return None - def detab(self, text: str, length: int=None) -> str: + def detab(self, text: str, length: int = None) -> str: """ Remove a tab from the front of each line of the given text. """ if length is None: length = self.tab_length @@ -93,7 +97,7 @@ def detab(self, text: str, length: int=None) -> str: break return '\n'.join(newtext), '\n'.join(lines[len(newtext):]) - def looseDetab(self, text: str, level: int=1) -> str: + def looseDetab(self, text: str, level: int = 1) -> str: """ Remove a tab from front of lines but allowing dedented lines. """ lines = text.split('\n') for i in range(len(lines)): @@ -136,7 +140,7 @@ def run(self, parent: etree.Element, blocks: list[str]) -> bool | None: to the parent, and should remove (`pop`) or add (`insert`) items to the list of blocks. - If `False` is retured, this will have the same effect as returning `False` + If `False` is returned, this will have the same effect as returning `False` from the `test` method. Keyword arguments: @@ -332,7 +336,7 @@ class OListProcessor(BlockProcessor): OListProcessor.STARTSWITH (str): The integer (as a string ) with which the list starts. For example, if a list is initialized as `3. Item`, then the `ol` tag will be assigned an HTML attribute of `starts="3"`. Default: `"1"`. - OListProcessor.LAZY_OL (bool): Ignore STARTSWITH is `True`. Default: `True`. + OListProcessor.LAZY_OL (bool): Ignore `STARTSWITH` if `True`. Default: `True`. OListProcessor.SIBLING_TAGS (list[str]): Markdown does not require the type of a new list item match the previous list item type. This is the list of types which can be mixed. Default: `['ol', 'ul']`. @@ -455,10 +459,6 @@ class UListProcessor(OListProcessor): Attributes: UListProcessor.TAG (str): The tag used for the the wrapping element. Default: `ul`. - UListProcessor.STARTSWITH (str): The integer (as a string ) with which the list starts. - For example, if a list is initialized as `3. Item`, then the `ol` tag will be - assigned an HTML attribute of `starts="3"`. Default: `"1"`. - UListProcessor.LAZY_OL (bool): Ignore STARTSWITH is `True`. Default: `True`. UListProcessor.SIBLING_TAGS (list[str]): Markdown does not require the type of a new list item match the previous list item type. This is the list of types which can be mixed. Default: `['ol', 'ul']`. diff --git a/markdown/htmlparser.py b/markdown/htmlparser.py index d662c2186..bf70b73de 100644 --- a/markdown/htmlparser.py +++ b/markdown/htmlparser.py @@ -18,7 +18,7 @@ # License: BSD (see LICENSE.md for details). """ -This module imports a copy of [`html.parser.HTMLParser`][] and modifies it heavly through monkeypathes. +This module imports a copy of [`html.parser.HTMLParser`][] and modifies it heavily through monkey-patches. A copy is imported rather than the module being directly imported as this ensures that the user can import and use the unmodified library for their own needs. """ diff --git a/markdown/postprocessors.py b/markdown/postprocessors.py index eaccc3870..d907ce1b6 100644 --- a/markdown/postprocessors.py +++ b/markdown/postprocessors.py @@ -29,9 +29,13 @@ from __future__ import annotations from collections import OrderedDict +from typing import TYPE_CHECKING, Any from . import util import re +if TYPE_CHECKING: # pragma: no cover + from markdown import Markdown + def build_postprocessors(md: Markdown, **kwargs: Any) -> util.Registry: """ Build the default postprocessors for Markdown. """ diff --git a/markdown/preprocessors.py b/markdown/preprocessors.py index b7059b031..8787e56bd 100644 --- a/markdown/preprocessors.py +++ b/markdown/preprocessors.py @@ -25,10 +25,14 @@ from __future__ import annotations +from typing import TYPE_CHECKING, Any from . import util from .htmlparser import HTMLExtractor import re +if TYPE_CHECKING: # pragma: no cover + from markdown import Markdown + def build_preprocessors(md: Markdown, **kwargs: Any) -> util.Registry: """ Build and return the default set of preprocessors used by Markdown. """ @@ -75,7 +79,8 @@ class HtmlBlockPreprocessor(Preprocessor): """ Remove html blocks from the text and store them for later retrieval. - The raw HTML is stored in the [`htmlStash`][markdown.util.HtmlStash] of the [`Markdown`][markdown.Markdown] instance. + The raw HTML is stored in the [`htmlStash`][markdown.util.HtmlStash] of the + [`Markdown`][markdown.Markdown] instance. """ def run(self, lines: list[str]) -> list[str]: diff --git a/markdown/test_tools.py b/markdown/test_tools.py index 15be9c2f8..cf057eb2d 100644 --- a/markdown/test_tools.py +++ b/markdown/test_tools.py @@ -17,7 +17,7 @@ # License: BSD (see LICENSE.md for details). -""" A collection of tools for testing the Markdown codebase and extensions. """ +""" A collection of tools for testing the Markdown code base and extensions. """ from __future__ import annotations @@ -39,7 +39,7 @@ class TestCase(unittest.TestCase): """ A [`unittest.TestCase`][] subclass with helpers for testing Markdown output. - Define `default_kwargs` as a dict of keywords to pass to Markdown for each + Define `default_kwargs` as a `dict` of keywords to pass to Markdown for each test. The defaults can be overridden on individual tests. The `assertMarkdownRenders` method accepts the source text, the expected @@ -60,7 +60,7 @@ def assertMarkdownRenders(self, source, expected, expected_attrs=None, **kwargs) """ Test that source Markdown text renders to expected output with given keywords. - `expected_attrs` accepts a dict. Each key should be the name of an attribute + `expected_attrs` accepts a `dict`. Each key should be the name of an attribute on the `Markdown` instance and the value should be the expected value after the source text is parsed by Markdown. After the expected output is tested, the expected value for each attribute is compared against the actual @@ -100,7 +100,7 @@ class recursionlimit: # test code here ``` - See https://stackoverflow.com/a/50120316/866026 + See . """ def __init__(self, limit): @@ -120,12 +120,12 @@ def __exit__(self, type, value, tb): class Kwargs(dict): - """ A dict like class for holding keyword arguments. """ + """ A `dict` like class for holding keyword arguments. """ pass def _normalize_whitespace(text): - """ Normalize whitespace for a string of html using `tidylib`. """ + """ Normalize whitespace for a string of HTML using `tidylib`. """ output, errors = tidylib.tidy_fragment(text, options={ 'drop_empty_paras': 0, 'fix_backslash': 0, diff --git a/markdown/treeprocessors.py b/markdown/treeprocessors.py index 6ab865443..941bbadb7 100644 --- a/markdown/treeprocessors.py +++ b/markdown/treeprocessors.py @@ -28,10 +28,13 @@ import re import xml.etree.ElementTree as etree -from typing import Sequence +from typing import TYPE_CHECKING, Sequence from . import util from . import inlinepatterns +if TYPE_CHECKING: # pragma: no cover + from markdown import Markdown + def build_treeprocessors(md: Markdown, **kwargs: Any) -> util.Registry: """ Build the default `treeprocessors` for Markdown. """ diff --git a/markdown/util.py b/markdown/util.py index 36e6716f8..f922ff0ca 100644 --- a/markdown/util.py +++ b/markdown/util.py @@ -30,7 +30,10 @@ from collections import namedtuple from functools import wraps, lru_cache from itertools import count -from typing import Any +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: # pragma: no cover + from markdown import Markdown """ @@ -54,7 +57,7 @@ """ List of HTML tags which get treated as block-level elements. Same as the `block_level_elements` attribute of the [`Markdown`][markdown.Markdown] class. Generally one should use the -attribute on the class. This remains for compatability with older extensions. +attribute on the class. This remains for compatibility with older extensions. """ # Placeholders @@ -91,9 +94,8 @@ # ============================================================================= - @lru_cache(maxsize=None) -def get_installed_extensions() -> metadata.entry_points: +def get_installed_extensions(): """ Return all entry_points in the `markdown.extensions` group. """ if sys.version_info >= (3, 10): from importlib import metadata @@ -128,7 +130,7 @@ def deprecated_func(*args, **kwargs): return wrapper -def parseBoolValue(value: str, fail_on_errors: bool=True, preserve_none: bool=False) -> bool | None: +def parseBoolValue(value: str, fail_on_errors: bool = True, preserve_none: bool = False) -> bool | None: """Parses a string representing a boolean value. If parsing was successful, returns `True` or `False`. If `preserve_none=True`, returns `True`, `False`, or `None`. If parsing was not successful, raises `ValueError`, or, if @@ -178,7 +180,6 @@ def nearing_recursion_limit(): # ============================================================================= - class AtomicString(str): """A string which should not be further processed.""" pass @@ -194,7 +195,7 @@ class Processor: md: The `Markdown` instance this processor is a part of. """ - def __init__(self, md: Markdown=None): + def __init__(self, md: Markdown = None): self.md = md From 290cf0d11b5f10abcfb7316fe81c264296a59a9a Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Thu, 21 Sep 2023 16:25:13 -0400 Subject: [PATCH 29/61] more Cleanup --- markdown/blockprocessors.py | 2 +- markdown/treeprocessors.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/markdown/blockprocessors.py b/markdown/blockprocessors.py index 5f13769f1..e9c24baad 100644 --- a/markdown/blockprocessors.py +++ b/markdown/blockprocessors.py @@ -29,7 +29,7 @@ import logging import re import xml.etree.ElementTree as etree -from typing import TYPE_CHECKING, Tuple +from typing import TYPE_CHECKING, Tuple, Any from . import util from .blockparser import BlockParser diff --git a/markdown/treeprocessors.py b/markdown/treeprocessors.py index 941bbadb7..fceb18814 100644 --- a/markdown/treeprocessors.py +++ b/markdown/treeprocessors.py @@ -28,7 +28,7 @@ import re import xml.etree.ElementTree as etree -from typing import TYPE_CHECKING, Sequence +from typing import TYPE_CHECKING, Sequence, Any from . import util from . import inlinepatterns From ef34df719c1f565213785b9286adcf09068bf776 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Fri, 22 Sep 2023 11:49:42 -0400 Subject: [PATCH 30/61] Order objects by source --- mkdocs.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mkdocs.yml b/mkdocs.yml index 43fe0903c..e3f28cdc4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -82,8 +82,10 @@ plugins: docstring_style: google docstring_section_style: list filters: ["!^_"] + group_by_category: false heading_level: 1 inherited_members: true + members_order: source merge_init_into_class: true separate_signature: false show_root_heading: true From 6d2a365d11387ce6fe6c2b36229a4779178054e2 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Fri, 22 Sep 2023 16:27:36 -0400 Subject: [PATCH 31/61] Update serializers --- markdown/serializers.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/markdown/serializers.py b/markdown/serializers.py index e21de0d3b..87f8add30 100644 --- a/markdown/serializers.py +++ b/markdown/serializers.py @@ -34,10 +34,19 @@ # OF THIS SOFTWARE. # -------------------------------------------------------------------- +""" +Python-Markdown provides two serializers which render [`ElementTree.Element`][xml.etree.ElementTree.Element] +objects to a string of HTML. Both functions wrap the same underliying code with only a few minor +differences as outlined below: + +1. Empty (self-closing) tags are rendered as `` for HTML and as `` for XHTML. +2. Boolean attributes are rendered as `attrname` for HTML and as `attrname="attrname"` for XHTML. +""" + from __future__ import annotations from xml.etree.ElementTree import ProcessingInstruction -from xml.etree.ElementTree import Comment, ElementTree, QName, HTML_EMPTY +from xml.etree.ElementTree import Comment, ElementTree, Element, QName, HTML_EMPTY import re __all__ = ['to_html_string', 'to_xhtml_string'] @@ -173,9 +182,12 @@ def _write_html(root, format="html"): # -------------------------------------------------------------------- # public functions -def to_html_string(element): + +def to_html_string(element: Element) -> str: + """ Serialize element and its children to a string of HTML5. """ return _write_html(ElementTree(element).getroot(), format="html") -def to_xhtml_string(element): +def to_xhtml_string(element: Element) -> str: + """ Serialize element and its children to a string of XHTML. """ return _write_html(ElementTree(element).getroot(), format="xhtml") From a22f3dbe687762e861f54ba8b5ac7ba4dcc23f29 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Mon, 25 Sep 2023 10:45:19 -0400 Subject: [PATCH 32/61] Add styles for labels --- docs/mkdocstrings.css | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/mkdocstrings.css b/docs/mkdocstrings.css index c1a1d7d45..5bd9e8295 100644 --- a/docs/mkdocstrings.css +++ b/docs/mkdocstrings.css @@ -36,6 +36,23 @@ a.autorefs:hover code { color: #E32E00; } +/* Customize labels. */ +.doc-label { + border-radius: 15px; + padding: 2px 8px; + background-color: #ddd; +} + +.doc-label code { + color: #444; +} + +/* No shadows in any code. */ + +code { + text-shadow: none; +} + /* Customize symbol names. */ code.doc-symbol-attribute::after { content: "Attr"; From cecec299b6edadcd219fa1c0969f44aa9cf2d5e9 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Mon, 25 Sep 2023 11:49:31 -0400 Subject: [PATCH 33/61] Update extensions --- markdown/extensions/__init__.py | 92 ++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 18 deletions(-) diff --git a/markdown/extensions/__init__.py b/markdown/extensions/__init__.py index 23d07c78f..2d341de6f 100644 --- a/markdown/extensions/__init__.py +++ b/markdown/extensions/__init__.py @@ -17,9 +17,17 @@ # 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 +from typing import TYPE_CHECKING, Any, Tuple from ..util import parseBoolValue if TYPE_CHECKING: # pragma: no cover @@ -29,44 +37,92 @@ class Extension: """ Base class for extensions to subclass. """ - # Default configuration -- to be overridden by a subclass - # Must be of the following format: - # { - # 'key': ['value', 'description'] - # } - # Note that `Extension.setConfig` will raise a `KeyError` - # if a default is not set here. config = {} + """ + 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, default=''): - """ Return a setting for the given key or an empty string. """ + 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): - """ Return all configs settings as a dict. """ + def getConfigs(self) -> dict[str, Any]: + """ + Return all config options. + + Returns: + All configuration options. + """ return {key: self.getConfig(key) for key in self.config.keys()} - def getConfigInfo(self): - """ Return all `config` descriptions as a list of tuples. """ + 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, value): - """ Set a `config` setting for `key` with the given `value`. """ + def setConfig(self, key: str, value: Any): + """ + 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): - """ Set multiple `config` settings given a dict or list of tuples. """ + def setConfigs(self, items: dict[str, Any] | list[Tuple[str, Any]]): + """ + 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() From 8a0d9dbb59951a80d7b720c755cc0470fef38893 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Tue, 26 Sep 2023 11:49:15 -0400 Subject: [PATCH 34/61] Update inlinepatterns --- markdown/inlinepatterns.py | 133 +++++++++++++++++++++++++------------ 1 file changed, 89 insertions(+), 44 deletions(-) diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py index 7bf14f3dc..025db31b1 100644 --- a/markdown/inlinepatterns.py +++ b/markdown/inlinepatterns.py @@ -18,53 +18,50 @@ # License: BSD (see LICENSE.md for details). """ -INLINE PATTERNS -============================================================================= +In version 3.0, a new, more flexible inline processor was added, [`markdown.inlinepatterns.InlineProcessor`][]. The +original inline patterns, which inherit from [`markdown.inlinepatterns.Pattern`][] or one of its children are still +supported, though users are encouraged to migrate. -Inline patterns such as *emphasis* are handled by means of auxiliary -objects, one per pattern. Pattern objects must be instances of classes -that extend markdown.Pattern. Each pattern object uses a single regular -expression and needs support the following methods: +The new `InlineProcessor` provides two major enhancements to `Patterns`: - pattern.getCompiledRegExp() # returns a regular expression +1. Inline Processors no longer need to match the entire block, so regular expressions no longer need to start with + `r'^(.*?)'` and end with `r'(.*?)%'`. This runs faster. The returned [match object][] will only contain what is + explicitly matched in the pattern, and extension pattern groups now start with `m.group(1)`. - pattern.handleMatch(m) # takes a match object and returns - # an ElementTree element or just plain text +2. The `handleMatch` method now takes an additional input called `data`, which is the entire block under analysis, + not just what is matched with the specified pattern. The method now returns the element *and* the indexes relative + to `data` that the return element is replacing (usually `m.start(0)` and `m.end(0)`). If the boundaries are + returned as `None`, it is assumed that the match did not take place, and nothing will be altered in `data`. -All of python markdown's built-in patterns subclass from Pattern, -but you can add additional patterns that don't. + This allows handling of more complex constructs than regular expressions can handle, e.g., matching nested + brackets, and explicit control of the span "consumed" by the processor. -Also note that all the regular expressions used by inline must -capture the whole block. For this reason, they all start with -`^(.*)` and end with `(.*)!`. In case with built-in expression -Pattern takes care of adding the `^(.*)` and `(.*)!`. - -Finally, the order in which regular expressions are applied is very +The order in which processors and/or patterns are applied is very important - e.g. if we first replace `http://.../` links with `` tags and _then_ try to replace inline html, we would end up with a mess. So, we apply the expressions in the following order: * escape and backticks have to go before everything else, so - that we can preempt any markdown patterns by escaping them. + that we can preempt any markdown patterns by escaping them; -* then we handle auto-links (must be done before inline html) +* then we handle auto-links (must be done before inline html); * then we handle inline HTML. At this point we will simply replace all inline HTML strings with a placeholder and add - the actual HTML to a hash. + the actual HTML to a hash; -* then inline images (must be done before links) +* then inline images (must be done before links); -* then bracketed links, first regular then reference-style +* then bracketed links, first regular then reference-style; -* finally we apply strong and emphasis +* finally we apply strong and emphasis. """ from __future__ import annotations from . import util from collections import namedtuple -from typing import TYPE_CHECKING, Match +from typing import TYPE_CHECKING, Tuple, Match import re import xml.etree.ElementTree as etree try: # pragma: no cover @@ -76,7 +73,7 @@ from markdown import Markdown -def build_inlinepatterns(md, **kwargs): +def build_inlinepatterns(md: Markdown, **kwargs: Any) -> util.Registry: """ Build the default set of inline patterns for Markdown. """ inlinePatterns = util.Registry() inlinePatterns.register(BacktickInlineProcessor(BACKTICK_RE), 'backtick', 190) @@ -104,10 +101,8 @@ def build_inlinepatterns(md, **kwargs): return inlinePatterns -""" -The actual regular expressions for patterns ------------------------------------------------------------------------------ -""" +# The actual regular expressions for patterns +# ----------------------------------------------------------------------------- NOIMG = r'(? str: """Remove quotes from around a string.""" if ((string.startswith('"') and string.endswith('"')) or (string.startswith("'") and string.endswith("'"))): @@ -191,14 +186,35 @@ class EmStrongItem(namedtuple('EmStrongItem', ['pattern', 'builder', 'tags'])): """Emphasis/strong pattern item.""" -""" -The pattern classes ------------------------------------------------------------------------------ -""" +# The pattern classes +# ----------------------------------------------------------------------------- class Pattern: # pragma: no cover - """Base class that inline patterns subclass. """ + """ + Base class that inline patterns subclass. + + Inline patterns are handled by means of `Pattern` subclasses, one per regular expression. + Each pattern object uses a single regular expression and must support the following methods: + [`getCompiledRegExp`][markdown.inlinepatterns.Pattern.getCompiledRegExp] and + [`handleMatch`][markdown.inlinepatterns.Pattern.handleMatch]. + + All the regular expressions used by `Pattern` subclasses must capture the whole block. For this + reason, they all start with `^(.*)` and end with `(.*)!`. When passing a regular expression on + class inititialiation, the `^(.*)` and `(.*)!` are added automatically and the regular expression + is precompiled. + + It is strongly suggested that the newer style [`markdown.inlinepatterns.InlineProcessor`][] that + use a more efficient and flexible search approach be used instead. However, the older style + `Pattern` remains for backward compatability with many existing third-party extensions. + + Attributes: + ANCESTOR_EXCLUDES (Tuple[str]): A collection of elements which are undesirable ancestors. + The processor will be skipped if it would cause the content to be a descendant of one + of the listed tag names. + md (Markdown | None): The instance of the `Markdown` class this matter is assigned to. + + """ ANCESTOR_EXCLUDES = tuple() @@ -208,6 +224,9 @@ def __init__(self, pattern: str, md: Markdown | None = None): Arguments: pattern: A regular expression that matches a pattern. + md: An optional pointer to the instance of `markdown.Markdown` and is available as + `self.md` on the class instance. + """ self.pattern = pattern @@ -216,11 +235,11 @@ def __init__(self, pattern: str, md: Markdown | None = None): self.md = md - def getCompiledRegExp(self): + def getCompiledRegExp(self) -> re.Pattern: """ Return a compiled regular expression. """ return self.compiled_re - def handleMatch(self, m: Match): + def handleMatch(self, m: Match) -> etree.Element: """Return a ElementTree element from the given match. Subclasses should override this method. @@ -228,14 +247,16 @@ def handleMatch(self, m: Match): Arguments: m: A match object containing a match of the pattern. + Returns: An ElementTree Element object. + """ pass # pragma: no cover - def type(self): + def type(self) -> str: """ Return class name, to define pattern type """ return self.__class__.__name__ - def unescape(self, text): + def unescape(self, text: str) -> str: """ Return unescaped text given text with an inline placeholder. """ try: stash = self.md.treeprocessors['inline'].stashed_nodes @@ -256,18 +277,26 @@ def get_stash(m): class InlineProcessor(Pattern): """ - Base class that inline patterns subclass. + Base class that inline processors subclass. This is the newer style inline processor that uses a more efficient and flexible search approach. + + Attributes: + ANCESTOR_EXCLUDES (Tuple[str]): A collection of elements which are undesirable ancestors. + The processor will be skipped if it would cause the content to be a descendant of one + of the listed tag names. + md (Markdown | None): The instance of the `Markdown` class this matter is assigned to. """ def __init__(self, pattern: str, md: Markdown | None = None): """ - Create an instant of an inline pattern. + Create an instant of an inline processor. Arguments: pattern: A regular expression that matches a pattern. + md: An optional pointer to the instance of `markdown.Markdown` and is available as + `self.md` on the class instance. """ self.pattern = pattern @@ -277,7 +306,7 @@ def __init__(self, pattern: str, md: Markdown | None = None): self.safe_mode = False self.md = md - def handleMatch(self, m: Match, data: str) -> tuple[etree.ElementTree | str | None, int | None, int | None]: + def handleMatch(self, m: Match, data: str) -> tuple[etree.Element | str | None, int | None, int | None]: """Return a ElementTree element from the given match and the start and end index of the matched text. @@ -288,7 +317,7 @@ def handleMatch(self, m: Match, data: str) -> tuple[etree.ElementTree | str | No Arguments: m: A re match object containing a match of the pattern. - data: The buffer current under analysis. + data: The buffer currently under analysis. Returns: el: The ElementTree element, text or None. @@ -329,6 +358,14 @@ class SimpleTagPattern(Pattern): # pragma: no cover """ def __init__(self, pattern, tag): + """ + Create an instant of an simple tag pattern. + + Arguments: + pattern: A regular expression that matches a pattern. + tag: Tag of element. + + """ Pattern.__init__(self, pattern) self.tag = tag @@ -345,6 +382,14 @@ class SimpleTagInlineProcessor(InlineProcessor): """ def __init__(self, pattern, tag): + """ + Create an instant of an simple tag processor. + + Arguments: + pattern: A regular expression that matches a pattern. + tag: Tag of element. + + """ InlineProcessor.__init__(self, pattern) self.tag = tag @@ -367,7 +412,7 @@ def handleMatch(self, m, data): class BacktickInlineProcessor(InlineProcessor): - """ Return a `` element containing the matching text. """ + """ Return a `` element containing the escaped matching text. """ def __init__(self, pattern): InlineProcessor.__init__(self, pattern) self.ESCAPED_BSLASH = '{}{}{}'.format(util.STX, ord('\\'), util.ETX) From 72cb6e096dbf1664046520ec63927180520aba84 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Tue, 26 Sep 2023 14:25:25 -0400 Subject: [PATCH 35/61] Update various extensions --- markdown/extensions/abbr.py | 24 +++--- markdown/extensions/admonition.py | 27 +++--- markdown/extensions/attr_list.py | 43 ++++++---- markdown/extensions/codehilite.py | 57 +++++++------ markdown/extensions/def_list.py | 22 +++-- markdown/extensions/extra.py | 28 ++++--- markdown/extensions/fenced_code.py | 25 ++++-- markdown/extensions/footnotes.py | 22 +++-- markdown/extensions/legacy_attrs.py | 4 +- markdown/extensions/legacy_em.py | 13 +-- markdown/extensions/md_in_html.py | 23 ++++-- markdown/extensions/meta.py | 22 +++-- markdown/extensions/nl2br.py | 26 +++--- markdown/extensions/sane_lists.py | 24 ++++-- markdown/extensions/smarty.py | 124 +++++++++++++++------------- markdown/extensions/tables.py | 22 +++-- markdown/extensions/toc.py | 36 ++++---- markdown/extensions/wikilinks.py | 25 ++++-- markdown/inlinepatterns.py | 4 +- 19 files changed, 334 insertions(+), 237 deletions(-) diff --git a/markdown/extensions/abbr.py b/markdown/extensions/abbr.py index 678ac9b2c..c060f4757 100644 --- a/markdown/extensions/abbr.py +++ b/markdown/extensions/abbr.py @@ -1,19 +1,23 @@ -""" -Abbreviation Extension for Python-Markdown -========================================== +# Abbreviation Extension for Python-Markdown +# ========================================== -This extension adds abbreviation handling to Python-Markdown. +# This extension adds abbreviation handling to Python-Markdown. + +# See https://Python-Markdown.github.io/extensions/abbreviations +# for documentation. -See https://Python-Markdown.github.io/extensions/abbreviations -for documentation. +# Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/) +# and [Seemant Kulleen](http://www.kulleen.org/) -Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/) -and [Seemant Kulleen](http://www.kulleen.org/) +# All changes Copyright 2008-2014 The Python Markdown Project -All changes Copyright 2008-2014 The Python Markdown Project +# License: [BSD](https://opensource.org/licenses/bsd-license.php) -License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" +This extension adds abbreviation handling to Python-Markdown. +See the [documentation](https://Python-Markdown.github.io/extensions/abbreviations) +for details. """ from __future__ import annotations diff --git a/markdown/extensions/admonition.py b/markdown/extensions/admonition.py index 92c744ae2..d5d273d7b 100644 --- a/markdown/extensions/admonition.py +++ b/markdown/extensions/admonition.py @@ -1,20 +1,27 @@ -""" -Admonition extension for Python-Markdown -======================================== +# Admonition extension for Python-Markdown +# ======================================== -Adds rST-style admonitions. Inspired by [rST][] feature with the same name. +# Adds rST-style admonitions. Inspired by [rST][] feature with the same name. -[rST]: http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-admonitions +# [rST]: http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-admonitions + +# See https://Python-Markdown.github.io/extensions/admonition +# for documentation. + +# Original code Copyright [Tiago Serafim](https://www.tiagoserafim.com/). -See https://Python-Markdown.github.io/extensions/admonition -for documentation. +# All changes Copyright The Python Markdown Project -Original code Copyright [Tiago Serafim](https://www.tiagoserafim.com/). +# License: [BSD](https://opensource.org/licenses/bsd-license.php) -All changes Copyright The Python Markdown Project -License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" +Adds rST-style admonitions. Inspired by [rST][] feature with the same name. + +[rST]: http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-admonitions +See the [documentation](https://Python-Markdown.github.io/extensions/admonition) +for details. """ from __future__ import annotations diff --git a/markdown/extensions/attr_list.py b/markdown/extensions/attr_list.py index b0ca1ccc2..30c075ce6 100644 --- a/markdown/extensions/attr_list.py +++ b/markdown/extensions/attr_list.py @@ -1,28 +1,38 @@ -""" -Attribute List Extension for Python-Markdown -============================================ +# Attribute List Extension for Python-Markdown +# ============================================ -Adds attribute list syntax. Inspired by -[Maruku](http://maruku.rubyforge.org/proposal.html#attribute_lists)'s -feature of the same name. +# Adds attribute list syntax. Inspired by +# [Maruku](http://maruku.rubyforge.org/proposal.html#attribute_lists)'s +# feature of the same name. + +# See https://Python-Markdown.github.io/extensions/attr_list +# for documentation. -See https://Python-Markdown.github.io/extensions/attr_list -for documentation. +# Original code Copyright 2011 [Waylan Limberg](http://achinghead.com/). -Original code Copyright 2011 [Waylan Limberg](http://achinghead.com/). +# All changes Copyright 2011-2014 The Python Markdown Project -All changes Copyright 2011-2014 The Python Markdown Project +# License: [BSD](https://opensource.org/licenses/bsd-license.php) -License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" + Adds attribute list syntax. Inspired by +[Maruku](http://maruku.rubyforge.org/proposal.html#attribute_lists)'s +feature of the same name. +See the [documentation](https://Python-Markdown.github.io/extensions/attr_list) +for details. """ from __future__ import annotations +from typing import TYPE_CHECKING, Tuple from . import Extension from ..treeprocessors import Treeprocessor import re +if TYPE_CHECKING: + from xml.etree.ElementTree import Element + def _handle_double_quote(s, t): k, v = t.split('=', 1) @@ -55,12 +65,12 @@ def _handle_word(s, t): ]) -def get_attrs(str): +def get_attrs(str: str) -> list[Tuple[str, str]]: """ Parse attribute list and return a list of attribute tuples. """ return _scanner.scan(str)[0] -def isheader(elem): +def isheader(elem: Element) -> bool: return elem.tag in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] @@ -76,7 +86,7 @@ class AttrListTreeprocessor(Treeprocessor): r'\uf900-\ufdcf\ufdf0-\ufffd' r'\:\-\.0-9\u00b7\u0300-\u036f\u203f-\u2040]+') - def run(self, doc): + def run(self, doc: Element): for elem in doc.iter(): if self.md.is_block_level(elem.tag): # Block level: check for `attrs` on last line of text @@ -136,7 +146,7 @@ def run(self, doc): self.assign_attrs(elem, m.group(1)) elem.tail = elem.tail[m.end():] - def assign_attrs(self, elem, attrs): + def assign_attrs(self, elem: Element, attrs: dict[str, str]): """ Assign `attrs` to element. """ for k, v in get_attrs(attrs): if k == '.': @@ -150,7 +160,7 @@ def assign_attrs(self, elem, attrs): # assign attribute `k` with `v` elem.set(self.sanitize_name(k), v) - def sanitize_name(self, name): + def sanitize_name(self, name: str) -> str: """ Sanitize name as 'an XML Name, minus the ":"'. See https://www.w3.org/TR/REC-xml-names/#NT-NCName @@ -159,6 +169,7 @@ def sanitize_name(self, name): class AttrListExtension(Extension): + """ Attribute List extension for Python-Markdown """ def extendMarkdown(self, md): md.treeprocessors.register(AttrListTreeprocessor(md), 'attr_list', 8) md.registerExtension(self) diff --git a/markdown/extensions/codehilite.py b/markdown/extensions/codehilite.py index 681041f63..0763034de 100644 --- a/markdown/extensions/codehilite.py +++ b/markdown/extensions/codehilite.py @@ -1,18 +1,22 @@ -""" -CodeHilite Extension for Python-Markdown -======================================== +# CodeHilite Extension for Python-Markdown +# ======================================== -Adds code/syntax highlighting to standard Python-Markdown code blocks. +# Adds code/syntax highlighting to standard Python-Markdown code blocks. + +# See https://Python-Markdown.github.io/extensions/code_hilite +# for documentation. -See https://Python-Markdown.github.io/extensions/code_hilite -for documentation. +# Original code Copyright 2006-2008 [Waylan Limberg](http://achinghead.com/). -Original code Copyright 2006-2008 [Waylan Limberg](http://achinghead.com/). +# All changes Copyright 2008-2014 The Python Markdown Project -All changes Copyright 2008-2014 The Python Markdown Project +# License: [BSD](https://opensource.org/licenses/bsd-license.php) -License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" +Adds code/syntax highlighting to standard Python-Markdown code blocks. +See the [documentation](https://Python-Markdown.github.io/extensions/code_hilite) +for details. """ from __future__ import annotations @@ -31,7 +35,7 @@ pygments = False -def parse_hl_lines(expr): +def parse_hl_lines(expr: str) -> list[int]: """Support our syntax for emphasizing certain lines of code. `expr` should be like '1 2' to emphasize lines 1 and 2 of a code block. @@ -53,8 +57,10 @@ class CodeHilite: Usage: - code = CodeHilite(src=some_code, lang='python') - html = code.hilite() + ```python + code = CodeHilite(src=some_code, lang='python') + html = code.hilite() + ``` Arguments: src: Source string or any object with a `.readline` attribute. @@ -72,14 +78,15 @@ class CodeHilite: lang_prefix (str): Prefix prepended to the language. Default: "language-". Other Options: + Any other options are accepted and passed on to the lexer and formatter. Therefore, valid options include any options which are accepted by the `html` formatter or whichever lexer the code's language uses. Note that most lexers do not have any options. However, a few have very useful options, such as PHP's `startinline` option. Any invalid options are ignored without error. - Formatter options: https://pygments.org/docs/formatters/#HtmlFormatter - Lexer Options: https://pygments.org/docs/lexers/ + * **Formatter options**: + * **Lexer Options**: Additionally, when Pygments is enabled, the code's language is passed to the formatter as an extra option `lang_str`, whose value being `{lang_prefix}{lang}`. @@ -87,15 +94,17 @@ class CodeHilite: Advanced Usage: - code = CodeHilite( - src = some_code, - lang = 'php', - startinline = True, # Lexer option. Snippet does not start with ` str: """ Pass code to the [Pygments](https://pygments.org/) highlighter with optional line numbers. The output should then be styled with CSS to diff --git a/markdown/extensions/def_list.py b/markdown/extensions/def_list.py index 76a2367ef..0d7fbe354 100644 --- a/markdown/extensions/def_list.py +++ b/markdown/extensions/def_list.py @@ -1,18 +1,22 @@ -""" -Definition List Extension for Python-Markdown -============================================= +# Definition List Extension for Python-Markdown +# ============================================= -Adds parsing of Definition Lists to Python-Markdown. +# Adds parsing of Definition Lists to Python-Markdown. + +# See https://Python-Markdown.github.io/extensions/definition_lists +# for documentation. -See https://Python-Markdown.github.io/extensions/definition_lists -for documentation. +# Original code Copyright 2008 [Waylan Limberg](http://achinghead.com) -Original code Copyright 2008 [Waylan Limberg](http://achinghead.com) +# All changes Copyright 2008-2014 The Python Markdown Project -All changes Copyright 2008-2014 The Python Markdown Project +# License: [BSD](https://opensource.org/licenses/bsd-license.php) -License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" +Adds parsing of Definition Lists to Python-Markdown. +See the [documentation]( https://Python-Markdown.github.io/extensions/definition_lists) +for details. """ from __future__ import annotations diff --git a/markdown/extensions/extra.py b/markdown/extensions/extra.py index 407a50ef3..a6a941082 100644 --- a/markdown/extensions/extra.py +++ b/markdown/extensions/extra.py @@ -1,12 +1,22 @@ -""" -Python-Markdown Extra Extension -=============================== +# Python-Markdown Extra Extension +# =============================== + +# A compilation of various Python-Markdown extensions that imitates +# [PHP Markdown Extra](http://michelf.com/projects/php-markdown/extra/). + +# See https://Python-Markdown.github.io/extensions/extra +# for documentation. + +# Copyright The Python Markdown Project + +# License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" A compilation of various Python-Markdown extensions that imitates [PHP Markdown Extra](http://michelf.com/projects/php-markdown/extra/). Note that each of the individual extensions still need to be available -on your PYTHONPATH. This extension simply wraps them all up as a +on your `PYTHONPATH`. This extension simply wraps them all up as a convenience so that only one extension needs to be listed when initiating Markdown. See the documentation for each individual extension for specifics about that extension. @@ -20,13 +30,8 @@ variable defined below, but be aware that such changes may be lost when you upgrade to any future version of Python-Markdown. -See https://Python-Markdown.github.io/extensions/extra -for documentation. - -Copyright The Python Markdown Project - -License: [BSD](https://opensource.org/licenses/bsd-license.php) - +See the [documentaiton](https://Python-Markdown.github.io/extensions/extra) +for details. """ from __future__ import annotations @@ -42,6 +47,7 @@ 'abbr', 'md_in_html' ] +""" The list of included extensions. """ class ExtraExtension(Extension): diff --git a/markdown/extensions/fenced_code.py b/markdown/extensions/fenced_code.py index 35a087c6d..f75b561a7 100644 --- a/markdown/extensions/fenced_code.py +++ b/markdown/extensions/fenced_code.py @@ -1,17 +1,22 @@ -""" -Fenced Code Extension for Python Markdown -========================================= +# Fenced Code Extension for Python Markdown +# ========================================= -This extension adds Fenced Code Blocks to Python-Markdown. +# This extension adds Fenced Code Blocks to Python-Markdown. -See https://Python-Markdown.github.io/extensions/fenced_code_blocks -for documentation. +# See https://Python-Markdown.github.io/extensions/fenced_code_blocks +# for documentation. -Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/). +# Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/). -All changes Copyright 2008-2014 The Python Markdown Project +# All changes Copyright 2008-2014 The Python Markdown Project + +# License: [BSD](https://opensource.org/licenses/bsd-license.php) -License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" +This extension adds Fenced Code Blocks to Python-Markdown. + +See the [documentation](https://Python-Markdown.github.io/extensions/fenced_code_blocks) +for details. """ from __future__ import annotations @@ -41,6 +46,8 @@ def extendMarkdown(self, md): class FencedBlockPreprocessor(Preprocessor): + """ Find and extract fenced code blocks. """ + FENCED_BLOCK_RE = re.compile( dedent(r''' (?P^(?:~{3,}|`{3,}))[ ]* # opening fence diff --git a/markdown/extensions/footnotes.py b/markdown/extensions/footnotes.py index 52ed31df4..8aaf62c17 100644 --- a/markdown/extensions/footnotes.py +++ b/markdown/extensions/footnotes.py @@ -1,16 +1,20 @@ -""" -Footnotes Extension for Python-Markdown -======================================= +# Footnotes Extension for Python-Markdown +# ======================================= -Adds footnote handling to Python-Markdown. +# Adds footnote handling to Python-Markdown. + +# See https://Python-Markdown.github.io/extensions/footnotes +# for documentation. -See https://Python-Markdown.github.io/extensions/footnotes -for documentation. +# Copyright The Python Markdown Project -Copyright The Python Markdown Project +# License: [BSD](https://opensource.org/licenses/bsd-license.php) -License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" +Adds footnote handling to Python-Markdown. +See the [documentation](https://Python-Markdown.github.io/extensions/footnotes) +for details. """ from __future__ import annotations @@ -299,7 +303,7 @@ def detab(self, block): class FootnoteInlineProcessor(InlineProcessor): - """ `InlinePattern` for footnote markers in a document's body text. """ + """ `InlineProcessor` for footnote markers in a document's body text. """ def __init__(self, pattern, footnotes): super().__init__(pattern) diff --git a/markdown/extensions/legacy_attrs.py b/markdown/extensions/legacy_attrs.py index 500022ab1..56ad2e89a 100644 --- a/markdown/extensions/legacy_attrs.py +++ b/markdown/extensions/legacy_attrs.py @@ -18,9 +18,6 @@ # License: BSD (see LICENSE.md for details). """ -Legacy Attributes Extension -=========================== - An extension to Python Markdown which implements legacy attributes. Prior to Python-Markdown version 3.0, the Markdown class had an `enable_attributes` @@ -62,6 +59,7 @@ def attributeCallback(match): class LegacyAttrExtension(Extension): def extendMarkdown(self, md): + """ Add `LegacyAttrs` to Markdown instance. """ md.treeprocessors.register(LegacyAttrs(md), 'legacyattrs', 15) diff --git a/markdown/extensions/legacy_em.py b/markdown/extensions/legacy_em.py index 5aa0ae64e..a6f67b7ef 100644 --- a/markdown/extensions/legacy_em.py +++ b/markdown/extensions/legacy_em.py @@ -1,13 +1,14 @@ -""" -Legacy Em Extension for Python-Markdown -======================================= +# Legacy Em Extension for Python-Markdown +# ======================================= -This extension provides legacy behavior for _connected_words_. +# This extension provides legacy behavior for _connected_words_. -Copyright 2015-2018 The Python Markdown Project +# Copyright 2015-2018 The Python Markdown Project -License: [BSD](https://opensource.org/licenses/bsd-license.php) +# License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" +This extension provides legacy behavior for _connected_words_. """ from __future__ import annotations diff --git a/markdown/extensions/md_in_html.py b/markdown/extensions/md_in_html.py index 7446ba4c8..982d60399 100644 --- a/markdown/extensions/md_in_html.py +++ b/markdown/extensions/md_in_html.py @@ -1,17 +1,22 @@ -""" -Python-Markdown Markdown in HTML Extension -=============================== +# Python-Markdown Markdown in HTML Extension +# =============================== -An implementation of [PHP Markdown Extra](http://michelf.com/projects/php-markdown/extra/)'s -parsing of Markdown syntax in raw HTML. +# An implementation of [PHP Markdown Extra](http://michelf.com/projects/php-markdown/extra/)'s +# parsing of Markdown syntax in raw HTML. + +# See https://Python-Markdown.github.io/extensions/raw_html +# for documentation. -See https://Python-Markdown.github.io/extensions/raw_html -for documentation. +# Copyright The Python Markdown Project -Copyright The Python Markdown Project +# License: [BSD](https://opensource.org/licenses/bsd-license.php) -License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" +An implementation of [PHP Markdown Extra](http://michelf.com/projects/php-markdown/extra/)'s +parsing of Markdown syntax in raw HTML. +See the [documentation](https://Python-Markdown.github.io/extensions/raw_html) +for details. """ from __future__ import annotations diff --git a/markdown/extensions/meta.py b/markdown/extensions/meta.py index ff6700e96..147d3b93c 100644 --- a/markdown/extensions/meta.py +++ b/markdown/extensions/meta.py @@ -1,18 +1,22 @@ -""" -Meta Data Extension for Python-Markdown -======================================= +# Meta Data Extension for Python-Markdown +# ======================================= -This extension adds Meta Data handling to markdown. +# This extension adds Meta Data handling to markdown. + +# See https://Python-Markdown.github.io/extensions/meta_data +# for documentation. -See https://Python-Markdown.github.io/extensions/meta_data -for documentation. +# Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com). -Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com). +# All changes Copyright 2008-2014 The Python Markdown Project -All changes Copyright 2008-2014 The Python Markdown Project +# License: [BSD](https://opensource.org/licenses/bsd-license.php) -License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" +This extension adds Meta Data handling to markdown. +See the [documentation](https://Python-Markdown.github.io/extensions/meta_data) +for details. """ from __future__ import annotations diff --git a/markdown/extensions/nl2br.py b/markdown/extensions/nl2br.py index 43417c4d8..fec0a14bd 100644 --- a/markdown/extensions/nl2br.py +++ b/markdown/extensions/nl2br.py @@ -1,19 +1,24 @@ -""" -`NL2BR` Extension -=============== +# NL2BR Extension +# =============== -A Python-Markdown extension to treat newlines as hard breaks; like -GitHub-flavored Markdown does. +# A Python-Markdown extension to treat newlines as hard breaks; like +# GitHub-flavored Markdown does. + +# See https://Python-Markdown.github.io/extensions/nl2br +# for documentation. -See https://Python-Markdown.github.io/extensions/nl2br -for documentation. +# Original code Copyright 2011 [Brian Neal](https://deathofagremmie.com/) -Original code Copyright 2011 [Brian Neal](https://deathofagremmie.com/) +# All changes Copyright 2011-2014 The Python Markdown Project -All changes Copyright 2011-2014 The Python Markdown Project +# License: [BSD](https://opensource.org/licenses/bsd-license.php) -License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" +A Python-Markdown extension to treat newlines as hard breaks; like +GitHub-flavored Markdown does. +See the [documentation](https://Python-Markdown.github.io/extensions/nl2br) +for details. """ from __future__ import annotations @@ -27,6 +32,7 @@ class Nl2BrExtension(Extension): def extendMarkdown(self, md): + """ Add a `SubstituteTagInlineProcessor` to Markdown. """ br_tag = SubstituteTagInlineProcessor(BR_RE, 'br') md.inlinePatterns.register(br_tag, 'nl', 5) diff --git a/markdown/extensions/sane_lists.py b/markdown/extensions/sane_lists.py index aab3fbb84..b8a783a97 100644 --- a/markdown/extensions/sane_lists.py +++ b/markdown/extensions/sane_lists.py @@ -1,18 +1,22 @@ -""" -Sane List Extension for Python-Markdown -======================================= +# Sane List Extension for Python-Markdown +# ======================================= -Modify the behavior of Lists in Python-Markdown to act in a sane manor. +# Modify the behavior of Lists in Python-Markdown to act in a sane manor. + +# See https://Python-Markdown.github.io/extensions/sane_lists +# for documentation. -See https://Python-Markdown.github.io/extensions/sane_lists -for documentation. +# Original code Copyright 2011 [Waylan Limberg](http://achinghead.com) -Original code Copyright 2011 [Waylan Limberg](http://achinghead.com) +# All changes Copyright 2011-2014 The Python Markdown Project -All changes Copyright 2011-2014 The Python Markdown Project +# License: [BSD](https://opensource.org/licenses/bsd-license.php) -License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" +Modify the behavior of Lists in Python-Markdown to act in a sane manor. +See [documentation](https://Python-Markdown.github.io/extensions/sane_lists) +for details. """ from __future__ import annotations @@ -23,6 +27,7 @@ class SaneOListProcessor(OListProcessor): + """ Override `SIBLING_TAGS` to not include `ul` and set `LAZY_OL` to `False`. """ SIBLING_TAGS = ['ol'] LAZY_OL = False @@ -34,6 +39,7 @@ def __init__(self, parser): class SaneUListProcessor(UListProcessor): + """ Override `SIBLING_TAGS` to not include `ol`. """ SIBLING_TAGS = ['ul'] diff --git a/markdown/extensions/smarty.py b/markdown/extensions/smarty.py index 7d7be491d..06bfab50a 100644 --- a/markdown/extensions/smarty.py +++ b/markdown/extensions/smarty.py @@ -1,82 +1,87 @@ -""" -Smarty extension for Python-Markdown -==================================== +# Smarty extension for Python-Markdown +# ==================================== -Adds conversion of ASCII dashes, quotes and ellipses to their HTML -entity equivalents. +# Adds conversion of ASCII dashes, quotes and ellipses to their HTML +# entity equivalents. + +# See https://Python-Markdown.github.io/extensions/smarty +# for documentation. -See https://Python-Markdown.github.io/extensions/smarty -for documentation. +# Author: 2013, Dmitry Shachnev -Author: 2013, Dmitry Shachnev +# All changes Copyright 2013-2014 The Python Markdown Project -All changes Copyright 2013-2014 The Python Markdown Project +# License: [BSD](https://opensource.org/licenses/bsd-license.php) -License: [BSD](https://opensource.org/licenses/bsd-license.php) +# SmartyPants license: -SmartyPants license: +# Copyright (c) 2003 John Gruber +# All rights reserved. - Copyright (c) 2003 John Gruber - All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. +# * Neither the name "SmartyPants" nor the names of its contributors +# may be used to endorse or promote products derived from this +# software without specific prior written permission. - * Neither the name "SmartyPants" nor the names of its contributors - may be used to endorse or promote products derived from this - software without specific prior written permission. +# This software is provided by the copyright holders and contributors "as +# is" and any express or implied warranties, including, but not limited +# to, the implied warranties of merchantability and fitness for a +# particular purpose are disclaimed. In no event shall the copyright +# owner or contributors be liable for any direct, indirect, incidental, +# special, exemplary, or consequential damages (including, but not +# limited to, procurement of substitute goods or services; loss of use, +# data, or profits; or business interruption) however caused and on any +# theory of liability, whether in contract, strict liability, or tort +# (including negligence or otherwise) arising in any way out of the use +# of this software, even if advised of the possibility of such damage. - This software is provided by the copyright holders and contributors "as - is" and any express or implied warranties, including, but not limited - to, the implied warranties of merchantability and fitness for a - particular purpose are disclaimed. In no event shall the copyright - owner or contributors be liable for any direct, indirect, incidental, - special, exemplary, or consequential damages (including, but not - limited to, procurement of substitute goods or services; loss of use, - data, or profits; or business interruption) however caused and on any - theory of liability, whether in contract, strict liability, or tort - (including negligence or otherwise) arising in any way out of the use - of this software, even if advised of the possibility of such damage. +# smartypants.py license: -`smartypants.py` license: +# smartypants.py is a derivative work of SmartyPants. +# Copyright (c) 2004, 2007 Chad Miller - `smartypants.py` is a derivative work of SmartyPants. - Copyright (c) 2004, 2007 Chad Miller +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. +# This software is provided by the copyright holders and contributors "as +# is" and any express or implied warranties, including, but not limited +# to, the implied warranties of merchantability and fitness for a +# particular purpose are disclaimed. In no event shall the copyright +# owner or contributors be liable for any direct, indirect, incidental, +# special, exemplary, or consequential damages (including, but not +# limited to, procurement of substitute goods or services; loss of use, +# data, or profits; or business interruption) however caused and on any +# theory of liability, whether in contract, strict liability, or tort +# (including negligence or otherwise) arising in any way out of the use +# of this software, even if advised of the possibility of such damage. - This software is provided by the copyright holders and contributors "as - is" and any express or implied warranties, including, but not limited - to, the implied warranties of merchantability and fitness for a - particular purpose are disclaimed. In no event shall the copyright - owner or contributors be liable for any direct, indirect, incidental, - special, exemplary, or consequential damages (including, but not - limited to, procurement of substitute goods or services; loss of use, - data, or profits; or business interruption) however caused and on any - theory of liability, whether in contract, strict liability, or tort - (including negligence or otherwise) arising in any way out of the use - of this software, even if advised of the possibility of such damage. +""" +Adds conversion of ASCII dashes, quotes and ellipses to their HTML +entity equivalents. +See the [documentation](https://Python-Markdown.github.io/extensions/smarty) +for details. """ from __future__ import annotations @@ -167,6 +172,7 @@ def handleMatch(self, m, data): class SmartyExtension(Extension): + """ Add Smarty to Markdown. """ def __init__(self, **kwargs): self.config = { 'smart_quotes': [True, 'Educate quotes'], diff --git a/markdown/extensions/tables.py b/markdown/extensions/tables.py index 1deb68608..6b4cbcad9 100644 --- a/markdown/extensions/tables.py +++ b/markdown/extensions/tables.py @@ -1,18 +1,22 @@ -""" -Tables Extension for Python-Markdown -==================================== +# Tables Extension for Python-Markdown +# ==================================== -Added parsing of tables to Python-Markdown. +# Added parsing of tables to Python-Markdown. + +# See https://Python-Markdown.github.io/extensions/tables +# for documentation. -See https://Python-Markdown.github.io/extensions/tables -for documentation. +# Original code Copyright 2009 [Waylan Limberg](http://achinghead.com) -Original code Copyright 2009 [Waylan Limberg](http://achinghead.com) +# All changes Copyright 2008-2014 The Python Markdown Project -All changes Copyright 2008-2014 The Python Markdown Project +# License: [BSD](https://opensource.org/licenses/bsd-license.php) -License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" +Added parsing of tables to Python-Markdown. +See the [documentation](https://Python-Markdown.github.io/extensions/tables) +for details. """ from __future__ import annotations diff --git a/markdown/extensions/toc.py b/markdown/extensions/toc.py index 36f1287d1..759d9494a 100644 --- a/markdown/extensions/toc.py +++ b/markdown/extensions/toc.py @@ -1,16 +1,20 @@ -""" -Table of Contents Extension for Python-Markdown -=============================================== +# Table of Contents Extension for Python-Markdown +# =============================================== + +# See https://Python-Markdown.github.io/extensions/toc +# for documentation. -See https://Python-Markdown.github.io/extensions/toc -for documentation. +# Original code Copyright 2008 [Jack Miller](https://codezen.org/) -Original code Copyright 2008 [Jack Miller](https://codezen.org/) +# All changes Copyright 2008-2014 The Python Markdown Project -All changes Copyright 2008-2014 The Python Markdown Project +# License: [BSD](https://opensource.org/licenses/bsd-license.php) -License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" +Add table of contents support to Python-Markdown. +See the [documentation](https://Python-Markdown.github.io/extensions/toc) +for details. """ from __future__ import annotations @@ -92,14 +96,16 @@ def unescape(text): def nest_toc_tokens(toc_list): """Given an unsorted list with errors and skips, return a nested one. - [{'level': 1}, {'level': 2}] - => - [{'level': 1, 'children': [{'level': 2, 'children': []}]}] + + [{'level': 1}, {'level': 2}] + => + [{'level': 1, 'children': [{'level': 2, 'children': []}]}] A wrong list is also converted: - [{'level': 2}, {'level': 1}] - => - [{'level': 2, 'children': []}, {'level': 1, 'children': []}] + + [{'level': 2}, {'level': 1}] + => + [{'level': 2, 'children': []}, {'level': 1, 'children': []}] """ ordered_list = [] @@ -154,6 +160,8 @@ def nest_toc_tokens(toc_list): class TocTreeprocessor(Treeprocessor): + """ Step through document and build TOC. """ + def __init__(self, md, config): super().__init__(md) diff --git a/markdown/extensions/wikilinks.py b/markdown/extensions/wikilinks.py index 30cf02c1e..6f59e32da 100644 --- a/markdown/extensions/wikilinks.py +++ b/markdown/extensions/wikilinks.py @@ -1,18 +1,22 @@ -""" -WikiLinks Extension for Python-Markdown -====================================== +# WikiLinks Extension for Python-Markdown +# ====================================== + +# Converts [[WikiLinks]] to relative links. -Converts [[WikiLinks]] to relative links. +# See https://Python-Markdown.github.io/extensions/wikilinks +# for documentation. -See https://Python-Markdown.github.io/extensions/wikilinks -for documentation. +# Original code Copyright [Waylan Limberg](http://achinghead.com/). -Original code Copyright [Waylan Limberg](http://achinghead.com/). +# All changes Copyright The Python Markdown Project -All changes Copyright The Python Markdown Project +# License: [BSD](https://opensource.org/licenses/bsd-license.php) -License: [BSD](https://opensource.org/licenses/bsd-license.php) +""" +Converts `[[WikiLinks]]` to relative links. +See the [documentation](https://Python-Markdown.github.io/extensions/wikilinks) +for details. """ from __future__ import annotations @@ -30,6 +34,7 @@ def build_url(label, base, end): class WikiLinkExtension(Extension): + """ Add inline processor to Markdown. """ def __init__(self, **kwargs): self.config = { @@ -52,6 +57,8 @@ def extendMarkdown(self, md): class WikiLinksInlineProcessor(InlineProcessor): + """ Build link from wikilink. """ + def __init__(self, pattern, config): super().__init__(pattern) self.config = config diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py index 025db31b1..59238a79c 100644 --- a/markdown/inlinepatterns.py +++ b/markdown/inlinepatterns.py @@ -357,7 +357,7 @@ class SimpleTagPattern(Pattern): # pragma: no cover of a Pattern. """ - def __init__(self, pattern, tag): + def __init__(self, pattern: str, tag: str): """ Create an instant of an simple tag pattern. @@ -381,7 +381,7 @@ class SimpleTagInlineProcessor(InlineProcessor): of a Pattern. """ - def __init__(self, pattern, tag): + def __init__(self, pattern: str, tag: str): """ Create an instant of an simple tag processor. From a4cff19650693ae385f9eb0a7e7a3933e3d0fe0f Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Tue, 26 Sep 2023 14:55:33 -0400 Subject: [PATCH 36/61] Some cleanup --- markdown/blockprocessors.py | 4 ++-- markdown/extensions/__init__.py | 6 +++--- markdown/extensions/attr_list.py | 4 ++-- markdown/extensions/def_list.py | 2 +- markdown/inlinepatterns.py | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/markdown/blockprocessors.py b/markdown/blockprocessors.py index e9c24baad..5e76f092b 100644 --- a/markdown/blockprocessors.py +++ b/markdown/blockprocessors.py @@ -29,7 +29,7 @@ import logging import re import xml.etree.ElementTree as etree -from typing import TYPE_CHECKING, Tuple, Any +from typing import TYPE_CHECKING, Any from . import util from .blockparser import BlockParser @@ -222,7 +222,7 @@ def create_item(self, parent: etree.Element, block: str): li = etree.SubElement(parent, 'li') self.parser.parseBlocks(li, [block]) - def get_level(self, parent: etree.Element, block: str) -> Tuple[int, etree.Element]: + def get_level(self, parent: etree.Element, block: str) -> tuple[int, etree.Element]: """ Get level of indentation based on list level. """ # Get indent level m = self.INDENT_RE.match(block) diff --git a/markdown/extensions/__init__.py b/markdown/extensions/__init__.py index 2d341de6f..4c2d1f460 100644 --- a/markdown/extensions/__init__.py +++ b/markdown/extensions/__init__.py @@ -27,7 +27,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Tuple +from typing import TYPE_CHECKING, Any from ..util import parseBoolValue if TYPE_CHECKING: # pragma: no cover @@ -82,7 +82,7 @@ def getConfigs(self) -> dict[str, Any]: """ return {key: self.getConfig(key) for key in self.config.keys()} - def getConfigInfo(self) -> list[Tuple[str, str]]: + def getConfigInfo(self) -> list[tuple[str, str]]: """ Return descriptions of all configuration options. @@ -112,7 +112,7 @@ def setConfig(self, key: str, value: Any): value = parseBoolValue(value, preserve_none=True) self.config[key][0] = value - def setConfigs(self, items: dict[str, Any] | list[Tuple[str, Any]]): + def setConfigs(self, items: dict[str, Any] | list[tuple[str, Any]]): """ Loop through a collection of configuration options, passing each to [`setConfig`][markdown.extensions.Extension.setConfig]. diff --git a/markdown/extensions/attr_list.py b/markdown/extensions/attr_list.py index 30c075ce6..6c2d60df0 100644 --- a/markdown/extensions/attr_list.py +++ b/markdown/extensions/attr_list.py @@ -24,7 +24,7 @@ """ from __future__ import annotations -from typing import TYPE_CHECKING, Tuple +from typing import TYPE_CHECKING from . import Extension from ..treeprocessors import Treeprocessor @@ -65,7 +65,7 @@ def _handle_word(s, t): ]) -def get_attrs(str: str) -> list[Tuple[str, str]]: +def get_attrs(str: str) -> list[tuple[str, str]]: """ Parse attribute list and return a list of attribute tuples. """ return _scanner.scan(str)[0] diff --git a/markdown/extensions/def_list.py b/markdown/extensions/def_list.py index 0d7fbe354..378b4c1ec 100644 --- a/markdown/extensions/def_list.py +++ b/markdown/extensions/def_list.py @@ -15,7 +15,7 @@ """ Adds parsing of Definition Lists to Python-Markdown. -See the [documentation]( https://Python-Markdown.github.io/extensions/definition_lists) +See the [documentation](https://Python-Markdown.github.io/extensions/definition_lists) for details. """ diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py index 59238a79c..34537bb2a 100644 --- a/markdown/inlinepatterns.py +++ b/markdown/inlinepatterns.py @@ -61,7 +61,7 @@ from . import util from collections import namedtuple -from typing import TYPE_CHECKING, Tuple, Match +from typing import TYPE_CHECKING, Match import re import xml.etree.ElementTree as etree try: # pragma: no cover @@ -209,7 +209,7 @@ class inititialiation, the `^(.*)` and `(.*)!` are added automatically and the r `Pattern` remains for backward compatability with many existing third-party extensions. Attributes: - ANCESTOR_EXCLUDES (Tuple[str]): A collection of elements which are undesirable ancestors. + ANCESTOR_EXCLUDES (tuple[str]): A collection of elements which are undesirable ancestors. The processor will be skipped if it would cause the content to be a descendant of one of the listed tag names. md (Markdown | None): The instance of the `Markdown` class this matter is assigned to. @@ -283,7 +283,7 @@ class InlineProcessor(Pattern): efficient and flexible search approach. Attributes: - ANCESTOR_EXCLUDES (Tuple[str]): A collection of elements which are undesirable ancestors. + ANCESTOR_EXCLUDES (tuple[str]): A collection of elements which are undesirable ancestors. The processor will be skipped if it would cause the content to be a descendant of one of the listed tag names. md (Markdown | None): The instance of the `Markdown` class this matter is assigned to. From bcfd78e55461d4099be88a83adf75b16d9525ecc Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Tue, 26 Sep 2023 15:03:00 -0400 Subject: [PATCH 37/61] more cleanup --- markdown/extensions/__init__.py | 2 +- markdown/extensions/extra.py | 2 +- markdown/extensions/nl2br.py | 2 +- markdown/extensions/smarty.py | 4 ++-- markdown/extensions/wikilinks.py | 2 +- markdown/inlinepatterns.py | 8 ++++---- markdown/serializers.py | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/markdown/extensions/__init__.py b/markdown/extensions/__init__.py index 4c2d1f460..49e3b021c 100644 --- a/markdown/extensions/__init__.py +++ b/markdown/extensions/__init__.py @@ -75,7 +75,7 @@ def getConfig(self, key: str, default: Any = '') -> Any: def getConfigs(self) -> dict[str, Any]: """ - Return all config options. + Return all configuration options. Returns: All configuration options. diff --git a/markdown/extensions/extra.py b/markdown/extensions/extra.py index a6a941082..74ebc192c 100644 --- a/markdown/extensions/extra.py +++ b/markdown/extensions/extra.py @@ -30,7 +30,7 @@ variable defined below, but be aware that such changes may be lost when you upgrade to any future version of Python-Markdown. -See the [documentaiton](https://Python-Markdown.github.io/extensions/extra) +See the [documentation](https://Python-Markdown.github.io/extensions/extra) for details. """ diff --git a/markdown/extensions/nl2br.py b/markdown/extensions/nl2br.py index fec0a14bd..177df1ee4 100644 --- a/markdown/extensions/nl2br.py +++ b/markdown/extensions/nl2br.py @@ -1,4 +1,4 @@ -# NL2BR Extension +# `NL2BR` Extension # =============== # A Python-Markdown extension to treat newlines as hard breaks; like diff --git a/markdown/extensions/smarty.py b/markdown/extensions/smarty.py index 06bfab50a..dd9ea77bf 100644 --- a/markdown/extensions/smarty.py +++ b/markdown/extensions/smarty.py @@ -47,9 +47,9 @@ # of this software, even if advised of the possibility of such damage. -# smartypants.py license: +# `smartypants.py` license: -# smartypants.py is a derivative work of SmartyPants. +# `smartypants.py` is a derivative work of SmartyPants. # Copyright (c) 2004, 2007 Chad Miller # Redistribution and use in source and binary forms, with or without diff --git a/markdown/extensions/wikilinks.py b/markdown/extensions/wikilinks.py index 6f59e32da..b8c0ba2be 100644 --- a/markdown/extensions/wikilinks.py +++ b/markdown/extensions/wikilinks.py @@ -57,7 +57,7 @@ def extendMarkdown(self, md): class WikiLinksInlineProcessor(InlineProcessor): - """ Build link from wikilink. """ + """ Build link from `wikilink`. """ def __init__(self, pattern, config): super().__init__(pattern) diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py index 34537bb2a..813634ada 100644 --- a/markdown/inlinepatterns.py +++ b/markdown/inlinepatterns.py @@ -61,7 +61,7 @@ from . import util from collections import namedtuple -from typing import TYPE_CHECKING, Match +from typing import TYPE_CHECKING, Match, Any import re import xml.etree.ElementTree as etree try: # pragma: no cover @@ -201,12 +201,12 @@ class Pattern: # pragma: no cover All the regular expressions used by `Pattern` subclasses must capture the whole block. For this reason, they all start with `^(.*)` and end with `(.*)!`. When passing a regular expression on - class inititialiation, the `^(.*)` and `(.*)!` are added automatically and the regular expression - is precompiled. + class initialization, the `^(.*)` and `(.*)!` are added automatically and the regular expression + is pre-compiled. It is strongly suggested that the newer style [`markdown.inlinepatterns.InlineProcessor`][] that use a more efficient and flexible search approach be used instead. However, the older style - `Pattern` remains for backward compatability with many existing third-party extensions. + `Pattern` remains for backward compatibility with many existing third-party extensions. Attributes: ANCESTOR_EXCLUDES (tuple[str]): A collection of elements which are undesirable ancestors. diff --git a/markdown/serializers.py b/markdown/serializers.py index 87f8add30..5a8818e28 100644 --- a/markdown/serializers.py +++ b/markdown/serializers.py @@ -36,7 +36,7 @@ """ Python-Markdown provides two serializers which render [`ElementTree.Element`][xml.etree.ElementTree.Element] -objects to a string of HTML. Both functions wrap the same underliying code with only a few minor +objects to a string of HTML. Both functions wrap the same underlying code with only a few minor differences as outlined below: 1. Empty (self-closing) tags are rendered as `` for HTML and as `` for XHTML. From 5388f831b260f712e7b97df0c75e66c2694aba5f Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Wed, 27 Sep 2023 14:37:16 -0400 Subject: [PATCH 38/61] Add changelog entry --- docs/changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index d233abfda..21c464dd2 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -27,6 +27,8 @@ links to the header, placing them after all other header content. * Refactor changelog to use the format defined at . * Update the list of empty HTML tags (#1353). * Add customizable TOC title class to TOC extension (#1293). +* Add API documentation of the code base which is generated by + [mkdocstrings](https://mkdocstrings.github.io/) (#1220). ## [3.4.4] -- 2023-07-25 From 6f0f4a81ad337eef41bf6f8693fe39fbf3b7dde9 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Wed, 27 Sep 2023 15:23:14 -0400 Subject: [PATCH 39/61] Update spelling dict --- .spell-dict | 1 + 1 file changed, 1 insertion(+) diff --git a/.spell-dict b/.spell-dict index e3944f1c0..13cdea5b1 100644 --- a/.spell-dict +++ b/.spell-dict @@ -69,6 +69,7 @@ md merchantability metadata MkDocs +mkdocstrings multi MultiMarkdown munge From 09e152dee165cce58384362de24608be6dde4ca6 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Wed, 27 Sep 2023 16:06:18 -0400 Subject: [PATCH 40/61] Add custom template for proper admonitions (no more details elements). --- docs/templates/python/nature/docstring/admonition.html | 5 +++++ markdown/postprocessors.py | 4 ++-- mkdocs.yml | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 docs/templates/python/nature/docstring/admonition.html diff --git a/docs/templates/python/nature/docstring/admonition.html b/docs/templates/python/nature/docstring/admonition.html new file mode 100644 index 000000000..14ec034aa --- /dev/null +++ b/docs/templates/python/nature/docstring/admonition.html @@ -0,0 +1,5 @@ +{{ log.debug("Rendering admonition") }} +
+

{{ section.title|convert_markdown(heading_level, html_id, strip_paragraph=True) }}

+ {{ section.value.contents|convert_markdown(heading_level, html_id) }} +
diff --git a/markdown/postprocessors.py b/markdown/postprocessors.py index d907ce1b6..0bbb8c18f 100644 --- a/markdown/postprocessors.py +++ b/markdown/postprocessors.py @@ -135,10 +135,10 @@ class UnescapePostprocessor(Postprocessor): """ Restore escaped chars. - !!! warning "Deprecated" - + Warning: Deprecated This class is deprecated and will be removed in the future; use [`UnescapeTreeprocessor`][markdown.treeprocessors.UnescapeTreeprocessor] instead. + """ RE = re.compile(r'{}(\d+){}'.format(util.STX, util.ETX)) diff --git a/mkdocs.yml b/mkdocs.yml index e3f28cdc4..bb8f7de0a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -71,6 +71,7 @@ plugins: nav_file: SUMMARY.md - section-index - mkdocstrings: + custom_templates: docs/templates handlers: python: import: From 92dfdcd2de9898eb664327b8821ed67f5b4df3a7 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Thu, 28 Sep 2023 08:43:52 -0400 Subject: [PATCH 41/61] Coverage --- markdown/extensions/attr_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/markdown/extensions/attr_list.py b/markdown/extensions/attr_list.py index 6c2d60df0..f430ec300 100644 --- a/markdown/extensions/attr_list.py +++ b/markdown/extensions/attr_list.py @@ -30,7 +30,7 @@ from ..treeprocessors import Treeprocessor import re -if TYPE_CHECKING: +if TYPE_CHECKING: # pragma: no cover from xml.etree.ElementTree import Element From 3448847f72e9fd64d6bac86ba594927edf002e1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Thu, 28 Sep 2023 16:21:16 +0200 Subject: [PATCH 42/61] Add support for deprecated decorator --- mkdocs.yml | 2 ++ scripts/griffe_deprecated.py | 41 ++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 scripts/griffe_deprecated.py diff --git a/mkdocs.yml b/mkdocs.yml index bb8f7de0a..d30d853aa 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -82,6 +82,8 @@ plugins: ignore_init_summary: true docstring_style: google docstring_section_style: list + extensions: + - scripts/griffe_deprecated.py filters: ["!^_"] group_by_category: false heading_level: 1 diff --git a/scripts/griffe_deprecated.py b/scripts/griffe_deprecated.py new file mode 100644 index 000000000..f89382dfa --- /dev/null +++ b/scripts/griffe_deprecated.py @@ -0,0 +1,41 @@ +"""Griffe extension for `@markdown.util.deprecated` decorator support.""" + +from __future__ import annotations + +import ast +from typing import TYPE_CHECKING + +from griffe import Docstring, Extension +from griffe.docstrings.dataclasses import DocstringSectionAdmonition + +if TYPE_CHECKING: + from griffe import Class, Function, ObjectNode + + +def _deprecated(obj: Class | Function) -> str | None: + for decorator in obj.decorators: + if decorator.callable_path == "markdown.util.deprecated": + return ast.literal_eval(str(decorator.value.arguments[0])) + return None + + +class DeprecatedExtension(Extension): + """Griffe extension for `@markdown.util.deprecated` decorator support.""" + + def _insert_message(self, obj: Function | Class, message: str) -> None: + if not obj.docstring: + obj.docstring = Docstring("", parent=obj) + sections = obj.docstring.parsed + sections.insert(0, DocstringSectionAdmonition(kind="warning", text=message, title="Deprecated")) + + def on_class_instance(self, node: ast.AST | ObjectNode, cls: Class) -> None: # noqa: ARG002 + """Add section to docstrings of deprecated classes.""" + if message := _deprecated(cls): + self._insert_message(cls, message) + cls.labels.add("deprecated") + + def on_function_instance(self, node: ast.AST | ObjectNode, func: Function) -> None: # noqa: ARG002 + """Add section to docstrings of deprecated functions.""" + if message := _deprecated(func): + self._insert_message(func, message) + func.labels.add("deprecated") From 2dacbed0af1f0efa18711e8cda457c31aee73000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Thu, 28 Sep 2023 16:28:47 +0200 Subject: [PATCH 43/61] Don't show inherited members in extension subclasses --- scripts/gen_ref_nav.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/gen_ref_nav.py b/scripts/gen_ref_nav.py index 5e388aa16..2ecbd5767 100755 --- a/scripts/gen_ref_nav.py +++ b/scripts/gen_ref_nav.py @@ -50,6 +50,9 @@ if ident in per_module_options: yaml_options = yaml.dump({"options": per_module_options[ident]}) fd.write(f"\n{textwrap.indent(yaml_options, prefix=' ')}") + elif ident.startswith("markdown.extensions."): + yaml_options = yaml.dump({"options": {"inherited_members": False}}) + fd.write(f"\n{textwrap.indent(yaml_options, prefix=' ')}") mkdocs_gen_files.set_edit_path(full_doc_path, ".." / path) From 7f7648ca889ff4aa98f67c8757da199e412f1257 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Thu, 28 Sep 2023 14:08:52 -0400 Subject: [PATCH 44/61] CLeanup deprecations and style label --- docs/mkdocstrings.css | 5 +++++ markdown/postprocessors.py | 13 +++---------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/docs/mkdocstrings.css b/docs/mkdocstrings.css index 5bd9e8295..88b6c65ee 100644 --- a/docs/mkdocstrings.css +++ b/docs/mkdocstrings.css @@ -47,6 +47,11 @@ a.autorefs:hover code { color: #444; } +.doc-label-deprecated { + background-color: #ffe4e4; + border: 1px solid #f66; +} + /* No shadows in any code. */ code { diff --git a/markdown/postprocessors.py b/markdown/postprocessors.py index 0bbb8c18f..4a18e18ee 100644 --- a/markdown/postprocessors.py +++ b/markdown/postprocessors.py @@ -128,18 +128,11 @@ def run(self, text): @util.deprecated( - "This class will be removed in the future; " - "use 'treeprocessors.UnescapeTreeprocessor' instead." + "This class is deprecated and will be removed in the future; " + "use [`UnescapeTreeprocessor`][markdown.treeprocessors.UnescapeTreeprocessor] instead." ) class UnescapePostprocessor(Postprocessor): - """ - Restore escaped chars. - - Warning: Deprecated - This class is deprecated and will be removed in the future; use - [`UnescapeTreeprocessor`][markdown.treeprocessors.UnescapeTreeprocessor] instead. - - """ + """ Restore escaped chars. """ RE = re.compile(r'{}(\d+){}'.format(util.STX, util.ETX)) From af74150211464e2bfecd7433bc0c9d835c3699e6 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Thu, 28 Sep 2023 14:42:04 -0400 Subject: [PATCH 45/61] Add details to various extensions --- markdown/extensions/codehilite.py | 1 + markdown/extensions/def_list.py | 2 ++ markdown/extensions/fenced_code.py | 3 ++- markdown/extensions/footnotes.py | 1 + markdown/extensions/sane_lists.py | 3 +++ markdown/extensions/smarty.py | 1 + markdown/extensions/tables.py | 1 + markdown/extensions/toc.py | 2 ++ markdown/extensions/wikilinks.py | 2 +- 9 files changed, 14 insertions(+), 2 deletions(-) diff --git a/markdown/extensions/codehilite.py b/markdown/extensions/codehilite.py index 0763034de..8efdaf0af 100644 --- a/markdown/extensions/codehilite.py +++ b/markdown/extensions/codehilite.py @@ -311,6 +311,7 @@ def __init__(self, **kwargs): 'Default: "html"', ], } + """ Default configuration options. """ for key, value in kwargs.items(): if key in self.config: diff --git a/markdown/extensions/def_list.py b/markdown/extensions/def_list.py index 378b4c1ec..54273b602 100644 --- a/markdown/extensions/def_list.py +++ b/markdown/extensions/def_list.py @@ -95,7 +95,9 @@ class DefListIndentProcessor(ListIndentProcessor): # Definition lists need to be aware of all list types ITEM_TYPES = ['dd', 'li'] + """ Include `dd` in list item types. """ LIST_TYPES = ['dl', 'ol', 'ul'] + """ Include `dl` is list types. """ def create_item(self, parent, block): """ Create a new `dd` or `li` (depending on parent) and parse the block with it as the parent. """ diff --git a/markdown/extensions/fenced_code.py b/markdown/extensions/fenced_code.py index f75b561a7..241bb6d40 100644 --- a/markdown/extensions/fenced_code.py +++ b/markdown/extensions/fenced_code.py @@ -36,6 +36,7 @@ def __init__(self, **kwargs): self.config = { 'lang_prefix': ['language-', 'Prefix prepended to the language. Default: "language-"'] } + """ Default configuration options. """ super().__init__(**kwargs) def extendMarkdown(self, md): @@ -151,7 +152,7 @@ def run(self, lines): return text.split("\n") def handle_attrs(self, attrs): - """ Return tuple: (id, [list, of, classes], {configs}) """ + """ Return tuple: `(id, [list, of, classes], {configs})` """ id = '' classes = [] configs = {} diff --git a/markdown/extensions/footnotes.py b/markdown/extensions/footnotes.py index 8aaf62c17..ad7ae78d5 100644 --- a/markdown/extensions/footnotes.py +++ b/markdown/extensions/footnotes.py @@ -66,6 +66,7 @@ def __init__(self, **kwargs): [":", "Footnote separator."] } + """ Default configuration options. """ super().__init__(**kwargs) # In multiple invocations, emit links that don't get tangled. diff --git a/markdown/extensions/sane_lists.py b/markdown/extensions/sane_lists.py index b8a783a97..305bd9923 100644 --- a/markdown/extensions/sane_lists.py +++ b/markdown/extensions/sane_lists.py @@ -30,7 +30,9 @@ class SaneOListProcessor(OListProcessor): """ Override `SIBLING_TAGS` to not include `ul` and set `LAZY_OL` to `False`. """ SIBLING_TAGS = ['ol'] + """ Exclude `ul` from list of siblings. """ LAZY_OL = False + """ Disable lazy list behavior. """ def __init__(self, parser): super().__init__(parser) @@ -42,6 +44,7 @@ class SaneUListProcessor(UListProcessor): """ Override `SIBLING_TAGS` to not include `ol`. """ SIBLING_TAGS = ['ul'] + """ Exclude `ol` from list of siblings. """ def __init__(self, parser): super().__init__(parser) diff --git a/markdown/extensions/smarty.py b/markdown/extensions/smarty.py index dd9ea77bf..ca6a017d3 100644 --- a/markdown/extensions/smarty.py +++ b/markdown/extensions/smarty.py @@ -181,6 +181,7 @@ def __init__(self, **kwargs): 'smart_ellipses': [True, 'Educate ellipses'], 'substitutions': [{}, 'Overwrite default substitutions'], } + """ Default configuration options. """ super().__init__(**kwargs) self.substitutions = dict(substitutions) self.substitutions.update(self.getConfig('substitutions', default={})) diff --git a/markdown/extensions/tables.py b/markdown/extensions/tables.py index 6b4cbcad9..a9e5f13d5 100644 --- a/markdown/extensions/tables.py +++ b/markdown/extensions/tables.py @@ -227,6 +227,7 @@ def __init__(self, **kwargs): self.config = { 'use_align_attribute': [False, 'True to use align attribute instead of style.'], } + """ Default configuration options. """ super().__init__(**kwargs) diff --git a/markdown/extensions/toc.py b/markdown/extensions/toc.py index 759d9494a..ed2462cc8 100644 --- a/markdown/extensions/toc.py +++ b/markdown/extensions/toc.py @@ -385,10 +385,12 @@ def __init__(self, **kwargs): 'in between ("2-5"), define the top (t) and the' 'bottom (b) (..). Defaults to `6` (bottom).'], } + """ Default configuration options. """ super().__init__(**kwargs) def extendMarkdown(self, md): + """ Add TOC treeprocessor to Markdown. """ md.registerExtension(self) self.md = md self.reset() diff --git a/markdown/extensions/wikilinks.py b/markdown/extensions/wikilinks.py index b8c0ba2be..9d5acfa35 100644 --- a/markdown/extensions/wikilinks.py +++ b/markdown/extensions/wikilinks.py @@ -43,7 +43,7 @@ def __init__(self, **kwargs): 'html_class': ['wikilink', 'CSS hook. Leave blank for none.'], 'build_url': [build_url, 'Callable formats URL from label.'], } - + """ Default configuration options. """ super().__init__(**kwargs) def extendMarkdown(self, md): From 326b56f2ff8a4a906a2e9726462e4c7f8181fb8e Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Thu, 28 Sep 2023 15:44:17 -0400 Subject: [PATCH 46/61] spelling cleanup --- markdown/extensions/toc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/markdown/extensions/toc.py b/markdown/extensions/toc.py index ed2462cc8..010aab374 100644 --- a/markdown/extensions/toc.py +++ b/markdown/extensions/toc.py @@ -390,7 +390,7 @@ def __init__(self, **kwargs): super().__init__(**kwargs) def extendMarkdown(self, md): - """ Add TOC treeprocessor to Markdown. """ + """ Add TOC tree processor to Markdown. """ md.registerExtension(self) self.md = md self.reset() From 13e62545a9d50b14311dbd6cd7e9b0925da481cf Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Fri, 29 Sep 2023 10:26:09 -0400 Subject: [PATCH 47/61] Force attributes to always have separate signature --- docs/templates/python/nature/attribute.html | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 docs/templates/python/nature/attribute.html diff --git a/docs/templates/python/nature/attribute.html b/docs/templates/python/nature/attribute.html new file mode 100644 index 000000000..5f5bed43a --- /dev/null +++ b/docs/templates/python/nature/attribute.html @@ -0,0 +1,11 @@ +{% extends "_base/attribute.html" %} + +{% block heading scoped %} + {{ attribute_name }} +{% endblock heading %} + +{% block signature scoped %} + {% filter format_attribute(attribute, config.line_length, crossrefs=config.signature_crossrefs) %} + {{ attribute.name }} + {% endfilter %} +{% endblock signature %} From 9198aa513d4ed992e71af0c130dda1e8b9724311 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Fri, 29 Sep 2023 10:41:35 -0400 Subject: [PATCH 48/61] Ensure attribute name is wrapped in code tag. --- docs/templates/python/nature/attribute.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/templates/python/nature/attribute.html b/docs/templates/python/nature/attribute.html index 5f5bed43a..e7180b0da 100644 --- a/docs/templates/python/nature/attribute.html +++ b/docs/templates/python/nature/attribute.html @@ -1,7 +1,9 @@ {% extends "_base/attribute.html" %} {% block heading scoped %} - {{ attribute_name }} + {%+ filter highlight(language="python", inline=True) %} + {{ attribute_name }} + {% endfilter %} {% endblock heading %} {% block signature scoped %} From fdbcd4fc53c12de5280d8eb8b8c537f9b3848e86 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Fri, 29 Sep 2023 11:00:54 -0400 Subject: [PATCH 49/61] Use attribute.source to preserve formatting in signature --- docs/templates/python/nature/attribute.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/templates/python/nature/attribute.html b/docs/templates/python/nature/attribute.html index e7180b0da..723bfe1ab 100644 --- a/docs/templates/python/nature/attribute.html +++ b/docs/templates/python/nature/attribute.html @@ -7,7 +7,7 @@ {% endblock heading %} {% block signature scoped %} - {% filter format_attribute(attribute, config.line_length, crossrefs=config.signature_crossrefs) %} - {{ attribute.name }} + {%+ filter highlight(language="python", inline=False) %} +{{ attribute.source }} {% endfilter %} {% endblock signature %} From 0d26314a1160001ffca8e7462120e3ba91bcea49 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Fri, 29 Sep 2023 11:40:17 -0400 Subject: [PATCH 50/61] preserve annotations in attrs, move source to end of content, & only show source for attrs with a value (properties to not have a value). --- docs/templates/python/nature/attribute.html | 9 ++++++--- markdown/util.py | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/templates/python/nature/attribute.html b/docs/templates/python/nature/attribute.html index 723bfe1ab..1e26c7a34 100644 --- a/docs/templates/python/nature/attribute.html +++ b/docs/templates/python/nature/attribute.html @@ -2,12 +2,15 @@ {% block heading scoped %} {%+ filter highlight(language="python", inline=True) %} - {{ attribute_name }} + {{ attribute_name }}{% if attribute.annotation %}: {{ attribute.annotation }}{% endif %} {% endfilter %} {% endblock heading %} -{% block signature scoped %} +{% block contents scoped %} + {{ super() }} + {% if attribute.value %} {%+ filter highlight(language="python", inline=False) %} {{ attribute.source }} {% endfilter %} -{% endblock signature %} + {% endif %} +{% endblock contents %} diff --git a/markdown/util.py b/markdown/util.py index f922ff0ca..c1bdc4b53 100644 --- a/markdown/util.py +++ b/markdown/util.py @@ -42,7 +42,7 @@ """ -BLOCK_LEVEL_ELEMENTS = [ +BLOCK_LEVEL_ELEMENTS: list[str] = [ # Elements which are invalid to wrap in a `

` tag. # See https://w3c.github.io/html/grouping-content.html#the-p-element 'address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl', From d36a22239650c614d33a27d4a40a8eff5ed9889a Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Fri, 29 Sep 2023 11:50:13 -0400 Subject: [PATCH 51/61] Add a section header for the attr source --- docs/templates/python/nature/attribute.html | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/templates/python/nature/attribute.html b/docs/templates/python/nature/attribute.html index 1e26c7a34..267c5ce31 100644 --- a/docs/templates/python/nature/attribute.html +++ b/docs/templates/python/nature/attribute.html @@ -9,6 +9,7 @@ {% block contents scoped %} {{ super() }} {% if attribute.value %} +

Defined Value:

{%+ filter highlight(language="python", inline=False) %} {{ attribute.source }} {% endfilter %} From 87153b45881a043fa895ba86cf4b30c76e6f02dd Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Fri, 29 Sep 2023 16:25:42 -0400 Subject: [PATCH 52/61] cleanup attributes --- markdown/blockprocessors.py | 57 +++++++------------- markdown/core.py | 26 +++++---- markdown/extensions/__init__.py | 4 +- markdown/extensions/codehilite.py | 51 +++++++++--------- markdown/extensions/footnotes.py | 43 +++++++-------- markdown/extensions/toc.py | 88 ++++++++++++++++--------------- markdown/inlinepatterns.py | 18 +++---- markdown/test_tools.py | 3 +- markdown/util.py | 7 ++- 9 files changed, 141 insertions(+), 156 deletions(-) diff --git a/markdown/blockprocessors.py b/markdown/blockprocessors.py index 5e76f092b..9f9951bd6 100644 --- a/markdown/blockprocessors.py +++ b/markdown/blockprocessors.py @@ -160,15 +160,12 @@ class ListIndentProcessor(BlockProcessor): or this part - Attributes: - ListIndentProcessor.ITEM_TYPES (list[str]): List of tags used for list items. Default: `['li']`. - ListIndentProcessor.LIST_TYPES (list[str]): Types of lists this processor can operate on. - Default: `['ul', 'ol']`. - """ ITEM_TYPES = ['li'] + """ List of tags used for list items. """ LIST_TYPES = ['ul', 'ol'] + """ Types of lists this processor can operate on. """ def __init__(self, *args): super().__init__(*args) @@ -328,30 +325,22 @@ def clean(self, line: str) -> str: class OListProcessor(BlockProcessor): - """ - Process ordered list blocks. - - Attributes: - OListProcessor.TAG (str): The tag used for the the wrapping element. Default: `ol`. - OListProcessor.STARTSWITH (str): The integer (as a string ) with which the list starts. - For example, if a list is initialized as `3. Item`, then the `ol` tag will be - assigned an HTML attribute of `starts="3"`. Default: `"1"`. - OListProcessor.LAZY_OL (bool): Ignore `STARTSWITH` if `True`. Default: `True`. - OListProcessor.SIBLING_TAGS (list[str]): Markdown does not require the type of a new list - item match the previous list item type. This is the list of types which can be mixed. - Default: `['ol', 'ul']`. + """ Process ordered list blocks. """ + TAG: str = 'ol' + """ The tag used for the the wrapping element. """ + STARTSWITH: int = '1' + """ + The integer (as a string ) with which the list starts. For example, if a list is initialized as + `3. Item`, then the `ol` tag will be assigned an HTML attribute of `starts="3"`. Default: `"1"`. + """ + LAZY_OL: bool = True + """ Ignore `STARTSWITH` if `True`. """ + SIBLING_TAGS: list[str] = ['ol', 'ul'] + """ + Markdown does not require the type of a new list item match the previous list item type. + This is the list of types which can be mixed. """ - - TAG = 'ol' - # The integer (python string) with which the lists starts (default=1) - # Example: If list is initialized as: `3. Item` - # The `ol` tag will get `starts="3"` attribute - STARTSWITH = '1' - # Lazy `ol` - ignore `startswith` - LAZY_OL = True - # List of allowed sibling tags. - SIBLING_TAGS = ['ol', 'ul'] def __init__(self, parser): super().__init__(parser) @@ -454,18 +443,10 @@ def get_items(self, block: str) -> list[str]: class UListProcessor(OListProcessor): - """ - Process unordered list blocks. - - Attributes: - UListProcessor.TAG (str): The tag used for the the wrapping element. Default: `ul`. - UListProcessor.SIBLING_TAGS (list[str]): Markdown does not require the type of a new list - item match the previous list item type. This is the list of types which can be mixed. - Default: `['ol', 'ul']`. - - """ + """ Process unordered list blocks. """ - TAG = 'ul' + TAG: str = 'ul' + """ The tag used for the the wrapping element. """ def __init__(self, parser): super().__init__(parser) diff --git a/markdown/core.py b/markdown/core.py index f4bcfaacc..98ada12f7 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -45,7 +45,7 @@ class Markdown: A parser which converts Markdown to HTML. Attributes: - Markdown.tab_length (int): The number of spaces which correspond to a single tab. Default: `4` + Markdown.tab_length (int): The number of spaces which correspond to a single tab. Default: `4`. Markdown.ESCAPED_CHARS (list[str]): List of characters which get the backslash escape treatment. Markdown.block_level_elements (list[str]): List of HTML tags which get treated as block-level elements. See [`markdown.util.BLOCK_LEVEL_ELEMENTS`][] for the full list of elements. @@ -73,10 +73,14 @@ class Markdown: doc_tag = "div" # Element used to wrap document - later removed - output_formats = { + output_formats: dict[str, Callable[xml.etree.ElementTree.Element]] = { 'html': to_html_string, 'xhtml': to_xhtml_string, } + """ + A mapping of known output formats by name and their respective serializers. Each serializer must be a + callable which accepts an [`Element`][xml.etree.ElementTree.Element] and returns a `str`. + """ def __init__(self, **kwargs): """ @@ -99,21 +103,23 @@ def __init__(self, **kwargs): """ - self.tab_length = kwargs.get('tab_length', 4) + self.tab_length: int = kwargs.get('tab_length', 4) - self.ESCAPED_CHARS = ['\\', '`', '*', '_', '{', '}', '[', ']', - '(', ')', '>', '#', '+', '-', '.', '!'] + self.ESCAPED_CHARS: list[str] = [ + '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!' + ] + """ List of characters which get the backslash escape treatment. """ - self.block_level_elements = BLOCK_LEVEL_ELEMENTS.copy() + self.block_level_elements: list[str] = BLOCK_LEVEL_ELEMENTS.copy() - self.registeredExtensions = [] + self.registeredExtensions: list[Extension] = [] self.docType = "" # TODO: Maybe delete this. It does not appear to be used anymore. - self.stripTopLevelTags = True + self.stripTopLevelTags: bool = True self.build_parser() - self.references = {} - self.htmlStash = util.HtmlStash() + self.references: dict[str, tuple[str, str]] = {} + self.htmlStash: util.HtmlStash = util.HtmlStash() self.registerExtensions(extensions=kwargs.get('extensions', []), configs=kwargs.get('extension_configs', {})) self.set_output_format(kwargs.get('output_format', 'xhtml')) diff --git a/markdown/extensions/__init__.py b/markdown/extensions/__init__.py index 49e3b021c..8d6375a59 100644 --- a/markdown/extensions/__init__.py +++ b/markdown/extensions/__init__.py @@ -37,7 +37,7 @@ class Extension: """ Base class for extensions to subclass. """ - config = {} + config: dict[str, tuple[Any, str]] = {} """ Default configuration for an extension. @@ -45,7 +45,7 @@ class Extension: ``` python config = { - 'key': ['value', 'description'] + 'key': ('value', 'description') } ``` diff --git a/markdown/extensions/codehilite.py b/markdown/extensions/codehilite.py index 8efdaf0af..d2f70b17f 100644 --- a/markdown/extensions/codehilite.py +++ b/markdown/extensions/codehilite.py @@ -285,32 +285,31 @@ class CodeHiliteExtension(Extension): def __init__(self, **kwargs): # define default configs self.config = { - 'linenums': [None, - "Use lines numbers. True|table|inline=yes, False=no, None=auto"], - 'guess_lang': [True, - "Automatic language detection - Default: True"], - 'css_class': ["codehilite", - "Set class name for wrapper
- " - "Default: codehilite"], - 'pygments_style': ['default', - 'Pygments HTML Formatter Style ' - '(Colorscheme) - Default: default'], - 'noclasses': [False, - 'Use inline styles instead of CSS classes - ' - 'Default false'], - 'use_pygments': [True, - 'Use Pygments to Highlight code blocks. ' - 'Disable if using a JavaScript library. ' - 'Default: True'], - 'lang_prefix': [ - 'language-', - 'Prefix prepended to the language when use_pygments is false. Default: "language-"' - ], - 'pygments_formatter': ['html', - 'Use a specific formatter for Pygments highlighting.' - 'Default: "html"', - ], - } + 'linenums': ( + None, "Use lines numbers. True|table|inline=yes, False=no, None=auto. Default: `None`." + ), + 'guess_lang': ( + True, "Automatic language detection - Default: `True`." + ), + 'css_class': ( + "codehilite", "Set class name for wrapper
- Default: `codehilite`." + ), + 'pygments_style': ( + 'default', 'Pygments HTML Formatter Style (Colorscheme). Default: `default`.' + ), + 'noclasses': ( + False, 'Use inline styles instead of CSS classes - Default `False`.' + ), + 'use_pygments': ( + True, 'Highlight code blocks with pygments. Disable if using a JavaScript library. Default: `True`.' + ), + 'lang_prefix': ( + 'language-', 'Prefix prepended to the language when `use_pygments` is false. Default: `language-`.' + ), + 'pygments_formatter': ( + 'html', 'Use a specific formatter for Pygments highlighting. Default: `html`.' + ), + } """ Default configuration options. """ for key, value in kwargs.items(): diff --git a/markdown/extensions/footnotes.py b/markdown/extensions/footnotes.py index ad7ae78d5..c63f280bd 100644 --- a/markdown/extensions/footnotes.py +++ b/markdown/extensions/footnotes.py @@ -42,29 +42,26 @@ def __init__(self, **kwargs): """ Setup configs. """ self.config = { - 'PLACE_MARKER': - ["///Footnotes Go Here///", - "The text string that marks where the footnotes go"], - 'UNIQUE_IDS': - [False, - "Avoid name collisions across " - "multiple calls to reset()."], - "BACKLINK_TEXT": - ["↩", - "The text string that links from the footnote " - "to the reader's place."], - "SUPERSCRIPT_TEXT": - ["{}", - "The text string that links from the reader's place " - "to the footnote."], - "BACKLINK_TITLE": - ["Jump back to footnote %d in the text", - "The text string used for the title HTML attribute " - "of the backlink. %d will be replaced by the " - "footnote number."], - "SEPARATOR": - [":", - "Footnote separator."] + 'PLACE_MARKER': ( + '///Footnotes Go Here///', 'The text string that marks where the footnotes go' + ), + 'UNIQUE_IDS': ( + False, 'Avoid name collisions across multiple calls to `reset()`.' + ), + 'BACKLINK_TEXT': ( + '↩', "The text string that links from the footnote to the reader's place." + ), + 'SUPERSCRIPT_TEXT': ( + '{}', "The text string that links from the reader's place to the footnote." + ), + 'BACKLINK_TITLE': ( + 'Jump back to footnote %d in the text', + 'The text string used for the title HTML attribute of the backlink. ' + '%d will be replaced by the footnote number.' + ), + 'SEPARATOR': ( + ':', 'Footnote separator.' + ) } """ Default configuration options. """ super().__init__(**kwargs) diff --git a/markdown/extensions/toc.py b/markdown/extensions/toc.py index 010aab374..b5e4ee01d 100644 --- a/markdown/extensions/toc.py +++ b/markdown/extensions/toc.py @@ -341,49 +341,51 @@ class TocExtension(Extension): def __init__(self, **kwargs): self.config = { - "marker": ['[TOC]', - 'Text to find and replace with Table of Contents - ' - 'Set to an empty string to disable. Defaults to "[TOC]"'], - "title": ["", - "Title to insert into TOC
- " - "Defaults to an empty string"], - "title_class": ['toctitle', - 'CSS class used for the title. ' - 'Defaults to "toctitle"'], - "toc_class": ['toc', - 'CSS class(es) used for the link. ' - 'Defaults to "toclink"'], - "anchorlink": [False, - "True if header should be a self link - " - "Defaults to False"], - "anchorlink_class": ['toclink', - 'CSS class(es) used for the link. ' - 'Defaults to "toclink"'], - "permalink": [0, - "True or link text if a Sphinx-style permalink should " - "be added - Defaults to False"], - "permalink_class": ['headerlink', - 'CSS class(es) used for the link. ' - 'Defaults to "headerlink"'], - "permalink_title": ["Permanent link", - "Title attribute of the permalink - " - "Defaults to 'Permanent link'"], - "permalink_leading": [False, - "True if permalinks should be placed at " - "the start of the header, rather than the " - "end - Defaults to False."], - "baselevel": ['1', 'Base level for headers.'], - "slugify": [slugify, - "Function to generate anchors based on header text - " - "Defaults to the headerid ext's slugify function."], - 'separator': ['-', 'Word separator. Defaults to "-".'], - "toc_depth": [6, - 'Define the range of section levels to include in' - 'the Table of Contents. A single integer (b) defines' - 'the bottom section level (

..) only.' - 'A string consisting of two digits separated by a hyphen' - 'in between ("2-5"), define the top (t) and the' - 'bottom (b) (..). Defaults to `6` (bottom).'], + 'marker': ( + '[TOC]', + 'Text to find and replace with Table of Contents. Set to an empty string to disable. ' + 'Default: `[TOC]`.' + ), + 'title': ( + '', 'Title to insert into TOC `
`. Default: an empty string.' + ), + 'title_class': ( + 'toctitle', 'CSS class used for the title. Default: `toctitle`.' + ), + 'toc_class': ( + 'toc', 'CSS class(es) used for the link. Default: `toclink`.' + ), + 'anchorlink': ( + False, 'True if header should be a self link. Default: `False`.' + ), + 'anchorlink_class': ( + 'toclink', 'CSS class(es) used for the link. Defaults: `toclink`.' + ), + 'permalink': ( + 0, 'True or link text if a Sphinx-style permalink should be added. Default: `False`.' + ), + 'permalink_class': ( + 'headerlink', 'CSS class(es) used for the link. Default: `headerlink`.' + ), + 'permalink_title': ( + 'Permanent link', 'Title attribute of the permalink. Default: `Permanent link`.' + ), + 'permalink_leading': ( + False, + 'True if permalinks should be placed at start of the header, rather than end. Default: False.' + ), + 'baselevel': ('1', 'Base level for headers. Default: `1`.'), + 'slugify': ( + slugify, 'Function to generate anchors based on header text. Default: `slugify`.' + ), + 'separator': ('-', 'Word separator. Default: `-`.'), + 'toc_depth': ( + 6, + 'Define the range of section levels to include in the Table of Contents. A single integer ' + '(b) defines the bottom section level (

..) only. A string consisting of two digits ' + 'separated by a hyphen in between (`2-5`) defines the top (t) and the bottom (b) (..). ' + 'Default: `6` (bottom).' + ), } """ Default configuration options. """ diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py index 813634ada..394186f69 100644 --- a/markdown/inlinepatterns.py +++ b/markdown/inlinepatterns.py @@ -208,15 +208,13 @@ class initialization, the `^(.*)` and `(.*)!` are added automatically and the re use a more efficient and flexible search approach be used instead. However, the older style `Pattern` remains for backward compatibility with many existing third-party extensions. - Attributes: - ANCESTOR_EXCLUDES (tuple[str]): A collection of elements which are undesirable ancestors. - The processor will be skipped if it would cause the content to be a descendant of one - of the listed tag names. - md (Markdown | None): The instance of the `Markdown` class this matter is assigned to. - """ ANCESTOR_EXCLUDES = tuple() + """ + A collection of elements which are undesirable ancestors. The processor will be skipped if it + would cause the content to be a descendant of one of the listed tag names. + """ def __init__(self, pattern: str, md: Markdown | None = None): """ @@ -282,11 +280,6 @@ class InlineProcessor(Pattern): This is the newer style inline processor that uses a more efficient and flexible search approach. - Attributes: - ANCESTOR_EXCLUDES (tuple[str]): A collection of elements which are undesirable ancestors. - The processor will be skipped if it would cause the content to be a descendant of one - of the listed tag names. - md (Markdown | None): The instance of the `Markdown` class this matter is assigned to. """ def __init__(self, pattern: str, md: Markdown | None = None): @@ -368,6 +361,7 @@ def __init__(self, pattern: str, tag: str): """ Pattern.__init__(self, pattern) self.tag = tag + """ The tag of the rendered element. """ def handleMatch(self, m): el = etree.Element(self.tag) @@ -392,6 +386,7 @@ def __init__(self, pattern: str, tag: str): """ InlineProcessor.__init__(self, pattern) self.tag = tag + """ The tag of the rendered element. """ def handleMatch(self, m, data): # pragma: no cover el = etree.Element(self.tag) @@ -417,6 +412,7 @@ def __init__(self, pattern): InlineProcessor.__init__(self, pattern) self.ESCAPED_BSLASH = '{}{}{}'.format(util.STX, ord('\\'), util.ETX) self.tag = 'code' + """ The tag of the rendered element. """ def handleMatch(self, m, data): if m.group(3): diff --git a/markdown/test_tools.py b/markdown/test_tools.py index cf057eb2d..89575c8e4 100644 --- a/markdown/test_tools.py +++ b/markdown/test_tools.py @@ -54,7 +54,8 @@ class TestCase(unittest.TestCase): In all other respects, behaves as `unittest.TestCase`. """ - default_kwargs = {} + default_kwargs: dict[str, Any] = {} + """ Default options to pass to Markdown for each test. """ def assertMarkdownRenders(self, source, expected, expected_attrs=None, **kwargs): """ diff --git a/markdown/util.py b/markdown/util.py index c1bdc4b53..1ee602973 100644 --- a/markdown/util.py +++ b/markdown/util.py @@ -61,9 +61,12 @@ """ # Placeholders -STX = '\u0002' # Use `STX` ("Start of text") for start-of-placeholder -ETX = '\u0003' # Use `ETX` ("End of text") for end-of-placeholder +STX = '\u0002' +""" "Start of Text" marker for placeholder templates. """ +ETX = '\u0003' +""" "End of Text" marker for placeholder templates. """ INLINE_PLACEHOLDER_PREFIX = STX+"klzzwxh:" +""" Prefix for inline placeholder template. """ INLINE_PLACEHOLDER = INLINE_PLACEHOLDER_PREFIX + "%s" + ETX """ Placeholder template for stashed inline text. """ INLINE_PLACEHOLDER_RE = re.compile(INLINE_PLACEHOLDER % r'([0-9]+)') From 1620acb69b235196e368675a92350a114f8e3343 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Fri, 29 Sep 2023 16:33:16 -0400 Subject: [PATCH 53/61] lint cleanup --- markdown/core.py | 7 +++++-- markdown/test_tools.py | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/markdown/core.py b/markdown/core.py index 98ada12f7..5cf5d2399 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -23,7 +23,7 @@ import sys import logging import importlib -from typing import Any, TextIO +from typing import Any, TextIO, Callable from . import util from .preprocessors import build_preprocessors from .blockprocessors import build_block_parser @@ -34,6 +34,9 @@ from .serializers import to_html_string, to_xhtml_string from .util import BLOCK_LEVEL_ELEMENTS +if TYPE_CHECKING: # pragma: no cover + from xml.etree.ElementTree import Element + __all__ = ['Markdown', 'markdown', 'markdownFromFile'] @@ -73,7 +76,7 @@ class Markdown: doc_tag = "div" # Element used to wrap document - later removed - output_formats: dict[str, Callable[xml.etree.ElementTree.Element]] = { + output_formats: dict[str, Callable[Element]] = { 'html': to_html_string, 'xhtml': to_xhtml_string, } diff --git a/markdown/test_tools.py b/markdown/test_tools.py index 89575c8e4..895e44ec5 100644 --- a/markdown/test_tools.py +++ b/markdown/test_tools.py @@ -25,6 +25,7 @@ import sys import unittest import textwrap +from typing import Any from . import markdown, Markdown, util try: From 7e7242a96e3152bb3ab33687577507ecb20146f0 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Mon, 2 Oct 2023 09:06:41 -0400 Subject: [PATCH 54/61] ext config requires list not tuple --- markdown/core.py | 2 +- markdown/extensions/__init__.py | 4 +-- markdown/extensions/codehilite.py | 32 +++++++++---------- markdown/extensions/footnotes.py | 24 +++++++------- markdown/extensions/toc.py | 52 +++++++++++++++---------------- 5 files changed, 57 insertions(+), 57 deletions(-) diff --git a/markdown/core.py b/markdown/core.py index 5cf5d2399..51fe8ee88 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -23,7 +23,7 @@ import sys import logging import importlib -from typing import Any, TextIO, Callable +from typing import TYPE_CHECKING, Any, TextIO, Callable from . import util from .preprocessors import build_preprocessors from .blockprocessors import build_block_parser diff --git a/markdown/extensions/__init__.py b/markdown/extensions/__init__.py index 8d6375a59..36baf1f75 100644 --- a/markdown/extensions/__init__.py +++ b/markdown/extensions/__init__.py @@ -37,7 +37,7 @@ class Extension: """ Base class for extensions to subclass. """ - config: dict[str, tuple[Any, str]] = {} + config: dict[str, list[Any, str]] = {} """ Default configuration for an extension. @@ -45,7 +45,7 @@ class Extension: ``` python config = { - 'key': ('value', 'description') + 'key': ['value', 'description'] } ``` diff --git a/markdown/extensions/codehilite.py b/markdown/extensions/codehilite.py index d2f70b17f..f8d25b0fa 100644 --- a/markdown/extensions/codehilite.py +++ b/markdown/extensions/codehilite.py @@ -285,30 +285,30 @@ class CodeHiliteExtension(Extension): def __init__(self, **kwargs): # define default configs self.config = { - 'linenums': ( + 'linenums': [ None, "Use lines numbers. True|table|inline=yes, False=no, None=auto. Default: `None`." - ), - 'guess_lang': ( + ], + 'guess_lang': [ True, "Automatic language detection - Default: `True`." - ), - 'css_class': ( + ], + 'css_class': [ "codehilite", "Set class name for wrapper
- Default: `codehilite`." - ), - 'pygments_style': ( + ], + 'pygments_style': [ 'default', 'Pygments HTML Formatter Style (Colorscheme). Default: `default`.' - ), - 'noclasses': ( + ], + 'noclasses': [ False, 'Use inline styles instead of CSS classes - Default `False`.' - ), - 'use_pygments': ( + ], + 'use_pygments': [ True, 'Highlight code blocks with pygments. Disable if using a JavaScript library. Default: `True`.' - ), - 'lang_prefix': ( + ], + 'lang_prefix': [ 'language-', 'Prefix prepended to the language when `use_pygments` is false. Default: `language-`.' - ), - 'pygments_formatter': ( + ], + 'pygments_formatter': [ 'html', 'Use a specific formatter for Pygments highlighting. Default: `html`.' - ), + ], } """ Default configuration options. """ diff --git a/markdown/extensions/footnotes.py b/markdown/extensions/footnotes.py index c63f280bd..cf1ab43a6 100644 --- a/markdown/extensions/footnotes.py +++ b/markdown/extensions/footnotes.py @@ -42,26 +42,26 @@ def __init__(self, **kwargs): """ Setup configs. """ self.config = { - 'PLACE_MARKER': ( + 'PLACE_MARKER': [ '///Footnotes Go Here///', 'The text string that marks where the footnotes go' - ), - 'UNIQUE_IDS': ( + ], + 'UNIQUE_IDS': [ False, 'Avoid name collisions across multiple calls to `reset()`.' - ), - 'BACKLINK_TEXT': ( + ], + 'BACKLINK_TEXT': [ '↩', "The text string that links from the footnote to the reader's place." - ), - 'SUPERSCRIPT_TEXT': ( + ], + 'SUPERSCRIPT_TEXT': [ '{}', "The text string that links from the reader's place to the footnote." - ), - 'BACKLINK_TITLE': ( + ], + 'BACKLINK_TITLE': [ 'Jump back to footnote %d in the text', 'The text string used for the title HTML attribute of the backlink. ' '%d will be replaced by the footnote number.' - ), - 'SEPARATOR': ( + ], + 'SEPARATOR': [ ':', 'Footnote separator.' - ) + ] } """ Default configuration options. """ super().__init__(**kwargs) diff --git a/markdown/extensions/toc.py b/markdown/extensions/toc.py index b5e4ee01d..5490d0dd5 100644 --- a/markdown/extensions/toc.py +++ b/markdown/extensions/toc.py @@ -341,51 +341,51 @@ class TocExtension(Extension): def __init__(self, **kwargs): self.config = { - 'marker': ( + 'marker': [ '[TOC]', 'Text to find and replace with Table of Contents. Set to an empty string to disable. ' 'Default: `[TOC]`.' - ), - 'title': ( + ], + 'title': [ '', 'Title to insert into TOC `
`. Default: an empty string.' - ), - 'title_class': ( + ], + 'title_class': [ 'toctitle', 'CSS class used for the title. Default: `toctitle`.' - ), - 'toc_class': ( + ], + 'toc_class': [ 'toc', 'CSS class(es) used for the link. Default: `toclink`.' - ), - 'anchorlink': ( + ], + 'anchorlink': [ False, 'True if header should be a self link. Default: `False`.' - ), - 'anchorlink_class': ( + ], + 'anchorlink_class': [ 'toclink', 'CSS class(es) used for the link. Defaults: `toclink`.' - ), - 'permalink': ( + ], + 'permalink': [ 0, 'True or link text if a Sphinx-style permalink should be added. Default: `False`.' - ), - 'permalink_class': ( + ], + 'permalink_class': [ 'headerlink', 'CSS class(es) used for the link. Default: `headerlink`.' - ), - 'permalink_title': ( + ], + 'permalink_title': [ 'Permanent link', 'Title attribute of the permalink. Default: `Permanent link`.' - ), - 'permalink_leading': ( + ], + 'permalink_leading': [ False, 'True if permalinks should be placed at start of the header, rather than end. Default: False.' - ), - 'baselevel': ('1', 'Base level for headers. Default: `1`.'), - 'slugify': ( + ], + 'baselevel': ['1', 'Base level for headers. Default: `1`.'], + 'slugify': [ slugify, 'Function to generate anchors based on header text. Default: `slugify`.' - ), - 'separator': ('-', 'Word separator. Default: `-`.'), - 'toc_depth': ( + ], + 'separator': ['-', 'Word separator. Default: `-`.'], + 'toc_depth': [ 6, 'Define the range of section levels to include in the Table of Contents. A single integer ' '(b) defines the bottom section level (

..) only. A string consisting of two digits ' 'separated by a hyphen in between (`2-5`) defines the top (t) and the bottom (b) (..). ' 'Default: `6` (bottom).' - ), + ], } """ Default configuration options. """ From 29debb4abed66f9f1ae9a3ba9f94681926414120 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Tue, 3 Oct 2023 13:34:58 -0400 Subject: [PATCH 55/61] document all regexes for inlinepatterns --- markdown/inlinepatterns.py | 45 +++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py index 394186f69..806ecfe18 100644 --- a/markdown/inlinepatterns.py +++ b/markdown/inlinepatterns.py @@ -105,72 +105,73 @@ def build_inlinepatterns(md: Markdown, **kwargs: Any) -> util.Registry: # ----------------------------------------------------------------------------- NOIMG = r'(?)` or `[text](url "title")` LINK_RE = NOIMG + r'\[' +""" Match start of in-line link (`[text](url)` or `[text]()` or `[text](url "title")`). """ -# `![alttxt](http://x.com/)` or `![alttxt]()` IMAGE_LINK_RE = r'\!\[' +""" Match start of in-line image link (`![alttxt](url)` or `![alttxt]()`). """ -# `[Google][3]` REFERENCE_RE = LINK_RE +""" Match start of reference link (`[Label][3]`). """ -# `![alt text][2]` IMAGE_REFERENCE_RE = IMAGE_LINK_RE +""" Match start of image reference (`![alt text][2]`). """ -# stand-alone `*` or `_` NOT_STRONG_RE = r'((^|(?<=\s))(\*{1,3}|_{1,3})(?=\s|$))' +""" Match a stand-alone `*` or `_`. """ -# `` AUTOLINK_RE = r'<((?:[Ff]|[Hh][Tt])[Tt][Pp][Ss]?://[^<>]*)>' +""" Match an automatic link (``). """ -# `` AUTOMAIL_RE = r'<([^<> !]+@[^@<> ]+)>' +""" Match an automatic email link (``). """ -# `<...>` HTML_RE = r'(<(\/?[a-zA-Z][^<>@ ]*( [^<>]*)?|!--(?:(?!).)*--)>)' +""" Match an HTML tag (`<...>`). """ -# `&` (decimal) or `&` (hex) or `&` (named) ENTITY_RE = r'(&(?:\#[0-9]+|\#x[0-9a-fA-F]+|[a-zA-Z0-9]+);)' +""" Match an HTML entity (`&` (decimal) or `&` (hex) or `&` (named)). """ -# two spaces at end of line LINE_BREAK_RE = r' \n' +""" Match two spaces at end of line. """ def dequote(string: str) -> str: From c5d8c0dfc9ae0e1fdf4d716697dff57c2bb6b61a Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Wed, 4 Oct 2023 15:06:44 -0400 Subject: [PATCH 56/61] Add priority table to each build* function via an extention --- mkdocs.yml | 9 +++- scripts/griffe_deprecated.py | 41 ---------------- scripts/griffe_extensions.py | 91 ++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 42 deletions(-) delete mode 100644 scripts/griffe_deprecated.py create mode 100644 scripts/griffe_extensions.py diff --git a/mkdocs.yml b/mkdocs.yml index d30d853aa..159b7a839 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -83,7 +83,14 @@ plugins: docstring_style: google docstring_section_style: list extensions: - - scripts/griffe_deprecated.py + - scripts/griffe_extensions.py:DeprecatedExtension + - scripts/griffe_extensions.py:PriorityTableExtension: + paths: + - markdown.preprocessors.build_preprocessors + - markdown.blockprocessors.build_block_parser + - markdown.treeprocessors.build_treeprocessors + - markdown.inlinepatterns.build_inlinepatterns + - markdown.postprocessors.build_postprocessors filters: ["!^_"] group_by_category: false heading_level: 1 diff --git a/scripts/griffe_deprecated.py b/scripts/griffe_deprecated.py deleted file mode 100644 index f89382dfa..000000000 --- a/scripts/griffe_deprecated.py +++ /dev/null @@ -1,41 +0,0 @@ -"""Griffe extension for `@markdown.util.deprecated` decorator support.""" - -from __future__ import annotations - -import ast -from typing import TYPE_CHECKING - -from griffe import Docstring, Extension -from griffe.docstrings.dataclasses import DocstringSectionAdmonition - -if TYPE_CHECKING: - from griffe import Class, Function, ObjectNode - - -def _deprecated(obj: Class | Function) -> str | None: - for decorator in obj.decorators: - if decorator.callable_path == "markdown.util.deprecated": - return ast.literal_eval(str(decorator.value.arguments[0])) - return None - - -class DeprecatedExtension(Extension): - """Griffe extension for `@markdown.util.deprecated` decorator support.""" - - def _insert_message(self, obj: Function | Class, message: str) -> None: - if not obj.docstring: - obj.docstring = Docstring("", parent=obj) - sections = obj.docstring.parsed - sections.insert(0, DocstringSectionAdmonition(kind="warning", text=message, title="Deprecated")) - - def on_class_instance(self, node: ast.AST | ObjectNode, cls: Class) -> None: # noqa: ARG002 - """Add section to docstrings of deprecated classes.""" - if message := _deprecated(cls): - self._insert_message(cls, message) - cls.labels.add("deprecated") - - def on_function_instance(self, node: ast.AST | ObjectNode, func: Function) -> None: # noqa: ARG002 - """Add section to docstrings of deprecated functions.""" - if message := _deprecated(func): - self._insert_message(func, message) - func.labels.add("deprecated") diff --git a/scripts/griffe_extensions.py b/scripts/griffe_extensions.py new file mode 100644 index 000000000..5318e10db --- /dev/null +++ b/scripts/griffe_extensions.py @@ -0,0 +1,91 @@ +"""Griffe extensions.""" + +from __future__ import annotations + +import ast +from typing import TYPE_CHECKING + +from griffe import Docstring, Extension +from griffe.docstrings.dataclasses import DocstringSectionAdmonition, DocstringSectionText + +if TYPE_CHECKING: + from griffe import Class, Function, ObjectNode + + +def _deprecated(obj: Class | Function) -> str | None: + for decorator in obj.decorators: + if decorator.callable_path == "markdown.util.deprecated": + return ast.literal_eval(str(decorator.value.arguments[0])) + return None + + +class DeprecatedExtension(Extension): + """Griffe extension for `@markdown.util.deprecated` decorator support.""" + + def _insert_message(self, obj: Function | Class, message: str) -> None: + if not obj.docstring: + obj.docstring = Docstring("", parent=obj) + sections = obj.docstring.parsed + sections.insert(0, DocstringSectionAdmonition(kind="warning", text=message, title="Deprecated")) + + def on_class_instance(self, node: ast.AST | ObjectNode, cls: Class) -> None: # noqa: ARG002 + """Add section to docstrings of deprecated classes.""" + if message := _deprecated(cls): + self._insert_message(cls, message) + cls.labels.add("deprecated") + + def on_function_instance(self, node: ast.AST | ObjectNode, func: Function) -> None: # noqa: ARG002 + """Add section to docstrings of deprecated functions.""" + if message := _deprecated(func): + self._insert_message(func, message) + func.labels.add("deprecated") + + +class PriorityTableExtension(Extension): + """ Griffe extension to insert a table of processor priority in specified functions. """ + + def __init__(self, paths: list[str] | None = None) -> None: + super().__init__() + self.paths = paths + + def linked_obj(self, value: str, path: str) -> str: + """ Wrap object name in reference link. """ + return f'[{value}][{path}.{value}]' + + def on_function_instance(self, node: ast.AST | ObjectNode, func: Function) -> None: # noqa: ARG002 + """Add table to specified function docstrings.""" + if self.paths and func.path not in self.paths: + return # skip objects that were not selected + + # Table header + data = [ + 'Class Instance | Name | Priority', + '-------------- | ---- | :------:' + ] + + # Extract table body from source code of function. + for obj in node.body: + # Extract the arguments passed to `util.Registry.register`. + if isinstance(obj, ast.Expr) and isinstance(obj.value, ast.Call) and obj.value.func.attr == 'register': + _args = obj.value.args + cls = self.linked_obj(_args[0].func.id, func.path.rsplit('.', 1)[0]) + name = _args[1].value + priority = str(_args[2].value) + if func.name == ('build_inlinepatterns'): + # Include Pattern: first arg passed to class + if isinstance(_args[0].args[0], ast.Constant): + # Pattern is a string + value = f'`"{_args[0].args[0].value}"`' + else: + # Pattern is a variable + value = self.linked_obj(_args[0].args[0].id, func.path.rsplit('.', 1)[0]) + cls = f'{cls}({value})' + data.append(f'{cls} | {name} | {priority}') + + table = "\n".join(data) + + # Add to docstring. + if not func.docstring: + func.docstring = Docstring("", parent=func) + sections = func.docstring.parsed + sections.append(DocstringSectionText(table, title="Priority Table")) From dea11582001953bfe5919cb756b63f92dc3994c6 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Wed, 4 Oct 2023 15:45:17 -0400 Subject: [PATCH 57/61] wrap names in code spans --- scripts/griffe_extensions.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/scripts/griffe_extensions.py b/scripts/griffe_extensions.py index 5318e10db..7dafb7f59 100644 --- a/scripts/griffe_extensions.py +++ b/scripts/griffe_extensions.py @@ -4,6 +4,7 @@ import ast from typing import TYPE_CHECKING +import textwrap from griffe import Docstring, Extension from griffe.docstrings.dataclasses import DocstringSectionAdmonition, DocstringSectionText @@ -80,12 +81,17 @@ def on_function_instance(self, node: ast.AST | ObjectNode, func: Function) -> No # Pattern is a variable value = self.linked_obj(_args[0].args[0].id, func.path.rsplit('.', 1)[0]) cls = f'{cls}({value})' - data.append(f'{cls} | {name} | {priority}') + data.append(f'{cls} | `{name}` | {priority}') - table = "\n".join(data) + table = '\n'.join(data) + body = ( + "Return a [`Registry`][markdown.util.Registry] instance which contains the following collection " + "of classes with their assigned names and priorities.\n\n" + f"{table}" + ) # Add to docstring. if not func.docstring: func.docstring = Docstring("", parent=func) sections = func.docstring.parsed - sections.append(DocstringSectionText(table, title="Priority Table")) + sections.append(DocstringSectionText(body, title="Priority Table")) From cb78d4f2d3c6250b1033b4bc83c328a4be767f6d Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Wed, 4 Oct 2023 16:03:36 -0400 Subject: [PATCH 58/61] Some tweaks to styling --- docs/mkdocstrings.css | 6 ++++++ scripts/griffe_extensions.py | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/mkdocstrings.css b/docs/mkdocstrings.css index 88b6c65ee..110f52f4a 100644 --- a/docs/mkdocstrings.css +++ b/docs/mkdocstrings.css @@ -58,6 +58,12 @@ code { text-shadow: none; } +/* Code spans in tables. */ + +table code { + background-color: transparent !important; +} + /* Customize symbol names. */ code.doc-symbol-attribute::after { content: "Attr"; diff --git a/scripts/griffe_extensions.py b/scripts/griffe_extensions.py index 7dafb7f59..cc59eaf9d 100644 --- a/scripts/griffe_extensions.py +++ b/scripts/griffe_extensions.py @@ -51,7 +51,7 @@ def __init__(self, paths: list[str] | None = None) -> None: def linked_obj(self, value: str, path: str) -> str: """ Wrap object name in reference link. """ - return f'[{value}][{path}.{value}]' + return f'[`{value}`][{path}.{value}]' def on_function_instance(self, node: ast.AST | ObjectNode, func: Function) -> None: # noqa: ARG002 """Add table to specified function docstrings.""" @@ -81,7 +81,7 @@ def on_function_instance(self, node: ast.AST | ObjectNode, func: Function) -> No # Pattern is a variable value = self.linked_obj(_args[0].args[0].id, func.path.rsplit('.', 1)[0]) cls = f'{cls}({value})' - data.append(f'{cls} | `{name}` | {priority}') + data.append(f'{cls} | `{name}` | `{priority}`') table = '\n'.join(data) body = ( From 675858a372f1e54c03cb31ae4de8324158b7579a Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Thu, 5 Oct 2023 13:33:45 -0400 Subject: [PATCH 59/61] build_block_parser returns a BlockParser not a Registry --- markdown/blockprocessors.py | 2 +- scripts/griffe_extensions.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/markdown/blockprocessors.py b/markdown/blockprocessors.py index 9f9951bd6..7a3688c2b 100644 --- a/markdown/blockprocessors.py +++ b/markdown/blockprocessors.py @@ -39,7 +39,7 @@ logger = logging.getLogger('MARKDOWN') -def build_block_parser(md: Markdown, **kwargs: Any) -> util.Registry: +def build_block_parser(md: Markdown, **kwargs: Any) -> BlockParser: """ Build the default block parser used by Markdown. """ parser = BlockParser(md) parser.blockprocessors.register(EmptyBlockProcessor(parser), 'empty', 100) diff --git a/scripts/griffe_extensions.py b/scripts/griffe_extensions.py index cc59eaf9d..551687fde 100644 --- a/scripts/griffe_extensions.py +++ b/scripts/griffe_extensions.py @@ -85,8 +85,8 @@ def on_function_instance(self, node: ast.AST | ObjectNode, func: Function) -> No table = '\n'.join(data) body = ( - "Return a [`Registry`][markdown.util.Registry] instance which contains the following collection " - "of classes with their assigned names and priorities.\n\n" + f"Return a [`{func.returns.canonical_name}`][{func.returns.canonical_path}] instance which contains " + "the following collection of classes with their assigned names and priorities.\n\n" f"{table}" ) From 59c1299ab2fbddd6e5323d43d655cdbe7ed46c55 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Thu, 5 Oct 2023 15:49:05 -0400 Subject: [PATCH 60/61] finish documenting inlinepatterns --- markdown/inlinepatterns.py | 145 +++++++++++++++++++++++++------------ 1 file changed, 97 insertions(+), 48 deletions(-) diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py index 806ecfe18..7df7939f6 100644 --- a/markdown/inlinepatterns.py +++ b/markdown/inlinepatterns.py @@ -25,8 +25,8 @@ The new `InlineProcessor` provides two major enhancements to `Patterns`: 1. Inline Processors no longer need to match the entire block, so regular expressions no longer need to start with - `r'^(.*?)'` and end with `r'(.*?)%'`. This runs faster. The returned [match object][] will only contain what is - explicitly matched in the pattern, and extension pattern groups now start with `m.group(1)`. + `r'^(.*?)'` and end with `r'(.*?)%'`. This runs faster. The returned [`Match`][re.Match] object will only contain + what is explicitly matched in the pattern, and extension pattern groups now start with `m.group(1)`. 2. The `handleMatch` method now takes an additional input called `data`, which is the entire block under analysis, not just what is matched with the specified pattern. The method now returns the element *and* the indexes relative @@ -36,25 +36,6 @@ This allows handling of more complex constructs than regular expressions can handle, e.g., matching nested brackets, and explicit control of the span "consumed" by the processor. -The order in which processors and/or patterns are applied is very -important - e.g. if we first replace `http://.../` links with `` tags -and _then_ try to replace inline html, we would end up with a mess. -So, we apply the expressions in the following order: - -* escape and backticks have to go before everything else, so - that we can preempt any markdown patterns by escaping them; - -* then we handle auto-links (must be done before inline html); - -* then we handle inline HTML. At this point we will simply - replace all inline HTML strings with a placeholder and add - the actual HTML to a hash; - -* then inline images (must be done before links); - -* then bracketed links, first regular then reference-style; - -* finally we apply strong and emphasis. """ from __future__ import annotations @@ -74,7 +55,24 @@ def build_inlinepatterns(md: Markdown, **kwargs: Any) -> util.Registry: - """ Build the default set of inline patterns for Markdown. """ + """ + Build the default set of inline patterns for Markdown. + + The order in which processors and/or patterns are applied is very important - e.g. if we first replace + `http://.../` links with `` tags and _then_ try to replace inline HTML, we would end up with a mess. So, we + apply the expressions in the following order: + + * backticks and escaped characters have to be handled before everything else so that we can preempt any markdown + patterns by escaping them; + + * then we handle the various types of links (auto-links must be handled before inline HTML); + + * then we handle inline HTML. At this point we will simply replace all inline HTML strings with a placeholder + and add the actual HTML to a stash; + + * finally we apply strong, emphasis, etc. + + """ inlinePatterns = util.Registry() inlinePatterns.register(BacktickInlineProcessor(BACKTICK_RE), 'backtick', 190) inlinePatterns.register(EscapeInlineProcessor(ESCAPE_RE, md), 'escape', 180) @@ -323,21 +321,31 @@ def handleMatch(self, m: Match, data: str) -> tuple[etree.Element | str | None, class SimpleTextPattern(Pattern): # pragma: no cover - """ Return a simple text of group(2) of a Pattern. """ - def handleMatch(self, m): + """ Return a simple text of `group(2)` of a Pattern. """ + def handleMatch(self, m: Match) -> str: + """ Return string content of `group(2)` of a matching pattern. """ return m.group(2) class SimpleTextInlineProcessor(InlineProcessor): - """ Return a simple text of group(1) of a Pattern. """ - def handleMatch(self, m, data): + """ Return a simple text of `group(1)` of a Pattern. """ + def handleMatch(self, m: Match, data: str) -> tuple[str, int, int]: + """ Return string content of `group(1)` of a matching pattern. """ return m.group(1), m.start(0), m.end(0) class EscapeInlineProcessor(InlineProcessor): """ Return an escaped character. """ - def handleMatch(self, m, data): + def handleMatch(self, m: Match, data: str) -> tuple[str | None, int, int]: + """ + If the character matched by `group(1)` of a pattern is in [`ESCAPED_CHARS`][markdown.Markdown.ESCAPED_CHARS] + then return the integer representing the character's Unicode code point (as returned by [`ord`][]) wrapped + in [`util.STX`][markdown.util.STX] and [`util.ETX`][markdown.util.ETX]. + + If the matched character is not in [`ESCAPED_CHARS`][markdown.Markdown.ESCAPED_CHARS], then return `None`. + """ + char = m.group(1) if char in self.md.ESCAPED_CHARS: return '{}{}{}'.format(util.STX, ord(char), util.ETX), m.start(0), m.end(0) @@ -347,7 +355,7 @@ def handleMatch(self, m, data): class SimpleTagPattern(Pattern): # pragma: no cover """ - Return element of type `tag` with a text attribute of group(3) + Return element of type `tag` with a text attribute of `group(3)` of a Pattern. """ @@ -364,7 +372,11 @@ def __init__(self, pattern: str, tag: str): self.tag = tag """ The tag of the rendered element. """ - def handleMatch(self, m): + def handleMatch(self, m: Match) -> etree.Element: + """ + Return [`Element`][xml.etree.ElementTree.Element] of type `tag` with the string in `group(3)` of a + matching pattern as the Element's text. + """ el = etree.Element(self.tag) el.text = m.group(3) return el @@ -372,7 +384,7 @@ def handleMatch(self, m): class SimpleTagInlineProcessor(InlineProcessor): """ - Return element of type `tag` with a text attribute of group(2) + Return element of type `tag` with a text attribute of `group(2)` of a Pattern. """ @@ -389,7 +401,11 @@ def __init__(self, pattern: str, tag: str): self.tag = tag """ The tag of the rendered element. """ - def handleMatch(self, m, data): # pragma: no cover + def handleMatch(self, m: Match, data: str) -> tuple[etree.Element, int, int]: # pragma: no cover + """ + Return [`Element`][xml.etree.ElementTree.Element] of type `tag` with the string in `group(2)` of a + matching pattern as the Element's text. + """ el = etree.Element(self.tag) el.text = m.group(2) return el, m.start(0), m.end(0) @@ -397,13 +413,15 @@ def handleMatch(self, m, data): # pragma: no cover class SubstituteTagPattern(SimpleTagPattern): # pragma: no cover """ Return an element of type `tag` with no children. """ - def handleMatch(self, m): + def handleMatch(self, m: Match) -> etree.Element: + """ Return empty [`Element`][xml.etree.ElementTree.Element] of type `tag`. """ return etree.Element(self.tag) class SubstituteTagInlineProcessor(SimpleTagInlineProcessor): """ Return an element of type `tag` with no children. """ - def handleMatch(self, m, data): + def handleMatch(self, m: Match, data: str) -> tuple[etree.Element, int, int]: + """ Return empty [`Element`][xml.etree.ElementTree.Element] of type `tag`. """ return etree.Element(self.tag), m.start(0), m.end(0) @@ -415,7 +433,15 @@ def __init__(self, pattern): self.tag = 'code' """ The tag of the rendered element. """ - def handleMatch(self, m, data): + def handleMatch(self, m: Match, data: str) -> tuple[etree.Element | str, int, int]: + """ + If the match contains `group(3)` of a pattern, then return a `code` + [`Element`][xml.etree.ElementTree.Element] which contains HTML escaped text (with + [`code_escape`][markdown.util.code_escape]) as an [`AtomicString`][markdown.util.AtomicString]. + + If the match does not contain `group(3)` then return the text of `group(1)` backslash escaped. + + """ if m.group(3): el = etree.Element(self.tag) el.text = util.AtomicString(util.code_escape(m.group(3).strip())) @@ -430,7 +456,12 @@ class DoubleTagPattern(SimpleTagPattern): # pragma: no cover Useful for strong emphasis etc. """ - def handleMatch(self, m): + def handleMatch(self, m: Match) -> etree.Element: + """ + Return [`Element`][xml.etree.ElementTree.Element] in following format: + `group(3)group(4)` where `group(4)` is optional. + + """ tag1, tag2 = self.tag.split(",") el1 = etree.Element(tag1) el2 = etree.SubElement(el1, tag2) @@ -446,7 +477,12 @@ class DoubleTagInlineProcessor(SimpleTagInlineProcessor): Useful for strong emphasis etc. """ - def handleMatch(self, m, data): # pragma: no cover + def handleMatch(self, m: Match, data: str) -> tuple[etree.Element, int, int]: # pragma: no cover + """ + Return [`Element`][xml.etree.ElementTree.Element] in following format: + `group(2)group(3)` where `group(3)` is optional. + + """ tag1, tag2 = self.tag.split(",") el1 = etree.Element(tag1) el2 = etree.SubElement(el1, tag2) @@ -458,7 +494,8 @@ def handleMatch(self, m, data): # pragma: no cover class HtmlInlineProcessor(InlineProcessor): """ Store raw inline html and return a placeholder. """ - def handleMatch(self, m, data): + def handleMatch(self, m: Match, data: str) -> tuple[str, int, int]: + """ Store the text of `group(1)` of a pattern and return a placeholder string. """ rawhtml = self.backslash_unescape(self.unescape(m.group(1))) place_holder = self.md.htmlStash.store(rawhtml) return place_holder, m.start(0), m.end(0) @@ -504,6 +541,7 @@ class AsteriskProcessor(InlineProcessor): EmStrongItem(re.compile(STRONG_RE, re.DOTALL | re.UNICODE), 'single', 'strong'), EmStrongItem(re.compile(EMPHASIS_RE, re.DOTALL | re.UNICODE), 'single', 'em') ] + """ The various strong and emphasis patterns handled by this processor. """ def build_single(self, m, tag, idx): """Return single tag.""" @@ -613,7 +651,7 @@ def build_element(self, m, builder, tags, index): else: return self.build_single(m, tags, index) - def handleMatch(self, m, data): + def handleMatch(self, m: Match, data: str) -> tuple[etree.Element, int, int]: """Parse patterns.""" el = None @@ -640,6 +678,7 @@ class UnderscoreProcessor(AsteriskProcessor): EmStrongItem(re.compile(SMART_STRONG_RE, re.DOTALL | re.UNICODE), 'single', 'strong'), EmStrongItem(re.compile(SMART_EMPHASIS_RE, re.DOTALL | re.UNICODE), 'single', 'em') ] + """ The various strong and emphasis patterns handled by this processor. """ class LinkInlineProcessor(InlineProcessor): @@ -647,7 +686,8 @@ class LinkInlineProcessor(InlineProcessor): RE_LINK = re.compile(r'''\(\s*(?:(<[^<>]*>)\s*(?:('[^']*'|"[^"]*")\s*)?\))?''', re.DOTALL | re.UNICODE) RE_TITLE_CLEAN = re.compile(r'\s') - def handleMatch(self, m, data): + def handleMatch(self, m: Match, data: str) -> tuple[etree.Element | None, int | None, int | None]: + """ Return an `a` [`Element`][xml.etree.ElementTree.Element] or `(None, None, None)`. """ text, index, handled = self.getText(data, m.end(0)) if not handled: @@ -806,7 +846,8 @@ def getText(self, data, index): class ImageInlineProcessor(LinkInlineProcessor): """ Return a `img` element from the given match. """ - def handleMatch(self, m, data): + def handleMatch(self, m: Match, data: str) -> tuple[etree.Element | None, int | None, int | None]: + """ Return an `img` [`Element`][xml.etree.ElementTree.Element] or `(None, None, None)`. """ text, index, handled = self.getText(data, m.end(0)) if not handled: return None, None, None @@ -832,7 +873,11 @@ class ReferenceInlineProcessor(LinkInlineProcessor): RE_LINK = re.compile(r'\s?\[([^\]]*)\]', re.DOTALL | re.UNICODE) - def handleMatch(self, m, data): + def handleMatch(self, m: Match, data: str) -> tuple[etree.Element | None, int | None, int | None]: + """ + Return [`Element`][xml.etree.ElementTree.Element] returned by `makeTag` method or `(None, None, None)`. + + """ text, index, handled = self.getText(data, m.end(0)) if not handled: return None, None, None @@ -866,7 +911,8 @@ def evalId(self, data, index, text): id = text.lower() return id, end, True - def makeTag(self, href, title, text): + def makeTag(self, href: str, title: str, text: str) -> etree.Element: + """ Return an `a` [`Element`][xml.etree.ElementTree.Element]. """ el = etree.Element('a') el.set('href', href) @@ -878,16 +924,17 @@ def makeTag(self, href, title, text): class ShortReferenceInlineProcessor(ReferenceInlineProcessor): - """Short form of reference: [google]. """ + """Short form of reference: `[google]`. """ def evalId(self, data, index, text): - """Evaluate the id from of [ref] """ + """Evaluate the id of `[ref]`. """ return text.lower(), index, True class ImageReferenceInlineProcessor(ReferenceInlineProcessor): """ Match to a stored reference and return `img` element. """ - def makeTag(self, href, title, text): + def makeTag(self, href: str, title: str, text: str) -> etree.Element: + """ Return an `img` [`Element`][xml.etree.ElementTree.Element]. """ el = etree.Element("img") el.set("src", href) if title: @@ -899,14 +946,15 @@ def makeTag(self, href, title, text): class ShortImageReferenceInlineProcessor(ImageReferenceInlineProcessor): """ Short form of image reference: `![ref]`. """ def evalId(self, data, index, text): - """Evaluate the id from of [ref] """ + """Evaluate the id of `[ref]`. """ return text.lower(), index, True class AutolinkInlineProcessor(InlineProcessor): """ Return a link Element given an auto-link (``). """ - def handleMatch(self, m, data): + def handleMatch(self, m: Match, data: str) -> tuple[etree.Element, int, int]: + """ Return an `a` [`Element`][xml.etree.ElementTree.Element] of `group(1)`. """ el = etree.Element("a") el.set('href', self.unescape(m.group(1))) el.text = util.AtomicString(m.group(1)) @@ -917,7 +965,8 @@ class AutomailInlineProcessor(InlineProcessor): """ Return a `mailto` link Element given an auto-mail link (``). """ - def handleMatch(self, m, data): + def handleMatch(self, m: Match, data: str) -> tuple[etree.Element, int, int]: + """ Return an [`Element`][xml.etree.ElementTree.Element] containing a `mailto` link of `group(1)`. """ el = etree.Element('a') email = self.unescape(m.group(1)) if email.startswith("mailto:"): From c9bbb682a51ff511e57def54a7b77beadae2fb8d Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Fri, 6 Oct 2023 14:11:35 -0400 Subject: [PATCH 61/61] Add links to source on Github --- docs/mkdocstrings.css | 21 ++++++++++++++++++++- docs/templates/python/nature/attribute.html | 1 + docs/templates/python/nature/class.html | 6 ++++++ docs/templates/python/nature/function.html | 6 ++++++ docs/templates/python/nature/module.html | 6 ++++++ mkdocs.yml | 4 ++++ 6 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 docs/templates/python/nature/class.html create mode 100644 docs/templates/python/nature/function.html create mode 100644 docs/templates/python/nature/module.html diff --git a/docs/mkdocstrings.css b/docs/mkdocstrings.css index 110f52f4a..efc62f485 100644 --- a/docs/mkdocstrings.css +++ b/docs/mkdocstrings.css @@ -40,7 +40,8 @@ a.autorefs:hover code { .doc-label { border-radius: 15px; padding: 2px 8px; - background-color: #ddd; + background-color: #f2f2f3; + text-wrap: nowrap; } .doc-label code { @@ -64,6 +65,24 @@ table code { background-color: transparent !important; } +/* Style source links */ +a.doc-source-link { + position: relative; + float: right; + border: 1px #005B81 solid; + margin: 0 5px; + padding: 0 5px; + font-weight: normal; + text-shadow: none; + background-color: #f2f2f3; + font-size: 1rem; +} + +a.doc-source-link:hover { + text-decoration: none; + border-color: #E32E00; +} + /* Customize symbol names. */ code.doc-symbol-attribute::after { content: "Attr"; diff --git a/docs/templates/python/nature/attribute.html b/docs/templates/python/nature/attribute.html index 267c5ce31..abef8a077 100644 --- a/docs/templates/python/nature/attribute.html +++ b/docs/templates/python/nature/attribute.html @@ -1,6 +1,7 @@ {% extends "_base/attribute.html" %} {% block heading scoped %} + ‹› {%+ filter highlight(language="python", inline=True) %} {{ attribute_name }}{% if attribute.annotation %}: {{ attribute.annotation }}{% endif %} {% endfilter %} diff --git a/docs/templates/python/nature/class.html b/docs/templates/python/nature/class.html new file mode 100644 index 000000000..7193c3419 --- /dev/null +++ b/docs/templates/python/nature/class.html @@ -0,0 +1,6 @@ +{% extends "_base/class.html" %} + +{% block heading scoped %} + ‹› + {{ super() }} +{% endblock heading %} diff --git a/docs/templates/python/nature/function.html b/docs/templates/python/nature/function.html new file mode 100644 index 000000000..82a696a34 --- /dev/null +++ b/docs/templates/python/nature/function.html @@ -0,0 +1,6 @@ +{% extends "_base/function.html" %} + +{% block heading scoped %} + ‹› + {{ super() }} +{% endblock heading %} diff --git a/docs/templates/python/nature/module.html b/docs/templates/python/nature/module.html new file mode 100644 index 000000000..4d758a388 --- /dev/null +++ b/docs/templates/python/nature/module.html @@ -0,0 +1,6 @@ +{% extends "_base/module.html" %} + +{% block heading scoped %} + ‹› + {{ super() }} +{% endblock heading %} diff --git a/mkdocs.yml b/mkdocs.yml index 159b7a839..1db47dc59 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -106,3 +106,7 @@ plugins: show_symbol_type_toc: true signature_crossrefs: false summary: true + source: + repo: https://github.com/Python-Markdown/markdown + tag: !!python/name:markdown.__version__ + title: "View source code on GitHub."