Пример #1
0
def _clean_notebook(notebook):
    cleaner = NotebookCleaner(notebook)
    cleaner.remove_cells(empty=True)
    cleaner.remove_cells(search_text="# HIDDEN")
    cleaner.clear('stderr')
    cleaner.save(notebook)
    return notebook
Пример #2
0
def generate_report(ntbk, path_out):

    # Clean up the notebook
    cleaner = NotebookCleaner(ntbk)
    cleaner.remove_cells(empty=True)
    cleaner.remove_cells(search_text='hide_cell')
    cleaner.clear(kind="content", search_text='hide_code')
    cleaner.clear('stderr')

    path_out_tmp = path_out + '_TMP'
    cleaner.save(path_out_tmp)

    # Build the HTML
    call = [
        'jupyter', 'nbconvert', '--log-level="CRITICAL"', '--to', 'html',
        '--template', path_template,
        "--EmbedImagesPreprocessor.embed_images=True",
        "--TemplateExporter.exclude_input_prompt=True",
        "--TemplateExporter.exclude_output_prompt=True",
        '--FilesWriter.build_directory={}'.format(op.dirname(path_out)),
        path_out_tmp
    ]
    subprocess.run(call)
    os.remove(path_out_tmp)
Пример #3
0
 def _process_notebook(self, link, new_folder):
     nb = nbf.read(link, nbf.NO_CONVERT)
     site_yaml = self.site_yaml
     if self.execute:
         nb = execute_nb(nb,
                         cwd=op.dirname(link),
                         default_pre=self.default_pre)
     # Clean up the file before converting
     cleaner = NotebookCleaner(nb)
     cleaner.remove_cells(empty=True)
     if site_yaml.get('hide_cell_text', False):
         cleaner.remove_cells(search_text=site_yaml.get('hide_cell_text'))
     if site_yaml.get('hide_code_text', False):
         cleaner.clear(kind="content",
                       search_text=site_yaml.get('hide_code_text'))
     nb = cleaner.ntbk
     # Beware! By default, this cleans warnings etc from the output.
     # Set metadata in notebook YaML to allow stderr.
     if not nb['metadata'].get('jupyterbook', {}).get('show_stderr', False):
         cleaner.clear('stderr')
     self._process_nb_for_md(nb)
     # Convert notebook to markdown
     out_base, _ = op.splitext(op.basename(link))
     self._nb2md(nb, new_folder, out_base)
Пример #4
0
            next_file_title = ''
        else:
            next_file_title, next_page_link, _ = files[ix_file + 1]
            next_page_link = _prepare_link(next_page_link)

        # Convert notebooks or just copy md if no notebook.
        if link.endswith('.ipynb'):
            # Create a temporary version of the notebook we can modify
            tmp_notebook = link + '_TMP'
            sh.copy2(link, tmp_notebook)

            # Clean up the file before converting
            cleaner = NotebookCleaner(tmp_notebook)
            cleaner.remove_cells(empty=True)
            cleaner.remove_cells(search_text="# HIDDEN")
            cleaner.clear('stderr')
            cleaner.save(tmp_notebook)

            # Run nbconvert moving it to the output folder
            # This is the output directory for `.md` files
            build_call = '--FilesWriter.build_directory={}'.format(new_folder)
            # This is where images go - remove the _ so Jekyll will copy them over
            images_call = '--NbConvertApp.output_files_dir={}'.format(
                op.join(IMAGES_FOLDER, new_folder.lstrip('_')))
            call = [
                'jupyter', 'nbconvert', '--log-level="CRITICAL"', '--to',
                'markdown', '--template', TEMPLATE_PATH, images_call,
                build_call, tmp_notebook
            ]
            if execute is True:
                call.insert(-1, '--execute')
