mkdocs-md-to-pdf 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mkdocs_md_to_pdf-0.1.0/LICENSE +21 -0
- mkdocs_md_to_pdf-0.1.0/PKG-INFO +117 -0
- mkdocs_md_to_pdf-0.1.0/README.md +84 -0
- mkdocs_md_to_pdf-0.1.0/pyproject.toml +48 -0
- mkdocs_md_to_pdf-0.1.0/setup.cfg +4 -0
- mkdocs_md_to_pdf-0.1.0/src/mkdocs_md_to_pdf/__init__.py +7 -0
- mkdocs_md_to_pdf-0.1.0/src/mkdocs_md_to_pdf/cli.py +36 -0
- mkdocs_md_to_pdf-0.1.0/src/mkdocs_md_to_pdf/converter.py +140 -0
- mkdocs_md_to_pdf-0.1.0/src/mkdocs_md_to_pdf.egg-info/PKG-INFO +117 -0
- mkdocs_md_to_pdf-0.1.0/src/mkdocs_md_to_pdf.egg-info/SOURCES.txt +13 -0
- mkdocs_md_to_pdf-0.1.0/src/mkdocs_md_to_pdf.egg-info/dependency_links.txt +1 -0
- mkdocs_md_to_pdf-0.1.0/src/mkdocs_md_to_pdf.egg-info/entry_points.txt +2 -0
- mkdocs_md_to_pdf-0.1.0/src/mkdocs_md_to_pdf.egg-info/requires.txt +10 -0
- mkdocs_md_to_pdf-0.1.0/src/mkdocs_md_to_pdf.egg-info/top_level.txt +1 -0
- mkdocs_md_to_pdf-0.1.0/tests/test_converter.py +48 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Lode Rosseel
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mkdocs-md-to-pdf
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Convert Markdown files to PDF using MkDocs Material theme and Playwright
|
|
5
|
+
Author-email: Lode Rosseel <lode.rosseel@cegeka.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/lode-braced/mkdocs-md-to-pdf
|
|
8
|
+
Project-URL: Repository, https://github.com/lode-braced/mkdocs-md-to-pdf
|
|
9
|
+
Project-URL: Issues, https://github.com/lode-braced/mkdocs-md-to-pdf/issues
|
|
10
|
+
Keywords: markdown,pdf,mkdocs,converter,documentation
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Documentation
|
|
19
|
+
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
20
|
+
Requires-Python: >=3.12
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: mkdocs>=1.6.1
|
|
24
|
+
Requires-Dist: mkdocs-material>=9.6
|
|
25
|
+
Requires-Dist: playwright>=1.42
|
|
26
|
+
Requires-Dist: pymdown-extensions>=10.14
|
|
27
|
+
Requires-Dist: plantuml-markdown>=3.11
|
|
28
|
+
Requires-Dist: mkdocs-callouts>=1.16
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-mock>=3.14; extra == "dev"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# mkdocs-md-to-pdf
|
|
35
|
+
|
|
36
|
+
Convert Markdown files to styled PDFs using [MkDocs Material](https://squidfunk.github.io/mkdocs-material/) theme and [Playwright](https://playwright.dev/).
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
- Material Design styling via MkDocs Material theme
|
|
41
|
+
- Syntax highlighting for code blocks
|
|
42
|
+
- Mermaid diagram support
|
|
43
|
+
- PlantUML diagram support (requires Java)
|
|
44
|
+
- Admonitions and callouts
|
|
45
|
+
- Automatic handling of linked images and files
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Using uv
|
|
51
|
+
uv add mkdocs-md-to-pdf
|
|
52
|
+
|
|
53
|
+
# Using pip
|
|
54
|
+
pip install mkdocs-md-to-pdf
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
After installation, install the Chromium browser for Playwright:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
playwright install chromium
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### PlantUML Setup
|
|
64
|
+
|
|
65
|
+
#### macOS
|
|
66
|
+
1. Download PlantUML JAR from [GitHub releases](https://github.com/plantuml/plantuml/releases/latest)
|
|
67
|
+
2. Place JAR: `mv plantuml-mit-1.2025.8.jar ~/.local/bin/plantuml.jar`
|
|
68
|
+
3. Make executable: `chmod +x ~/.local/bin/plantuml.jar`
|
|
69
|
+
4. Add to shell profile (.bashrc/.zshrc):
|
|
70
|
+
```bash
|
|
71
|
+
export PATH="$PATH:~/.local/bin"
|
|
72
|
+
export PATH="/opt/homebrew/opt/openjdk/bin:$PATH"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### Ubuntu/Debian
|
|
76
|
+
```bash
|
|
77
|
+
sudo apt install default-jdk plantuml
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Usage
|
|
81
|
+
|
|
82
|
+
### Command Line
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Output to stdout (pipe to file)
|
|
86
|
+
md-to-pdf document.md > output.pdf
|
|
87
|
+
|
|
88
|
+
# Output to specific file
|
|
89
|
+
md-to-pdf document.md -o output.pdf
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Python API
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from mkdocs_md_to_pdf import convert
|
|
96
|
+
|
|
97
|
+
# Get PDF as bytes
|
|
98
|
+
pdf_bytes = convert("document.md")
|
|
99
|
+
|
|
100
|
+
# Write directly to file
|
|
101
|
+
convert("document.md", output_file="output.pdf")
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Supported Markdown Features
|
|
105
|
+
|
|
106
|
+
- Standard Markdown syntax
|
|
107
|
+
- Fenced code blocks with syntax highlighting
|
|
108
|
+
- Tables
|
|
109
|
+
- Admonitions (`!!! note`, `!!! warning`, etc.)
|
|
110
|
+
- Callouts (`> [!NOTE]`, `> [!WARNING]`)
|
|
111
|
+
- Mermaid diagrams
|
|
112
|
+
- PlantUML diagrams
|
|
113
|
+
- Linked images (relative paths)
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
MIT
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# mkdocs-md-to-pdf
|
|
2
|
+
|
|
3
|
+
Convert Markdown files to styled PDFs using [MkDocs Material](https://squidfunk.github.io/mkdocs-material/) theme and [Playwright](https://playwright.dev/).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Material Design styling via MkDocs Material theme
|
|
8
|
+
- Syntax highlighting for code blocks
|
|
9
|
+
- Mermaid diagram support
|
|
10
|
+
- PlantUML diagram support (requires Java)
|
|
11
|
+
- Admonitions and callouts
|
|
12
|
+
- Automatic handling of linked images and files
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Using uv
|
|
18
|
+
uv add mkdocs-md-to-pdf
|
|
19
|
+
|
|
20
|
+
# Using pip
|
|
21
|
+
pip install mkdocs-md-to-pdf
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
After installation, install the Chromium browser for Playwright:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
playwright install chromium
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### PlantUML Setup
|
|
31
|
+
|
|
32
|
+
#### macOS
|
|
33
|
+
1. Download PlantUML JAR from [GitHub releases](https://github.com/plantuml/plantuml/releases/latest)
|
|
34
|
+
2. Place JAR: `mv plantuml-mit-1.2025.8.jar ~/.local/bin/plantuml.jar`
|
|
35
|
+
3. Make executable: `chmod +x ~/.local/bin/plantuml.jar`
|
|
36
|
+
4. Add to shell profile (.bashrc/.zshrc):
|
|
37
|
+
```bash
|
|
38
|
+
export PATH="$PATH:~/.local/bin"
|
|
39
|
+
export PATH="/opt/homebrew/opt/openjdk/bin:$PATH"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### Ubuntu/Debian
|
|
43
|
+
```bash
|
|
44
|
+
sudo apt install default-jdk plantuml
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
### Command Line
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Output to stdout (pipe to file)
|
|
53
|
+
md-to-pdf document.md > output.pdf
|
|
54
|
+
|
|
55
|
+
# Output to specific file
|
|
56
|
+
md-to-pdf document.md -o output.pdf
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Python API
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from mkdocs_md_to_pdf import convert
|
|
63
|
+
|
|
64
|
+
# Get PDF as bytes
|
|
65
|
+
pdf_bytes = convert("document.md")
|
|
66
|
+
|
|
67
|
+
# Write directly to file
|
|
68
|
+
convert("document.md", output_file="output.pdf")
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Supported Markdown Features
|
|
72
|
+
|
|
73
|
+
- Standard Markdown syntax
|
|
74
|
+
- Fenced code blocks with syntax highlighting
|
|
75
|
+
- Tables
|
|
76
|
+
- Admonitions (`!!! note`, `!!! warning`, etc.)
|
|
77
|
+
- Callouts (`> [!NOTE]`, `> [!WARNING]`)
|
|
78
|
+
- Mermaid diagrams
|
|
79
|
+
- PlantUML diagrams
|
|
80
|
+
- Linked images (relative paths)
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
MIT
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "mkdocs-md-to-pdf"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Convert Markdown files to PDF using MkDocs Material theme and Playwright"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
requires-python = ">=3.12"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Lode Rosseel", email = "lode.rosseel@cegeka.com" }
|
|
10
|
+
]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 4 - Beta",
|
|
13
|
+
"Environment :: Console",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Topic :: Documentation",
|
|
20
|
+
"Topic :: Text Processing :: Markup :: Markdown",
|
|
21
|
+
]
|
|
22
|
+
keywords = ["markdown", "pdf", "mkdocs", "converter", "documentation"]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"mkdocs>=1.6.1",
|
|
25
|
+
"mkdocs-material>=9.6",
|
|
26
|
+
"playwright>=1.42",
|
|
27
|
+
"pymdown-extensions>=10.14",
|
|
28
|
+
"plantuml-markdown>=3.11",
|
|
29
|
+
"mkdocs-callouts>=1.16",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
dev = [
|
|
34
|
+
"pytest>=8.0",
|
|
35
|
+
"pytest-mock>=3.14",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.scripts]
|
|
39
|
+
md-to-pdf = "mkdocs_md_to_pdf.cli:main"
|
|
40
|
+
|
|
41
|
+
[project.urls]
|
|
42
|
+
Homepage = "https://github.com/lode-braced/mkdocs-md-to-pdf"
|
|
43
|
+
Repository = "https://github.com/lode-braced/mkdocs-md-to-pdf"
|
|
44
|
+
Issues = "https://github.com/lode-braced/mkdocs-md-to-pdf/issues"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
[tool.pytest.ini_options]
|
|
48
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Command-line interface for md-to-pdf."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from mkdocs_md_to_pdf.converter import convert
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def main() -> None:
|
|
10
|
+
"""CLI entry point for md-to-pdf."""
|
|
11
|
+
parser = argparse.ArgumentParser(
|
|
12
|
+
prog="md-to-pdf",
|
|
13
|
+
description="Convert a markdown file to PDF using MkDocs and Playwright.",
|
|
14
|
+
)
|
|
15
|
+
parser.add_argument("input_file", help="Path to the markdown file to convert")
|
|
16
|
+
parser.add_argument(
|
|
17
|
+
"-o", "--output",
|
|
18
|
+
help="Output PDF file path (default: write to stdout)",
|
|
19
|
+
)
|
|
20
|
+
args = parser.parse_args()
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
pdf_bytes = convert(args.input_file, args.output)
|
|
24
|
+
if not args.output:
|
|
25
|
+
sys.stdout.buffer.write(pdf_bytes)
|
|
26
|
+
sys.stdout.flush()
|
|
27
|
+
except FileNotFoundError as e:
|
|
28
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
29
|
+
sys.exit(1)
|
|
30
|
+
except Exception as e:
|
|
31
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
32
|
+
sys.exit(1)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if __name__ == "__main__":
|
|
36
|
+
main()
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""Core conversion logic for markdown to PDF."""
|
|
2
|
+
|
|
3
|
+
import importlib.resources
|
|
4
|
+
import os
|
|
5
|
+
import re
|
|
6
|
+
import shutil
|
|
7
|
+
import subprocess
|
|
8
|
+
import tempfile
|
|
9
|
+
import time
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from playwright.sync_api import sync_playwright
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _get_template_content() -> str:
|
|
16
|
+
"""Load the mkdocs.yml template from package resources."""
|
|
17
|
+
return importlib.resources.files("mkdocs_md_to_pdf").joinpath(
|
|
18
|
+
"mkdocs.yml.template"
|
|
19
|
+
).read_text()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _create_temp_mkdocs_config(input_file: Path, temp_dir: Path) -> Path:
|
|
23
|
+
"""Create a temporary mkdocs.yml configuration for the specified file."""
|
|
24
|
+
template_content = _get_template_content()
|
|
25
|
+
|
|
26
|
+
temp_docs_dir = temp_dir / "docs"
|
|
27
|
+
temp_docs_dir.mkdir(parents=True, exist_ok=True)
|
|
28
|
+
|
|
29
|
+
temp_file_path = temp_docs_dir / "index.md"
|
|
30
|
+
shutil.copy2(input_file, temp_file_path)
|
|
31
|
+
|
|
32
|
+
# Extract and copy linked files
|
|
33
|
+
linked_files = _extract_linked_files(input_file)
|
|
34
|
+
for linked_file in linked_files:
|
|
35
|
+
linked_file_path = input_file.parent / linked_file
|
|
36
|
+
if linked_file_path.is_file():
|
|
37
|
+
shutil.copy2(linked_file_path, temp_docs_dir)
|
|
38
|
+
|
|
39
|
+
config_content = template_content.replace(
|
|
40
|
+
"{{site_name}}", input_file.name
|
|
41
|
+
).replace("{{docs_dir}}", "docs")
|
|
42
|
+
|
|
43
|
+
temp_config_path = temp_dir / "mkdocs.yml"
|
|
44
|
+
temp_config_path.write_text(config_content)
|
|
45
|
+
|
|
46
|
+
return temp_config_path
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _extract_linked_files(input_file: Path) -> list[str]:
|
|
50
|
+
"""Extract relative file links from markdown content."""
|
|
51
|
+
content = input_file.read_text()
|
|
52
|
+
linked_files = []
|
|
53
|
+
|
|
54
|
+
link_re = re.compile(r"\[.*?]\((.*?)\)")
|
|
55
|
+
image_tag_re = re.compile(r'<img.*?src="(.*?)".*?>')
|
|
56
|
+
|
|
57
|
+
for match in link_re.findall(content):
|
|
58
|
+
if not match.startswith(("http", "#")):
|
|
59
|
+
linked_files.append(match)
|
|
60
|
+
|
|
61
|
+
for match in image_tag_re.findall(content):
|
|
62
|
+
if not match.startswith("http"):
|
|
63
|
+
linked_files.append(match)
|
|
64
|
+
|
|
65
|
+
return linked_files
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _serve_mkdocs(temp_dir: Path, port: int = 8765) -> subprocess.Popen:
|
|
69
|
+
"""Build and serve the mkdocs site."""
|
|
70
|
+
subprocess.run(["mkdocs", "build"], cwd=temp_dir, check=True, capture_output=True)
|
|
71
|
+
|
|
72
|
+
server_process = subprocess.Popen(
|
|
73
|
+
["mkdocs", "serve", "-a", f"127.0.0.1:{port}"],
|
|
74
|
+
cwd=temp_dir,
|
|
75
|
+
stdout=subprocess.PIPE,
|
|
76
|
+
stderr=subprocess.PIPE,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
time.sleep(2)
|
|
80
|
+
return server_process
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _generate_pdf_bytes(port: int = 8765) -> bytes:
|
|
84
|
+
"""Use Playwright to render the served page to PDF."""
|
|
85
|
+
with sync_playwright() as p:
|
|
86
|
+
browser = p.chromium.launch()
|
|
87
|
+
page = browser.new_page()
|
|
88
|
+
page.goto(f"http://127.0.0.1:{port}/")
|
|
89
|
+
page.wait_for_load_state("load")
|
|
90
|
+
page.wait_for_function("() => document.fonts.ready")
|
|
91
|
+
|
|
92
|
+
pdf_bytes = page.pdf(
|
|
93
|
+
print_background=True,
|
|
94
|
+
margin={
|
|
95
|
+
"top": "0.4in",
|
|
96
|
+
"right": "0.4in",
|
|
97
|
+
"bottom": "0.4in",
|
|
98
|
+
"left": "0.4in",
|
|
99
|
+
},
|
|
100
|
+
display_header_footer=False,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
browser.close()
|
|
104
|
+
return pdf_bytes
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def convert(input_file: str | Path, output_file: str | Path | None = None) -> bytes:
|
|
108
|
+
"""
|
|
109
|
+
Convert a markdown file to PDF.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
input_file: Path to the markdown file to convert.
|
|
113
|
+
output_file: Optional path to write the PDF. If None, returns bytes only.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
The PDF content as bytes.
|
|
117
|
+
|
|
118
|
+
Raises:
|
|
119
|
+
FileNotFoundError: If the input file does not exist.
|
|
120
|
+
"""
|
|
121
|
+
input_path = Path(input_file).resolve()
|
|
122
|
+
|
|
123
|
+
if not input_path.is_file():
|
|
124
|
+
raise FileNotFoundError(f"File not found: {input_path}")
|
|
125
|
+
|
|
126
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
127
|
+
temp_path = Path(temp_dir)
|
|
128
|
+
_create_temp_mkdocs_config(input_path, temp_path)
|
|
129
|
+
server_process = _serve_mkdocs(temp_path)
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
pdf_bytes = _generate_pdf_bytes()
|
|
133
|
+
finally:
|
|
134
|
+
server_process.terminate()
|
|
135
|
+
server_process.wait()
|
|
136
|
+
|
|
137
|
+
if output_file:
|
|
138
|
+
Path(output_file).write_bytes(pdf_bytes)
|
|
139
|
+
|
|
140
|
+
return pdf_bytes
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mkdocs-md-to-pdf
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Convert Markdown files to PDF using MkDocs Material theme and Playwright
|
|
5
|
+
Author-email: Lode Rosseel <lode.rosseel@cegeka.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/lode-braced/mkdocs-md-to-pdf
|
|
8
|
+
Project-URL: Repository, https://github.com/lode-braced/mkdocs-md-to-pdf
|
|
9
|
+
Project-URL: Issues, https://github.com/lode-braced/mkdocs-md-to-pdf/issues
|
|
10
|
+
Keywords: markdown,pdf,mkdocs,converter,documentation
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Documentation
|
|
19
|
+
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
20
|
+
Requires-Python: >=3.12
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: mkdocs>=1.6.1
|
|
24
|
+
Requires-Dist: mkdocs-material>=9.6
|
|
25
|
+
Requires-Dist: playwright>=1.42
|
|
26
|
+
Requires-Dist: pymdown-extensions>=10.14
|
|
27
|
+
Requires-Dist: plantuml-markdown>=3.11
|
|
28
|
+
Requires-Dist: mkdocs-callouts>=1.16
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-mock>=3.14; extra == "dev"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# mkdocs-md-to-pdf
|
|
35
|
+
|
|
36
|
+
Convert Markdown files to styled PDFs using [MkDocs Material](https://squidfunk.github.io/mkdocs-material/) theme and [Playwright](https://playwright.dev/).
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
- Material Design styling via MkDocs Material theme
|
|
41
|
+
- Syntax highlighting for code blocks
|
|
42
|
+
- Mermaid diagram support
|
|
43
|
+
- PlantUML diagram support (requires Java)
|
|
44
|
+
- Admonitions and callouts
|
|
45
|
+
- Automatic handling of linked images and files
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Using uv
|
|
51
|
+
uv add mkdocs-md-to-pdf
|
|
52
|
+
|
|
53
|
+
# Using pip
|
|
54
|
+
pip install mkdocs-md-to-pdf
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
After installation, install the Chromium browser for Playwright:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
playwright install chromium
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### PlantUML Setup
|
|
64
|
+
|
|
65
|
+
#### macOS
|
|
66
|
+
1. Download PlantUML JAR from [GitHub releases](https://github.com/plantuml/plantuml/releases/latest)
|
|
67
|
+
2. Place JAR: `mv plantuml-mit-1.2025.8.jar ~/.local/bin/plantuml.jar`
|
|
68
|
+
3. Make executable: `chmod +x ~/.local/bin/plantuml.jar`
|
|
69
|
+
4. Add to shell profile (.bashrc/.zshrc):
|
|
70
|
+
```bash
|
|
71
|
+
export PATH="$PATH:~/.local/bin"
|
|
72
|
+
export PATH="/opt/homebrew/opt/openjdk/bin:$PATH"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### Ubuntu/Debian
|
|
76
|
+
```bash
|
|
77
|
+
sudo apt install default-jdk plantuml
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Usage
|
|
81
|
+
|
|
82
|
+
### Command Line
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Output to stdout (pipe to file)
|
|
86
|
+
md-to-pdf document.md > output.pdf
|
|
87
|
+
|
|
88
|
+
# Output to specific file
|
|
89
|
+
md-to-pdf document.md -o output.pdf
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Python API
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from mkdocs_md_to_pdf import convert
|
|
96
|
+
|
|
97
|
+
# Get PDF as bytes
|
|
98
|
+
pdf_bytes = convert("document.md")
|
|
99
|
+
|
|
100
|
+
# Write directly to file
|
|
101
|
+
convert("document.md", output_file="output.pdf")
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Supported Markdown Features
|
|
105
|
+
|
|
106
|
+
- Standard Markdown syntax
|
|
107
|
+
- Fenced code blocks with syntax highlighting
|
|
108
|
+
- Tables
|
|
109
|
+
- Admonitions (`!!! note`, `!!! warning`, etc.)
|
|
110
|
+
- Callouts (`> [!NOTE]`, `> [!WARNING]`)
|
|
111
|
+
- Mermaid diagrams
|
|
112
|
+
- PlantUML diagrams
|
|
113
|
+
- Linked images (relative paths)
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
MIT
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/mkdocs_md_to_pdf/__init__.py
|
|
5
|
+
src/mkdocs_md_to_pdf/cli.py
|
|
6
|
+
src/mkdocs_md_to_pdf/converter.py
|
|
7
|
+
src/mkdocs_md_to_pdf.egg-info/PKG-INFO
|
|
8
|
+
src/mkdocs_md_to_pdf.egg-info/SOURCES.txt
|
|
9
|
+
src/mkdocs_md_to_pdf.egg-info/dependency_links.txt
|
|
10
|
+
src/mkdocs_md_to_pdf.egg-info/entry_points.txt
|
|
11
|
+
src/mkdocs_md_to_pdf.egg-info/requires.txt
|
|
12
|
+
src/mkdocs_md_to_pdf.egg-info/top_level.txt
|
|
13
|
+
tests/test_converter.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mkdocs_md_to_pdf
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Tests for the converter module."""
|
|
2
|
+
|
|
3
|
+
import tempfile
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from mkdocs_md_to_pdf import __version__, convert
|
|
9
|
+
from mkdocs_md_to_pdf.converter import _extract_linked_files, _get_template_content
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_version():
|
|
13
|
+
assert __version__ == "0.1.0"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_get_template_content():
|
|
17
|
+
content = _get_template_content()
|
|
18
|
+
assert "{{site_name}}" in content
|
|
19
|
+
assert "{{docs_dir}}" in content
|
|
20
|
+
assert "mkdocs-material" in content or "material" in content
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_extract_linked_files():
|
|
24
|
+
with tempfile.NamedTemporaryFile(mode="w", suffix=".md", delete=False) as f:
|
|
25
|
+
f.write("""
|
|
26
|
+
# Test Document
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+
[Link](other.md)
|
|
30
|
+
[External](https://example.com)
|
|
31
|
+
[Anchor](#section)
|
|
32
|
+
<img src="photo.jpg" alt="Photo">
|
|
33
|
+
<img src="https://example.com/img.png" alt="External">
|
|
34
|
+
""")
|
|
35
|
+
f.flush()
|
|
36
|
+
|
|
37
|
+
linked = _extract_linked_files(Path(f.name))
|
|
38
|
+
|
|
39
|
+
assert "image.png" in linked
|
|
40
|
+
assert "other.md" in linked
|
|
41
|
+
assert "photo.jpg" in linked
|
|
42
|
+
assert "https://example.com" not in linked
|
|
43
|
+
assert "#section" not in linked
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_convert_file_not_found():
|
|
47
|
+
with pytest.raises(FileNotFoundError):
|
|
48
|
+
convert("/nonexistent/path/to/file.md")
|