rep2nb
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
- Discovery — finds all
.pyfiles, skippingvenv/,__pycache__/, etc. - Section Detection — subdirectories without
__init__.pyare treated as independent sections; packages stay in the root section - AST Analysis — parses each file to extract imports, definitions, docstrings, and
if __name__ == '__main__'blocks - Dependency Graph — builds a directed graph of which files import from which (per section)
- Topological Sort — determines the correct execution order (dependencies first)
- Transform — for each file:
- Library modules: strips
if __name__ == '__main__'test blocks, addssys.modulesregistration so imports resolve correctly - Entry points: unwraps
if __name__ == '__main__'so the code runs, resetssys.argvfor argparse compatibility - Relative imports (
from . import X) are rewritten to absolute form - Module-level docstrings are extracted and placed in markdown cells
- Library modules: strips
- Notebook Assembly — produces a valid
.ipynbwith:- README content as a markdown header (if found)
- A notice about required data files
- Optional
!pip installcell (uses kernel-safesys.executable) - Section headers and
os.chdirfor multi-project repos - Markdown cells with module docstrings above each code cell
sys.modulescleanup 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 withsys.modulescleanup between them, so files with the same name (likehelpers.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 withif __name__ == '__main__'that nothing else imports - Argparse handling — resets
sys.argvin entry points soargparseuses defaults instead of crashing on Jupyter kernel args __file__support — injects__file__so scripts usingos.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
.pyfiles (notebooks run Python kernels) - Dynamic imports —
importlib.import_module(name)wherenameis 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
Release files for rep2nb 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rep2nb-0.1.0.tar.gz | 19.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rep2nb-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 37.6 kB
Release files / rep2nb-0.1.0.tar.gz
| Download URL | rep2nb-0.1.0.tar.gz |
|---|---|
| Size | 19.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
09002922274941a0bcc7089c64f8fc334b0fe28f29914844075354fa3cd114a2
|
|
BLAKE2b-256 checksum How to use checksums |
7fba1c4fda348d6158a1e817d5f8288f3694737b4ab142a7daa73a7a6631186c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.0
|
Release files / rep2nb-0.1.0-py3-none-any.whl
| Download URL | rep2nb-0.1.0-py3-none-any.whl |
|---|---|
| Size | 18.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
54ff49f08c4e34aad8d5fa6678f038a31a498de48466cc511b292b87b8f4ab74
|
|
BLAKE2b-256 checksum How to use checksums |
80c0f5921cbf1e27b9c163fbbb28ab000de36962d7a004a79bfc67498b0cbf01
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.0
|