A pure-Python library for programmatically generating Markdown files.
Project description
MarkdownPal
A pure-Python library for programmatically generating Markdown (.md) files via a clean, block-based document builder API.
Features
- Block-based API — compose documents from typed, self-contained block objects
- Inline formatting helpers —
bold(),italic(),code(),strikethrough() - Full block support — headings, paragraphs, quotes, code, lists, tables, images, links
- Save to file — UTF-8 output with full support for international characters and emoji
- Zero dependencies — no third-party packages required
- Python 3.9+
Installation
pip3 install markdownpal
Quick Start
from markdownpal import Document
from markdownpal.blocks import H1Block, H2Block, TextBlock, CodeBlock, ULBlock
from markdownpal.inline import bold
doc = Document()
doc.append(H1Block("My Project"))
doc.append(TextBlock(f"A {bold('simple')} example of MarkdownPal."))
doc.append(H2Block("Installation"))
doc.append(CodeBlock("pip install markdownpal", lang="bash"))
doc.append(H2Block("Features"))
doc.append(ULBlock(["Zero dependencies", "Clean API", "Python 3.9+"]))
doc.save("output.md")
Output (output.md):
# My Project
A **simple** example of MarkdownPal.
## Installation
```bash
pip install markdownpal
Features
- Zero dependencies
- Clean API
- Python 3.9+
---
## Block Reference
### Headings
```python
from markdownpal.blocks import H1Block, H2Block, H3Block, H4Block, H5Block, H6Block
doc.append(H1Block("Title")) # # Title
doc.append(H2Block("Section")) # ## Section
doc.append(H3Block("Subsection")) # ### Subsection
Text
from markdownpal.blocks import TextBlock, QuoteBlock, HRBlock, CommentBlock
doc.append(TextBlock("A plain paragraph."))
doc.append(QuoteBlock("A blockquote.\nSpanning multiple lines."))
doc.append(HRBlock()) # ---
doc.append(CommentBlock("Hidden in rendered output.")) # <!-- ... -->
Code
from markdownpal.blocks import CodeBlock
doc.append(CodeBlock("print('hello')", lang="python"))
doc.append(CodeBlock("SELECT * FROM users;", lang="sql"))
doc.append(CodeBlock("no language specified"))
Lists
from markdownpal.blocks import ULBlock, OLBlock, TaskListBlock
doc.append(ULBlock(["Apples", "Bananas", "Cherries"]))
doc.append(OLBlock(["Install", "Configure", "Run"]))
doc.append(TaskListBlock([
("Write tests", True),
("Write code", True),
("Deploy", False),
]))
Table
from markdownpal.blocks import TableBlock
doc.append(TableBlock(
headers=["Name", "Role", "Status"],
rows=[
["Alice", "Engineer", "Active"],
["Bob", "Designer", "Active"],
]
))
Images & Links
from markdownpal.blocks import ImageBlock, LinkBlock
doc.append(ImageBlock(src="logo.png", alt="Project Logo"))
doc.append(LinkBlock(text="Documentation", url="https://example.com/docs"))
Inline Helpers
Inline helpers return plain strings and can be embedded inside any block content:
from markdownpal.inline import bold, italic, code, strikethrough
bold("important") # **important**
italic("note") # *note*
code("os.path.join()") # `os.path.join()`
strikethrough("deprecated") # ~~deprecated~~
# Composable
bold(italic("emphasis")) # ***emphasis***
# Embed in blocks
doc.append(TextBlock(f"Call {code('render()')} to get the output string."))
Document API
doc = Document()
doc.append(block) # Add a Block instance
doc.render() # Returns the full Markdown string
doc.save("out.md") # Writes UTF-8 Markdown file to disk
append() raises TypeError if the argument is not a Block instance.
render() joins all blocks with a blank line (\n\n) between them.
Project Structure
markdownpal/
├── __init__.py # Top-level public API
├── document.py # Document class
├── inline.py # Inline format helpers
└── blocks/
├── base.py # Block abstract base class
├── heading.py # H1Block ~ H6Block
├── text.py # TextBlock, QuoteBlock, HRBlock, CommentBlock
├── code.py # CodeBlock
├── list_.py # ULBlock, OLBlock, TaskListBlock
├── table.py # TableBlock
└── media.py # ImageBlock, LinkBlock
Development
# Clone the repository
git clone https://github.com/rogerstacker/markdownpal.git
cd markdownpal
# Install dev dependencies
pip3 install -e ".[dev]"
# Run tests
pytest
License
MIT © 2026 Rogerstacker
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file markdownpal-0.1.0.tar.gz.
File metadata
- Download URL: markdownpal-0.1.0.tar.gz
- Upload date:
- Size: 22.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ced132280f316c8bbbad9dfeb4b8bbdd651489654d0ffdbdfe75a0a93c56d8a1
|
|
| MD5 |
34aaf642e66ccefb3427d9e8bcfb0bdd
|
|
| BLAKE2b-256 |
3e347e09269eb01aab74a3dda5ec58f065ef61ae771fb6f7c156bbe597a20170
|
File details
Details for the file markdownpal-0.1.0-py3-none-any.whl.
File metadata
- Download URL: markdownpal-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cb21547577bbee7515109ae3ae92b80a4d9c1daf23a9dca681b3ed09b93d2f19
|
|
| MD5 |
0c0e0287d747558198e7032be108b157
|
|
| BLAKE2b-256 |
d60832a6fe9dfd322d5042a76cf929daef2fb68f1dabdb7d4e3afc370efe0a8e
|