Пример #5
0
def build_book(path_book,
               path_toc_yaml=None,
               config_file=None,
               path_template=None,
               local_build=False,
               execute=False,
               overwrite=False):
    """Build the markdown for a book using its TOC and a content folder.

    Parameters
    ----------
    path_book : str
        Path to the root of the book repository
    path_toc_yaml : str | None
        Path to the Table of Contents YAML file
    config_file : str | None
        Path to the Jekyll configuration file
    path_template : str | None
        Path to the template nbconvert uses to build markdown
        files
    local_build : bool
        Specify you are building site locally for later upload
    execute : bool
        Whether to execute notebooks before converting to markdown
    overwrite : bool
        Whether to overwrite existing markdown files
    """

    PATH_IMAGES_FOLDER = op.join(path_book, '_build', 'images')
    BUILD_FOLDER = op.join(path_book, BUILD_FOLDER_NAME)

    ###############################################
    # Read in textbook configuration

    # Load the yaml for this site
    with open(config_file, 'r') as ff:
        site_yaml = yaml.safe_load(ff.read())
    CONTENT_FOLDER_NAME = site_yaml.get('content_folder_name').strip('/')
    PATH_CONTENT_FOLDER = op.join(path_book, CONTENT_FOLDER_NAME)

    # Load the textbook yaml for this site
    if not op.exists(path_toc_yaml):
        raise _error("No toc.yml file found, please create one at `{}`".format(
            path_toc_yaml))
    with open(path_toc_yaml, 'r') as ff:
        toc = yaml.safe_load(ff.read())

    # Drop divider items and non-linked pages in the sidebar, un-nest sections
    toc = _prepare_toc(toc)

    ################################################
    # Generating the Jekyll files for all content

    n_skipped_files = 0
    n_built_files = 0
    case_check = _case_sensitive_fs(BUILD_FOLDER) and local_build
    print("Convert and copy notebook/md files...")
    for ix_file, page in enumerate(tqdm(list(toc))):
        url_page = page.get('url', None)
        title = page.get('title', None)
        if page.get('external', None):
            # If its an external link, just pass
            continue

        # Make sure URLs (file paths) have correct structure
        _check_url_page(url_page, CONTENT_FOLDER_NAME)

        ##############################################
        # Create path to old/new file and create directory

        # URL will be relative to the CONTENT_FOLDER
        path_url_page = os.path.join(PATH_CONTENT_FOLDER, url_page.lstrip('/'))
        path_url_folder = os.path.dirname(path_url_page)

        # URLs shouldn't have the suffix in there already so
        # now we find which one to add
        for suf in SUPPORTED_FILE_SUFFIXES:
            if op.exists(path_url_page + suf):
                path_url_page = path_url_page + suf
                break

        if not op.exists(path_url_page):
            raise _error(
                "Could not find file called {} with any of these extensions: {}"
                .format(path_url_page, SUPPORTED_FILE_SUFFIXES))

        # Create and check new folder / file paths
        path_build_new_folder = path_url_folder.replace(
            os.sep + CONTENT_FOLDER_NAME, os.sep + BUILD_FOLDER_NAME) + os.sep
        path_build_new_file = op.join(
            path_build_new_folder,
            op.basename(path_url_page).replace('.ipynb', '.md'))

        if overwrite is False and op.exists(path_build_new_file) \
           and os.stat(path_build_new_file).st_mtime > os.stat(path_url_page).st_mtime:
            n_skipped_files += 1
            continue

        if not op.isdir(path_build_new_folder):
            os.makedirs(path_build_new_folder)

        ################################################
        # Generate previous/next page URLs
        if ix_file == 0:
            url_prev_page = ''
            prev_file_title = ''
        else:
            prev_file_title = toc[ix_file - 1].get('title')
            url_prev_page = toc[ix_file - 1].get('url')
            pre_external = toc[ix_file - 1].get('external', False)
            if pre_external is False:
                url_prev_page = _prepare_url(url_prev_page)

        if ix_file == len(toc) - 1:
            url_next_page = ''
            next_file_title = ''
        else:
            next_file_title = toc[ix_file + 1].get('title')
            url_next_page = toc[ix_file + 1].get('url')
            next_external = toc[ix_file + 1].get('external', False)
            if next_external is False:
                url_next_page = _prepare_url(url_next_page)

        ###############################################################################
        # Get kernel name and presence of widgets from notebooks metadata

        kernel_name = ''
        if path_url_page.endswith('.ipynb'):
            data = nbf.read(path_url_page, nbf.NO_CONVERT)
            if 'metadata' in data and 'kernelspec' in data['metadata']:
                kernel_name = data['metadata']['kernelspec']['name']
            has_widgets = "true" if any(
                "interactive" in cell['metadata'].get('tags', [])
                for cell in data['cells']) else "false"

        ############################################
        # Content conversion

        # Convert notebooks or just copy md if no notebook.
        if path_url_page.endswith('.ipynb'):
            notebook_name = op.splitext(op.basename(path_url_page))[0]
            ntbk = nbf.read(path_url_page, nbf.NO_CONVERT)

            ########################################
            # Notebook cleaning

            # Clean up the file before converting
            cleaner = NotebookCleaner(ntbk)
            cleaner.remove_cells(empty=True)
            cleaner.clear('stderr')
            ntbk = cleaner.ntbk
            _clean_notebook_cells(ntbk)

            #############################################
            # Conversion to Jekyll Markdown
            # create a configuration object that changes the preprocessors
            c = Config()
            c.FilesWriter.build_directory = path_build_new_folder

            if execute is True:
                # Excution of the notebook if we wish
                ep = ExecutePreprocessor(timeout=600, kernel_name=kernel_name)
                ep.preprocess(
                    ntbk, {'metadata': {
                        'path': op.dirname(path_url_folder)
                    }})

            # Define the path to images and then the relative path to where they'll originally be placed
            path_after_build_folder = path_build_new_folder.split(
                os.sep + BUILD_FOLDER_NAME + os.sep)[-1]
            path_images_new_folder = op.join(PATH_IMAGES_FOLDER,
                                             path_after_build_folder)
            path_images_rel = op.relpath(path_images_new_folder,
                                         path_build_new_folder)

            # Generate Markdown from our notebook using the template
            output_resources = {
                'output_files_dir': path_images_rel,
                'unique_key': notebook_name
            }
            exp = MarkdownExporter(template_file=path_template, config=c)
            markdown, resources = exp.from_notebook_node(
                ntbk, resources=output_resources)

            # Now write the markdown and resources
            writer = FilesWriter(config=c)
            writer.write(markdown, resources, notebook_name=notebook_name)

        elif path_url_page.endswith('.md'):
            # If a non-notebook file, just copy it over.
            # If markdown we'll add frontmatter later
            sh.copy2(path_url_page, path_build_new_file)
        else:
            raise _error("Files must end in ipynb or md. Found file {}".format(
                path_url_page))

        ###############################################################################
        # Modify the generated Markdown to work with Jekyll
        # Clean markdown for Jekyll quirks (e.g. extra escape characters)
        with open(path_build_new_file, 'r', encoding='utf8') as ff:
            lines = ff.readlines()
        lines = _clean_lines(lines, path_build_new_file, path_book,
                             PATH_IMAGES_FOLDER)

        # Split off original yaml
        yaml_orig, lines = _split_yaml(lines)

        # Front-matter YAML
        yaml_fm = []
        yaml_fm += ['---']
        # In case pre-existing links are sanitized
        sanitized = url_page.lower().replace('_', '-')
        if sanitized != url_page:
            if case_check and url_page.lower() == sanitized:
                raise RuntimeError(
                    'Redirect {} clashes with page {} for local build on '
                    'case-insensitive FS\n'.format(sanitized, url_page) +
                    'Rename source page to lower case or build on a case '
                    'sensitive FS, e.g. case-sensitive disk image on Mac')
            yaml_fm += ['redirect_from:']
            yaml_fm += ['  - "{}"'.format(sanitized)]
        if path_url_page.endswith('.ipynb'):
            interact_path = CONTENT_FOLDER_NAME + '/' + \
                path_url_page.split(CONTENT_FOLDER_NAME + '/')[-1]
            yaml_fm += ['interact_link: {}'.format(interact_path)]
            yaml_fm += ["kernel_name: {}".format(kernel_name)]
            yaml_fm += ["has_widgets: {}".format(has_widgets)]

        # Page metadata
        yaml_fm += ["title: '{}'".format(title)]
        yaml_fm += ['prev_page:']
        yaml_fm += ['  url: {}'.format(url_prev_page)]
        yaml_fm += ["  title: '{}'".format(prev_file_title)]
        yaml_fm += ['next_page:']
        yaml_fm += ['  url: {}'.format(url_next_page)]
        yaml_fm += ["  title: '{}'".format(next_file_title)]

        # Add back any original YaML, and end markers
        yaml_fm += yaml_orig
        yaml_fm += [
            'comment: "***PROGRAMMATICALLY GENERATED, DO NOT EDIT. SEE ORIGINAL FILES IN /{}***"'
            .format(CONTENT_FOLDER_NAME)
        ]
        yaml_fm += ['---']
        yaml_fm = [ii + '\n' for ii in yaml_fm]
        lines = yaml_fm + lines

        # Write the result as UTF-8.
        with open(path_build_new_file, 'w', encoding='utf8') as ff:
            ff.writelines(lines)
        n_built_files += 1

    #######################################################
    # Finishing up...

    # Copy non-markdown files in notebooks/ in case they're referenced in the notebooks
    print('Copying non-content files inside `{}/`...'.format(
        CONTENT_FOLDER_NAME))
    _copy_non_content_files(PATH_CONTENT_FOLDER, CONTENT_FOLDER_NAME,
                            BUILD_FOLDER_NAME)

    # Message at the end
    msg = [
        "Generated {} new files\nSkipped {} already-built files".format(
            n_built_files, n_skipped_files)
    ]
    if n_built_files == 0:
        msg += [
            "Delete the markdown files in '{}' for any pages that you wish to re-build, or use --overwrite option to re-build all."
            .format(BUILD_FOLDER_NAME)
        ]
    msg += ["Your Jupyter Book is now in `{}/`.".format(BUILD_FOLDER_NAME)]
    msg += ["Demo your Jupyter book with `make serve` or push to GitHub!"]
    print_message_box('\n'.join(msg))
