jupyter / notebook

Jupyter Interactive Notebook
https://jupyter-notebook.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
11.59k stars 4.86k forks source link

cell.attachments don't appear to be accessible in the notebook model #2606

Open Analect opened 7 years ago

Analect commented 7 years ago

I've been experimenting around enriching a notebook with cell meta-data, leveraging nbformat and saving changes to a 'shadow' notebook, since I can't overwrite an already open file in jupyterlab. This has been working fine.

from nbformat import NotebookNode
...
...
def add_eolas_metadata_pre_save(model, **kwargs):

...
...
# now let's handle the cell meta-data
    for i, cell in enumerate(model['content']['cells']):

        if 'eolas_cell' not in model['content']['cells'][i]['metadata']:
            #let's check that it's not in the shadow notebook
            try:
                #new cells in model (but not yet in nb_shadow may throw an error here)
                #in which case the except below should force generation of cell UUIDs and apply to model.
                if 'eolas_cell' not in shadow_nb.cells[i]['metadata']:
                    #then generate new cell UUID
                    eolas_cell_metadata = NotebookNode(dict(cell_uuid=str(uuid.uuid4())))
                    eolas_cell_metadata_parent = NotebookNode(dict(eolas_cell=eolas_cell_metadata))
                    cell_metadata_wrapper = NotebookNode(dict(metadata=eolas_cell_metadata_parent))
                    cell_metadata_copy = nb_from_model.cells[i].metadata.copy()
                    cell_metadata_copy.update(eolas_cell_metadata_parent)

However, when it comes to handling cell attachments, this approach no longer works. While the notebook in jupyterlab still doesn't allow adding cell attachments, if I select Launch Classic Notebook from the help menu in JupyterLab, I am able to work with that instance of a notebook to copy and paste images into a cell which are automatically added as cell attachments.

From the readthedocs, it would appear that "attachments" are not exposed as part of the 'model', alongside cell_type, metadata and source.

image

That might explain why enriching the model cells.metadata (as per script above) and then using that updated in-memory 'model' to save a copy of the notebook (on right below) is missing the attachments element from the json (red box below).

image

Could anyone suggest how I might access the attachments part of a notebook from a pre-save hook python script, so that I can include it as part of a saved 'shadow' notebook that includes my enriched meta-data?

takluyver commented 7 years ago

I see the attachments in a pre-save hook with the following code:

def pre_save(model, path, contents_manager=None):
    print('pre_save called')
    if model['type'] != 'notebook':
        return
    print("pre_save with notebook")
    for i, cell in enumerate(model['content']['cells']):
        for attachment in cell.get('attachments', {}):
            print('Cell {} has attachment {}'.format(i, attachment))

Note that they're a separate key on the cell, not part of metadata.