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 — or a whole new format — with register_ebook_backend.

Note that only unambiguous ebook extensions are auto-detected. Several formats calibre reads are usually something else entirely (.rb is Ruby far more often than Rocket eBook, .pdb is usually a Protein Data Bank file), so those never get claimed from a filename; convert them by asking: ebook_to_markdown(src, input_format='rb').

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)

'auto' engages only when the document has no text layer anywhere — the scanned-book case, where the alternative is an empty result. A text PDF never pays the OCR cost, not even one with blank or figure-only pages. For a PDF that's mostly text with a few scanned inserts, ask explicitly:

md = pdf_to_markdown(pdf_bytes, ocr=True)  # OCR every text-less page

'auto' is also opportunistic: if OCR is unavailable or fails, you still get the plain-extraction result. ocr=True raises instead.

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

from dn import check_ocr_requirements

check_ocr_requirements()

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.14.tar.gz (176.5 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.14-py3-none-any.whl (177.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: dn-0.0.14.tar.gz
  • Upload date:
  • Size: 176.5 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.14.tar.gz
Algorithm Hash digest
SHA256 b1badfb3c372772b31ae9500464fc3eb383082085251e02786dd7287fb36f3de
MD5 3d09f8b40391e8848f189c22bac9aeaf
BLAKE2b-256 96aa03f1f94357368a0e37b10438e0080b83731b7b3e2bab76be75fd6a9981cd

See more details on using hashes here.

File details

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

File metadata

  • Download URL: dn-0.0.14-py3-none-any.whl
  • Upload date:
  • Size: 177.2 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.14-py3-none-any.whl
Algorithm Hash digest
SHA256 62be14e2f0b83db5ff146214be6c4a6c7afbb4a7033cf628a59ddae4e30d497e
MD5 41ac559be99167996d93de22de42ddc8
BLAKE2b-256 b66b3e220ab863a6f3b2cf6b7e8dc86ae7ff3951bcabfe8adbc305f945a245eb

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.0.14 This release

2 files

0.0.13

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