Ejemplo n.º 1
0
def remove_solutions(nb, nb_name):
    """Convert solution cells to markdown; embed images from Python output."""

    # -- Extract image data from the cell outputs
    c = Config()
    template = (f"../static/{nb_name}"
                "_Solution_{cell_index}_{index}{extension}")
    c.ExtractOutputPreprocessor.output_filename_template = template

    # Note: using the RST exporter means we need to install pandoc as a dep
    # in the github workflow, which adds a little bit of latency, and we don't
    # actually care about the RST output. It's just a convenient way to get the
    # image resources the way we want them.
    exporter = RSTExporter()
    extractor = ExtractOutputPreprocessor(config=c)
    exporter.register_preprocessor(extractor, True)
    _, resources = exporter.from_notebook_node(nb)

    # -- Convert solution cells to markdown with embedded image
    nb_cells = nb.get("cells", [])
    outputs = resources["outputs"]
    solution_resources = {}

    for i, cell in enumerate(nb_cells):
        cell_text = cell["source"].replace(" ", "").lower()
        if cell_text.startswith("#@titlesolution"):

            # Just remove solution cells that generate no outputs
            if not cell["outputs"]:
                nb_cells.remove(cell)
                continue

            # Filter the resources for solution images
            image_paths = [k for k in outputs if f"Solution_{i}" in k]
            solution_resources.update({k: outputs[k] for k in image_paths})

            # Conver the solution cell to markdown, strip the source,
            # and embed the image as a link to static resource
            new_source = "**Example output:**\n\n" + "\n\n".join(
                [f"<img src='{f}' align='left'>" for f in image_paths])
            cell["source"] = new_source
            cell["cell_type"] = "markdown"
            del cell["outputs"]
            del cell["execution_count"]

    return nb, solution_resources
Ejemplo n.º 2
0
def compile_tutorial(tutorial_name, force_recompile=False):
    print('- Tutorial "' + tutorial_name + '"')

    notebook_path = 'tutorial_notebooks/' + tutorial_name + '/' + tutorial_name + '.ipynb'
    export_path = 'tutorials/' + tutorial_name + '/' + tutorial_name
    thumb_dest = os.path.dirname(export_path) + '/thumb.png'

    if not os.path.exists(os.path.dirname(export_path)):
        os.makedirs(os.path.dirname(export_path))

    # Read in notebook
    print('  Reading notebook...')
    notebook = nbformat.read(notebook_path, 4)

    # Scrape title, description and thumbnail
    first_cell = notebook.cells[0]

    title = first_cell.source.splitlines()[0]
    if '#' in title:
        title = title.replace('#', '').strip()

    description = ''
    for line in first_cell.source.splitlines()[1:]:
        if line.strip():
            description = line.strip()
            break

    if not description:
        print('  Description could not be found in the notebook.')

    if 'thumbnail_figure_index' in notebook.metadata:
        thumbnail_figure_index = notebook.metadata['thumbnail_figure_index']
    else:
        thumbnail_figure_index = -1

    if 'level' in notebook.metadata:
        level = notebook.metadata['level'].capitalize()
    elif 'difficulty' in notebook.metadata:
        level = notebook.metadata['difficulty'].capitalize()
    else:
        level = 'Unknown'

    # Check if the tutorial was already executed.
    if os.path.exists(export_path + '.rst'):
        if os.path.getmtime(export_path +
                            '.rst') > os.path.getmtime(notebook_path):
            if force_recompile:
                print('  Already compiled. Recompiling anyway...')
            else:
                print('  Already compiled. Skipping compilation...')
                return title, level, description, thumb_dest.split('/', 1)[-1]

    # Execute notebook if not already executed
    already_executed = any(
        c.get('outputs') or c.get('execution_count') for c in notebook.cells
        if c.cell_type == 'code')

    resources = {'metadata': {'path': os.path.dirname(notebook_path)}}

    if not already_executed:
        print('  Executing', end='')
        start = time.time()

        additional_cell_1 = {
            "cell_type":
            "code",
            "execution_count":
            None,
            "metadata": {},
            "outputs": [],
            "source":
            r"%matplotlib inline" + '\n' +
            r"%config InlineBackend.print_figure_kwargs = {'bbox_inches': None}"
        }

        additional_cell_2 = {
            "cell_type":
            "code",
            "execution_count":
            None,
            "metadata": {},
            "outputs": [],
            "source":
            "import matplotlib as mpl\nmpl.rcParams['figure.figsize'] = (8, 6)\nmpl.rcParams['figure.dpi'] = 150\nmpl.rcParams['savefig.dpi'] = 150"
        }

        notebook.cells.insert(1, nbformat.from_dict(additional_cell_1))
        notebook.cells.insert(2, nbformat.from_dict(additional_cell_2))

        client = NotebookClient(nb=notebook,
                                resources=resources,
                                timeout=585,
                                kernel_name='python3')

        try:
            with client.setup_kernel():
                for i, cell in enumerate(notebook.cells):
                    print('.', end='')

                    client.execute_cell(cell, i)

            client.set_widgets_metadata()
        except CellExecutionError as err:
            print('  Error while processing notebook:')
            print('  ', err)

        print('')

        notebook.cells.pop(2)
        notebook.cells.pop(1)

        end = time.time()

        time_taken = end - start
        if time_taken > 60:
            print('  Execution took %dm%02ds.' %
                  (time_taken / 60, time_taken % 60))
        else:
            print('  Execution took %ds.' % time_taken)
    else:
        print('  Notebook was already executed.')

    print('  Rendering tutorial...')
    exporter = RSTExporter()
    output, resources = exporter.from_notebook_node(notebook, resources)

    writer = FilesWriter(build_directory=os.path.dirname(export_path))
    writer.write(output,
                 resources,
                 notebook_name=os.path.basename(export_path))

    pictures = sorted(resources['outputs'], key=output.find)

    try:
        thumbnail_source = pictures[thumbnail_figure_index]

        # Read in thumbnail source image
        img = Image.open(os.path.dirname(export_path) + '/' + thumbnail_source)

        # Trim whitespace
        bg = Image.new(img.mode, img.size, img.getpixel((0, 0)))
        diff = ImageChops.difference(img, bg)
        diff = ImageChops.add(diff, diff)
        bbox = diff.getbbox()
        if bbox:
            img = img.crop(bbox)

        # Resize image to have a width of 400px
        img.thumbnail([400, 1000])

        # Save thumbnail
        img.save(thumb_dest)
    except:
        shutil.copyfile('_static/no_thumb.png', thumb_dest)

    print('  Done!')

    return title, level, description, thumb_dest.split('/', 1)[-1]
