Skip to main content

A Python library for converting Atlassian Document Format (ADF) to Markdown

Project description

pyadf

A high-performance Python library for converting Atlassian Document Format (ADF) to Markdown.

Features

  • Rust-powered — parsing and rendering run in native code via PyO3
  • Streaming JSONL API for ETL pipelines processing millions of documents
  • Same Document class API — drop-in upgrade for most users (see changelog for breaking changes)
  • Flexible input — accepts JSON strings, dictionaries, or any ADF node type
  • Comprehensive node support:
    • Text formatting (bold, italic, links)
    • Headings (h1-h6)
    • Lists (bullet, ordered, task lists)
    • Tables with headers and column spans
    • Code blocks with syntax highlighting
    • Blockquotes and panels
    • Status badges, inline cards, emoji, mentions
  • Type-safe with comprehensive type hints and Python 3.11+ support
  • Eager validation — ADF structure errors surface at construction time, not render time
  • Robust error handling with detailed, context-aware error messages

Installation

pip install pyadf

Prebuilt wheels are available for Linux and macOS (x86_64 and aarch64) and Windows (x86_64).

Usage

Basic Usage

from pyadf import Document

adf_data = {
    "type": "doc",
    "content": [
        {
            "type": "paragraph",
            "content": [
                {"type": "text", "text": "Hello, "},
                {"type": "text", "text": "world!", "marks": [{"type": "strong"}]}
            ]
        }
    ]
}

doc = Document(adf_data)
print(doc.to_markdown())
# Output: Hello, **world!**

Converting from JSON String

from pyadf import Document

adf_json = '{"type": "doc", "content": [...]}'
doc = Document(adf_json)
markdown = doc.to_markdown()

Converting Individual Nodes

from pyadf import Document

node = {
    "type": "heading",
    "attrs": {"level": 2},
    "content": [{"type": "text", "text": "My Heading"}]
}

doc = Document(node)
print(doc.to_markdown())
# Output: ## My Heading

Batch JSONL Processing

For ETL pipelines processing large volumes of ADF documents:

from pyadf import convert_jsonl, MarkdownConfig

# From a JSONL file (one ADF document per line)
for result in convert_jsonl("export.jsonl"):
    print(result)

# From bytes with custom config
config = MarkdownConfig(bullet_marker="*", show_links=True)
for result in convert_jsonl(jsonl_bytes, config=config, batch_size=10_000):
    print(result)

# Error handling modes
from pyadf import ConversionError

for result in convert_jsonl(data, on_error="include"):
    if isinstance(result, ConversionError):
        print(f"Line {result.line_number}: {result.error}")
    else:
        print(result)

convert_jsonl accepts:

  • source: file path (str), raw bytes, or a binary file-like object
  • config: optional MarkdownConfig
  • on_error: "include" (default, yields ConversionError), "skip", or "raise"
  • batch_size: lines per Rust batch (default 10,000)

Error Handling

from pyadf import Document, InvalidJSONError, UnsupportedNodeTypeError

try:
    doc = Document('invalid json')
except InvalidJSONError as e:
    print(f"Invalid JSON: {e}")

try:
    doc = Document({"type": "unsupported_type"})
except UnsupportedNodeTypeError as e:
    print(f"Unsupported node: {e}")

Customizing Markdown Output

from pyadf import Document, MarkdownConfig

doc = Document(adf_data)

# Default bullet marker is +
doc.to_markdown()  # "+ Item 1\n+ Item 2"

# Use * for bullet lists
config = MarkdownConfig(bullet_marker="*")
doc.to_markdown(config)  # "* Item 1\n* Item 2"

# Show links with both display text and underlying href
config = MarkdownConfig(show_links=True)
doc.to_markdown(config)  # [Link text](http://example.com)
Option Values Default Description
bullet_marker +, -, * + Character used for bullet list items
show_links True, False False Show underlying links in markdown

Supported ADF Node Types