Пример #6
0
        if path_url_page.endswith('.ipynb'):
            # Create a temporary version of the notebook we can modify
            tmp_notebook = path_url_page + '_TMP'
            sh.copy2(path_url_page, tmp_notebook)

            ###############################################################################
            # Notebook cleaning

            # Clean up the file before converting
            cleaner = NotebookCleaner(tmp_notebook)
            cleaner.remove_cells(empty=True)
            if site_yaml.get('hide_cell_text', False):
                cleaner.remove_cells(
                    search_text=site_yaml.get('hide_cell_text'))
            if site_yaml.get('hide_code_text', False):
                cleaner.clear(kind="content",
                              search_text=site_yaml.get('hide_code_text'))
            cleaner.clear('stderr')
            cleaner.save(tmp_notebook)
            _clean_notebook_cells(tmp_notebook)

            ###############################################################################
            # Conversion to Jekyll Markdown

            # Run nbconvert moving it to the output folder
            # This is the output directory for `.md` files
            build_call = '--FilesWriter.build_directory={}'.format(
                path_new_folder)
            # This is where images go - remove the _ so Jekyll will copy them over
            images_call = '--NbConvertApp.output_files_dir={}'.format(
                op.join(
                    PATH_IMAGES_FOLDER,
Пример #7
0
def build_book():
    """Build the markdown for a book using its TOC and a content folder."""
    parser = argparse.ArgumentParser(description=DESCRIPTION)
    parser.add_argument("path_book",
                        help="Path to the root of the book repository.")
    parser.add_argument(
        "--template",
        default=None,
        help="Path to the template nbconvert uses to build markdown files")
    parser.add_argument("--config",
                        default=None,
                        help="Path to the Jekyll configuration file")
    parser.add_argument("--toc",
                        default=None,
                        help="Path to the Table of Contents YAML file")
    parser.add_argument("--overwrite",
                        action='store_true',
                        help="Overwrite md files if they already exist.")
    parser.add_argument("--execute",
                        action='store_true',
                        help="Execute notebooks before converting to MD.")
    parser.add_argument(
        "--local-build",
        action='store_true',
        help="Specify you are building site locally for later upload.")
    parser.set_defaults(overwrite=False, execute=False)

    ###############################################################################
    # Default values and arguments

    args = parser.parse_args(sys.argv[2:])
    overwrite = bool(args.overwrite)
    execute = bool(args.execute)

    # Paths for our notebooks
    PATH_BOOK = op.abspath(args.path_book)

    PATH_TOC_YAML = args.toc if args.toc is not None else op.join(
        PATH_BOOK, '_data', 'toc.yml')
    CONFIG_FILE = args.config if args.config is not None else op.join(
        PATH_BOOK, '_config.yml')
    PATH_TEMPLATE = args.template if args.template is not None else op.join(
        PATH_BOOK, 'scripts', 'templates', 'jekyllmd.tpl')
    PATH_IMAGES_FOLDER = op.join(PATH_BOOK, '_build', 'images')
    BUILD_FOLDER = op.join(PATH_BOOK, BUILD_FOLDER_NAME)

    ###############################################################################
    # Read in textbook configuration

    # Load the yaml for this site
    with open(CONFIG_FILE, 'r') as ff:
        site_yaml = yaml.load(ff.read())
    CONTENT_FOLDER_NAME = site_yaml.get('content_folder_name').strip('/')
    PATH_CONTENT_FOLDER = op.join(PATH_BOOK, CONTENT_FOLDER_NAME)

    # Load the textbook yaml for this site
    if not op.exists(PATH_TOC_YAML):
        raise _error("No toc.yml file found, please create one at `{}`".format(
            PATH_TOC_YAML))
    with open(PATH_TOC_YAML, 'r') as ff:
        toc = yaml.load(ff.read())

    # Drop divider items and non-linked pages in the sidebar, un-nest sections
    toc = _prepare_toc(toc)

    ###############################################################################
    # Generating the Jekyll files for all content

    n_skipped_files = 0
    n_built_files = 0
    case_check = _case_sensitive_fs(BUILD_FOLDER) and args.local_build
    print("Convert and copy notebook/md files...")
    for ix_file, page in enumerate(tqdm(list(toc))):
        url_page = page.get('url', None)
        title = page.get('title', None)
        if page.get('external', None):
            # If its an external link, just pass
            continue

        # Make sure URLs (file paths) have correct structure
        _check_url_page(url_page, CONTENT_FOLDER_NAME)

        ###############################################################################
        # Create path to old/new file and create directory

        # URL will be relative to the CONTENT_FOLDER
        path_url_page = os.path.join(PATH_CONTENT_FOLDER, url_page.lstrip('/'))
        path_url_folder = os.path.dirname(path_url_page)

        # URLs shouldn't have the suffix in there already so now we find which one to add
        for suf in SUPPORTED_FILE_SUFFIXES:
            if op.exists(path_url_page + suf):
                path_url_page = path_url_page + suf
                break

        if not op.exists(path_url_page):
            raise _error(
                "Could not find file called {} with any of these extensions: {}"
                .format(path_url_page, SUPPORTED_FILE_SUFFIXES))

        # Create and check new folder / file paths
        path_new_folder = path_url_folder.replace(os.sep + CONTENT_FOLDER_NAME,
                                                  os.sep + BUILD_FOLDER_NAME)
        path_new_file = op.join(
            path_new_folder,
            op.basename(path_url_page).replace('.ipynb', '.md'))

        if overwrite is False and op.exists(path_new_file) \
           and os.stat(path_new_file).st_mtime > os.stat(path_url_page).st_mtime:
            n_skipped_files += 1
            continue

        if not op.isdir(path_new_folder):
            os.makedirs(path_new_folder)

        ###############################################################################
        # Generate previous/next page URLs
        if ix_file == 0:
            url_prev_page = ''
            prev_file_title = ''
        else:
            prev_file_title = toc[ix_file - 1].get('title')
            url_prev_page = toc[ix_file - 1].get('url')
            url_prev_page = _prepare_url(url_prev_page)

        if ix_file == len(toc) - 1:
            url_next_page = ''
            next_file_title = ''
        else:
            next_file_title = toc[ix_file + 1].get('title')
            url_next_page = toc[ix_file + 1].get('url')
            url_next_page = _prepare_url(url_next_page)

        ###############################################################################
        # Get kernel name from notebooks metadata

        kernel_name = ''
        if path_url_page.endswith('.ipynb'):
            data = nbf.read(path_url_page, nbf.NO_CONVERT)
            kernel_name = data['metadata']['kernelspec']['name']

        ###############################################################################
        # Content conversion

        # Convert notebooks or just copy md if no notebook.
        if path_url_page.endswith('.ipynb'):
            # Create a temporary version of the notebook we can modify
            tmp_notebook = path_url_page + '_TMP'
            sh.copy2(path_url_page, tmp_notebook)

            ###############################################################################
            # Notebook cleaning

            # Clean up the file before converting
            cleaner = NotebookCleaner(tmp_notebook)
            cleaner.remove_cells(empty=True)
            if site_yaml.get('hide_cell_text', False):
                cleaner.remove_cells(
                    search_text=site_yaml.get('hide_cell_text'))
            if site_yaml.get('hide_code_text', False):
                cleaner.clear(kind="content",
                              search_text=site_yaml.get('hide_code_text'))
            cleaner.clear('stderr')
            cleaner.save(tmp_notebook)
            _clean_notebook_cells(tmp_notebook)

            ###############################################################################
            # Conversion to Jekyll Markdown

            # Run nbconvert moving it to the output folder
            # This is the output directory for `.md` files
            build_call = '--FilesWriter.build_directory={}'.format(
                path_new_folder)
            # Copy notebook output images to the build directory using the base folder name
            path_after_build_folder = path_new_folder.split(os.sep +
                                                            BUILD_FOLDER_NAME +
                                                            os.sep)[-1]
            nb_output_folder = op.join(PATH_IMAGES_FOLDER,
                                       path_after_build_folder)
            images_call = '--NbConvertApp.output_files_dir={}'.format(
                nb_output_folder)
            call = [
                'jupyter', 'nbconvert', '--log-level="CRITICAL"', '--to',
                'markdown', '--template', PATH_TEMPLATE, images_call,
                build_call, tmp_notebook
            ]
            if execute is True:
                call.insert(-1, '--execute')

            check_call(call)
            os.remove(tmp_notebook)
        elif path_url_page.endswith('.md'):
            # If a non-notebook file, just copy it over.
            # If markdown we'll add frontmatter later
            sh.copy2(path_url_page, path_new_file)
        else:
            raise _error("Files must end in ipynb or md. Found file {}".format(
                path_url_page))

        ###############################################################################
        # Modify the generated Markdown to work with Jekyll

        # Clean markdown for Jekyll quirks (e.g. extra escape characters)
        with open(path_new_file, 'r') as ff:
            lines = ff.readlines()
        lines = _clean_lines(lines, path_new_file, PATH_BOOK,
                             PATH_IMAGES_FOLDER)

        # Split off original yaml
        yaml_orig, lines = _split_yaml(lines)

        # Front-matter YAML
        yaml_fm = []
        yaml_fm += ['---']
        # In case pre-existing links are sanitized
        sanitized = url_page.lower().replace('_', '-')
        if sanitized != url_page:
            if case_check and url_page.lower() == sanitized:
                raise RuntimeError(
                    'Redirect {} clashes with page {} for local build on '
                    'case-insensitive FS\n'.format(sanitized, url_page) +
                    'Rename source page to lower case or build on a case '
                    'sensitive FS, e.g. case-sensitive disk image on Mac')
            yaml_fm += ['redirect_from:']
            yaml_fm += ['  - "{}"'.format(sanitized)]
        if path_url_page.endswith('.ipynb'):
            interact_path = CONTENT_FOLDER_NAME + '/' + path_url_page.split(
                CONTENT_FOLDER_NAME + '/')[-1]
            yaml_fm += ['interact_link: {}'.format(interact_path)]
            yaml_fm += ["kernel_name: {}".format(kernel_name)]
        yaml_fm += ["title: '{}'".format(title)]
        yaml_fm += ['prev_page:']
        yaml_fm += ['  url: {}'.format(url_prev_page)]
        yaml_fm += ["  title: '{}'".format(prev_file_title)]
        yaml_fm += ['next_page:']
        yaml_fm += ['  url: {}'.format(url_next_page)]
        yaml_fm += ["  title: '{}'".format(next_file_title)]

        # Add back any original YaML, and end markers
        yaml_fm += yaml_orig
        yaml_fm += [
            'comment: "***PROGRAMMATICALLY GENERATED, DO NOT EDIT. SEE ORIGINAL FILES IN /{}***"'
            .format(CONTENT_FOLDER_NAME)
        ]
        yaml_fm += ['---']
        yaml_fm = [ii + '\n' for ii in yaml_fm]
        lines = yaml_fm + lines

        # Write the result
        with open(path_new_file, 'w') as ff:
            ff.writelines(lines)
        n_built_files += 1

    ###############################################################################
    # Finishing up...

    # Copy non-markdown files in notebooks/ in case they're referenced in the notebooks
    print('Copying non-content files inside `{}/`...'.format(
        CONTENT_FOLDER_NAME))
    _copy_non_content_files(PATH_CONTENT_FOLDER, CONTENT_FOLDER_NAME,
                            BUILD_FOLDER_NAME)

    # Message at the end
    msg = [
        "Generated {} new files\nSkipped {} already-built files".format(
            n_built_files, n_skipped_files)
    ]
    if n_built_files == 0:
        msg += [
            "Delete the markdown files in '{}' for any pages that you wish to re-build, or use --overwrite option to re-build all."
            .format(BUILD_FOLDER_NAME)
        ]
    msg += ["Your Jupyter Book is now in `{}/`.".format(BUILD_FOLDER_NAME)]
    msg += ["Demo your Jupyter book with `make serve` or push to GitHub!"]
    print_message_box('\n'.join(msg))
Пример #8
0
def build_page(path_ntbk, path_html_output, path_media_output=None, execute=False,
               path_template=None, verbose=False, kernel_name=None):
    """Build the HTML for a single notebook page.

    Inputs
    ======

    path_ntbk : string
        The path to a notebook we want to convert.
    path_html_output : string
        The path to the folder where the HTML will be output.
    path_media_output : string | None
        If a string, the path to where images should be extracted. If None,
        images will be embedded in the HTML.
    execute : bool
        Whether to execute the notebook before converting
    path_template : string
        A path to the template used in conversion.
    kernel_name : string
        The name of the kernel to use if we execute notebooks.
    """
    ntbk = nbf.read(path_ntbk, nbf.NO_CONVERT)
    notebook_name = op.splitext(op.basename(path_ntbk))[0]

    ########################################
    # Notebook cleaning

    # Clean up the file before converting
    cleaner = NotebookCleaner(ntbk)
    cleaner.remove_cells(empty=True)
    cleaner.clear('stderr')
    ntbk = cleaner.ntbk
    _clean_notebook_cells(ntbk)

    #############################################
    # Conversion to HTML
    # create a configuration object that changes the preprocessors
    c = Config()

    c.FilesWriter.build_directory = path_html_output
    # So the images are written to disk
    c.HTMLExporter.preprocessors = ['nbconvert.preprocessors.ExtractOutputPreprocessor']

    # The text used as the text for anchor links. Set to empty since we'll use anchor.js for the links
    c.HTMLExporter.anchor_link_text = " "

    # Excluding input/output prompts
    c.HTMLExporter.exclude_input_prompt = True
    c.HTMLExporter.exclude_output_prompt = True

    if execute is True:
        if kernel_name is None:
            kernel_name = ntbk['metadata']['kernelspec']['name']

        # Excution of the notebook if we wish
        ep = ExecutePreprocessor(timeout=600, kernel_name=kernel_name)
        ep.preprocess(ntbk, {'metadata': {'path': op.dirname(path_ntbk)}})

    # Define the path to images and then the relative path to where they'll originally be placed
    if isinstance(path_media_output, str):
        path_media_output_rel = op.relpath(path_media_output, path_html_output)

    # Generate HTML from our notebook using the template

    output_resources = {'output_files_dir': path_media_output_rel, 'unique_key': notebook_name}
    exp = HTMLExporter(template_file=path_template, config=c)
    html, resources = exp.from_notebook_node(ntbk, resources=output_resources)

    # Now write the markdown and resources
    writer = FilesWriter(config=c)
    writer.write(html, resources, notebook_name=notebook_name)
    if verbose:
        print("Finished writing notebook to {}".format(path_html_output))
Пример #9
0
        # Convert notebooks or just copy md if no notebook.
        if path_url_page.endswith('.ipynb'):
            # Create a temporary version of the notebook we can modify
            tmp_notebook = path_url_page + '_TMP'
            sh.copy2(path_url_page, tmp_notebook)

            ###############################################################################
            # Notebook cleaning

            # Clean up the file before converting
            cleaner = NotebookCleaner(tmp_notebook)
            cleaner.remove_cells(empty=True)
            if site_yaml.get('hide_cell_text', False):
                cleaner.remove_cells(search_text=site_yaml.get('hide_cell_text'))
            if site_yaml.get('hide_code_text', False):
                cleaner.clear(kind="content", search_text=site_yaml.get('hide_code_text'))
            cleaner.clear('stderr')
            cleaner.save(tmp_notebook)
            _clean_notebook_cells(tmp_notebook)

            ###############################################################################
            # Conversion to Jekyll Markdown

            # Run nbconvert moving it to the output folder
            # This is the output directory for `.md` files
            build_call = '--FilesWriter.build_directory={}'.format(path_new_folder)
            # Copy notebook output images to the build directory using the base folder name
            path_after_build_folder = path_new_folder.split(os.sep + BUILD_FOLDER_NAME + os.sep)[-1]
            nb_output_folder = op.join(PATH_IMAGES_FOLDER, path_after_build_folder)
            images_call = '--NbConvertApp.output_files_dir={}'.format(nb_output_folder)
            call = ['jupyter', 'nbconvert', '--log-level="CRITICAL"',