Skip to main content

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 MutableSequence of cells
  • Dict-like file storage: Manage notebook files using MutableMapping interface
  • Template system: Composable cell generators using Mapping protocol
  • 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:

  1. Use built-in protocols: Leverage MutableSequence, MutableMapping, etc.
  2. Composability: Mix and match functions and classes
  3. Type safety: Proper type hints throughout
  4. Minimal abstraction: Thin wrappers over nbformat
  5. 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 info
  • setup: Data parameters, package installation, imports
  • load: 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

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nbdol-0.0.2.tar.gz (22.6 kB view details)

Uploaded Source

Built Distribution

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

nbdol-0.0.2-py3-none-any.whl (15.5 kB view details)

Uploaded Python 3

File details

Details for the file nbdol-0.0.2.tar.gz.

File metadata

  • Download URL: nbdol-0.0.2.tar.gz
  • Upload date:
  • Size: 22.6 kB
  • Tags: Source
  • Uploaded using 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}

File hashes

Hashes for nbdol-0.0.2.tar.gz
Algorithm Hash digest
SHA256 8b3320f7b831f5bf3c815dba76d72fab917faa45095d10d487b0dbb6db117f53
MD5 7a14f801a29a222c55d6e3a5b0f88458
BLAKE2b-256 b5615e539d6a72d6906fafff6ec7d19805d5d0dfb4bcf9a2f75c61dbe2fa3397

See more details on using hashes here.

File details

Details for the file nbdol-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: nbdol-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 15.5 kB
  • Tags: Python 3
  • Uploaded using 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}

File hashes

Hashes for nbdol-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 40bd8d2a70be403ac6143ace292e32d6bde211f216488a3706bf1cfcca98b463
MD5 fbfe8d0a3b89a27e0c6e7bf2d3981f2d
BLAKE2b-256 997c7253f0c2fd941c5f430c7a14c10c467104d370a48e2cca65f1f211d593e8

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.0.2 This release

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