Ejemplo n.º 1
0
    def find_best_kernel(notebook_file: str) -> str:
        """Determines the best kernel to use via the following algorithm:

           1. Loads notebook and gets kernel_name and kernel_language from NB metadata.
           2. Gets the list of configured kernels using KernelSpecManager.
           3. If notebook kernel_name is in list, use that, else
           4. If not found, load each configured kernel.json file and find a language match.
           5. On first match, log info message regarding the switch and use that kernel.
           6. If no language match is found, revert to notebook kernel and log warning message.
        """
        import json
        import nbformat
        from jupyter_client.kernelspec import KernelSpecManager

        nb = nbformat.read(notebook_file, 4)

        nb_kspec = nb.metadata.kernelspec
        nb_kernel_name = nb_kspec.get('name')
        nb_kernel_lang = nb_kspec.get('language')

        kernel_specs = KernelSpecManager().find_kernel_specs()

        # see if we have a direct match...
        if nb_kernel_name in kernel_specs.keys():
            return nb_kernel_name

        # no match found for kernel, try matching language...
        for name, file in kernel_specs.items():
            # load file (JSON) and pick out language, if match, use first found
            with open(os.path.join(file, 'kernel.json')) as f:
                kspec = json.load(f)
                if kspec.get('language').lower() == nb_kernel_lang.lower():
                    matched_kernel = os.path.basename(file)
                    logger.info(
                        f"Matched kernel by language ({nb_kernel_lang}), using kernel "
                        f"'{matched_kernel}' instead of the missing kernel '{nb_kernel_name}'."
                    )
                    return matched_kernel

        # no match found for language, return notebook kernel and let execution fail
        logger.warning(
            f"Reverting back to missing notebook kernel '{nb_kernel_name}' since no "
            f"language match ({nb_kernel_lang}) was found in current kernel specifications."
        )
        return nb_kernel_name
Ejemplo n.º 2
0
def run_notebook(nb_path, output_dir):
    """Run a notebook tests

    executes the notebook and stores the output in a file
    """

    import nbformat
    from jupyter_client.kernelspec import KernelSpecManager
    from nbconvert.preprocessors.execute import executenb
    from datetime import datetime

    log.info("Testing notebook " + str(nb_path))
    with open(nb_path) as f:
        nb = nbformat.read(f, as_version=4)

    kernel_specs = KernelSpecManager().get_all_specs()
    kernel_info = nb.metadata.get("kernelspec") or {}
    kernel_name = kernel_info.get("name", "")
    kernel_language = kernel_info.get("language") or ""
    if kernel_name in kernel_specs:
        log.info("Found kernel " + str(kernel_name))
    elif kernel_language:
        log.warning("No such kernel " + str(kernel_name) +
                    ", falling back on kernel language=" +
                    str(kernel_language))
        kernel_language = kernel_language.lower()
        # no exact name match, re-implement js notebook fallback,
        # using kernel language instead
        # nbconvert does not implement this, but it should
        for kernel_spec_name, kernel_info in kernel_specs.items():
            if (kernel_info.get("spec",
                                {}).get("language",
                                        "").lower() == kernel_language):
                log.warning("Using kernel " + str(kernel_spec_name) +
                            " to provide language: " + str(kernel_language))
                kernel_name = kernel_spec_name
                break
        else:
            log.warning("Found no matching kernel for name=" +
                        str(kernel_name) + ", language=" +
                        str(kernel_language))
            summary_specs = [
                "name=" + str(name) + ", language=" +
                str(info['spec'].get('language'))
                for name, info in kernel_specs.items()
            ]
            log.warning("Found kernel specs: " + '; '.join(summary_specs))

    start_time = datetime.now()
    exported = executenb(nb,
                         cwd=os.path.dirname(nb_path),
                         kernel_name=kernel_name,
                         timeout=600)
    execution_time = (datetime.now() - start_time).seconds
    log.info("Execution time is " + str(execution_time))
    rel_path = os.path.relpath(nb_path, os.getcwd())
    dest_path = os.path.join(output_dir, "notebooks", rel_path)
    log.info("Saving exported notebook to " + str(dest_path))
    try:
        os.makedirs(os.path.dirname(dest_path))
    except FileExistsError:
        pass

    with open(dest_path, "w") as f:
        nbformat.write(exported, f)