Files
mdpolish/README.md
T

8.1 KiB
Raw Blame History

mdpolish

mdpolish 是实验室共用的、项目无关的 Python Markdown 修改库。它提供函数式 Modifier、精确文本编辑执行器、 有序 Pipeline、正则修改器工厂,以及少量可以用合成样例完整说明的通用修改器。

当前版本是 0.2.0。库只处理内存中的 Markdown 字符串,不读取或写入文件,不提供默认流水线,也不包含任何项目的 规则集合、数据清单、实验脚本或评审工具。

当前能力

能力 作用 明确边界
Modifier 把不可变元数据与普通提议函数组合起来 函数只提议修改,不直接改字符串或文件
精确编辑执行器 校验快照、范围、原文、重复和冲突后原子应用一个批次 不判断项目业务语义
Pipeline 按调用方顺序运行修改器,并对最终快照做只读稳定性复查 不自动选规则、不重排、不循环执行
regex_replace() 把非空正则匹配转换为精确编辑 不提供规则注册表、配置加载或默认模式
mapped_line_join() 按调用方提供的映射合并跨行片段 库内没有默认词表,不猜测未知词
HTML 表格修改器 处理严格表格子集的实体和单行布局 不是完整 HTML parser,也不是 HTML→GFM 转换器

一次运行会返回 successfailedunstable

  • success:所选修改器完成运行,且对最终结果不再提出修改;
  • failed:修改器、契约或编辑验证发生错误;
  • unstable:运行没有错误,但最终复查仍发现有效候选修改。

success 只代表本次选择的修改器已经稳定,不代表文档不存在其他质量问题。

安装

项目仍在仓库内开发,使用项目可以从本地路径安装:

python -m pip install /path/to/mdpolish

开发环境:

python -m venv .venv
.venv/bin/python -m pip install -e '.[dev]'

运行时只依赖 Python 标准库,支持 Python 3.11 及以上版本。

组装自己的流水线

项目拥有规则、参数和顺序。下面的正则规则与两个通用修改器最终都是 Modifier

from mdpolish import Pipeline, RunStatus, regex_replace
from mdpolish.modifiers import html_table_entity_unescape, mapped_line_join

normalize_spaces = regex_replace(
    modifier_id="my_project.normalize_spaces",
    version="1.0.0",
    pattern=r" {2,}",
    replacement=" ",
    applicability="把正文中连续两个及以上的 ASCII 空格收敛为一个;项目需自行排除不适用区域。",
)

join_fragments = mapped_line_join(
    (
        ("exam-", "ple", "example"),
        ("rule-", "based", "rule-based"),
    )
)

pipeline = Pipeline(
    (
        normalize_spaces,
        join_fragments,
        html_table_entity_unescape(),
    )
)

result = pipeline.transform("an exam-\nple  text")
if result.status is not RunStatus.SUCCESS:
    raise RuntimeError(f"cleaning did not succeed: {result.status}")

assert result.output_markdown == "an example text"

库不会保存 output_markdown。调用项目应先检查状态,再自行决定写入位置:

from pathlib import Path

source_path = Path("input.md")
output_path = Path("output.md")

result = pipeline.transform(source_path.read_text(encoding="utf-8"))
if result.status is RunStatus.SUCCESS and result.output_markdown is not None:
    output_path.write_text(result.output_markdown, encoding="utf-8")

文件读取、输出命名、覆盖策略、批处理、CLI 和报告都属于调用项目,不属于 mdpolish

编写项目自己的修改器

复杂规则使用普通函数返回精确候选修改,不需要继承库基类:

from mdpolish import DocumentSnapshot, Modifier, ProposedChange, TextEdit, TextSpan