ADF Node Type Markdown Output Notes
doc Document root Top-level container
paragraph Plain text with newlines
text Text with optional formatting Supports bold, italic, links
heading # Heading (levels 1-6)
bulletList + Item
orderedList 1. Item
taskList - [ ] Task Checkbox tasks
codeBlock ```language\ncode\n``` Optional language syntax
blockquote > Quote
panel > Panel content Info/warning/error boxes
table Markdown table Supports headers and colspan
status **[STATUS]** Status badges
inlineCard [link] or code block Link previews
emoji Unicode emoji
hardBreak Line break
mention @DisplayName Jira user mentions

Exception Types

  • PyADFError — Base exception for all pyadf errors
  • InvalidJSONError — Raised when JSON parsing fails
  • InvalidInputError — Raised when input type is incorrect
  • InvalidADFError — Raised when ADF structure is invalid
  • MissingFieldError — Raised when required fields are missing
  • InvalidFieldError — Raised when field values are invalid
  • UnsupportedNodeTypeError — Raised when encountering unsupported node types
  • NodeCreationError — Raised when node creation fails

All exceptions include detailed context about the error location in the ADF tree.

Development

Prerequisites

  • Python 3.11+
  • Rust toolchain (stable)
  • maturin (uv tool install maturin)

Setup

git clone https://github.com/YoungseokCh/pyadf.git
cd pyadf
uv sync
uv run maturin develop

Testing

cargo test              # Rust unit tests
uv run pytest tests/ -v # Python tests

Linting

# Rust
cargo fmt --check
cargo clippy -- -D warnings

# Python
ruff check src/ tests/ benchmarks/
ruff format --check src/ tests/ benchmarks/

License

MIT License — see LICENSE file for details.

Changelog

0.4.1

  • Fix linux x86_64 wheel builds

0.4.0 (Current)

  • Rust core via PyO3 — 5x faster single-doc, 24x faster batch processing
  • New convert_jsonl() streaming API for batch JSONL processing
  • New ConversionError dataclass for structured batch error handling
  • Build system switched from setuptools to maturin
  • abi3 stable ABI wheels for Linux, macOS (x86_64 + aarch64) and Windows (x86_64)

Breaking changes:

  • Removed set_debug_mode() and _logger module (will be replaced with Rust-native tracing in a future release)
  • nodes and _types modules removed (internal implementation replaced by Rust)

0.3.2

  • Added support for showing href links in markdown output

0.3.1

  • Added mention node support

0.3.0

  • Added emoji node support
  • Added configurable bullet markers via MarkdownConfig

0.1.0

  • Class-based API with Document class
  • Support for common ADF node types
  • Type-safe architecture with comprehensive type hints (Python 3.11+)
  • Flexible input handling (JSON strings, dictionaries, individual nodes)

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

pyadf-0.4.1.tar.gz (42.7 kB view details)

Uploaded Source

Built Distributions

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

pyadf-0.4.1-cp311-abi3-win_amd64.whl (249.7 kB view details)

Uploaded CPython 3.11+Windows x86-64

