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
Built Distribution
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 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f43cc331547a7c37f8852ccf074f49c085521f039e6e1583210b5415ebe0bae8
|
|
| MD5 |
5fcafd162de4590f40980473676db3b6
|
|
| BLAKE2b-256 |
347dc5268b636eea3303be3d7b83d9073b632ec86db517c001567206cff8d49b
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1589894c3b54a2971f14e66dd04cb118aeb608a6523cdaaea845bd0937ddd162
|
|
| MD5 |
68acc19a428857b2c3e7b394ac0d6a4b
|
|
| BLAKE2b-256 |
af8fbb5d9569fdb151fe1026111f259654c5a26f6976257fe1e922625e62d591
|