def propose_marker_removal(snapshot: DocumentSnapshot) -> tuple[ProposedChange, ...]:
    marker = "[REMOVE-ME]"
    start = snapshot.markdown.find(marker)
    if start < 0:
        return ()
    end = start + len(marker)
    return (
        ProposedChange(
            snapshot_sha256=snapshot.sha256,
            reason="删除项目确认过的占位标记",
            edits=(
                TextEdit(
                    snapshot_sha256=snapshot.sha256,
                    span=TextSpan(start, end),
                    expected_text=marker,
                    replacement="",
                ),
            ),
        ),
    )


remove_marker = Modifier(
    modifier_id="my_project.remove_marker",
    version="1.0.0",
    parameters={"marker": "[REMOVE-ME]"},
    applicability="只删除项目声明的完整占位标记;不处理近似文本。",
    propose=propose_marker_removal,
)

修改器决定“建议改哪里、为什么改、改成什么”;公共执行器真正修改内存字符串。每项 TextEdit 都绑定当前快照哈希、 半开字符串范围、预期原文和替换文本。任意候选无效时,该修改器当前批次不会产生部分修改。

项目函数应保持确定且无副作用,不读取文件、网络、环境变量、当前时间或随机数。Python 无法沙箱隔离任意函数;项目 函数私下产生的外部副作用不属于本库的验证或审计范围。

通用修改器的严格边界

mapped_line_join() 只使用调用方显式传入的三元组:左片段、右片段和最终文本。它只处理相邻物理行或中间恰好一个 同风格空行的情况,并检查 ASCII 词边界。

html_table_entity_unescape() 只在严格完整的 <td> / <th> 文本中处理 &amp;lt;&amp;gt;&amp;amp;html_table_layout() 只调整严格单行表格的外层行布局,并保留标签、属性和单元格内容。

这两个 HTML 修改器采用保守的词法子集,不识别 Markdown 围栏。混合换行、嵌套标签、<tbody>、嵌套表格或损坏 结构会保持原样。

仓库结构

src/mdpolish/
├── models.py              # 不可变快照、精确编辑、审计和结果模型
├── modifier.py            # 函数式 Modifier 契约
├── edits.py               # 批次验证与原子应用
├── pipeline.py            # 有序执行与最终稳定性复查
├── regex.py               # 正则修改器工厂
└── modifiers/             # 少量项目无关的通用修改器
tests/                     # 只使用虚构文本的核心与通用修改器测试
research-wiki/
├── design/                # 已批准决策及被冻结的历史记录
├── explanation/           # 当前有效机制
├── reference/             # 代码无法完整表达的稳定查询事实
├── guides/                # 已实际验证的操作步骤
└── scratch/               # 不作为当前事实的本地草稿

当前不提供

  • 文件适配器、公共 CLI、配置文件、profile 或批处理协议;
  • 自动规则发现、注册表或默认流水线;
  • Markdown AST、完整 HTML parser 或新运行依赖;
  • artifact、报告、Web/桌面评审器;
  • 任何业务项目的规则、固定参数、文档 ID、数据或验收统计。

公共边界与原因见 0008-generic-functional-library-boundary.md,当前机制见 functional-modifier-core.md。旧 design 只保存历史决策,不代表当前 交付能力。

当前可用检查

在已经安装开发依赖的仓库环境中运行:

.venv/bin/ruff check .
.venv/bin/mypy src tests
.venv/bin/pytest
.venv/bin/python -m pip wheel . --no-deps --wheel-dir /tmp/mdpolish-wheel-check

检查本地变更:

git diff --check
git status --short

上述检查已于 2026-08-26 在 Python 3.13.11 环境实际运行:Ruff 通过,mypy 检查 21 个源码和测试文件无问题, pytest 共 104 项测试通过,mdpolish-0.2.0-py3-none-any.whl 构建成功。wheel 内容已单独检查,只包含通用 Python 包、类型标记和包元数据,不包含项目规则、实验脚本、评审器或 Node.js 文件。

pyproject.toml 声明的 Python 3.11 及以上为支持范围;本次结果不表示已经在每个受支持版本上完成兼容性验证。