Skip to main content

dn

Markdown parsing and generation

To install: pip install dn

Optional Dependencies

This package supports converting various file formats to Markdown, with each format requiring specific dependencies:

Format      Required Package(s)
----------- -----------------
PDF         pypdf
Word        mammoth
Excel       pandas, openpyxl, tabulate
PowerPoint  python-pptx
HTML        html2text
Notebooks   nbconvert, nbformat
Ebooks      calibre and/or pandoc (system tools) -- see below
Scanned PDF tesseract (system tool) + pytesseract, PyMuPDF

Installation Options

You can install these dependencies after the fact, if and when package complains it needs some specific resource.

You can also install these when installing dn, like so:

    # Install with minimal dependencies
    pip install dn

    # Install with support for specific formats
    pip install dn[pdf]               # PDF conversion support
    pip install dn[word]              # Word document support
    pip install dn[excel]             # Excel support
    pip install dn[powerpoint]        # PowerPoint support
    pip install dn[html]              # HTML conversion
    pip install dn[notebook]          # Jupyter Notebook support
    pip install dn[ebook]             # EPUB (pure-python backend)
    pip install dn[ocr]               # OCR for scanned PDFs

    # Install multiple format support
    pip install dn[pdf,word,excel]    # Multiple formats

    # Install all optional dependencies
    pip install dn[all]

Examples

To and from jupyter notebooks

from dn import markdown_to_notebook

sample_markdown = """# Sample Notebook

This is a markdown cell with some explanation.

```python
# This is a code cell
print("Hello, World!")
x = 42
print(f"The answer is {x}")
```

## Another Section

More markdown content here.

```python
# Another code cell
def greet(name):
    return f"Hello, {name}!"


print(greet("Jupyter"))
```

Final markdown cell."""

Test basic functionality

notebook = markdown_to_notebook(sample_markdown)
print(f"Created notebook with {len(notebook['cells'])} cells")

Test with file output

output_path = markdown_to_notebook(sample_markdown, egress="./sample_notebook.ipynb")
print(f"Saved notebook to: {output_path}")
Created notebook with 5 cells
Saved notebook to: /Users/thorwhalen/Dropbox/py/proj/t/dn/misc/sample_notebook.ipynb
from dn import notebook_to_markdown

md_string = notebook_to_markdown(notebook)
print(md_string)
# Sample Notebook

This is a markdown cell with some explanation.



```python
# This is a code cell
print("Hello, World!")
x = 42
print(f"The answer 
...
nt(greet("Jupyter"))

```

Final markdown cell.

... and other formats

from dn import pdf_to_markdown  # requires pypdf
from dn import docx_to_markdown  # requires mammoth
from dn import excel_to_markdown  # requires pandas
from dn import pptx_to_markdown  # requires python-pptx
from dn import html_to_markdown  # requires html2text

Ebooks (EPUB, MOBI, AZW3, ...)

dn converts ebooks to markdown through a registry of interchangeable backends, tried best-first:

Backend          Needs                  Notes
---------------- ---------------------- ------------------------------------
calibre_pandoc   calibre + pandoc       Best fidelity; all ebook formats
pandoc           pandoc                 EPUB/FB2/ODT/RTF; loses CSS emphasis
calibre_txt      calibre                All formats; noisier output
ebooklib         pip install dn[ebook]  EPUB only; no external binary

Calibre and pandoc are system tools, not pip packages. Ask what you have, and how to get the rest:

from dn import check_ebook_requirements

check_ebook_requirements()

Then convert a path, a URL, or bytes:

from dn import ebook_to_markdown

md = ebook_to_markdown("book.mobi")

Ebook formats also route through the generic entry point, detected from the filename or from the file's own leading bytes:

from dn import bytes_to_markdown

md = bytes_to_markdown(epub_bytes, key="book.epub")
md = bytes_to_markdown(epub_bytes)  # format sniffed from the bytes

Add your own strategy with register_ebook_backend.

What cannot be converted. DRM-protected ebooks (Amazon KFX/AZW, Adobe-DRM EPUB) are encrypted: no backend can read them, and you must remove the DRM yourself — where you are legally entitled to — before converting. Image-only containers (CBZ, CBR, DJVU) hold no text layer and are deliberately excluded from EBOOK_FORMATS. Scanned PDFs are handled -- see the OCR section below.

