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.2.tar.gz (9.1 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.2-py3-none-any.whl (11.0 kB view details)

Uploaded Python 3

File details

Details for the file dog_markdown-1.0.2.tar.gz.

File metadata

  • Download URL: dog_markdown-1.0.2.tar.gz
  • Upload date:
  • Size: 9.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.17

File hashes

Hashes for dog_markdown-1.0.2.tar.gz
Algorithm Hash digest
SHA256 1565e259b348f08d55ba2e7c9c3c43c09657790b61078f28c9f8870916ba5f77
MD5 ce37cdf5c9b62d03ccaba4206413b747
BLAKE2b-256 d2f2e8dfcb52a00dfbc8e81984dfcd40040ab285dc0c012ed46259c4fc11e96f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for dog_markdown-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 4693de54e171490756f59cf5cb6bd8c35b29be8b6d502e6b66a2335c3aa40852
MD5 d8655b7f49117f2a43a0674da28a8be8
BLAKE2b-256 9b4b124db45238455ac8dfefee13cfdf7b4807b62bf1a52c70e28687be4ba6ec

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