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, block 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
blockCard [link] or code block Link previews

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.2 (Current)

  • Add support for (new?) blockCard node type

0.4.1

  • Fix linux x86_64 wheel builds

0.4.0

  • 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.2.tar.gz (43.9 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.2-cp311-abi3-win_amd64.whl (250.0 kB view details)

Uploaded CPython 3.11+Windows x86-64

pyadf-0.4.2-cp311-abi3-manylinux_2_34_x86_64.whl (343.5 kB view details)

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

pyadf-0.4.2-cp311-abi3-manylinux_2_28_x86_64.whl (343.9 kB view details)

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

pyadf-0.4.2-cp311-abi3-manylinux_2_28_aarch64.whl (322.7 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.28+ ARM64

pyadf-0.4.2-cp311-abi3-macosx_11_0_arm64.whl (301.8 kB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

pyadf-0.4.2-cp311-abi3-macosx_10_12_x86_64.whl (321.7 kB view details)

Uploaded CPython 3.11+macOS 10.12+ x86-64

File details

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

File metadata

  • Download URL: pyadf-0.4.2.tar.gz
  • Upload date:
  • Size: 43.9 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.2.tar.gz
Algorithm Hash digest
SHA256 52adf6de3edd5ac7d3a1ce4141a3a1fc8ed58a40e6b4928faee45f0d75c44a9e
MD5 e489d8800fc546a3aa24530cdceb0259
BLAKE2b-256 0287afd908bfafe84f8530e303c05a8cea3638f4f8d06c3af5f30e8bc55f7d56

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadf-0.4.2.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.2-cp311-abi3-win_amd64.whl.

File metadata

  • Download URL: pyadf-0.4.2-cp311-abi3-win_amd64.whl
  • Upload date:
  • Size: 250.0 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.2-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 9a347cfbe212d6d408ed269a295f30091e3ed81289d621e8ef329388dc9fb637
MD5 839ff92aec295aacb0055c59fd3801ea
BLAKE2b-256 d520cfb7454fa8a3c9fbae90e49a11d41ef0c778f1bf7facb48df8e233e5372b

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadf-0.4.2-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.2-cp311-abi3-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for pyadf-0.4.2-cp311-abi3-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 f189d215d26d8db22a59355ce0d5e0a60d450182616b2ce14760ccd7917c137d
MD5 8814ef2d540d41a23c01c871f5735cca
BLAKE2b-256 f242d96d3cf66788bf9410631afcad691b30632a41950454dab99eac9772418f

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadf-0.4.2-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.2-cp311-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pyadf-0.4.2-cp311-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 5d364b903b357c05c82cbd8bc8a4c64bfa2c61906b47292ac1154c7bdd4bd426
MD5 386e5ed470714cdf1d17999dad5b8e3b
BLAKE2b-256 54622d7f9073773a4852c0e1471e08472238ac4da082992899167dcb93ef3076

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadf-0.4.2-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.2-cp311-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for pyadf-0.4.2-cp311-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 c8212a9f4a6de0a2533a5ce2c69073cac78d53da46cba655c23ce02721f02637
MD5 6c68abf97fa9cc954a38e6853359190e
BLAKE2b-256 d47edc9e7d2b3d8b9933eab5567564cf63248c20af633a6b2a3df3f902abdfeb

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadf-0.4.2-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.2-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pyadf-0.4.2-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 7ecc7ab182e87e4749fa5a223b1dafe5c22ba648189343b95b8ad57153ec3afb
MD5 fe13c9bc223a2b8e15c1aeb399d4f6ea
BLAKE2b-256 03843b27beb62fd001fefb99e24539e94acf6aef90f6b9e5cfcdc041d1b683ab

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadf-0.4.2-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.2-cp311-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for pyadf-0.4.2-cp311-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 7ae665840b486163418dcc1484015c20a81f77dcb53389c0579baf731da2a559
MD5 11255d2cc0b5083025ba9cd1ca6be477
BLAKE2b-256 0cd3c0c9db25b76a7e97ba9576ff9e7a485c3c8f4232391e0aab401944b55b29

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadf-0.4.2-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