Scanned PDFs (OCR)

A scanned book is a PDF full of pictures of pages, so ordinary text extraction returns nothing. dn notices and runs OCR on exactly those pages:

from dn import pdf_to_markdown

md = pdf_to_markdown(scanned_pdf_bytes)  # OCRs the pages that have no text
md = pdf_to_markdown(pdf_bytes, ocr=False)  # opt out (OCR costs ~1s/page)

This needs the Tesseract binary plus pip install dn[ocr]:

from dn import check_ocr_requirements

check_ocr_requirements()

PDFs that already carry a text layer never pay the OCR cost.

Markdown stores

User story: I have a directory with multiple files in different formats.

I want to batch convert all supported files to markdown and store them in memory.

from dn import Files, bytes_store_to_markdown_store

from dn.tests.utils_for_testing_dn import test_data_dir

# Setup source files from test directory
src_files = Files(test_data_dir)

# Setup target store as an in-memory dictionary
target_store = {}

# Convert all files in directory to markdown
result = bytes_store_to_markdown_store(src_files, target_store, verbose=False)

# Check that the result is the target_store
assert result is target_store

# Verify that the supported file types were converted correctly
supported_files = [
    "test.docx",
    "test.pptx",
    "test.pdf",
    "test.html",
    "test.xlsx",
    "test.txt",
    "test.md",
    "test.ipynb",
]

print(
    f"\nSupported files (given what packages are installed here): {supported_files}\n"
)

for filename in supported_files:
    assert f"{filename}.md" in target_store, f"{filename} not found in target_store"
    assert len(target_store[f"{filename}.md"]) > 0, f"{filename} conversion failed"
invalid pdf header: b'PK\x03\x04\n'
EOF marker not found
EOF marker not found
invalid pdf header: b'PK\x03\x04\x14'
EOF marker not found
invalid pdf h
...
df header: b'PK\x03\x04\x14'
EOF marker not found



Supported files (given what packages are installed here): ['test.docx', 'test.pptx', 'test.pdf', 'test.html', 'test.xlsx', 'test.txt', 'test.md', 'test.ipynb']

Convert this notebook into a markdown for the README.md

from dn import notebook_to_markdown

notebook_to_markdown(
    "~/Dropbox/py/proj/t/dn/misc/dn_readme.ipynb", target_file="../README.md"
)
HTML output truncated. (Data removed)

Download files

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

Source Distribution

dn-0.0.13.tar.gz (172.6 kB view details)

Uploaded Source

Built Distribution

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

dn-0.0.13-py3-none-any.whl (172.9 kB view details)

Uploaded Python 3

File details

Details for the file dn-0.0.13.tar.gz.

File metadata

  • Download URL: dn-0.0.13.tar.gz
  • Upload date:
  • Size: 172.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for dn-0.0.13.tar.gz
Algorithm Hash digest
SHA256 f43cc331547a7c37f8852ccf074f49c085521f039e6e1583210b5415ebe0bae8
MD5 5fcafd162de4590f40980473676db3b6
BLAKE2b-256 347dc5268b636eea3303be3d7b83d9073b632ec86db517c001567206cff8d49b

See more details on using hashes here.

File details

Details for the file dn-0.0.13-py3-none-any.whl.

File metadata

  • Download URL: dn-0.0.13-py3-none-any.whl
  • Upload date:
  • Size: 172.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for dn-0.0.13-py3-none-any.whl
Algorithm Hash digest
SHA256 1589894c3b54a2971f14e66dd04cb118aeb608a6523cdaaea845bd0937ddd162
MD5 68acc19a428857b2c3e7b394ac0d6a4b
BLAKE2b-256 af8fbb5d9569fdb151fe1026111f259654c5a26f6976257fe1e922625e62d591

See more details on using hashes here.

Release history Release notifications | RSS feed

0.0.14

2 files

This release

0.0.13 This release

2 files

0.0.12

2 files

0.0.11

2 files

0.0.10

2 files

0.0.9

2 files

0.0.8

2 files

0.0.7

2 files

0.0.6

2 files

0.0.5

2 files

0.0.4

2 files

0.0.3

2 files

0.0.2

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page