trallard
1/4/2018 - 12:19 PM

JekyllExporter

Exporter used for HTML; deprecated it in favour of a .md + beautiful soup one

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Jul  6 10:09:43 2017

@author: tania
"""

from os import remove, close
import re, glob, os, fnmatch
from shutil import move
from tempfile import mkstemp
from pathlib import Path


#---------------------------------------
def find_notebooks():
    """ Find all the notebooks in the repo previsouly converted to 
    markdown"""
    
    basePath = Path(os.getcwd())
    notebooksAll = [nb for nb in glob.glob('**/*.ipynb')]
    exception = str(basePath) + '/_site/*/*'
    notebooks = [nb for nb in notebooksAll if not fnmatch.fnmatch(nb, exception)]
    notebooks = [os.path.abspath(nb).replace('ipynb', 'md') for nb in notebooks]
    return notebooks


def replace(file_path):
    """ Replaces the expressions"""
    fh, abs_path = mkstemp()
    with open(abs_path,'w') as new_file:
        with open(file_path) as source_file:
            for line in source_file:
                if any(s in line for s in s_repl):
                    line_new = robj.sub(lambda m: rdict[m.group(0)], line)
                    line_new2 = quoteobj.sub(lambda m: rquote[m.group(0)], line_new)
                    new_file.write(line_new2)
                elif any(s in line for s in scope):
                    line_new = scopeobj.sub(lambda m: rscope[m.group(0)], line)
                    new_file.write(line_new)
                else:
                    new_file.write(line)
    new_file.close()
    #Remove original file
    remove(file_path)
    #Move new file
    move(abs_path, file_path)
    
    print(f"Replaced {file_path}")


# Replacement rules: needed to parse the html properly
rdict = {'class=': 'class="', '<table>':'<table class="table-responsive table-striped>'}
s_repl = {'class=', '<table>'}
robj = re.compile('|'.join(rdict.keys()))

rquote ={'>':'">' }
quoteobj= re.compile('|'.join(rquote.keys()))

rscope = {'scope=row':'scope="row"','scope=col':'scope="col"'}
scope = {'scope=row', 'scope=col'}
scopeobj = re.compile('|'.join(rscope.keys()))


notebooks = find_notebooks()
for nb in notebooks: replace(nb)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: trallard

This code is used to generate Jekyll blogpost from Jupyter notebooks
within a main Jekyll repository. This uses the library 'nbconvert-jekyll'.

Since the templates are given in this package there is no need to specify a c
ustom template, unless you need to modify the default output. If doing so you also
need to provide a path for the templates.
"""

# Import libraries
import fnmatch
import glob
import os
from pathlib import Path


try:
    from urllib.parse import quote  # Py 3
except ImportError:
    from urllib2 import quote  # Py 2


# ---------------------------------------

def find_notebooks():
    """ Find all the notebooks in the repo, but excludes those
    in the _site folder, this will be default if no specific
    notebook was passed for conversion """

    basePath = Path(os.getcwd())
    notebooksAll = [nb for nb in glob.glob('**/*.ipynb')]
    exception = str(basePath) + '/_site/*/*'
    notebooks = [nb for nb in notebooksAll if not fnmatch.fnmatch(nb, exception)]
    return notebooks


# modify this function to point the  images to a custom path
# the default for nbconvert is to create a directory {notebook_name}_files
# where the notebook is located
def jekyllpath(path):
    """
	Take the filepath of an image output by the ExportOutputProcessor
	and convert it into a URL we can use with Jekyll
	"""
    base = os.path.split(path)[1]
    return path.replace("..", "{{site.url}}{{site.baseurl}}")


# ---------------------------------------
notebooks = find_notebooks()
# check if the list is empty
if not notebooks:
    print("No notebook found in this repository \n")
else:
    for nb in notebooks:
        print(" ***** Notebook found: {} \n)".format(nb))

"""Converting  notebooks now: this uses nbconvert with
a custom generated template"""

c = get_config()
c.NbConvertApp.export_format = 'markdown'
scriptsPath = os.path.join(os.getcwd(), 'scripts')
c.MarkdownExporter.template_path = [scriptsPath] # point this to the location of the jekyll template file
c.MarkdownExporter.template_file = 'jekyll'

# Uncomment if you want to pass a custom template
#c.MarkdownExporter.template_path = [scriptsPath]  # point this to the location of the jekyll template file
#c.MarkdownExporter.template_file = 'jekyll_html'

# convert all notebooks found
c.NbConvertApp.notebooks = notebooks

# customise the images output directory
c.NbConvertApp.output_files_dir = '../images/notebook_images/{notebook_name}'

# c.Application.verbose_crash = True


# modify this function to point the  images to a custom path
# the default for nbconvert is to create a directory {notebook_name}_files
# where the notebook is located
def jekyllpath(path):
    """
	Take the filepath of an image output by the ExportOutputProcessor
	and convert it into a URL we can use with Jekyll
	"""
    base = os.path.split(path)[1]
    return path.replace("..", "{{site.url}}{{site.baseurl}}")

