Skip to main content

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. Supports Heading, 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 or Paragraph object

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. Supports Text, 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 content
  • bold: 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 text
  • url: Target URL
  • title: 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 accessibility
  • url: Image URL or path
  • title: 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 of ListItem objects
  • indent: 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, a Document object

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 content
  • language: 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, a Document object

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 headers
  • rows: List of table data rows. Each cell supports strings, Text, Link, Image
  • align: Optional list of column alignments. Supports left, 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 heading
  • add_paragraph(content: str | List[str | Text | Link | Image] | Paragraph): Add a paragraph
  • add_code_block(content: str, language: str | None = None): Add a code block
  • add_blockquote(content: str | Document | List[...]): Add a blockquote
  • add_table(headers: List[str], rows: List[List[...]], align: List[str | None] | None = None): Add a table
  • build(): Build and return the final Document
  • to_str(): Build and return the document as a Markdown string
List Operations
  • start_unordered_list(): Start an unordered list
  • end_unordered_list(): End the current unordered list
  • unordered_list(): Return a list context manager
Context Managers
  • paragraph(): Context manager for creating complex rich text paragraphs
  • unordered_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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dog_markdown-1.0.1.tar.gz (8.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dog_markdown-1.0.1-py3-none-any.whl (10.7 kB view details)

Uploaded Python 3

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

Hashes for dog_markdown-1.0.1.tar.gz
Algorithm Hash digest
SHA256 b5e765a9314c76208b2ac78df70f5578c4f6a1c374813fdfa4027bf53d2a5607
MD5 cb9cb7cfb54bf055804e4289434f6241
BLAKE2b-256 5acdf5bbfa41ec91f941af9ea4dbbeeb24f0d5a43be9a86095241ec52c5494e8

See more details on using hashes here.

File details

Details for the file dog_markdown-1.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for dog_markdown-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6c3a105542fc1020061c48498a3538fb273e389c08987037b9e9e28513edf162
MD5 5f6190224dc47349d05325ced17913e3
BLAKE2b-256 e1eb2414d00003ff58051b7d830c741226650c43b3a8a0e3d01e507e3d7426b5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page