<commit_before>import time
import os
import json
import traceback
from io import BytesIO

from IPython.nbformat import reader
from IPython.display import Javascript, display

from IPython.nbconvert.preprocessors import Preprocessor
from IPython.nbconvert import HTMLExporter

import param
from ..core.io import FileArchive
from ..plotting import PlotRenderer, HTML_TAGS

import threading

class NotebookArchive(FileArchive):

    export_timeout = param.Integer(default=None, allow_None=True,  doc="""
       A timeout in seconds between when the export method is run and
       when export actually occurs.

       When 'Run All' is used in the notebook, all cells have to
       either execute or an Exception has to occurs before the export
       can occur. This timeout helps avoid exporting stale or partial
       notebooks and can be avoided by making sure the call to export
       is the last code cell in your notebook.""")

    exporter = param.Callable(default=PlotRenderer)

    namespace = param.String('holoviews.archive', doc="""
        The name of the current in the NotebookArchive instance in the
        IPython namespace that must be available.""")

    snapshot_name = param.String('{timestamp}-snapshot', doc="""
        The basename of the exported notebook snapshot (html)""")

    auto = param.Boolean(False)

    # Used for debugging to view Exceptions raised from Javascript!
    traceback = None

    def __init__(self, **params):
        super(NotebookArchive, self).__init__(**params)
        self.notebook = BytesIO()
        self.nbversion = None
        self._replacements = {}
        self._exported, self._cancel = False, False
        self._timestamp = None
        self._tags = {val[0]:val[1] for val in HTML_TAGS.values()
                      if isinstance(val, tuple) and len(val)==2}

    def _timeout(self, parent):
        """
        Timeout run in a separate thread to allow the notebook to keep
        running after export is called.

        If you click 'Run All' in the notebook, all code cells are
        queued which means export may never actually happen (e.g. if
        an Exception occurs between the export and the end of the
        notebook. This method helps ensure the exported data isn't
        stale and generates a warning if the timeout is exceeded.
        """
        if parent.export_timeout is None: return
        for i in range(parent.export_timeout):
            time.sleep(1)
            if parent._exported: break
        else:
            parent._cancel = True
            parent.warning("Export cancelled: export_timeout exceed.\n"
                           "Make sure to export at the end of your notebook.")

    def export(self, export_timeout=None, timestamp=None):
        """
        Get the current notebook data and export.
        """
        self.export_timeout = export_timeout if export_timeout else self.export_timeout
        self._timestamp = timestamp if (timestamp is not None) else tuple(time.localtime())
        self._cancel, self._exported = False, False
        name = self.namespace
        # Unfortunate javascript hacks to get at notebook data
        cmd = (r'var kernel = IPython.notebook.kernel;'
               r'var json_data = IPython.notebook.toJSON();'
               r'var json_string = JSON.stringify(json_data);'
               + (r"var command = '%s.notebook.write(r\"\"\"'+json_string+'\"\"\".encode(\'utf-16\'))';" % name)
               + "var pycmd = command + ';%s._export_with_html()';" % name
               + r"kernel.execute(pycmd)")
        display(Javascript(cmd))
        t = threading.Thread(target=self._timeout, args=(self,))
        t.start()
        tstamp = time.strftime(self.timestamp_format, self._timestamp)
        export_name = self._format(self.export_name, {'timestamp':tstamp})
        print('Attempting export %r to %r' % (export_name,
                                              os.path.join(os.path.abspath(self.root))))


    def add(self, obj=None, filename=None, data=None, info={}, html=None):
        if self.auto:
            super(NotebookArchive, self).add(obj, filename, data, info)
            last_key = self._files.keys()[-1]
            self._replacements[last_key] = html


    def _export_with_html(self):
        "Use nbconvert with Substitute preprocessor"
        self._exported = True
        try:
            tstamp = time.strftime(self.timestamp_format, self._timestamp)

            substitutions = {}
            for (basename, ext), entry in self._files.items():
                (_, info) = entry
                html_key = self._replacements[(basename, ext)]
                filename = self._format(basename, {'timestamp':tstamp})
                fpath = filename+(('.%s' % ext) if ext else '')
                msg = "<center><b>%s</b><center/>"
                if 'mime_type' not in info:
                    link_html = msg % "Could not determine data mime-type"
                if info['mime_type'] not in self._tags:
                    link_html = msg % 'Could not determine HTML tag from mime-type'

                info = {'src':fpath, 'mime_type':info['mime_type']}
                link_html = self._format(self._tags[info['mime_type']],<commit_msg>Improved the usability of NotebookArchive<commit_after>import time
import os
import json
import traceback
from io import BytesIO

from IPython.nbformat import reader
from IPython.display import Javascript, display

from IPython.nbconvert.preprocessors import Preprocessor
from IPython.nbconvert import HTMLExporter

import param
from ..core.io import FileArchive
from ..plotting import PlotRenderer, HTML_TAGS

import threading

class NotebookArchive(FileArchive):

    export_timeout = param.Integer(default=15, doc="""
       A timeout limit (in seconds) between when the export method is
       run and when the export process begins. Note that a few more
       seconds may elapse before the files actually appear on disk.""")

    exporter = param.Callable(default=PlotRenderer)

    namespace = param.String('holoviews.archive', doc="""
        The name of the current in the NotebookArchive instance in the
        IPython namespace that must be available.""")

    snapshot_name = param.String('{timestamp}-snapshot', doc="""
        The basename of the exported notebook snapshot (html)""")

    auto = param.Boolean(False)

    # Used for debugging to view Exceptions raised from Javascript!
    traceback = None

    def __init__(self, **params):
        super(NotebookArchive, self).__init__(**params)
        self.notebook = BytesIO()
        self.nbversion = None
        self._replacements = {}
        self._exported, self._cancel = False, False
        self._timestamp = None
        self._tags = {val[0]:val[1] for val in HTML_TAGS.values()
                      if isinstance(val, tuple) and len(val)==2}

    def _timeout(self, parent, export_name):
        """
        Timeout run in a separate thread to allow the notebook to keep
        running after export is called.

        If you click 'Run All' in the notebook, all code cells are
        queued which means export may never actually happen (e.g. if
        an Exception occurs between the export and the end of the
        notebook. This method helps ensure the exported data isn't
        stale and generates a warning if the timeout is exceeded.
        """
        timeout = time.time() + (parent.export_timeout if parent.export_timeout else float('inf'))
        while (time.time() < timeout or parent._exported):
            time.sleep(0.5)
        if not parent._exported:
            parent._cancel = True
            msg = ("Export \'{export_name}\' cancelled."
                   "\n\nTimeout of {export_timeout} seconds exceeded"
                   "\n\nPlease make sure to call export at the very end of your notebook.")
            msg = msg.format(export_name=export_name, export_timeout=parent.export_timeout)
            display(Javascript("alert({msg});".format(msg=repr(msg))))


    def export(self, export_timeout=None, timestamp=None):
        """
        Get the current notebook data and export.
        """
        self.export_timeout = export_timeout if export_timeout else self.export_timeout
        self._timestamp = timestamp if (timestamp is not None) else tuple(time.localtime())
        self._cancel, self._exported = False, False
        name = self.namespace
        # Unfortunate javascript hacks to get at notebook data
        cmd = (r'var kernel = IPython.notebook.kernel;'
               r'var json_data = IPython.notebook.toJSON();'
               r'var json_string = JSON.stringify(json_data);'
               + (r"var command = '%s.notebook.write(r\"\"\"'+json_string+'\"\"\".encode(\'utf-16\'))';" % name)
               + "var pycmd = command + ';%s._export_with_html()';" % name
               + r"kernel.execute(pycmd)")

        tstamp = time.strftime(self.timestamp_format, self._timestamp)
        export_name = self._format(self.export_name, {'timestamp':tstamp})
        info = (export_name, os.path.join(os.path.abspath(self.root)), self.export_timeout)
        print('Export name:  %r\nDirectory     %r\nTimeout limit: %d seconds' % info)
        display(Javascript(cmd))
        t = threading.Thread(target=self._timeout, args=(self,export_name))
        t.start()



    def add(self, obj=None, filename=None, data=None, info={}, html=None):
        if self.auto:
            super(NotebookArchive, self).add(obj, filename, data, info)
            last_key = self._files.keys()[-1]
            self._replacements[last_key] = html


    def _export_with_html(self):
        "Use nbconvert with Substitute preprocessor"
        self._exported = True
        try:
            tstamp = time.strftime(self.timestamp_format, self._timestamp)

            substitutions = {}
            for (basename, ext), entry in self._files.items():
                (_, info) = entry
                html_key = self._replacements[(basename, ext)]
                filename = self._format(basename, {'timestamp':tstamp})
                fpath = filename+(('.%s' % ext) if ext else '')
                msg = "<center><b>%s</b><center/>"
                if 'mime_type' not in info:
                    link_html = msg % "Could not determine data mime-type"
                if info['mime_type'] not in self._tags:
                    link_html = msg % 'Could not determine HTML tag from mime-type'

                info = {'src':fpath, 'mime_type':info['mime_type']}
                link_html = self._format(self._tags[info['mime_type']],
{'fraction_non_alphanumeric': 0.10178622058406578, 'fraction_numerical': 0.001606653435403081, 'mean_word_length': 2.4649639816633924, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6859740', 'n_tokens_mistral': 2971, 'n_tokens_neox': 2850, 'n_words': 896}