c.MarkdownExporter.filters = {'jekyllpath': jekyllpath}
{% extends 'markdown.tpl' %}

{# custom header for jekyll post #}
{%- block header -%}
---
layout: notebook
title: "{{resources['metadata']['name']}}"
tags:
update_date:
code_version: 1
validation_pass:
---
<br />

{%- endblock header -%}


{% block in_prompt -%}
{%- if cell.execution_count is defined -%}
{%- if resources.global_content_filter.include_input_prompt-%}
<font color ='#00bcd4'> In [{{ cell.execution_count }}]: </font>
{%- else -%}
In&nbsp;[&nbsp;]:
{%- endif -%}
{%- endif -%}
{%- endblock in_prompt %}


{# Images will be saved in the custom path #}
{% block data_svg %}
<img src="{{ output.metadata.filenames['image/svg+xml'] | jekyllpath }}" alt="svg" />
{% endblock data_svg %}

{% block data_png %}
<img src="{{ output.metadata.filenames['image/png'] | jekyllpath }}" alt="png"/>
{% endblock data_png %}

{% block data_jpg %}
<img src="{{ output.metadata.filenames['image/jpeg'] | jekyllpath }}" alt="jpeg" />
{% endblock data_jpg %}

{# cells containing markdown text only #}
{% block markdowncell scoped %}
{{ cell.source | wrap_text(80) }}
{% endblock markdowncell %}

{# headings #}
{% block headingcell scoped %}
{{ '#' * cell.level }} {{ cell.source | replace('\n', ' ') }}
{% endblock headingcell %}

{% block stream -%}
{% endblock stream %}

{# latex data block#}
{% block data_latex %}
{{ output.data['text/latex'] }}
{% endblock data_latex %}

{% block data_text scoped %}
{{ output.data['text/plain'] | indent }}
{% endblock data_text %}

{% block data_html scoped -%}

{{ output.data['text/html'] }}

{%- endblock data_html %}

{% block data_markdown scoped -%}
{{ output.data['text/markdown'] | markdown2html }}

{%- endblock data_markdown %}
from setuptools import setup
import os

name = 'jekyllconvert'

pkg_root = os.path.join(os.path.dirname(__file__), name)
here = os.path.dirname(__file__)

packages = []
for d, _, _ in os.walk(os.path.join(here, name)):
    if os.path.exists(os.path.join(d, '__init__.py')):
        packages.append(d[len(here)+1:].replace(os.path.sep, '.'))


setup_args = dict(name = name,
                  version = '0.2',
                  description = 'Package used for custom conversion from Jupyter notebook to Jekyll posts',
                  url = 'https://github.com/trallard/nbconvert-jekyllconvert.git',
                  author = 'Tania Allard',
                  author_email = 't.allard@sheffield.ac.uk',
                  description_file = 'README.md',
                  license = 'MIT',
                  entry_points ={'nbconvert.exporters': ['md_jk = jekyllconvert:JekyllExporter'],},
                  include_package_data=True,
                  packages = packages,
                  zip_safe=False,
                  install_requires = ['nbconvert'])


if __name__ == '__main__':
    setup(**setup_args)
# file __init__.py
import os
import os.path


from traitlets import default, Unicode
from traitlets.config import Config

from nbconvert.filters.highlight import Highlight2HTML
from nbconvert.filters.markdown_mistune import IPythonRenderer, MarkdownWithMath

from nbconvert.exporters.html import HTMLExporter



#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------

class JekyllExporter(HTMLExporter):
    """
    My custom exporter
    """

    anchor_link_text = Unicode(u'¶', help="The text used as the text for anchor links.").tag(config=True)
    output_mimetype = 'text/markdown'

    def _file_extension_default(self):
        """
        The new file extension is `.test_ext`
        """
        return '.md'

    @property
    def template_path(self):
        """
        We want to inherit from HTML template, and have template under
        `./templates/` so append it to the search path. (see next section)
        """
        #return super().template_path+[os.path.join(os.path.dirname(__file__), "templates")]
        module_path = os.path.join(os.path.dirname(__file__), "templates")
        print(module_path)
        return super().template_path + [module_path]

    def _template_file_default(self):
        """
        We want to use the new template we ship with our library.
        """
        return 'Jekyll_template'

    @property
    def default_config(self):
        c = Config({
            'NbConvertBase': {
                'display_data_priority': ['application/vnd.jupyter.widget-state+json',
                                          'application/vnd.jupyter.widget-view+json',
                                          'application/javascript',
                                          'text/html',
                                          'text/markdown',
                                          'image/svg+xml',
                                          'text/latex',
                                          'image/png',
                                          'image/jpeg',
                                          'text/plain'
                                          ]
            },
            'CSSHTMLHeaderPreprocessor': {
                'enabled': True
            },
            'HighlightMagicsPreprocessor': {
                'enabled': True
            }
        })
        c.merge(super(HTMLExporter, self).default_config)
        return c