nbdol - Notebook Data Object Layer
Pythonic interface for Jupyter notebook manipulation using standard Python protocols (Mapping, Sequence, Iterable).
Overview
nbdol provides a composable, functional approach to creating and modifying Jupyter notebooks. It uses built-in Python protocols to make notebook manipulation feel natural and intuitive.
Key Features
- List-like Notebook interface: Notebooks behave as
MutableSequenceof cells - Dict-like file storage: Manage notebook files using
MutableMappinginterface - Template system: Composable cell generators using
Mappingprotocol - Integration ready: Designed for use with cosmodata and cosmograph
- Type-safe: Proper type hints throughout
- Built on nbformat: Leverages the standard Jupyter notebook format library
Installation
pip install nbdol
Quick Start
Create a Simple Notebook
from nbdol import Notebook
# Create notebook
nb = Notebook()
nb.append_markdown("# My Analysis")
nb.append_code("import pandas as pd")
nb.append_code("df = pd.read_csv('data.csv')")
# Access like a list
print(f"Number of cells: {len(nb)}")
print(f"First cell: {nb[0]['source']}")
# Save
nb.save("analysis.ipynb")
Manage Notebooks as Files
from nbdol import NotebookStore
# Dict-like interface to notebook directory
store = NotebookStore("notebooks/")
# Save notebooks
store["analysis"] = nb # Creates notebooks/analysis.ipynb
# Load notebooks
nb = store["analysis"]
# List notebooks
print(list(store)) # ['analysis', 'exploration', ...]
# Check existence
if "analysis" in store:
print("Found it!")
# Delete
del store["old_notebook"]
Generate from Metadata
from nbdol import populate_notebook
# Metadata dict (e.g., from cosmodata)
metadata = {
"title": "Bitcoin Analysis",
"description": "BTC price history",
"src": "https://example.com/bitcoin.parquet",
"target_filename": "bitcoin.parquet",
}
# Generate notebook with templates
nb = populate_notebook(
metadata,
template_sequence=["intro", "setup", "load", "explore"],
n_viz_cells=5,
output_path="bitcoin.ipynb",
)
Core Components
Notebook (MutableSequence)
Acts like a list of cells with convenience methods:
nb = Notebook()
# Add cells
nb.append_markdown("# Title")
nb.append_code("x = 42")
# List operations
nb.insert(1, markdown_cell("## Section"))
del nb[0]
cell = nb[2]
nb[3] = new_cell
# Iterate
for cell in nb:
print(cell["cell_type"])
# Slice
first_five = nb[:5]
# Length
print(len(nb))
NotebookStore (MutableMapping)
Manage notebooks in a directory using dict syntax:
store = NotebookStore("notebooks/")
# Dict operations
store["name"] = notebook # Save
nb = store["name"] # Load
del store["name"] # Delete
"name" in store # Check existence
list(store) # List all keys
len(store) # Count notebooks
# Iteration
for key in store:
nb = store[key]
# process notebook
CellTemplates (Mapping)
Registry of template functions:
from nbdol import CellTemplates
import nbformat
templates = CellTemplates()
# Define template
def my_template(meta):
yield nbformat.v4.new_markdown_cell(f"# {meta['title']}")
yield nbformat.v4.new_code_cell("import pandas as pd")
# Register
templates.register("intro", my_template)
# Use in notebook
nb.extend_from_template(templates["intro"], {"title": "Test"})
Integration with cosmodata
from cosmodata import metas
from nbdol import NotebookStore, populate_notebook
# Create store
store = NotebookStore("cosmo_notebooks/notebooks/")
# Generate notebooks for datasets
for dataset_key in ["bitcoin", "weather", "covid"]:
meta = metas[dataset_key]
nb = populate_notebook(
meta, template_sequence=["intro", "setup", "load", "explore"], n_viz_cells=5
)
# Add custom sections
nb.append_markdown("## Custom Analysis")
nb.append_code("# Your code here")
# Save
store[dataset_key] = nb
Advanced Usage
Custom Templates
from nbdol import CellTemplates, Notebook
import nbformat
templates = CellTemplates()
@templates.register("custom_intro")
def custom_intro_template(meta):
"""Custom introduction with author info."""
yield nbformat.v4.new_markdown_cell(f"# {meta['title']}")
yield nbformat.v4.new_markdown_cell(f"*By {meta['author']}*")
yield nbformat.v4.new_markdown_cell(f"**Date:** {meta['date']}")
if "description" in meta:
yield nbformat.v4.new_markdown_cell(f"## Overview\n\n{meta['description']}")
# Use template
nb = Notebook()
nb.extend_from_template(
templates["custom_intro"],
{"title": "Analysis", "author": "Jane Doe", "date": "2024-01-01"},
)
Batch Operations
# Add section to multiple notebooks
store = NotebookStore("notebooks/")
for key in store:
nb = store[key]
nb.append_markdown("## New Section")
nb.append_code("# New code")
store[key] = nb # Save changes
Modify Existing Notebooks
# Load existing
nb = Notebook.from_file("existing.ipynb")
# Modify
nb[0]["source"] = "# Updated Title"
nb.insert(2, nbformat.v4.new_markdown_cell("## New Section"))
nb.append_code("# Additional code")
# Save
nb.save() # Saves to original path
Design Philosophy
nbdol follows these principles:
- Use built-in protocols: Leverage
MutableSequence,MutableMapping, etc. - Composability: Mix and match functions and classes
- Type safety: Proper type hints throughout
- Minimal abstraction: Thin wrappers over nbformat
- Discoverability: Standard Python patterns feel natural
API Reference
Notebook
class Notebook(MutableSequence):
def __init__(self, cells=None, *, path=None)
def append_markdown(self, content: str) -> None
def append_code(self, code: str) -> None
def extend_from_template(self, template_func, metadata: dict) -> None
@classmethod
def from_file(cls, path) -> 'Notebook'
def save(self, path=None) -> None
def to_dict(self) -> dict
@property
def cells -> list
@property
def metadata -> dict
NotebookStore
class NotebookStore(MutableMapping):
def __init__(self, root_path='.', *, extension='.ipynb')
# Implements: __getitem__, __setitem__, __delitem__,
# __iter__, __len__, __contains__
CellTemplates
class CellTemplates(Mapping):
def __init__(self)
def register(self, name: str, template_func: Callable) -> None
# Implements: __getitem__, __iter__, __len__
Utility Functions
def notebook_from_metadata(
metadata: dict,
*,
templates=None,
template_sequence=None
) -> Notebook
def populate_notebook(
metadata: Mapping,
*,
template_sequence=('intro', 'setup', 'load', 'explore'),
templates=None,
output_path=None,
n_viz_cells=0
) -> Notebook
def markdown_cell(content: str) -> dict
def code_cell(code: str) -> dict
Default Templates
The library includes default templates for data analysis notebooks:
intro: Dataset title, description, source infosetup: Data parameters, package installation, importsload: Data loading code (cosmodata integration)explore: Data exploration/inspection code
These work with metadata dicts from cosmodata.
Requirements
- Python 3.10+
- nbformat >= 5.0.0
License
MIT
Contributing
Contributions welcome! Please ensure:
- Code follows PEP 8
- All functions have docstrings with examples
- Tests pass
- Type hints are used
Metadata
Release files for nbdol 0.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nbdol-0.0.2.tar.gz | 22.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nbdol-0.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 38.1 kB
Release files / nbdol-0.0.2.tar.gz
| Download URL | nbdol-0.0.2.tar.gz |
|---|---|
| Size | 22.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8b3320f7b831f5bf3c815dba76d72fab917faa45095d10d487b0dbb6db117f53
|
|
BLAKE2b-256 checksum How to use checksums |
b5615e539d6a72d6906fafff6ec7d19805d5d0dfb4bcf9a2f75c61dbe2fa3397
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","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}
|
Release files / nbdol-0.0.2-py3-none-any.whl
| Download URL | nbdol-0.0.2-py3-none-any.whl |
|---|---|
| Size | 15.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
40bd8d2a70be403ac6143ace292e32d6bde211f216488a3706bf1cfcca98b463
|
|
BLAKE2b-256 checksum How to use checksums |
997c7253f0c2fd941c5f430c7a14c10c467104d370a48e2cca65f1f211d593e8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","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}
|