Ejemplo n.º 3
0
def compile_tutorial(tutorial_name, force_recompile=False):
	print('- Compiling tutorial ' + tutorial_name + '...')

	notebook_path = 'tutorial_notebooks/' + tutorial_name + '/' + tutorial_name + '.ipynb'
	export_path = 'tutorials/' + tutorial_name + '/' + tutorial_name
	thumb_dest = os.path.dirname(export_path) + '/thumb.png'

	if not os.path.exists(os.path.dirname(export_path)):
		os.makedirs(os.path.dirname(export_path))
	
	# Read in notebook
	notebook = nbformat.read(notebook_path, 4)

	# Scrape title, description and thumbnail
	first_cell = notebook.cells[0]

	title = first_cell.source.splitlines()[0]
	if '#' in title:
		title = title.replace('#', '').strip()
	
	description = first_cell.source.splitlines()[2].strip()
	
	if 'thumbnail_figure_index' in notebook.metadata:
		thumbnail_figure_index = notebook.metadata['thumbnail_figure_index']
	else:
		thumbnail_figure_index = -1
	
	if 'level' in notebook.metadata:
		level = notebook.metadata['level'].capitalize()
	elif 'difficulty' in notebook.metadata:
		level = notebook.metadata['difficulty'].capitalize()
	else:
		level = 'Unknown'
	
	# Check if the tutorial was already compiled.
	if os.path.exists(export_path + '.rst'):
		if os.path.getmtime(export_path + '.rst') > os.path.getmtime(notebook_path):
			if force_recompile:
				print('  Already compiled. Recompiling anyway...')
			else:
				print('  Already compiled. Skipping...')
				return title, level, description, thumb_dest.split('/', 1)[-1]

	# Execute notebook if not already executed
	already_executed = any(c.get('outputs') or c.get('execution_count') for c in notebook.cells if c.cell_type == 'code')

	resources = {}
	
	if not already_executed:
		ep = ExecutePreprocessor(timeout=120, kernel_name='python3')
		try:
			notebook, resources = ep.preprocess(notebook, resources={'metadata': {'path': os.path.abspath(os.path.dirname(notebook_path))}})
		except CellExecutionError as err:
			print('Error while processing notebook.')
			print(err)

	exporter = RSTExporter()
	output, resources = exporter.from_notebook_node(notebook, resources)

	writer = FilesWriter(build_directory=os.path.dirname(export_path))
	writer.write(output, resources, notebook_name=os.path.basename(export_path))

	pictures = sorted(resources['outputs'], key=output.find)

	try:
		thumbnail_source = pictures[thumbnail_figure_index]

		# Read in thumbnail source image
		img = Image.open(os.path.dirname(export_path) + '/' + thumbnail_source)

		# Trim whitespace
		bg = Image.new(img.mode, img.size, img.getpixel((0, 0)))
		diff = ImageChops.difference(img, bg)
		diff = ImageChops.add(diff, diff)
		bbox = diff.getbbox()
		if bbox:
			img = img.crop(bbox)

		# Resize image to have a width of 400px
		img.thumbnail([400, 1000])

		# Save thumbnail
		img.save(thumb_dest)
	except:
		shutil.copyfile('_static/no_thumb.png', thumb_dest)
	
	print('  Done!')

	return title, level, description, thumb_dest.split('/', 1)[-1]