Add your description here
Project description
dog-markdown
A type-safe Markdown generator for Python, built with Pydantic.
Features
- Type-safe: Uses Pydantic models to ensure valid Markdown structure
- Extensible: Easy to add new Markdown elements
- Human-friendly: Automatic spacing and formatting
- Nested elements: Supports deeply nested structures like nested blockquotes
Installation
uv add dog-markdown
API Documentation
Core Model API
Create structured Markdown documents using Pydantic models directly.
Document
Top-level document container that holds multiple Markdown elements.
from dog_markdown import Document, Heading, Paragraph, Text
doc = Document(
children=[
Heading(level=1, content="My Document"),
Paragraph(children=[Text(content="Hello World!")])
]
)
print(doc.to_str())
Parameters:
children: List of Markdown elements contained in the document. SupportsHeading,Paragraph,UnorderedList,CodeBlock,Blockquote,Table,Document
Methods:
to_str(): Convert document to Markdown string
Heading
Heading element supporting levels H1-H9.
from dog_markdown import Heading
# Basic usage
heading = Heading(level=2, content="Section Title")
# Using Paragraph as content (supports rich text)
from dog_markdown import Paragraph, Text, Link
heading = Heading(
level=3,
content=Paragraph(children=[
Text(content="See our "),
Link(text="API docs", url="/api"),
Text(content=" for details")
])
)
Parameters:
level: Heading level (1-9)content: Heading content, supports string orParagraphobject
Paragraph
Paragraph element that can contain text, links, and images.
from dog_markdown import Paragraph, Text, Link, Image
# Basic text paragraph
paragraph = Paragraph(children=[Text(content="Simple text paragraph")])
# Rich text paragraph
paragraph = Paragraph(children=[
Text(content="Visit our "),
Link(text="website", url="https://example.com"),
Text(content=" or check out our "),
Image(alt="Logo", url="/logo.png")
])
Parameters:
children: List of paragraph content. SupportsText,Link,Image
Text
Plain text element with optional bold formatting.
from dog_markdown import Text
# Plain text
text = Text(content="Plain text")
# Bold text
bold_text = Text(content="Important note", bold=True)
Parameters:
content: Text contentbold: Whether to render text as bold (default: False)
Link
Hyperlink element.
from dog_markdown import Link
# Basic link
link = Link(text="Click me", url="https://example.com")
# Link with title
link = Link(text="Download", url="/file.pdf", title="Download PDF document")
Parameters:
text: Link display texturl: Target URLtitle: Optional tooltip title displayed on hover
Image
Image element with support for alternative text and titles.
from dog_markdown import Image
# Basic image
image = Image(alt="Cat picture", url="/cat.jpg")
# Image with title
image = Image(alt="Dog picture", url="/dog.jpg", title="A cute dog")
Parameters:
alt: Alternative text for accessibilityurl: Image URL or pathtitle: Optional tooltip title displayed on hover
UnorderedList
Unordered (bullet) list.
from dog_markdown import UnorderedList, ListItem, Document, Paragraph, Text
# Simple list
list = UnorderedList(
items=[
ListItem(content=Document(children=[Paragraph(children=[Text(content="Item 1")])])),
ListItem(content=Document(children=[Paragraph(children=[Text(content="Item 2")])]))
]
)
# Nested list
nested_list = UnorderedList(
items=[
ListItem(content=Document(children=[
Paragraph(children=[Text(content="Parent item")]),
UnorderedList(
items=[
ListItem(content=Document(children=[Paragraph(children=[Text(content="Child item 1")])])),
ListItem(content=Document(children=[Paragraph(children=[Text(content="Child item 2")])]))
]
)
]))
]
)
Parameters:
items: List ofListItemobjectsindent: Indentation level (default: 1)
ListItem
List item element.
from dog_markdown import ListItem, Document, Paragraph, Text
list_item = ListItem(
content=Document(children=[Paragraph(children=[Text(content="List item content")])])
)
Parameters:
content: List item content, aDocumentobject
CodeBlock
Code block element with optional syntax highlighting.
from dog_markdown import CodeBlock
# Basic code block
code_block = CodeBlock(content="print('Hello World')")
# Code block with syntax highlighting
python_code = CodeBlock(
content="def add(a, b):\n return a + b",
language="python"
)
Parameters:
content: Code contentlanguage: Optional programming language name for syntax highlighting
Blockquote
Blockquote element that supports nesting.
from dog_markdown import Blockquote, Document, Paragraph, Text
# Basic quote
quote = Blockquote(
content=Document(children=[Paragraph(children=[Text(content="To be or not to be")])])
)
# Nested quote
nested_quote = Blockquote(
content=Document(children=[
Paragraph(children=[Text(content="Outer quote")]),
Blockquote(
content=Document(children=[Paragraph(children=[Text(content="Inner quote")])])
)
])
)
Parameters:
content: Quote content, aDocumentobject
Table
Table element with support for column alignment.
from dog_markdown import Table
# Basic table
table = Table(
headers=["Name", "Age", "Email"],
rows=[
["Alice", "30", "alice@example.com"],
["Bob", "25", "bob@example.com"]
]
)
# Table with alignment
table = Table(
headers=["Name", "Age", "Email"],
rows=[
["Alice", "30", "alice@example.com"],
["Bob", "25", "bob@example.com"]
],
align=["left", "center", "right"]
)
# Rich text table
table = Table(
headers=["Product", "Link", "Image"],
rows=[
[
"Laptop",
Link(text="Buy now", url="/laptop"),
Image(alt="Laptop", url="/laptop.jpg")
]
]
)
Parameters:
headers: List of table column headersrows: List of table data rows. Each cell supports strings,Text,Link,Imagealign: Optional list of column alignments. Supportsleft,center,right. Defaults to left alignment.
Builder API
Fluent API for building Markdown documents procedurally, ideal for programmatic creation.
Basic Usage
from dog_markdown import MarkdownBuilder
builder = MarkdownBuilder()
doc = builder
.add_heading(1, "My Document")
.add_paragraph("Welcome to dog-markdown!")
.add_code_block("print('Hello World')", language="python")
.build()
print(doc.to_str())
Quick Start
Use the markdown() function to quickly create a Builder:
from dog_markdown import markdown
doc = markdown()
.add_heading(2, "Quick Start")
.add_paragraph("Easy to use builder API")
.to_str()
Rich Text Paragraphs
# Basic usage
builder.add_paragraph([
"Visit our ",
builder.link("website", "https://example.com"),
" for more info"
])
# Create complex paragraphs using context managers
with builder.paragraph():
builder.add_bold_text("Note:")
builder.add_text(" This is a ")
builder.add_bold_text("very important")
builder.add_text(" message with ")
builder.add_link("links", "https://example.com")
List Operations
Use add_paragraph directly within lists to simplify API usage:
# Create lists using context managers
with builder.unordered_list():
# Simple list item
builder.add_paragraph("Simple list item")
# Rich text list item
with builder.paragraph():
builder.add_text("Item with a ")
builder.add_link("link", "https://example.com")
builder.add_text(" and ")
builder.add_bold_text("bold text")
# Complex list item with multiple paragraphs
with builder.paragraph():
builder.add_bold_text("Multi-paragraph item:")
builder.add_paragraph("This is the first paragraph")
builder.add_paragraph("This is the second paragraph")
# Nested lists
with builder.unordered_list():
builder.add_paragraph("Nested item 1")
builder.add_paragraph("Nested item 2")
Complex Document Example
from dog_markdown import MarkdownBuilder
builder = MarkdownBuilder()
# Create document title and description
builder.add_heading(1, "My Project")
builder.add_paragraph("A type-safe Markdown generator for Python")
# Add features list
builder.add_heading(2, "Features")
with builder.unordered_list():
with builder.paragraph():
builder.add_bold_text("Type-safe")
builder.add_text(": Uses Pydantic models to ensure valid Markdown structure")
with builder.paragraph():
builder.add_bold_text("Extensible")
builder.add_text(": Easy to add new Markdown elements")
builder.add_paragraph("Human-friendly automatic spacing and formatting")
# Add code example
builder.add_heading(2, "Example")
builder.add_code_block(
"def hello():\n print('Hello World!')",
language="python"
)
# Add blockquote
builder.add_blockquote([
"This is a blockquote",
builder.paragraph("It supports multiple paragraphs and "),
builder.paragraph(["even ", builder.bold_text("bold text"), " or ", builder.link("links", "https://example.com")])
])
# Add table
builder.add_table(
headers=["Feature", "Supported", "Description"],
rows=[
["Type safety", "✓", "Uses Pydantic models"],
["Nested elements", "✓", "Deeply nested structures"],
["Tables", "✓", "With alignment support"]
],
align=["left", "center", "left"]
)
# Output result
print(builder.to_str())
Builder Method Reference
Document Structure
add_heading(level: int, content: str | Paragraph): Add a headingadd_paragraph(content: str | List[str | Text | Link | Image] | Paragraph): Add a paragraphadd_code_block(content: str, language: str | None = None): Add a code blockadd_blockquote(content: str | Document | List[...]): Add a blockquoteadd_table(headers: List[str], rows: List[List[...]], align: List[str | None] | None = None): Add a tablebuild(): Build and return the finalDocumentto_str(): Build and return the document as a Markdown string
List Operations
start_unordered_list(): Start an unordered listend_unordered_list(): End the current unordered listunordered_list(): Return a list context manager
Context Managers
paragraph(): Context manager for creating complex rich text paragraphsunordered_list(): Context manager for creating nested lists
Text Elements
add_link(text: str, url: str, title: str | None = None): Create a link element (for nesting in paragraphs)add_image(alt: str, url: str, title: str | None = None): Create an image element (for nesting in paragraphs)add_text(content: str): Create a plain text element (for nesting in paragraphs)add_bold_text(content: str): Create a bold text element (for nesting in paragraphs)
Advanced Usage
Nested Elements
from dog_markdown import Document, Heading, Blockquote, Paragraph, Text, UnorderedList, ListItem
doc = Document(
children=[
Heading(level=1, content="Nested Example"),
Blockquote(
content=Document(
children=[
Paragraph(children=[Text(content="Quote with list:")]),
UnorderedList(
items=[
ListItem(content=Document(children=[Paragraph(children=[Text(content="Item 1")])])),
ListItem(content=Document(children=[Paragraph(children=[Text(content="Item 2")])]))
]
)
]
)
)
]
)
Generating Complex Documents
Combine Builder API context managers to create very complex document structures:
from dog_markdown import MarkdownBuilder
builder = MarkdownBuilder()
# Create technical documentation
builder.add_heading(1, "API Documentation")
builder.add_heading(2, "Introduction")
builder.add_paragraph("Welcome to our API documentation. This guide will help you get started.")
builder.add_heading(2, "Getting Started")
with builder.unordered_list():
builder.add_paragraph("Sign up for an API key")
builder.add_paragraph("Install the SDK")
builder.add_paragraph("Make your first request")
builder.add_heading(3, "Authentication")
builder.add_paragraph("Authenticate your requests using API keys in the Authorization header.")
builder.add_code_block(
"import requests\n\nheaders = {\n 'Authorization': 'Bearer YOUR_API_KEY'\n}\n\nresponse = requests.get('https://api.example.com/data', headers=headers)",
language="python"
)
builder.add_heading(2, "Endpoints")
with builder.unordered_list():
with builder.paragraph():
builder.add_bold_text("GET /api/data")
builder.add_text(": Retrieve data from the server")
with builder.paragraph():
builder.add_bold_text("POST /api/data")
builder.add_text(": Create new data on the server")
with builder.paragraph():
builder.add_bold_text("PUT /api/data/{id}")
builder.add_text(": Update existing data")
print(builder.to_str())
Output Example
The following code:
from dog_markdown import markdown
md = markdown()
.add_heading(1, "My Project")
.add_paragraph("A type-safe Markdown generator for Python")
.add_blockquote("The best way to create structured Markdown")
.start_unordered_list()
.add_paragraph("Type-safe with Pydantic")
.add_paragraph("Fluent builder API")
.add_paragraph("Nested element support")
.end_unordered_list()
.add_table(
headers=["Feature", "Status"],
rows=[
["Type safety", "✅"],
["Builder API", "✅"],
["Nested elements", "✅"]
],
align=["left", "center"]
)
.to_str()
print(md)
Will generate:
# My Project
A type-safe Markdown generator for Python
> The best way to create structured Markdown
- Type-safe with Pydantic
- Fluent builder API
- Nested element support
| Feature | Status |
| --- | :---: |
| Type safety | ✅ |
| Builder API | ✅ |
| Nested elements | ✅ |
Development
Setup
uv sync
Testing
uv run pytest
Linting
uv run ruff check .
Formatting
uv run ruff format .
License
MIT
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 dog_markdown-1.0.1.tar.gz.
File metadata
- Download URL: dog_markdown-1.0.1.tar.gz
- Upload date:
- Size: 8.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.17
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b5e765a9314c76208b2ac78df70f5578c4f6a1c374813fdfa4027bf53d2a5607
|
|
| MD5 |
cb9cb7cfb54bf055804e4289434f6241
|
|
| BLAKE2b-256 |
5acdf5bbfa41ec91f941af9ea4dbbeeb24f0d5a43be9a86095241ec52c5494e8
|
File details
Details for the file dog_markdown-1.0.1-py3-none-any.whl.
File metadata
- Download URL: dog_markdown-1.0.1-py3-none-any.whl
- Upload date:
- Size: 10.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.17
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6c3a105542fc1020061c48498a3538fb273e389c08987037b9e9e28513edf162
|
|
| MD5 |
5f6190224dc47349d05325ced17913e3
|
|
| BLAKE2b-256 |
e1eb2414d00003ff58051b7d830c741226650c43b3a8a0e3d01e507e3d7426b5
|