From d951114dea51f3309bc2a98003e364c9d9dce36a Mon Sep 17 00:00:00 2001 From: Semyon Moroz Date: Mon, 7 Jul 2025 13:16:22 +0000 Subject: [PATCH] [Markdown] Add missing stubs (#14285) --- stubs/Markdown/@tests/stubtest_allowlist.txt | 1 + stubs/Markdown/METADATA.toml | 4 --- stubs/Markdown/markdown/__main__.pyi | 10 +++++++ stubs/Markdown/markdown/core.pyi | 5 ++++ stubs/Markdown/markdown/extensions/abbr.pyi | 1 + .../markdown/extensions/md_in_html.pyi | 28 ++++++++++++++++- stubs/Markdown/markdown/extensions/meta.pyi | 2 ++ stubs/Markdown/markdown/extensions/smarty.pyi | 2 ++ stubs/Markdown/markdown/htmlparser.pyi | 28 +++++++++++++++++ stubs/Markdown/markdown/postprocessors.pyi | 13 ++++++++ stubs/Markdown/markdown/serializers.pyi | 5 ++++ stubs/Markdown/markdown/test_tools.pyi | 30 +++++++++++++++++++ 12 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 stubs/Markdown/markdown/__main__.pyi create mode 100644 stubs/Markdown/markdown/htmlparser.pyi create mode 100644 stubs/Markdown/markdown/test_tools.pyi diff --git a/stubs/Markdown/@tests/stubtest_allowlist.txt b/stubs/Markdown/@tests/stubtest_allowlist.txt index e7cd73098..1523b9aa7 100644 --- a/stubs/Markdown/@tests/stubtest_allowlist.txt +++ b/stubs/Markdown/@tests/stubtest_allowlist.txt @@ -1,3 +1,4 @@ # Deprecated types are infered as functions: markdown.extensions.abbr.AbbrPreprocessor markdown.extensions.abbr.AbbrInlineProcessor +markdown.postprocessors.UnescapePostprocessor diff --git a/stubs/Markdown/METADATA.toml b/stubs/Markdown/METADATA.toml index 68fead4ec..01a67268e 100644 --- a/stubs/Markdown/METADATA.toml +++ b/stubs/Markdown/METADATA.toml @@ -1,6 +1,2 @@ version = "3.8.*" upstream_repository = "https://github.com/Python-Markdown/markdown" -partial_stub = true - -[tool.stubtest] -ignore_missing_stub = true diff --git a/stubs/Markdown/markdown/__main__.pyi b/stubs/Markdown/markdown/__main__.pyi new file mode 100644 index 000000000..ca90cb1fa --- /dev/null +++ b/stubs/Markdown/markdown/__main__.pyi @@ -0,0 +1,10 @@ +import optparse +from logging import Logger +from typing import Any + +logger: Logger + +def parse_options( + args: list[str] | None = None, values: optparse.Values | None = None +) -> tuple[dict[str, Any], Any]: ... # first item is opts dict, second item is Values.verbose field +def run() -> None: ... diff --git a/stubs/Markdown/markdown/core.pyi b/stubs/Markdown/markdown/core.pyi index 48d3bac6d..80eacd4b2 100644 --- a/stubs/Markdown/markdown/core.pyi +++ b/stubs/Markdown/markdown/core.pyi @@ -1,5 +1,6 @@ from codecs import _ReadableStream, _WritableStream from collections.abc import Callable, Mapping, Sequence +from logging import Logger from typing import Any, ClassVar, Literal from typing_extensions import Self from xml.etree.ElementTree import Element @@ -8,6 +9,10 @@ from . import blockparser, inlinepatterns, postprocessors, preprocessors, treepr from .extensions import Extension from .util import HtmlStash, Registry +__all__ = ["Markdown", "markdown", "markdownFromFile"] + +logger: Logger + class Markdown: preprocessors: Registry[preprocessors.Preprocessor] inlinePatterns: Registry[inlinepatterns.Pattern] diff --git a/stubs/Markdown/markdown/extensions/abbr.pyi b/stubs/Markdown/markdown/extensions/abbr.pyi index ace06e144..810ab6016 100644 --- a/stubs/Markdown/markdown/extensions/abbr.pyi +++ b/stubs/Markdown/markdown/extensions/abbr.pyi @@ -19,6 +19,7 @@ class AbbrTreeprocessor(Treeprocessor): RE: Pattern[str] | None abbrs: dict[str, str] def __init__(self, md: Markdown | None = None, abbrs: dict[str, str] | None = None) -> None: ... + def create_element(self, title: str, text: str, tail: str) -> Element: ... def iter_element(self, el: Element, parent: Element | None = None) -> None: ... # Techinically it is the same type as `AbbrPreprocessor` just not deprecated. diff --git a/stubs/Markdown/markdown/extensions/md_in_html.pyi b/stubs/Markdown/markdown/extensions/md_in_html.pyi index b1ea12305..29cb8f631 100644 --- a/stubs/Markdown/markdown/extensions/md_in_html.pyi +++ b/stubs/Markdown/markdown/extensions/md_in_html.pyi @@ -1,8 +1,34 @@ -from xml.etree.ElementTree import Element +from collections.abc import Iterable, Mapping +from typing import Literal +from xml.etree.ElementTree import Element, TreeBuilder from markdown.blockprocessors import BlockProcessor from markdown.extensions import Extension +from markdown.htmlparser import HTMLExtractor from markdown.postprocessors import RawHtmlPostprocessor +from markdown.preprocessors import Preprocessor + +class HTMLExtractorExtra(HTMLExtractor): + block_level_tags: set[str] + span_tags: set[str] + raw_tags: set[str] + block_tags: set[str] + span_and_blocks_tags: set[str] + mdstack: list[str] + treebuilder: TreeBuilder + mdstate: list[Literal["block", "span", "off"] | None] + mdstarted: list[bool] + def get_element(self) -> Element: ... + def get_state(self, tag: str, attrs: Mapping[str, str]) -> Literal["block", "span", "off"] | None: ... + def handle_starttag(self, tag: str, attrs: Iterable[tuple[str, str | None]]) -> None: ... + def handle_endtag(self, tag: str) -> None: ... + def handle_startendtag(self, tag: str, attrs: Iterable[tuple[str, str | None]]) -> None: ... + def handle_data(self, data: str) -> None: ... + def handle_empty_tag(self, data: str, is_block: bool) -> None: ... + def parse_pi(self, i: int) -> int: ... + def parse_html_declaration(self, i: int) -> int: ... + +class HtmlBlockPreprocessor(Preprocessor): ... class MarkdownInHtmlProcessor(BlockProcessor): def parse_element_content(self, element: Element) -> None: ... diff --git a/stubs/Markdown/markdown/extensions/meta.pyi b/stubs/Markdown/markdown/extensions/meta.pyi index b0bead44a..d6a7f42a8 100644 --- a/stubs/Markdown/markdown/extensions/meta.pyi +++ b/stubs/Markdown/markdown/extensions/meta.pyi @@ -1,9 +1,11 @@ +from logging import Logger from re import Pattern from markdown.core import Markdown from markdown.extensions import Extension from markdown.preprocessors import Preprocessor +log: Logger META_RE: Pattern[str] META_MORE_RE: Pattern[str] BEGIN_RE: Pattern[str] diff --git a/stubs/Markdown/markdown/extensions/smarty.pyi b/stubs/Markdown/markdown/extensions/smarty.pyi index 9a0004630..eca70b7b7 100644 --- a/stubs/Markdown/markdown/extensions/smarty.pyi +++ b/stubs/Markdown/markdown/extensions/smarty.pyi @@ -15,6 +15,8 @@ singleQuoteStartRe: str doubleQuoteStartRe: str doubleQuoteSetsRe: str singleQuoteSetsRe: str +doubleQuoteSetsRe2: str +singleQuoteSetsRe2: str decadeAbbrRe: str openingDoubleQuotesRegex: str closingDoubleQuotesRegex: str diff --git a/stubs/Markdown/markdown/htmlparser.pyi b/stubs/Markdown/markdown/htmlparser.pyi new file mode 100644 index 000000000..c9319565b --- /dev/null +++ b/stubs/Markdown/markdown/htmlparser.pyi @@ -0,0 +1,28 @@ +import html.parser as htmlparser +import re +from _frozen_importlib import ModuleSpec +from collections.abc import Sequence + +from markdown import Markdown + +spec: ModuleSpec +blank_line_re: re.Pattern[str] + +class HTMLExtractor(htmlparser.HTMLParser): + empty_tags: set[str] + lineno_start_cache: list[int] + md: Markdown + def __init__(self, md: Markdown, *args, **kwargs): ... + inraw: bool + intail: bool + stack: list[str] + cleandoc: list[str] + @property + def line_offset(self) -> int: ... + def at_line_start(self) -> bool: ... + def get_endtag_text(self, tag: str) -> str: ... + def handle_starttag(self, tag: str, attrs: Sequence[tuple[str, str]]) -> None: ... # type: ignore[override] + def handle_empty_tag(self, data: str, is_block: bool) -> None: ... + def handle_decl(self, data: str) -> None: ... + def parse_bogus_comment(self, i: int, report: int = 0) -> int: ... + def get_starttag_text(self) -> str: ... diff --git a/stubs/Markdown/markdown/postprocessors.pyi b/stubs/Markdown/markdown/postprocessors.pyi index ad6e2a20d..24cb7d421 100644 --- a/stubs/Markdown/markdown/postprocessors.pyi +++ b/stubs/Markdown/markdown/postprocessors.pyi @@ -1,3 +1,7 @@ +import re +from typing import ClassVar +from typing_extensions import deprecated + from markdown.core import Markdown from . import util @@ -8,7 +12,16 @@ class Postprocessor(util.Processor): def run(self, text: str) -> str: ... class RawHtmlPostprocessor(Postprocessor): + BLOCK_LEVEL_REGEX: ClassVar[re.Pattern[str]] def isblocklevel(self, html: str) -> bool: ... def stash_to_string(self, text: str) -> str: ... class AndSubstitutePostprocessor(Postprocessor): ... + +@deprecated( + "This class is deprecated and will be removed in the future; " + "use [`UnescapeTreeprocessor`][markdown.treeprocessors.UnescapeTreeprocessor] instead." +) +class UnescapePostprocessor(Postprocessor): + RE: ClassVar[re.Pattern[str]] + def unescape(self, m: re.Match[str]) -> str: ... diff --git a/stubs/Markdown/markdown/serializers.pyi b/stubs/Markdown/markdown/serializers.pyi index b2e0a5ed5..0fbcf66b5 100644 --- a/stubs/Markdown/markdown/serializers.pyi +++ b/stubs/Markdown/markdown/serializers.pyi @@ -1,4 +1,9 @@ +import re from xml.etree.ElementTree import Element +__all__ = ["to_html_string", "to_xhtml_string"] + +RE_AMP: re.Pattern[str] + def to_html_string(element: Element) -> str: ... def to_xhtml_string(element: Element) -> str: ... diff --git a/stubs/Markdown/markdown/test_tools.pyi b/stubs/Markdown/markdown/test_tools.pyi new file mode 100644 index 000000000..8c9f300d2 --- /dev/null +++ b/stubs/Markdown/markdown/test_tools.pyi @@ -0,0 +1,30 @@ +import unittest +from _typeshed import Unused +from typing import Any + +__all__ = ["TestCase", "LegacyTestCase", "Kwargs"] + +class TestCase(unittest.TestCase): + default_kwargs: dict[str, Any] # taken from source code + def assertMarkdownRenders( + self, + source: str, + expected: str, + expected_attrs: dict[str, Any] | None = None, # values passing to self.assertEqual() + **kwargs, + ) -> None: ... + def dedent(self, text: str) -> str: ... + +class recursionlimit: + limit: int + old_limit: int + def __init__(self, limit: int) -> None: ... + def __enter__(self) -> None: ... + def __exit__(self, type: Unused, value: Unused, tb: Unused) -> None: ... + +class Kwargs(dict[str, Any]): ... + +class LegacyTestMeta(type): + def __new__(cls, name: str, bases: tuple[type, ...], dct: dict[str, Any]): ... # dct is namespace argument for type.__new__() + +class LegacyTestCase(unittest.TestCase, metaclass=LegacyTestMeta): ...