pyadf-0.4.1-cp311-abi3-manylinux_2_34_x86_64.whl (343.2 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.34+ x86-64

pyadf-0.4.1-cp311-abi3-manylinux_2_28_x86_64.whl (343.6 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.28+ x86-64

pyadf-0.4.1-cp311-abi3-manylinux_2_28_aarch64.whl (322.3 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.28+ ARM64

pyadf-0.4.1-cp311-abi3-macosx_11_0_arm64.whl (302.0 kB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

pyadf-0.4.1-cp311-abi3-macosx_10_12_x86_64.whl (322.2 kB view details)

Uploaded CPython 3.11+macOS 10.12+ x86-64

File details

Details for the file pyadf-0.4.1.tar.gz.

File metadata

  • Download URL: pyadf-0.4.1.tar.gz
  • Upload date:
  • Size: 42.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyadf-0.4.1.tar.gz
Algorithm Hash digest
SHA256 58eaf857a9f209cdd67940b842c9eb8d8c60d468ce852cbb50ff41db32bebf52
MD5 a1f203e3a709b77a1eb096cdc18a40bb
BLAKE2b-256 f55d9c8e8513deba862c7ee99ee63d3be687fc8665466a1aa438879073c2b996

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadf-0.4.1.tar.gz:

Publisher: publish.yml on YoungseokCh/pyadf

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyadf-0.4.1-cp311-abi3-win_amd64.whl.

File metadata

  • Download URL: pyadf-0.4.1-cp311-abi3-win_amd64.whl
  • Upload date:
  • Size: 249.7 kB
  • Tags: CPython 3.11+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyadf-0.4.1-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 d68aa0686000e31c0d3cc0308e1fad2ef622dcfc447c52396a9d983fa7108d1d
MD5 01f6aa6facdd6a739ac4ab0650fc068d
BLAKE2b-256 7b4329fd8f14e8598e5acba685537f8be6ce29c92313853eb312b8484f350b4d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadf-0.4.1-cp311-abi3-win_amd64.whl:

Publisher: publish.yml on YoungseokCh/pyadf

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyadf-0.4.1-cp311-abi3-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for pyadf-0.4.1-cp311-abi3-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 8659556c57a31461afc89e332c07f9d5e923af308b22051538a439bc3a97c711
MD5 ce8533fbc79cbf356bc55947e9a0884c
BLAKE2b-256 374f77e106411096f2df3b6860883e38ebdd08301bbf1c389fadccaff97e7d9a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadf-0.4.1-cp311-abi3-manylinux_2_34_x86_64.whl:

Publisher: publish.yml on YoungseokCh/pyadf

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyadf-0.4.1-cp311-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pyadf-0.4.1-cp311-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 6bf42bd6c674aa34281de2c0cf80e488acaae479f229f4158d94486b6da98995
MD5 1a6ee71d800984d8047a9155b37ad384
BLAKE2b-256 d5ebee29b0dd759322dad231047bdb9516ba7abaa31004df76e6c2d66a3dccb7

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadf-0.4.1-cp311-abi3-manylinux_2_28_x86_64.whl:

Publisher: publish.yml on YoungseokCh/pyadf

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyadf-0.4.1-cp311-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for pyadf-0.4.1-cp311-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 7f04062a5494cc97bcd7affe8afccf4d4923cff2c48b9c8c175a633ba3cf504b
MD5 14d107c6b89dea60f242d24191902307
BLAKE2b-256 00158a717df3791d9c54cc58e19282ac3fc118558cfa72c926495d4a244e7317

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadf-0.4.1-cp311-abi3-manylinux_2_28_aarch64.whl:

Publisher: publish.yml on YoungseokCh/pyadf

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyadf-0.4.1-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

  • Download URL: pyadf-0.4.1-cp311-abi3-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 302.0 kB
  • Tags: CPython 3.11+, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyadf-0.4.1-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 fcc6a198eb4dfbaedf8f4db850138bd9aaf4bfbf5f314291c63188de34f751bf
MD5 e0234b63057422441d8023b9b90bb179
BLAKE2b-256 211a8c4364a8f3dd8ce54059b7903ad3f06fc6ea62001bf2afa4d615a430fb02

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadf-0.4.1-cp311-abi3-macosx_11_0_arm64.whl:

Publisher: publish.yml on YoungseokCh/pyadf

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyadf-0.4.1-cp311-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for pyadf-0.4.1-cp311-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 ed4748ed94493e5259ffac21ddb0f1f8d14e33983da2364454dbbd339c6aed8c
MD5 9464ecb25f9be8357fb18373ad4caf81
BLAKE2b-256 6ac4df01c5b22de3c9af8713a4bb897bf087274413813088df33f912d445fb17

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadf-0.4.1-cp311-abi3-macosx_10_12_x86_64.whl:

Publisher: publish.yml on YoungseokCh/pyadf

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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