diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1351185..39d122d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,10 +18,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up Python 3.8 + - name: Set up Python uses: actions/setup-python@v5 with: - python-version: 3.8 + python-version: "3.10" - uses: pre-commit/action@v3.0.1 tests: @@ -30,7 +30,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['pypy-3.8', '3.8', '3.9', '3.10', '3.11', '3.12'] + python-version: ['pypy-3.10', '3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v4 @@ -46,13 +46,13 @@ jobs: run: | pytest --cov=mdit_py_plugins --cov-report=xml --cov-report=term-missing - name: Upload to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v5 if: github.event.pull_request.head.repo.full_name == github.repository with: token: ${{ secrets.CODECOV_TOKEN }} name: mdit-py-plugins-pytests flags: pytests - file: ./coverage.xml + files: ./coverage.xml fail_ci_if_error: true allgood: @@ -75,7 +75,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: "3.8" + python-version: "3.10" - name: install flit run: | pip install flit~=3.4 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 41c0fc9..091f2f9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ exclude: > repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v6.0.0 hooks: - id: check-json - id: check-yaml @@ -20,14 +20,14 @@ repos: - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.4 + rev: v0.12.8 hooks: - id: ruff args: [--fix] - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.10.0 + rev: v1.17.1 hooks: - id: mypy additional_dependencies: [markdown-it-py~=3.0] diff --git a/.readthedocs.yml b/.readthedocs.yml index cff72c5..f0758f4 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -3,7 +3,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.8" + python: "3.10" python: install: @@ -12,5 +12,6 @@ python: extra_requirements: [rtd] sphinx: + configuration: docs/conf.py builder: html fail_on_warning: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 26dbf23..1ad50e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change Log +## 0.5.0 - 2025-08-11 + +- ⬆️ Drop Python 3.9, which is EoL next month and allow for the, soon to be released, markdown-it-py v4. +- ✨ NEW: Add plugin & tests to render subscripts, thanks to @miteshashar + ## 0.4.2 - 2024-09-09 - 👌 Improve parsing of nested amsmath diff --git a/mdit_py_plugins/__init__.py b/mdit_py_plugins/__init__.py index df12433..3d18726 100644 --- a/mdit_py_plugins/__init__.py +++ b/mdit_py_plugins/__init__.py @@ -1 +1 @@ -__version__ = "0.4.2" +__version__ = "0.5.0" diff --git a/mdit_py_plugins/admon/index.py b/mdit_py_plugins/admon/index.py index cb24181..6e28940 100644 --- a/mdit_py_plugins/admon/index.py +++ b/mdit_py_plugins/admon/index.py @@ -2,9 +2,10 @@ from __future__ import annotations +from collections.abc import Callable, Sequence from contextlib import suppress import re -from typing import TYPE_CHECKING, Callable, Sequence +from typing import TYPE_CHECKING from markdown_it import MarkdownIt from markdown_it.rules_block import StateBlock diff --git a/mdit_py_plugins/amsmath/__init__.py b/mdit_py_plugins/amsmath/__init__.py index 0712618..bad1b21 100644 --- a/mdit_py_plugins/amsmath/__init__.py +++ b/mdit_py_plugins/amsmath/__init__.py @@ -2,8 +2,9 @@ from __future__ import annotations +from collections.abc import Callable, Sequence import re -from typing import TYPE_CHECKING, Callable, Sequence +from typing import TYPE_CHECKING from markdown_it import MarkdownIt from markdown_it.common.utils import escapeHtml diff --git a/mdit_py_plugins/anchors/index.py b/mdit_py_plugins/anchors/index.py index 59186c2..66bf0aa 100644 --- a/mdit_py_plugins/anchors/index.py +++ b/mdit_py_plugins/anchors/index.py @@ -1,5 +1,5 @@ +from collections.abc import Callable import re -from typing import Callable, List, Optional, Set from markdown_it import MarkdownIt from markdown_it.rules_core import StateCore @@ -10,7 +10,7 @@ def anchors_plugin( md: MarkdownIt, min_level: int = 1, max_level: int = 2, - slug_func: Optional[Callable[[str], str]] = None, + slug_func: Callable[[str], str] | None = None, permalink: bool = False, permalinkSymbol: str = "¶", permalinkBefore: bool = False, @@ -58,7 +58,7 @@ def anchors_plugin( def _make_anchors_func( - selected_levels: List[int], + selected_levels: list[int], slug_func: Callable[[str], str], permalink: bool, permalinkSymbol: str, @@ -66,7 +66,7 @@ def _make_anchors_func( permalinkSpace: bool, ) -> Callable[[StateCore], None]: def _anchor_func(state: StateCore) -> None: - slugs: Set[str] = set() + slugs: set[str] = set() for idx, token in enumerate(state.tokens): if token.type != "heading_open": continue @@ -119,7 +119,7 @@ def slugify(title: str) -> str: return re.sub(r"[^\w\u4e00-\u9fff\- ]", "", title.strip().lower().replace(" ", "-")) -def unique_slug(slug: str, slugs: Set[str]) -> str: +def unique_slug(slug: str, slugs: set[str]) -> str: uniq = slug i = 1 while uniq in slugs: diff --git a/mdit_py_plugins/attrs/index.py b/mdit_py_plugins/attrs/index.py index 3efaab6..9811ddc 100644 --- a/mdit_py_plugins/attrs/index.py +++ b/mdit_py_plugins/attrs/index.py @@ -1,7 +1,8 @@ from __future__ import annotations +from collections.abc import Sequence from functools import partial -from typing import Any, Sequence +from typing import Any from markdown_it import MarkdownIt from markdown_it.rules_block import StateBlock diff --git a/mdit_py_plugins/attrs/parse.py b/mdit_py_plugins/attrs/parse.py index 06539c2..061574f 100644 --- a/mdit_py_plugins/attrs/parse.py +++ b/mdit_py_plugins/attrs/parse.py @@ -22,9 +22,9 @@ class <- '.' name from __future__ import annotations +from collections.abc import Callable from enum import Enum import re -from typing import Callable class State(Enum): diff --git a/mdit_py_plugins/colon_fence.py b/mdit_py_plugins/colon_fence.py index c09e89c..70c95ed 100644 --- a/mdit_py_plugins/colon_fence.py +++ b/mdit_py_plugins/colon_fence.py @@ -1,6 +1,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Sequence +from collections.abc import Sequence +from typing import TYPE_CHECKING from markdown_it import MarkdownIt from markdown_it.common.utils import escapeHtml, unescapeAll diff --git a/mdit_py_plugins/container/index.py b/mdit_py_plugins/container/index.py index 7cc016f..c610268 100644 --- a/mdit_py_plugins/container/index.py +++ b/mdit_py_plugins/container/index.py @@ -2,8 +2,9 @@ from __future__ import annotations +from collections.abc import Callable, Sequence from math import floor -from typing import TYPE_CHECKING, Any, Callable, Sequence +from typing import TYPE_CHECKING, Any from markdown_it import MarkdownIt from markdown_it.rules_block import StateBlock diff --git a/mdit_py_plugins/dollarmath/index.py b/mdit_py_plugins/dollarmath/index.py index acfd83f..32039ad 100644 --- a/mdit_py_plugins/dollarmath/index.py +++ b/mdit_py_plugins/dollarmath/index.py @@ -1,7 +1,8 @@ from __future__ import annotations +from collections.abc import Callable, Sequence import re -from typing import TYPE_CHECKING, Any, Callable, Sequence +from typing import TYPE_CHECKING, Any from markdown_it import MarkdownIt from markdown_it.common.utils import escapeHtml, isWhiteSpace @@ -146,7 +147,7 @@ def is_escaped(state: StateInline, back_pos: int, mod: int = 0) -> bool: return False # if an odd number of \ then ignore - if (backslashes % 2) != mod: + if (backslashes % 2) != mod: # noqa: SIM103 return True return False diff --git a/mdit_py_plugins/field_list/__init__.py b/mdit_py_plugins/field_list/__init__.py index b3d6407..60745d7 100644 --- a/mdit_py_plugins/field_list/__init__.py +++ b/mdit_py_plugins/field_list/__init__.py @@ -1,7 +1,7 @@ """Field list plugin""" +from collections.abc import Iterator from contextlib import contextmanager -from typing import Iterator, Optional, Tuple from markdown_it import MarkdownIt from markdown_it.rules_block import StateBlock @@ -45,7 +45,7 @@ def fieldlist_plugin(md: MarkdownIt) -> None: ) -def parseNameMarker(state: StateBlock, startLine: int) -> Tuple[int, str]: +def parseNameMarker(state: StateBlock, startLine: int) -> tuple[int, str]: """Parse field name: `:name:` :returns: position after name marker, name text @@ -159,7 +159,7 @@ def _fieldlist_rule( # to figure out the indent of the body, # we look at all non-empty, indented lines and find the minimum indent - block_indent: Optional[int] = None + block_indent: int | None = None _line = startLine + 1 while _line < endLine: # if start_of_content < end_of_content, then non-empty line diff --git a/mdit_py_plugins/footnote/index.py b/mdit_py_plugins/footnote/index.py index 8d6ce26..67c0b67 100644 --- a/mdit_py_plugins/footnote/index.py +++ b/mdit_py_plugins/footnote/index.py @@ -2,8 +2,9 @@ from __future__ import annotations +from collections.abc import Sequence from functools import partial -from typing import TYPE_CHECKING, Sequence, TypedDict +from typing import TYPE_CHECKING, TypedDict from markdown_it import MarkdownIt from markdown_it.helpers import parseLinkLabel @@ -332,7 +333,7 @@ def footnote_tail(state: StateCore) -> None: tok_filter.append(not insideRef) - state.tokens = [t for t, f in zip(state.tokens, tok_filter) if f] + state.tokens = [t for t, f in zip(state.tokens, tok_filter, strict=False) if f] footnote_data = _data_from_env(state.env) if not footnote_data["list"]: diff --git a/mdit_py_plugins/myst_blocks/index.py b/mdit_py_plugins/myst_blocks/index.py index 25d14ff..11fc0fb 100644 --- a/mdit_py_plugins/myst_blocks/index.py +++ b/mdit_py_plugins/myst_blocks/index.py @@ -1,7 +1,8 @@ from __future__ import annotations +from collections.abc import Sequence import itertools -from typing import TYPE_CHECKING, Sequence +from typing import TYPE_CHECKING from markdown_it import MarkdownIt from markdown_it.common.utils import escapeHtml diff --git a/mdit_py_plugins/myst_role/index.py b/mdit_py_plugins/myst_role/index.py index b82daa1..97a5eb9 100644 --- a/mdit_py_plugins/myst_role/index.py +++ b/mdit_py_plugins/myst_role/index.py @@ -1,5 +1,6 @@ +from collections.abc import Sequence import re -from typing import TYPE_CHECKING, Sequence +from typing import TYPE_CHECKING from markdown_it import MarkdownIt from markdown_it.common.utils import escapeHtml diff --git a/mdit_py_plugins/texmath/index.py b/mdit_py_plugins/texmath/index.py index 63a169d..67372fa 100644 --- a/mdit_py_plugins/texmath/index.py +++ b/mdit_py_plugins/texmath/index.py @@ -1,7 +1,9 @@ from __future__ import annotations +from collections.abc import Callable, Sequence import re -from typing import TYPE_CHECKING, Any, Callable, Match, Sequence, TypedDict +from re import Match +from typing import TYPE_CHECKING, Any, TypedDict from markdown_it import MarkdownIt from markdown_it.common.utils import charCodeAt @@ -152,7 +154,7 @@ def _func(state: StateBlock, begLine: int, endLine: int, silent: bool) -> bool: def dollar_pre(src: str, beg: int) -> bool: prv = charCodeAt(src[beg - 1], 0) if beg > 0 else False return ( - (not prv) or prv != 0x5C and (prv < 0x30 or prv > 0x39) # no backslash, + (not prv) or (prv != 0x5C and (prv < 0x30 or prv > 0x39)) # no backslash, ) # no decimal digit .. before opening '$' diff --git a/mdit_py_plugins/wordcount/__init__.py b/mdit_py_plugins/wordcount/__init__.py index 63bdf24..bf65823 100644 --- a/mdit_py_plugins/wordcount/__init__.py +++ b/mdit_py_plugins/wordcount/__init__.py @@ -1,5 +1,5 @@ +from collections.abc import Callable import string -from typing import Callable, List from markdown_it import MarkdownIt from markdown_it.rules_core import StateCore @@ -33,7 +33,7 @@ def wordcount_plugin( """ def _word_count_rule(state: StateCore) -> None: - text: List[str] = [] + text: list[str] = [] words = 0 for token in state.tokens: if token.type == "text": @@ -53,6 +53,6 @@ def _word_count_rule(state: StateCore) -> None: data["text"] += text data.setdefault("words", 0) data["words"] += words - data["minutes"] = int(round(data["words"] / per_minute)) + data["minutes"] = int(round(data["words"] / per_minute)) # noqa: RUF046 md.core.ruler.push("wordcount", _word_count_rule) diff --git a/pyproject.toml b/pyproject.toml index de70116..a3416f2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,8 +25,8 @@ classifiers = [ "Topic :: Text Processing :: Markup", ] keywords = ["markdown", "markdown-it", "lexer", "parser", "development"] -requires-python = ">=3.8" -dependencies = ["markdown-it-py>=1.0.0,<4.0.0"] +requires-python = ">=3.10" +dependencies = ["markdown-it-py>=2.0.0,<5.0.0"] [project.urls] Homepage = "https://github.com/executablebooks/mdit-py-plugins" diff --git a/tox.ini b/tox.ini index c3c01e7..a9016f0 100644 --- a/tox.ini +++ b/tox.ini @@ -4,18 +4,18 @@ # then run `tox` or `tox -- {pytest args}` # run in parallel using `tox -p` [tox] -envlist = py38 +envlist = py310 [testenv] usedevelop = true -[testenv:py{38,39,310,311,312}] +[testenv:py{310,311,312,313}] extras = testing commands = pytest {posargs} [testenv:docs-{update,clean}] extras = rtd -whitelist_externals = rm +allowlist_externals = rm commands = clean: rm -rf docs/_build sphinx-build -nW --keep-going -b {posargs:html} docs/ docs/_build/{posargs:html}