Source code for nbtoolbelt.inline_attachments

"""
NbConvert Preprocessor to inline attachments

Copyright (c) 2017 - Eindhoven University of Technology, The Netherlands

This software is made available under the terms of the MIT License.

Parts of this code are reworked from the rendernb checklet for Momotor <momotor.org>.
"""

import base64
from typing import Any, Dict, Tuple
from urllib.parse import quote

from nbconvert.preprocessors import Preprocessor
from nbformat import NotebookNode

TEST = False


[docs]class InlineAttachmentsPreprocessor(Preprocessor): """To embed cell attachments inside the cell's source. """ ACCEPTABLE_TYPES = ( 'image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/bmp', )
[docs] def preprocess_cell(self, cell: NotebookNode, resources: Dict[str, Any], index: int) -> \ Tuple[NotebookNode, Dict[str, Any]]: """Take a Jupyter Notebook cell and inline all attachments as data. .. note:: **Modifies**: ``cell`` :param cell: cell for which to inline attachments :param resources: global resources :param index: cell index in notebook :return: modified cell, updated resources """ if 'attachments' in cell: remaining_attachments = {} for name, data in cell.attachments.items(): data_type, data_content = None, None # data_content = next((data[data_type] for data_type in data if data_type in ACCEPTABLE_TYPES), None) for data_type in data: if data_type in self.ACCEPTABLE_TYPES: if TEST: print("inline_attachments acceptable data type: {}".format(data_type)) data_content = data[data_type] break if data_content: # Re-encode base64 to strip whitespace try: decoded_content = base64.b64decode(data_content) except TypeError: if TEST: print("inline_attachment decoding gave TypeError") continue recoded_content = base64.b64encode(decoded_content) if TEST: print("inline_attachments recoded content") new_uri = 'data:{};base64,{}'.format(quote(data_type), quote(recoded_content)) if TEST: print("inline_attachments new URI: {}".format(new_uri[:100])) for att_name in (name, quote(name)): old_uri = 'attachment:' + att_name if TEST: print("inline_attachments old URI: {}".format(old_uri)) cell.source = cell.source.replace(old_uri, new_uri) if TEST: print("inline_attachments new cell source:\n{}".format(cell.source[:1000])) else: remaining_attachments[name] = data cell['attachments'] = remaining_attachments return cell, resources