Skip to main content

Convert a Python repository into a single executable Jupyter notebook

Project description

rep2nb

CI PyPI version Python License: MIT

Convert a Python repository into a single executable Jupyter notebook.

The problem: You built a well-structured repo with multiple files, proper separation of concerns, clean imports — then someone says "we need a .ipynb." You now have to manually copy-paste everything into cells, figure out the right order, inline your imports, and pray it runs.

The solution: One command.

rep2nb /path/to/your/repo -o submission.ipynb

rep2nb analyzes your repo's dependency graph, topologically sorts your files, and produces a single notebook where every cell runs in order — just like your repo does.

Installation

pip install rep2nb

From source

git clone https://github.com/tyephoenix/rep2nb.git
cd rep2nb
pip install .

Usage

CLI

# Auto-detect entry point, output to <repo-name>.ipynb
rep2nb myproject/

# Specify entry point and output file
rep2nb myproject/ --entry main.py -o submission.ipynb

# Exclude directories
rep2nb myproject/ --exclude tests/ --exclude docs/

# Add a pip install cell for external dependencies
rep2nb myproject/ --include-pip-install

# Multiple entry points in a specific order (e.g. generate data, then analyze it)
rep2nb myproject/ --entry generate.py --entry analyze.py

# Repo with multiple independent sub-projects (sections auto-detected)
rep2nb contest-repo/ --entry problem-1/pipeline.py --entry problem-2/main.py

# Disable auto-section detection
rep2nb myproject/ --no-sections

Python API

from rep2nb import convert

# Basic usage
convert("myproject/", output="submission.ipynb")

# With options
convert(
    "myproject/",
    output="submission.ipynb",
    entry="main.py",
    exclude=["tests/", "docs/"],
    include_pip_install=True,
)

# Multiple entry points with explicit ordering
convert("myproject/", entry=["generate.py", "analyze.py"])

# Multi-project repo with section-specific entries
convert(
    "contest-repo/",
    entry=["problem-1/pipeline.py", "problem-2/main.py"],
    output="submission.ipynb",
)

How It Works

  1. Discovery — finds all .py files, skipping venv/, __pycache__/, etc.
  2. Section Detection — subdirectories without __init__.py are treated as independent sections; packages stay in the root section
  3. AST Analysis — parses each file to extract imports, definitions, docstrings, and if __name__ == '__main__' blocks
  4. Dependency Graph — builds a directed graph of which files import from which (per section)
  5. Topological Sort — determines the correct execution order (dependencies first)
  6. Transform — for each file:
    • Library modules: strips if __name__ == '__main__' test blocks, adds sys.modules registration so imports resolve correctly
    • Entry points: unwraps if __name__ == '__main__' so the code runs, resets sys.argv for argparse compatibility
    • Relative imports (from . import X) are rewritten to absolute form
    • Module-level docstrings are extracted and placed in markdown cells
  7. Notebook Assembly — produces a valid .ipynb with:
    • README content as a markdown header (if found)
    • A notice about required data files
    • Optional !pip install cell (uses kernel-safe sys.executable)
    • Section headers and os.chdir for multi-project repos
    • Markdown cells with module docstrings above each code cell
    • sys.modules cleanup between sections to prevent name collisions

Features

  • Dependency resolution — handles import X, from X import Y, relative imports, and packages with __init__.py
  • Correct execution order — topological sort ensures definitions exist before use
  • Cross-file imports just work — each module is registered in sys.modules, so all import styles resolve correctly
  • Sections mode — independent subdirectories (e.g. problem-1/, problem-2/) become isolated notebook sections with sys.modules cleanup between them, so files with the same name (like helpers.py) don't collide
  • Docstring extraction — module-level docstrings become markdown cells above each code cell for readability; function/class docstrings stay in the code
  • Smart entry point detection — auto-detects main.py, app.py, pipeline.py, run.py, or files with if __name__ == '__main__' that nothing else imports
  • Argparse handling — resets sys.argv in entry points so argparse uses defaults instead of crashing on Jupyter kernel args
  • __file__ support — injects __file__ so scripts using os.path.dirname(__file__) for relative paths still work
  • README at the top — your repo's README becomes the notebook's header
  • Data file awareness — lists non-Python files that should be in the working directory
  • Portable notebooks — zero absolute paths; the generated notebook can be moved anywhere (bring your data files)
  • Zero config — works out of the box for typical repo structures

Limitations

  • Python only — only converts .py files (notebooks run Python kernels)
  • Dynamic importsimportlib.import_module(name) where name is a runtime value can't be detected statically
  • Subprocess calls — if your code shells out to other scripts, those won't be inlined
  • Circular imports — detected and reported as an error (fix them in your repo first)

Development

git clone https://github.com/tyephoenix/rep2nb.git
cd rep2nb
pip install -e ".[dev]"
pytest

Requirements

  • Python >= 3.10
  • nbformat (installed automatically)

License

MIT

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

rep2nb-0.1.0.tar.gz (19.3 kB view details)

Uploaded Source

Built Distribution

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

rep2nb-0.1.0-py3-none-any.whl (18.3 kB view details)

Uploaded Python 3

File details

Details for the file rep2nb-0.1.0.tar.gz.

File metadata

  • Download URL: rep2nb-0.1.0.tar.gz
  • Upload date:
  • Size: 19.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.0

File hashes

Hashes for rep2nb-0.1.0.tar.gz
Algorithm Hash digest
SHA256 09002922274941a0bcc7089c64f8fc334b0fe28f29914844075354fa3cd114a2
MD5 01136ac4f8326dc17a39aff9ea1f5596
BLAKE2b-256 7fba1c4fda348d6158a1e817d5f8288f3694737b4ab142a7daa73a7a6631186c

See more details on using hashes here.

File details

Details for the file rep2nb-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: rep2nb-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 18.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.0

File hashes

Hashes for rep2nb-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 54ff49f08c4e34aad8d5fa6678f038a31a498de48466cc511b292b87b8f4ab74
MD5 ef59b56a4965c84e370a868d8de67ebf
BLAKE2b-256 80c0f5921cbf1e27b9c163fbbb28ab000de36962d7a004a79bfc67498b0cbf01

See more details on using hashes here.

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