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
Documentclass 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 objectconfig: optionalMarkdownConfigon_error:"include"(default, yieldsConversionError),"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 errorsInvalidJSONError— Raised when JSON parsing failsInvalidInputError— Raised when input type is incorrectInvalidADFError— Raised when ADF structure is invalidMissingFieldError— Raised when required fields are missingInvalidFieldError— Raised when field values are invalidUnsupportedNodeTypeError— Raised when encountering unsupported node typesNodeCreationError— 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
ConversionErrordataclass 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_loggermodule (will be replaced with Rust-native tracing in a future release) nodesand_typesmodules 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
Documentclass - 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
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 Distributions
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 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
52adf6de3edd5ac7d3a1ce4141a3a1fc8ed58a40e6b4928faee45f0d75c44a9e
|
|
| MD5 |
e489d8800fc546a3aa24530cdceb0259
|
|
| BLAKE2b-256 |
0287afd908bfafe84f8530e303c05a8cea3638f4f8d06c3af5f30e8bc55f7d56
|
Provenance
The following attestation bundles were made for pyadf-0.4.2.tar.gz:
Publisher:
publish.yml on YoungseokCh/pyadf
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyadf-0.4.2.tar.gz -
Subject digest:
52adf6de3edd5ac7d3a1ce4141a3a1fc8ed58a40e6b4928faee45f0d75c44a9e - Sigstore transparency entry: 1245021274
- Sigstore integration time:
-
Permalink:
YoungseokCh/pyadf@4d51e23123bd0d01accd9d6b11803a82fb9d282e -
Branch / Tag:
refs/tags/v0.4.2 - Owner: https://github.com/YoungseokCh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4d51e23123bd0d01accd9d6b11803a82fb9d282e -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9a347cfbe212d6d408ed269a295f30091e3ed81289d621e8ef329388dc9fb637
|
|
| MD5 |
839ff92aec295aacb0055c59fd3801ea
|
|
| BLAKE2b-256 |
d520cfb7454fa8a3c9fbae90e49a11d41ef0c778f1bf7facb48df8e233e5372b
|
Provenance
The following attestation bundles were made for pyadf-0.4.2-cp311-abi3-win_amd64.whl:
Publisher:
publish.yml on YoungseokCh/pyadf
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyadf-0.4.2-cp311-abi3-win_amd64.whl -
Subject digest:
9a347cfbe212d6d408ed269a295f30091e3ed81289d621e8ef329388dc9fb637 - Sigstore transparency entry: 1245021569
- Sigstore integration time:
-
Permalink:
YoungseokCh/pyadf@4d51e23123bd0d01accd9d6b11803a82fb9d282e -
Branch / Tag:
refs/tags/v0.4.2 - Owner: https://github.com/YoungseokCh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4d51e23123bd0d01accd9d6b11803a82fb9d282e -
Trigger Event:
release
-
Statement type:
File details
Details for the file pyadf-0.4.2-cp311-abi3-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: pyadf-0.4.2-cp311-abi3-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 343.5 kB
- Tags: CPython 3.11+, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f189d215d26d8db22a59355ce0d5e0a60d450182616b2ce14760ccd7917c137d
|
|
| MD5 |
8814ef2d540d41a23c01c871f5735cca
|
|
| BLAKE2b-256 |
f242d96d3cf66788bf9410631afcad691b30632a41950454dab99eac9772418f
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyadf-0.4.2-cp311-abi3-manylinux_2_34_x86_64.whl -
Subject digest:
f189d215d26d8db22a59355ce0d5e0a60d450182616b2ce14760ccd7917c137d - Sigstore transparency entry: 1245021833
- Sigstore integration time:
-
Permalink:
YoungseokCh/pyadf@4d51e23123bd0d01accd9d6b11803a82fb9d282e -
Branch / Tag:
refs/tags/v0.4.2 - Owner: https://github.com/YoungseokCh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4d51e23123bd0d01accd9d6b11803a82fb9d282e -
Trigger Event:
release
-
Statement type:
File details
Details for the file pyadf-0.4.2-cp311-abi3-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: pyadf-0.4.2-cp311-abi3-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 343.9 kB
- Tags: CPython 3.11+, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5d364b903b357c05c82cbd8bc8a4c64bfa2c61906b47292ac1154c7bdd4bd426
|
|
| MD5 |
386e5ed470714cdf1d17999dad5b8e3b
|
|
| BLAKE2b-256 |
54622d7f9073773a4852c0e1471e08472238ac4da082992899167dcb93ef3076
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyadf-0.4.2-cp311-abi3-manylinux_2_28_x86_64.whl -
Subject digest:
5d364b903b357c05c82cbd8bc8a4c64bfa2c61906b47292ac1154c7bdd4bd426 - Sigstore transparency entry: 1245022226
- Sigstore integration time:
-
Permalink:
YoungseokCh/pyadf@4d51e23123bd0d01accd9d6b11803a82fb9d282e -
Branch / Tag:
refs/tags/v0.4.2 - Owner: https://github.com/YoungseokCh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4d51e23123bd0d01accd9d6b11803a82fb9d282e -
Trigger Event:
release
-
Statement type:
File details
Details for the file pyadf-0.4.2-cp311-abi3-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: pyadf-0.4.2-cp311-abi3-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 322.7 kB
- Tags: CPython 3.11+, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c8212a9f4a6de0a2533a5ce2c69073cac78d53da46cba655c23ce02721f02637
|
|
| MD5 |
6c68abf97fa9cc954a38e6853359190e
|
|
| BLAKE2b-256 |
d47edc9e7d2b3d8b9933eab5567564cf63248c20af633a6b2a3df3f902abdfeb
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyadf-0.4.2-cp311-abi3-manylinux_2_28_aarch64.whl -
Subject digest:
c8212a9f4a6de0a2533a5ce2c69073cac78d53da46cba655c23ce02721f02637 - Sigstore transparency entry: 1245023247
- Sigstore integration time:
-
Permalink:
YoungseokCh/pyadf@4d51e23123bd0d01accd9d6b11803a82fb9d282e -
Branch / Tag:
refs/tags/v0.4.2 - Owner: https://github.com/YoungseokCh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4d51e23123bd0d01accd9d6b11803a82fb9d282e -
Trigger Event:
release
-
Statement type:
File details
Details for the file pyadf-0.4.2-cp311-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: pyadf-0.4.2-cp311-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 301.8 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7ecc7ab182e87e4749fa5a223b1dafe5c22ba648189343b95b8ad57153ec3afb
|
|
| MD5 |
fe13c9bc223a2b8e15c1aeb399d4f6ea
|
|
| BLAKE2b-256 |
03843b27beb62fd001fefb99e24539e94acf6aef90f6b9e5cfcdc041d1b683ab
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyadf-0.4.2-cp311-abi3-macosx_11_0_arm64.whl -
Subject digest:
7ecc7ab182e87e4749fa5a223b1dafe5c22ba648189343b95b8ad57153ec3afb - Sigstore transparency entry: 1245022553
- Sigstore integration time:
-
Permalink:
YoungseokCh/pyadf@4d51e23123bd0d01accd9d6b11803a82fb9d282e -
Branch / Tag:
refs/tags/v0.4.2 - Owner: https://github.com/YoungseokCh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4d51e23123bd0d01accd9d6b11803a82fb9d282e -
Trigger Event:
release
-
Statement type:
File details
Details for the file pyadf-0.4.2-cp311-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: pyadf-0.4.2-cp311-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 321.7 kB
- Tags: CPython 3.11+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7ae665840b486163418dcc1484015c20a81f77dcb53389c0579baf731da2a559
|
|
| MD5 |
11255d2cc0b5083025ba9cd1ca6be477
|
|
| BLAKE2b-256 |
0cd3c0c9db25b76a7e97ba9576ff9e7a485c3c8f4232391e0aab401944b55b29
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyadf-0.4.2-cp311-abi3-macosx_10_12_x86_64.whl -
Subject digest:
7ae665840b486163418dcc1484015c20a81f77dcb53389c0579baf731da2a559 - Sigstore transparency entry: 1245022918
- Sigstore integration time:
-
Permalink:
YoungseokCh/pyadf@4d51e23123bd0d01accd9d6b11803a82fb9d282e -
Branch / Tag:
refs/tags/v0.4.2 - Owner: https://github.com/YoungseokCh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4d51e23123bd0d01accd9d6b11803a82fb9d282e -
Trigger Event:
release
-
Statement type: