markdown-fast-py
Fast Markdown to HTML renderer — GFM tables, syntax highlighting, XSS-safe, extensible.
Pure Python. Zero dependencies. Production-ready.
Install
pip install markdown-fast-py
Quick Start
import markdown_fast_py as md
html = md.convert("# Hello\n\nThis is **bold** and _italic_.")
print(html)
# <h1 id="hello">Hello</h1>
# <p>This is <strong>bold</strong> and <em>italic</em>.</p>
Features
- CommonMark-compatible block and inline parsing
- GFM tables with per-column alignment
- Syntax highlighting for 15+ languages — pure Python, no external deps
- XSS sanitization — allowlist-based, strips event handlers and
javascript:URIs - Task lists (
- [x] done/- [ ] todo) - Strikethrough (
~~text~~) - Autolinks (bare URLs and
<angle-bracket>style) - Setext and ATX headings with automatic slug
idattributes - Blockquotes, fenced and indented code blocks
- Ordered and unordered lists with nesting
- Hard line breaks (
\n) - Reference-style links and images
- Extension system: footnotes, math, anchors, TOC, definition lists
- Command-line tool (
markdown-fast)
Usage
One-shot conversion
from markdown_fast_py import convert
html = convert(source)
Reusable instance
from markdown_fast_py import Markdown
md = Markdown(
highlight_code=True, # syntax-highlight fenced code blocks
sanitize=True, # strip dangerous HTML (XSS-safe)
heading_ids=True, # add id="slug" to headings
safe_links=True, # block javascript: URLs
breaks=False, # treat single newline as <br>
xhtml=False, # emit XHTML-style void elements
table_class="", # optional CSS class on <table>
extensions=[], # see Extensions section
)
html = md.render(source)
# or equivalently:
html = md.convert(source)
html = md(source) # callable
API reference
convert(text, **options) -> str
One-shot Markdown-to-HTML conversion.
| Parameter | Type | Default | Description |
|---|---|---|---|
text |
str |
— | Markdown source |
highlight_code |
bool |
True |
Syntax-highlight fenced code blocks |
sanitize |
bool |
True |
XSS-sanitize the output |
heading_ids |
bool |
True |
Add id attributes to headings |
safe_links |
bool |
True |
Block javascript: / data: hrefs |
breaks |
bool |
False |
Newlines become <br> |
xhtml |
bool |
False |
Self-closing void elements |
smart_quotes |
bool |
False |
Curly quotes |
table_class |
str |
"" |
CSS class on <table> |
extensions |
list |
[] |
Extensions to enable |
sanitize(html) -> str
Standalone XSS sanitizer — works on HTML from any source.
from markdown_fast_py import sanitize
clean = sanitize('<a href="javascript:alert(1)">click</a>')
# <a href="#">click</a>
highlight(code, language) -> str
Standalone syntax highlighter returning HTML with hl-* CSS classes.
from markdown_fast_py import highlight
html = highlight("def foo(): pass", "python")
parse(text) -> Node
Low-level AST parser. Returns a Node tree you can traverse or transform.
from markdown_fast_py import parse, NodeType
doc = parse("# Hello\n\n- item")
for child in doc.children:
print(child.type, child.level if child.type == NodeType.HEADING else "")
Syntax Highlighting
Fenced code blocks are highlighted when a language tag is provided:
```python
def hello(name: str) -> str:
return f"Hello, {name}!"
```
Supported languages
| Language | Tags |
|---|---|
| Python | python, py |
| JavaScript | javascript, js, jsx |
| TypeScript | typescript, ts, tsx |
| HTML/XML | html, xml |
| CSS/SCSS | css, scss, sass |
| JSON | json |
| SQL | sql |
| Bash/Shell | bash, sh, shell, zsh |
| Go | go, golang |
| Rust | rust, rs |
| YAML | yaml, yml |
| Diff | diff, patch |
The highlighter emits <span class="hl-*"> markup. Include the bundled theme
or write your own CSS:
from markdown_fast_py import CSS_THEME_DARK, CSS_THEME_LIGHT
# Embed in a <style> tag:
print(f"<style>{CSS_THEME_DARK}</style>")
XSS Sanitization
The sanitizer uses a strict allowlist of safe tags and attributes. Event handlers
(onclick, onload, …), <script>, <iframe>, and javascript: / data: URIs
are stripped automatically.
dangerous = '<p onclick="steal()">Hi <script>alert(1)</script></p>'
safe = convert(dangerous)
# <p>Hi </p>
Extensions
Enable built-in extensions by name or instance:
md = Markdown(extensions=["footnotes", "anchors", "toc"])
Available extensions
| Name | Class | Description |
|---|---|---|
footnotes |
FootnotesExtension |
[^1] references and definitions |
math |
MathExtension |
$inline$ and $$block$$ pass-through for MathJax/KaTeX |
anchors |
AnchorExtension |
Self-link ¶ on every heading |
toc |
TableOfContentsExtension |
Replace [TOC] with a nested <nav> |
deflist |
DefinitionListExtension |
term\n: definition → <dl> |
Custom extensions
from markdown_fast_py import Extension, Markdown
class MyExtension(Extension):
name = "mine"
def preprocess(self, text: str) -> str:
return text.replace(":rocket:", "🚀")
def postprocess_html(self, html: str) -> str:
return html.replace("TODO", '<mark>TODO</mark>')
md = Markdown(extensions=[MyExtension()])
GFM Tables
| Name | Age | City |
|---------|:---:|----------:|
| Alice | 30 | New York |
| Bob | 25 | London |
Column alignment: :--- left, ---: right, :---: centre.
Command Line
# Convert from stdin
echo "# Hello" | markdown-fast
# Convert a file
markdown-fast README.md
# Output a full HTML page with dark theme
markdown-fast --page --theme dark --title "Docs" README.md > docs.html
# Disable highlighting and sanitization
markdown-fast --no-highlight --no-sanitize input.md
# Enable extensions
markdown-fast --extensions anchors toc footnotes README.md
usage: markdown-fast [-h] [-o FILE] [--no-highlight] [--no-sanitize]
[--no-heading-ids] [--breaks] [--xhtml]
[--page] [--title TITLE] [--theme {dark,light,none}]
[--extensions [EXT ...]] [--version]
[FILE]
License
MIT © Vladyslav Zaiets
Metadata
Release files for markdown-fast-py 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| markdown_fast_py-1.0.0.tar.gz | 25.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| markdown_fast_py-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 52.6 kB
Release files / markdown_fast_py-1.0.0.tar.gz
| Download URL | markdown_fast_py-1.0.0.tar.gz |
|---|---|
| Size | 25.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c1100823ffdd3afaeb3f629fd263e991c7afe2b1061a4ea53d82d0a6b8d6cc02
|
|
BLAKE2b-256 checksum How to use checksums |
a76bac6fac1e2c23f10ae914211a10c6dd62388e897bae8546a3faba5d41a6ce
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / markdown_fast_py-1.0.0-py3-none-any.whl
| Download URL | markdown_fast_py-1.0.0-py3-none-any.whl |
|---|---|
| Size | 27.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3e9e50dd0338b9ed4696432fbbe00264b9aa649dddd316ad3bf606a8e80f88d1
|
|
BLAKE2b-256 checksum How to use checksums |
f51b366a8821ed66a31fbc0fbd46d6a4fa9c01fc96410b5096ad16d852b93178
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|