diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..f46fbb8 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,6 @@ +[run] +omit = + ipypublish/ipysphinx/docutils_transforms.py + ipypublish/ipysphinx/extension.py + ipypublish/ipysphinx/directives.py + ipypublish/scripts/nb_setup.py diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000..c44965a --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,17 @@ +version: 2 + +conda: + environment: docs/environment.yaml + +python: + version: 3.6 + install: + - method: pip + path: . + +# default +# sphinx: +# builder: html +# configuration: conf.py +# fail_on_warning: true + diff --git a/.travis.yml b/.travis.yml index 0faad0a..53addea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -66,8 +66,15 @@ matrix: # TODO add read the docs test `pip install .[docs] cd docs; make` before_install: +# Pandoc +- url="https://github.com/jgm/pandoc/releases/tag/2.6" +- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then path=$(curl -L $url | grep -o '/jgm/pandoc/releases/download/.*-amd64\.deb') ; fi +- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then downloadUrl="https://github.com$path" ; fi +- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then file=${path##*/} ; fi +- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wget $downloadUrl && sudo dpkg -i $file ; fi +# LaTeX - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq update ; fi -- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y pandoc ; fi +# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y pandoc ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y texlive ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y texlive-xetex ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y texlive-latex-extra ; fi @@ -78,13 +85,11 @@ before_install: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y latexmk ; fi - pip install -U pip setuptools wheel install: -- travis_wait pip install -r requirements.txt -- pip install -r test_requirements.txt -- pip install . +- travis_wait pip install .[tests,sphinx] - pip install --quiet coveralls script: # - nosetests -v --nocapture --with-doctest --with-coverage --exe --cover-package=ipypublish -- pytest -v --cov=ipypublish --cov-report= ipypublish +- pytest -v --cov=ipypublish --cov-config .coveragerc --cov-report= ipypublish - nbpublish -pdf --pdf-debug -log debug example/notebooks/Example.ipynb after_success: - coveralls diff --git a/.vscode/jinja2.code-snippets b/.vscode/jinja2.code-snippets new file mode 100644 index 0000000..4615ac8 --- /dev/null +++ b/.vscode/jinja2.code-snippets @@ -0,0 +1,76 @@ +{ + "super": { + "prefix": "super", + "scope": "jinja,jinja-yaml,jinja-html", + "body": "{{ super() }}", + "description": "call inherited block" + }, + "set": { + "prefix": "set", + "scope": "jinja,jinja-yaml,jinja-html", + "body": "{% set ${1:name} = ${2:value} %}", + "description": "set variable" + }, + "print": { + "prefix": "print", + "scope": "jinja,jinja-yaml,jinja-html", + "body": "{{ ${1:variable} }}", + "description": "print variable" + }, + "block": { + "prefix": "block", + "scope": "jinja,jinja-yaml,jinja-html", + "body": [ + "{% block ${1:name} %}", + "$2", + "{% endblock ${1:name} %}" + ], + "description": "jinja block" + }, + "macro": { + "prefix": "macro", + "scope": "jinja,jinja-yaml,jinja-html", + "body": [ + "{% macro ${1:name} %}", + "$2", + "{% endmacro %}" + ], + "description": "macro function" + }, + "if": { + "prefix": "if", + "scope": "jinja,jinja-yaml,jinja-html", + "body": [ + "{% if ${1:condition} %}", + "$2", + "{% endif %}" + ], + "description": "if condition" + }, + "if-else": { + "prefix": "if-else", + "scope": "jinja,jinja-yaml,jinja-html", + "body": [ + "{% if ${1:condition} %}", + "$2", + "{% else %}", + "$3", + "{% endif %}" + ], + "description": "if-else condition" + }, + "if-elif-else": { + "prefix": "if-elif-else", + "scope": "jinja,jinja-yaml,jinja-html", + "body": [ + "{% if ${1:condition} %}", + "$2", + "{% else %}", + "$3", + "{% elif ${1:condition2} %}", + "", + "{% endif %}" + ], + "description": "if-else condition" + } +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index bb87823..30cd7cd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,6 +28,7 @@ "python.linting.flake8Enabled": true, "latex-workshop.latex.autoBuild.onSave.enabled": false, "cSpell.words": [ + "Jupyter", "ipynb", "ipypublish", "jupytext", @@ -42,7 +43,7 @@ "FIXME", "NOTE" ], - "todo-tree.regex": "((//|#| \n' + context['body'] diff --git a/ipypublish/ipysphinx/parser.py b/ipypublish/ipysphinx/parser.py new file mode 100644 index 0000000..fb99ccc --- /dev/null +++ b/ipypublish/ipysphinx/parser.py @@ -0,0 +1,118 @@ +import os +import logging + +from docutils.parsers import rst +from ipypublish.utils import handle_error +from ipypublish.ipysphinx.utils import import_sphinx +from ipypublish.convert.main import IpyPubMain + + +# TODO should inherit from sphinx.parsers.RSTParser +# https://www.sphinx-doc.org/en/master/extdev/parserapi.html +# however, sphinx is an optional dependency +class NBParser(rst.Parser): + """Sphinx source parser for Jupyter notebooks. + adapted from nbsphinx + """ + + supported = 'jupyter_notebook', + + def __init__(self, *args, **kwargs): + + self.app = None + self.config = None + self.env = None + + try: + sphinx = import_sphinx() + + class NotebookError(sphinx.errors.SphinxError): + """Error during notebook parsing.""" + + category = 'Notebook error' + + self.error_nb = NotebookError + self.error_config = sphinx.errors.ConfigError + self.logger = sphinx.util.logging.getLogger('nbparser') + + except (ImportError, AttributeError): + self.error_nb = IOError + self.error_config = TypeError + self.logger = logging.getLogger('nbparser') + + super(NBParser, self).__init__(*args, **kwargs) + + def set_application(self, app): + # type: (Sphinx) -> None + """set_application will be called from Sphinx to set app + and other instance variables + + Parameters + ---------- + app: sphinx.application.Sphinx + Sphinx application object + """ + self.app = app + self.config = app.config + self.env = app.env + + def parse(self, inputstring, document): + # type: (Union[str, StringList], nodes.document) -> None + """Parse text and generate a document tree.""" + + # fix for when calling on readthedocs + self.env = self.env or document.settings.env + self.config = self.config or document.settings.env.config + + # get file for conversion + filepath = self.env.doc2path(self.env.docname) + filedir = os.path.dirname(filepath) + self.logger.info("ipypublish: converting {}".format(filepath)) + + config = {"IpyPubMain": { + "conversion": self.config.ipysphinx_export_config, + "plugin_folder_paths": self.config.ipysphinx_config_folders, + "outpath": filedir, + "folder_suffix": self.config.ipysphinx_folder_suffix, + "log_to_stdout": False, + "log_to_file": False, + "default_pporder_kwargs": dict( + clear_existing=False, + dump_files=True) + }} + if self.config.ipysphinx_preconverters: + # NB: jupytext is already a default for .Rmd + config["IpyPubMain"]["pre_conversion_funcs"] = ( + self.config.ipysphinx_preconverters) + publish = IpyPubMain(config=config) + outdata = publish(filepath) + + self.logger.info("ipypublish: successful conversion") + + # check we got back restructuredtext + exporter = outdata["exporter"] + if not exporter.output_mimetype == 'text/restructuredtext': + handle_error( + "ipypublish: the output content is not of type " + "text/restructuredtext: {}".format(exporter.output_mimetype), + TypeError, self.logger + ) + + # TODO document use of orphan + if outdata["resources"].get("ipub", {}).get("orphan", False): + rst.Parser.parse(self, ':orphan:', document) + + # parse a prolog + if self.env.config.ipysphinx_prolog: + prolog = exporter.environment.from_string( + self.env.config.ipysphinx_prolog).render(env=self.env) + rst.Parser.parse(self, prolog, document) + + # parse the main body of the file + rst.Parser.parse(self, outdata["stream"], document) + + # parse an epilog + if self.env.config.ipysphinx_epilog: + prolog = exporter.environment.from_string( + self.env.config.ipysphinx_epilog).render(env=self.env) + rst.Parser.parse(self, prolog, document) diff --git a/ipypublish/ipysphinx/utils.py b/ipypublish/ipysphinx/utils.py new file mode 100644 index 0000000..59f110e --- /dev/null +++ b/ipypublish/ipysphinx/utils.py @@ -0,0 +1,16 @@ + +def import_sphinx(): + """ + sphinx is an optional extra, so only load it when necessary + """ + try: + import sphinx + except ImportError: + raise ImportError( + "Sphinx is not installed. " + "Please install ipypublish with the sphinx extras: " + ">> pip install ipypublish[sphinx]") + if not sphinx.__version__ >= '1.6': + # This is required for sphinx.ext.imgconverter + raise ImportError("Sphinx version must be >= 1.6") + return sphinx \ No newline at end of file diff --git a/ipypublish/postprocessors/__init__.py b/ipypublish/postprocessors/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ipypublish/postprocessors/base.py b/ipypublish/postprocessors/base.py new file mode 100644 index 0000000..cf8e021 --- /dev/null +++ b/ipypublish/postprocessors/base.py @@ -0,0 +1,176 @@ +import logging + +from six import string_types +from traitlets import Bool +from traitlets.config.configurable import Configurable + +from ipypublish.utils import handle_error, pathlib + +try: + from shutil import which as exe_exists +except ImportError: + from distutils.spawn import find_executable as exe_exists # noqa: F401 + + +class IPyPostProcessor(Configurable): + """ an abstract class for post-processors + """ + + @property + def allowed_mimetypes(self): + """ override in subclasses + + return a list of allowed mime types + if None, then all are allowed + + Text based mime-types include: text/plain, text/latex, + text/restructuredtext, text/html, text/x-python, application/json, + text/markdown, text/asciidoc, text/yaml + + """ + raise NotImplementedError('allowed_mimetypes') + + @property + def requires_path(self): + """ override in subclasses + + whether the prostprocessor requires the supplied filepath + to have an existing parent directory + + if True and filepath is None, will raise an IOError, otherwise, + will try to make the directory if it doesn't exist + + """ + raise NotImplementedError('requires_path') + + @property + def logger_name(self): + """ override in subclass + """ + return "post-processor" + + @property + def logger(self): + return logging.getLogger(self.logger_name) + + skip_mime = Bool( + True, + help="if False, raise a TypeError if the mimetype is not allowed, " + "else return without processing").tag(config=True) + + def __init__(self, config=None): + super(IPyPostProcessor, self).__init__(config=config) + + def __call__(self, stream, mimetype, filepath, resources=None): + """ + See def postprocess() ... + """ + self.postprocess(stream, mimetype, filepath, resources) + + def postprocess(self, stream, mimetype, filepath, + resources=None): + """ Post-process output. + + Parameters + ---------- + stream: str + the main file contents + mimetype: str + the mimetype of the file + filepath: None or str or pathlib.Path + the path to the output file + the path does not have to exist, but must be absolute + resources: None or dict + a resources dict, output from exporter.from_notebook_node + + Returns + ------- + stream: str + filepath: None or str or pathlib.Path + + """ + + if (self.allowed_mimetypes is not None + and mimetype not in self.allowed_mimetypes): + if not self.skip_mime: + self.handle_error( + "the mimetype {0} is not in the allowed list: {1}".format( + mimetype, self.allowed_mimetypes), + TypeError) + else: + self.logger.debug( + "skipping incorrect mime type: {}".format(mimetype)) + return stream, filepath, resources + + if self.requires_path and filepath is None: + self.handle_error( + "the filepath is None, " + "but the post-processor requires a folder", + IOError) + + if filepath is not None and isinstance(filepath, string_types): + filepath = pathlib.Path(filepath) + + if self.requires_path: + + if not filepath.is_absolute(): + self.handle_error( + "the post-processor requires a folder, " + "but the filepath is not absolute", + IOError) + + if filepath.parent.exists() and not filepath.parent.is_dir(): + self.handle_error( + "the filepath's parent is not a folder: {}".format( + filepath), + TypeError) + + if not filepath.parent.exists(): + filepath.parent.mkdir(parents=True) + + if resources is None: + resources = {} + + return self.run_postprocess(stream, filepath, resources) + + def run_postprocess(self, stream, filepath, resources): + """ should not be called directly + override in sub-class + + Parameters + ---------- + stream: str + the main file contents + filepath: None or pathlib.Path + the path to the output file + resources: dict + a resources dict, output from exporter.from_notebook_node + + Returns + ------- + stream: str + filepath: None or pathlib.Path + resources: dict + + """ + raise NotImplementedError('run_postprocess') + + def handle_error(self, msg, err_type, + raise_msg=None, log_msg=None): + """ handle error by logging it then raising + """ + handle_error(msg, err_type, self.logger, + raise_msg=raise_msg, log_msg=log_msg) + + def check_exe_exists(self, name, error_msg): + """ test if an executable exists + """ + if not exe_exists(name): + self.handle_error(error_msg, RuntimeError) + return True + + +if __name__ == "__main__": + + print(IPyPostProcessor.allowed_mimetypes) + IPyPostProcessor()("stream", "a") diff --git a/ipypublish/postprocessors/file_actions.py b/ipypublish/postprocessors/file_actions.py new file mode 100644 index 0000000..98a1ca7 --- /dev/null +++ b/ipypublish/postprocessors/file_actions.py @@ -0,0 +1,173 @@ +import os +import shutil +from traitlets import Unicode, List + +from ipypublish.postprocessors.base import IPyPostProcessor + + +class WriteTextFile(IPyPostProcessor): + """ write the stream to a text based file + """ + @property + def allowed_mimetypes(self): + return ("text/latex", "text/restructuredtext", "text/html", + "text/x-python", "application/json", "text/markdown") + + @property + def requires_path(self): + return True + + @property + def logger_name(self): + return "write-text-file" + + encoding = Unicode( + "utf8", + help="the encoding of the output file" + ).tag(config=True) + + def run_postprocess(self, stream, filepath, resources): + + self.logger.info('writing stream to file: {}'.format(filepath)) + with filepath.open("w", encoding=self.encoding) as fh: + fh.write(stream) + + return stream, filepath, resources + + +class RemoveFolder(IPyPostProcessor): + """ remove a folder and all its contents + """ + @property + def allowed_mimetypes(self): + return None + + @property + def requires_path(self): + return True + + @property + def logger_name(self): + return "remove-folder" + + files_folder = Unicode( + "_static", + help="the path (relative to the main file path) to remove" + ).tag(config=True) + + def run_postprocess(self, stream, filepath, resources): + + remove_folder = filepath.parent.joinpath(self.files_folder) + if remove_folder.exists() and remove_folder.is_dir(): + self.logger.info( + 'removing folder: {0}'.format(remove_folder)) + shutil.rmtree(remove_folder) + + return stream, filepath, resources + + +class WriteResourceFiles(IPyPostProcessor): + """ write content contained in the resources dict to file (as bytes) + """ + @property + def allowed_mimetypes(self): + return None + + @property + def requires_path(self): + return True + + @property + def logger_name(self): + return "write-resource-files" + + resource_keys = List( + Unicode, + ["outputs"], + help="the key names in the resources dict that contain files" + ).tag(config=True) + + # The files already have a relative path + # files_folder = Unicode( + # "_static", + # help="the path (relative to the main file path) to write to" + # ).tag(config=True) + + def run_postprocess(self, stream, filepath, resources): + + output_folder = filepath.parent + if not output_folder.exists(): + output_folder.mkdir(parents=True) + + for key in self.resource_keys: + if key not in resources: + continue + if not hasattr(resources[key], "items"): + self.handle_error( + "the value of resources[{0}] is not a mapping".format(key), + TypeError) + self.logger.info( + 'writing files in resources[{0}] to: {1}'.format( + key, output_folder)) + for filename, content in resources[key].items(): + + outpath = output_folder.joinpath(filename) + if not outpath.parent.exists(): + outpath.parent.mkdir(parents=True) + + with outpath.open("wb") as fh: + fh.write(content) + + self.logger.debug("finished") + + return stream, filepath, resources + + +class CopyResourcePaths(IPyPostProcessor): + """ copy filepaths in the resources dict to another folder + """ + @property + def allowed_mimetypes(self): + return None + + @property + def requires_path(self): + return True + + @property + def logger_name(self): + return "copy-resource-paths" + + resource_keys = List( + Unicode, + ["external_file_paths"], + help="the key names in the resources dict that contain filepaths" + ).tag(config=True) + + files_folder = Unicode( + "_static", + help="the path (relative to the main file path) to copy to" + ).tag(config=True) + + def run_postprocess(self, stream, filepath, resources): + + output_folder = filepath.parent.joinpath(self.files_folder) + if not output_folder.exists(): + output_folder.mkdir(parents=True) + + for key in self.resource_keys: + if key not in resources: + continue + if not isinstance(resources[key], (list, tuple, set)): + self.handle_error( + "the value of resources[{0}] is not an iterable".format( + key), TypeError) + self.logger.info( + 'copying files in resources[{0}] to: {1}'.format( + key, output_folder)) + for resfilepath in resources[key]: + shutil.copyfile(resfilepath, + str(output_folder.joinpath( + os.path.basename(resfilepath)))) + + return stream, filepath, resources diff --git a/ipypublish/postprocessors/pdfexport.py b/ipypublish/postprocessors/pdfexport.py new file mode 100755 index 0000000..341b2a3 --- /dev/null +++ b/ipypublish/postprocessors/pdfexport.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python +""" a module for exporting latex file to pdf +TODO could this be refactored as nbconvert postprocessor +""" +import os +import shutil +import tempfile +from subprocess import Popen, PIPE, STDOUT +import webbrowser + +import six +from traitlets import Bool, Unicode + +from ipypublish.postprocessors.base import IPyPostProcessor + + +class PDFExport(IPyPostProcessor): + """ a post processor to convert tex to pdf using latexmk + """ + @property + def allowed_mimetypes(self): + return ("text/latex") + + @property + def requires_path(self): + return True + + @property + def logger_name(self): + return "pdf-export" + + files_folder = Unicode( + "_static", + help="the path (relative to the main file path) " + "containing external files" + ).tag(config=True) + + convert_in_temp = Bool( + False, + help="run conversion in a temporary directory, " + "and copy back only PDF file" + ).tag(config=True) + + debug_mode = Bool( + False, + help="run in debug mode").tag(config=True) + + open_in_browser = Bool( + False, + help="launch a html page containing a pdf browser").tag(config=True) + + def run_postprocess(self, stream, filepath, resources): + """ should not be called directly + + Parameters + ---------- + stream: str + the main file contents + filepath: None or pathlib.Path + the path to the output file + + Returns + ------- + stream: str + filepath: None or pathlib.Path + + """ + self.logger.info('running pdf conversion') + self._export_pdf(filepath) + return stream, filepath, resources + + def _export_pdf(self, texpath): + + if not texpath.exists(): + self.handle_error( + 'the target file path does not exist: {}'.format( + texpath), IOError) + + texname = os.path.splitext(texpath.name)[0] + # NOTE outdir was originally passed, but would this ever be different + # to the texpath's parent + + external_files = texpath.parent.joinpath(self.files_folder) + + if external_files.exists() and not external_files.is_dir(): + self.handle_error( + 'the external folder path is not a directory: {}'.format( + external_files), IOError) + + self.check_exe_exists( + 'latexmk', + 'requires the latexmk executable to run. ' + 'See http://mg.readthedocs.io/latexmk.html#installation', + ) + + if self.convert_in_temp: + out_folder = tempfile.mkdtemp() + try: + exitcode = self._run_latexmk( + texpath, out_folder, external_files) + if exitcode == 0: + shutil.copyfile( + os.path.join(out_folder, texname + '.pdf'), + str(texpath.parent.joinpath(texname + '.pdf'))) + finally: + shutil.rmtree(out_folder) + else: + exitcode = self._run_latexmk( + texpath, str(texpath.parent), external_files) + + if exitcode == 0: + self.logger.info('pdf conversion complete') + + view_pdf = VIEW_PDF.format( + pdf_name=texname.replace(' ', '%20') + '.pdf') + view_pdf_path = texpath.parent.joinpath(texname + '.view_pdf.html') + with view_pdf_path.open('w', encoding='utf-8') as fobj: + fobj.write(six.u(view_pdf)) + else: + self.handle_error( + 'pdf conversion failed: ' + 'Try running with pdf-debug flag', + RuntimeError) + + if self.open_in_browser: + # 2 opens the url in a new tab + webbrowser.open(view_pdf_path.as_uri(), new=2) + + return + + def _run_latexmk(self, texpath, out_folder, external_files): + """ run latexmk conversion + """ + # make sure tex file in right place + outpath = os.path.join(out_folder, texpath.name) + if os.path.dirname(str(texpath)) != str(out_folder): + self.logger.debug('copying tex file to: {}'.format( + os.path.join(str(out_folder), texpath.name))) + shutil.copyfile(str(texpath), os.path.join( + str(out_folder), texpath.name)) + + # make sure the external files folder is in right place + if external_files.exists(): + self.logger.debug('external files folder set') + outfilespath = os.path.join(out_folder, str(external_files.name)) + if str(external_files) != str(outfilespath): + self.logger.debug( + 'copying external files to: {}'.format(outfilespath)) + if os.path.exists(outfilespath): + shutil.rmtree(outfilespath) + shutil.copytree(str(external_files), str(outfilespath)) + + # run latexmk in correct folder + with change_dir(out_folder): + latexmk = ['latexmk', '-xelatex', '-bibtex', '-pdf'] + latexmk += [] if self.debug_mode else ["--interaction=batchmode"] + latexmk += [outpath] + self.logger.info('running: ' + ' '.join(latexmk)) + + def log_latexmk_output(pipe): + for line in iter(pipe.readline, b''): + self.logger.info('latexmk: {}'.format( + line.decode("utf-8").strip())) + + process = Popen(latexmk, stdout=PIPE, stderr=STDOUT) + with process.stdout: + log_latexmk_output(process.stdout) + exitcode = process.wait() # 0 means success + + return exitcode + + +class change_dir: + """Context manager for changing the current working directory""" + + def __init__(self, new_path): + self.newPath = os.path.expanduser(new_path) + + def __enter__(self): + self.savedPath = os.getcwd() + os.chdir(self.newPath) + + def __exit__(self, etype, value, traceback): + os.chdir(self.savedPath) + + +VIEW_PDF = r""" + + + +
+ ++ {{ output.data[datatype] | ansi2html | indent | indent }} ++ + .. raw:: latex + + {{ output.data[datatype] | escape_latex | ansi2latex | indent | indent }} + {# % + { + \\kern-\\sphinxverbatimsmallskipamount\\kern-\\baselineskip + \\kern+\\FrameHeightAdjust\\kern-\\fboxrule + \\vspace{\\nbsphinxcodecellspacing} + \\sphinxsetup{VerbatimBorderColor={named}{nbsphinx-code-border}} + {%- if output.name == 'stderr' %} + \\sphinxsetup{VerbatimColor={named}{nbsphinx-stderr}} + {%- else %} + \\sphinxsetup{VerbatimColor={named}{white}} + {%- endif %} + \\fvset{hllines={, ,}}% + \\begin{sphinxVerbatim}[commandchars=\\\\\\{\\}] + {{ output.data[datatype] | escape_latex | ansi2latex | indent | indent }} + \\end{sphinxVerbatim} + } + % The following \\relax is needed to avoid problems with adjacent ANSI + % cells and some other stuff (e.g. bullet lists) following ANSI cells. + % See https://github.com/sphinx-doc/sphinx/issues/3594 + \\relax #} + {% else %} + + .. nbwarning:: Data type cannot be displayed: {{ datatype }} + {%- endif %} + {% endmacro %} + +# END \ No newline at end of file diff --git a/ipypublish/templates/segments/sphinx_rst.yaml.j2 b/ipypublish/templates/segments/sphinx_rst.yaml.j2 index 52d1b55..691e473 100644 --- a/ipypublish/templates/segments/sphinx_rst.yaml.j2 +++ b/ipypublish/templates/segments/sphinx_rst.yaml.j2 @@ -7,7 +7,7 @@ {%- if cell.metadata.nbsphinx != 'hidden' %} {{ super() }} {% endif %} - + "notebook_input_code": | .. nbinput:: {% if cell.metadata.magics_language -%} {{ cell.metadata.magics_language }} @@ -67,9 +67,10 @@ {{ ("#" * cell.level + cell.source) | replace('\n', ' ') | convert_pandoc("markdown", "rst") }} "notebook_input_unknown": | - unknown type {{cell.type}} + .. unknown type {{cell.type}} - + "notebook_output_all": | + {{ super() }} "new_blocks": | {% block nboutput -%} @@ -89,13 +90,10 @@ "notebook_output_error": | {{ self.nboutput() }} - "notebook_output_stream_stdout": | - {{ self.nboutput() }} - - "notebook_output_stream_stderr": | + "notebook_output_stream": | {{ self.nboutput() }} - "notebook_output_data_any": | + "notebook_output_data_all": | {{ self.nboutput() }} "jinja_macros": | diff --git a/ipypublish/templates/segments/std_rst.yaml.j2 b/ipypublish/templates/segments/std_rst.yaml.j2 index 601869b..fc58c20 100644 --- a/ipypublish/templates/segments/std_rst.yaml.j2 +++ b/ipypublish/templates/segments/std_rst.yaml.j2 @@ -34,6 +34,9 @@ "notebook_input_unknown": | unknown type {{cell.type}} + "notebook_output_all": | + {{ super() }} + "notebook_output_error": | :: @@ -42,6 +45,9 @@ "notebook_output_traceback_line": | {{ line | indent | strip_ansi }} + "notebook_output_stream": | + {{ super() }} + "notebook_output_stream_stdout": | .. parsed-literal:: diff --git a/ipypublish/tests/conftest.py b/ipypublish/tests/conftest.py index 2510867..4254e54 100644 --- a/ipypublish/tests/conftest.py +++ b/ipypublish/tests/conftest.py @@ -1,11 +1,18 @@ import os import shutil import tempfile +import logging import pytest +from nbconvert.utils.pandoc import get_pandoc_version from ipypublish.utils import pathlib from ipypublish.tests import TEST_FILES_DIR +@pytest.fixture(autouse=True) +def dont_open_webbrowser(monkeypatch): + def nullfunc(*arg, **kwrgs): + pass + monkeypatch.setattr('webbrowser.open', nullfunc) @pytest.fixture def ipynb1(): @@ -16,6 +23,31 @@ def ipynb1(): def ipynb2(): return pathlib.Path(os.path.join(TEST_FILES_DIR, 'ipynb2.ipynb')) +@pytest.fixture +def nb_markdown_cells(): + + # Table format has changed through the versions + logging.debug("pandoc version: {}".format(get_pandoc_version())) + if get_pandoc_version() < '1.18': + expected_ltx = 'latex_ipypublish_main.pandoc.1-12.tex' + expected_rst = 'sphinx_ipypublish_main.pandoc.1-12.rst' + else: + expected_ltx = 'latex_ipypublish_main.pandoc.2-2.tex' + if get_pandoc_version() < '2.6': + expected_rst = 'sphinx_ipypublish_main.pandoc.2-2.rst' + else: + expected_rst = 'sphinx_ipypublish_main.pandoc.2-6.rst' + + return { + "input_file": pathlib.Path(os.path.join( + TEST_FILES_DIR, 'nb_markdown_cells', + 'nb_markdown_cells.ipynb')), + "latex_ipypublish_main": pathlib.Path(os.path.join( + TEST_FILES_DIR, 'nb_markdown_cells', expected_ltx)), + "sphinx_ipypublish_main": pathlib.Path(os.path.join( + TEST_FILES_DIR, 'nb_markdown_cells', expected_rst)) + } + @pytest.fixture def ipynb_with_attach(): @@ -65,6 +97,16 @@ def ipynb_folder(temp_folder, ipynb1, ipynb2): @pytest.fixture def ipynb_folder_with_external(temp_folder): + # Table format has changed through the versions + logging.debug("pandoc version: {}".format(get_pandoc_version())) + if get_pandoc_version() < '1.18': + sphinx_ipypublish_all = 'sphinx_ipypublish_all.pandoc.1-12.rst' + else: + if get_pandoc_version() < '2.6': + sphinx_ipypublish_all = 'sphinx_ipypublish_all.pandoc.2-2.rst' + else: + sphinx_ipypublish_all = 'sphinx_ipypublish_all.pandoc.2-6.rst' + folder = os.path.join(temp_folder, "ipynb_with_external") os.makedirs(folder) @@ -84,10 +126,12 @@ def ipynb_folder_with_external(temp_folder): 'ipynb_with_external.html')) slides = pathlib.Path(os.path.join(TEST_FILES_DIR, 'ipynb_with_external', 'ipynb_with_external.slides.html')) - + rst = pathlib.Path(os.path.join(TEST_FILES_DIR, 'ipynb_with_external', + sphinx_ipypublish_all)) yield { "input_folder": folder, "latex_ipypublish_main": tex, "html_ipypublish_main": html, - "slides_ipypublish_main": slides + "slides_ipypublish_main": slides, + "sphinx_ipypublish_all": rst } diff --git a/ipypublish/tests/convert_notebooks.py b/ipypublish/tests/convert_notebooks.py index 03b4780..d8d08ec 100644 --- a/ipypublish/tests/convert_notebooks.py +++ b/ipypublish/tests/convert_notebooks.py @@ -3,7 +3,7 @@ import os from ipypublish.convert.config_manager import iter_all_export_paths -from ipypublish.convert.main import publish +from ipypublish.convert.main import IpyPubMain from ipypublish.tests import TEST_FILES_DIR @@ -12,9 +12,17 @@ def convert_all(inpath, outpath): for plugin_name, plugin_path in iter_all_export_paths(): out_folder = tempfile.mkdtemp() + publish = IpyPubMain( + config={ + "IpyPubMain": { + "conversion": plugin_name, + "outpath": out_folder + }}) try: - outpath, exporter = publish( - str(inpath), conversion=plugin_name, outpath=out_folder) + outdata = publish(str(inpath)) + + exporter = outdata["exporter"] + outpath = outdata["outpath"] extension = exporter.file_extension out_name = os.path.splitext( diff --git a/ipypublish/tests/test_files/.gitignore b/ipypublish/tests/test_files/.gitignore new file mode 100644 index 0000000..3f70810 --- /dev/null +++ b/ipypublish/tests/test_files/.gitignore @@ -0,0 +1 @@ +converted/ \ No newline at end of file diff --git a/ipypublish/tests/test_files/example.jpg b/ipypublish/tests/test_files/example.jpg new file mode 100644 index 0000000..1c1e83e Binary files /dev/null and b/ipypublish/tests/test_files/example.jpg differ diff --git a/ipypublish/tests/test_files/ipynb1_converted/latex_ipypublish_all.exec.tex b/ipypublish/tests/test_files/ipynb1_converted/latex_ipypublish_all.exec.tex new file mode 100644 index 0000000..70d431c --- /dev/null +++ b/ipypublish/tests/test_files/ipynb1_converted/latex_ipypublish_all.exec.tex @@ -0,0 +1,450 @@ + + +% A latex document created by ipypublish +% outline: ipypublish.templates.outline_schemas/latex_outline.latex.j2 +% with segments: +% - standard-standard_packages: with standard nbconvert packages +% - standard-standard_definitions: with standard nbconvert definitions +% - ipypublish-doc_article: with the main ipypublish article setup +% - ipypublish-front_pages: with the main ipypublish title and contents page setup +% - ipypublish-biblio_natbib: with the main ipypublish bibliography +% - ipypublish-contents_output: with the main ipypublish content +% - ipypublish-contents_framed_code: with the input code wrapped and framed +% +%%%%%%%%%%%% DOCCLASS + +\documentclass[10pt,parskip=half, +toc=sectionentrywithdots, +bibliography=totocnumbered, +captions=tableheading,numbers=noendperiod]{scrartcl} + +%%%%%%%%%%%% + +%%%%%%%%%%%% PACKAGES + +\usepackage[T1]{fontenc} % Nicer default font (+ math font) than Computer Modern for most use cases +\usepackage{mathpazo} +\usepackage{graphicx} +\usepackage[skip=3pt]{caption} +\usepackage{adjustbox} % Used to constrain images to a maximum size +\usepackage[table]{xcolor} % Allow colors to be defined +\usepackage{enumerate} % Needed for markdown enumerations to work +\usepackage{amsmath} % Equations +\usepackage{amssymb} % Equations +\usepackage{textcomp} % defines textquotesingle +% Hack from http://tex.stackexchange.com/a/47451/13684: +\AtBeginDocument{% + \def\PYZsq{\textquotesingle}% Upright quotes in Pygmentized code +} +\usepackage{upquote} % Upright quotes for verbatim code +\usepackage{eurosym} % defines \euro +\usepackage[mathletters]{ucs} % Extended unicode (utf-8) support +\usepackage[utf8x]{inputenc} % Allow utf-8 characters in the tex document +\usepackage{fancyvrb} % verbatim replacement that allows latex +\usepackage{grffile} % extends the file name processing of package graphics + % to support a larger range +% The hyperref package gives us a pdf with properly built +% internal navigation ('pdf bookmarks' for the table of contents, +% internal cross-reference links, web links for URLs, etc.) +\usepackage{hyperref} +\usepackage{longtable} % longtable support required by pandoc >1.10 +\usepackage{booktabs} % table support for pandoc > 1.12.2 +\usepackage[inline]{enumitem} % IRkernel/repr support (it uses the enumerate* environment) +\usepackage[normalem]{ulem} % ulem is needed to support strikethroughs (\sout) + % normalem makes italics be italics, not underlines + +\usepackage{translations} +\usepackage{microtype} % improves the spacing between words and letters +\usepackage{placeins} % placement of figures +% could use \usepackage[section]{placeins} but placing in subsection in command section +% Places the float at precisely the location in the LaTeX code (with H) +\usepackage{float} +\usepackage[colorinlistoftodos,obeyFinal,textwidth=.8in]{todonotes} % to mark to-dos +% number figures, tables and equations by section +% fix for new versions of texlive (see https://tex.stackexchange.com/a/425603/107738) +\let\counterwithout\relax +\let\counterwithin\relax +\usepackage{chngcntr} +% header/footer +\usepackage[footsepline=0.25pt]{scrlayer-scrpage} + +% bibliography formatting +\usepackage[numbers, square, super, sort&compress]{natbib} +% hyperlink doi's +\usepackage{doi} + + % define a code float + \usepackage{newfloat} % to define a new float types + \DeclareFloatingEnvironment[ + fileext=frm,placement={!ht}, + within=section,name=Code]{codecell} + \DeclareFloatingEnvironment[ + fileext=frm,placement={!ht}, + within=section,name=Text]{textcell} + \DeclareFloatingEnvironment[ + fileext=frm,placement={!ht}, + within=section,name=Text]{errorcell} + + \usepackage{listings} % a package for wrapping code in a box + \usepackage[framemethod=tikz]{mdframed} % to fram code + +%%%%%%%%%%%% + +%%%%%%%%%%%% DEFINITIONS + +% Pygments definitions + +\makeatletter +\def\PY@reset{\let\PY@it=\relax \let\PY@bf=\relax% + \let\PY@ul=\relax \let\PY@tc=\relax% + \let\PY@bc=\relax \let\PY@ff=\relax} +\def\PY@tok#1{\csname PY@tok@#1\endcsname} +\def\PY@toks#1+{\ifx\relax#1\empty\else% + \PY@tok{#1}\expandafter\PY@toks\fi} +\def\PY@do#1{\PY@bc{\PY@tc{\PY@ul{% + \PY@it{\PY@bf{\PY@ff{#1}}}}}}} +\def\PY#1#2{\PY@reset\PY@toks#1+\relax+\PY@do{#2}} + +\expandafter\def\csname PY@tok@w\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.73,0.73}{##1}}} +\expandafter\def\csname PY@tok@c\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}} +\expandafter\def\csname PY@tok@cp\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.74,0.48,0.00}{##1}}} +\expandafter\def\csname PY@tok@k\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}} +\expandafter\def\csname PY@tok@kp\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}} +\expandafter\def\csname PY@tok@kt\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.69,0.00,0.25}{##1}}} +\expandafter\def\csname PY@tok@o\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}} +\expandafter\def\csname PY@tok@ow\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.67,0.13,1.00}{##1}}} +\expandafter\def\csname PY@tok@nb\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}} +\expandafter\def\csname PY@tok@nf\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}} +\expandafter\def\csname PY@tok@nc\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}} +\expandafter\def\csname PY@tok@nn\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}} +\expandafter\def\csname PY@tok@ne\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.82,0.25,0.23}{##1}}} +\expandafter\def\csname PY@tok@nv\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}} +\expandafter\def\csname PY@tok@no\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.53,0.00,0.00}{##1}}} +\expandafter\def\csname PY@tok@nl\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.63,0.63,0.00}{##1}}} +\expandafter\def\csname PY@tok@ni\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.60,0.60,0.60}{##1}}} +\expandafter\def\csname PY@tok@na\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.49,0.56,0.16}{##1}}} +\expandafter\def\csname PY@tok@nt\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}} +\expandafter\def\csname PY@tok@nd\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.67,0.13,1.00}{##1}}} +\expandafter\def\csname PY@tok@s\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}} +\expandafter\def\csname PY@tok@sd\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}} +\expandafter\def\csname PY@tok@si\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.73,0.40,0.53}{##1}}} +\expandafter\def\csname PY@tok@se\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.73,0.40,0.13}{##1}}} +\expandafter\def\csname PY@tok@sr\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.40,0.53}{##1}}} +\expandafter\def\csname PY@tok@ss\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}} +\expandafter\def\csname PY@tok@sx\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}} +\expandafter\def\csname PY@tok@m\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}} +\expandafter\def\csname PY@tok@gh\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.50}{##1}}} +\expandafter\def\csname PY@tok@gu\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.50,0.00,0.50}{##1}}} +\expandafter\def\csname PY@tok@gd\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.63,0.00,0.00}{##1}}} +\expandafter\def\csname PY@tok@gi\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.63,0.00}{##1}}} +\expandafter\def\csname PY@tok@gr\endcsname{\def\PY@tc##1{\textcolor[rgb]{1.00,0.00,0.00}{##1}}} +\expandafter\def\csname PY@tok@ge\endcsname{\let\PY@it=\textit} +\expandafter\def\csname PY@tok@gs\endcsname{\let\PY@bf=\textbf} +\expandafter\def\csname PY@tok@gp\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.50}{##1}}} +\expandafter\def\csname PY@tok@go\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.53,0.53,0.53}{##1}}} +\expandafter\def\csname PY@tok@gt\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.27,0.87}{##1}}} +\expandafter\def\csname PY@tok@err\endcsname{\def\PY@bc##1{\setlength{\fboxsep}{0pt}\fcolorbox[rgb]{1.00,0.00,0.00}{1,1,1}{\strut ##1}}} +\expandafter\def\csname PY@tok@kc\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}} +\expandafter\def\csname PY@tok@kd\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}} +\expandafter\def\csname PY@tok@kn\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}} +\expandafter\def\csname PY@tok@kr\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}} +\expandafter\def\csname PY@tok@bp\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}} +\expandafter\def\csname PY@tok@fm\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}} +\expandafter\def\csname PY@tok@vc\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}} +\expandafter\def\csname PY@tok@vg\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}} +\expandafter\def\csname PY@tok@vi\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}} +\expandafter\def\csname PY@tok@vm\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}} +\expandafter\def\csname PY@tok@sa\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}} +\expandafter\def\csname PY@tok@sb\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}} +\expandafter\def\csname PY@tok@sc\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}} +\expandafter\def\csname PY@tok@dl\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}} +\expandafter\def\csname PY@tok@s2\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}} +\expandafter\def\csname PY@tok@sh\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}} +\expandafter\def\csname PY@tok@s1\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}} +\expandafter\def\csname PY@tok@mb\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}} +\expandafter\def\csname PY@tok@mf\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}} +\expandafter\def\csname PY@tok@mh\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}} +\expandafter\def\csname PY@tok@mi\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}} +\expandafter\def\csname PY@tok@il\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}} +\expandafter\def\csname PY@tok@mo\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}} +\expandafter\def\csname PY@tok@ch\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}} +\expandafter\def\csname PY@tok@cm\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}} +\expandafter\def\csname PY@tok@cpf\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}} +\expandafter\def\csname PY@tok@c1\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}} +\expandafter\def\csname PY@tok@cs\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}} + +\def\PYZbs{\char`\\} +\def\PYZus{\char`\_} +\def\PYZob{\char`\{} +\def\PYZcb{\char`\}} +\def\PYZca{\char`\^} +\def\PYZam{\char`\&} +\def\PYZlt{\char`\<} +\def\PYZgt{\char`\>} +\def\PYZsh{\char`\#} +\def\PYZpc{\char`\%} +\def\PYZdl{\char`\$} +\def\PYZhy{\char`\-} +\def\PYZsq{\char`\'} +\def\PYZdq{\char`\"} +\def\PYZti{\char`\~} +% for compatibility with earlier versions +\def\PYZat{@} +\def\PYZlb{[} +\def\PYZrb{]} +\makeatother + +% ANSI colors +\definecolor{ansi-black}{HTML}{3E424D} +\definecolor{ansi-black-intense}{HTML}{282C36} +\definecolor{ansi-red}{HTML}{E75C58} +\definecolor{ansi-red-intense}{HTML}{B22B31} +\definecolor{ansi-green}{HTML}{00A250} +\definecolor{ansi-green-intense}{HTML}{007427} +\definecolor{ansi-yellow}{HTML}{DDB62B} +\definecolor{ansi-yellow-intense}{HTML}{B27D12} +\definecolor{ansi-blue}{HTML}{208FFB} +\definecolor{ansi-blue-intense}{HTML}{0065CA} +\definecolor{ansi-magenta}{HTML}{D160C4} +\definecolor{ansi-magenta-intense}{HTML}{A03196} +\definecolor{ansi-cyan}{HTML}{60C6C8} +\definecolor{ansi-cyan-intense}{HTML}{258F8F} +\definecolor{ansi-white}{HTML}{C5C1B4} +\definecolor{ansi-white-intense}{HTML}{A1A6B2} + +% commands and environments needed by pandoc snippets +% extracted from the output of `pandoc -s` +\providecommand{\tightlist}{% + \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}} +\DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}} +% Add ',fontsize=\small' for more characters per line +\newenvironment{Shaded}{}{} +\newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{{#1}}}} +\newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.56,0.13,0.00}{{#1}}} +\newcommand{\DecValTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}} +\newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}} +\newcommand{\FloatTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}} +\newcommand{\CharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}} +\newcommand{\StringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}} +\newcommand{\CommentTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textit{{#1}}}} +\newcommand{\OtherTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{{#1}}} +\newcommand{\AlertTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}} +\newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.02,0.16,0.49}{{#1}}} +\newcommand{\RegionMarkerTok}[1]{{#1}} +\newcommand{\ErrorTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}} +\newcommand{\NormalTok}[1]{{#1}} + +% Additional commands for more recent versions of Pandoc +\newcommand{\ConstantTok}[1]{\textcolor[rgb]{0.53,0.00,0.00}{{#1}}} +\newcommand{\SpecialCharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}} +\newcommand{\VerbatimStringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}} +\newcommand{\SpecialStringTok}[1]{\textcolor[rgb]{0.73,0.40,0.53}{{#1}}} +\newcommand{\ImportTok}[1]{{#1}} +\newcommand{\DocumentationTok}[1]{\textcolor[rgb]{0.73,0.13,0.13}{\textit{{#1}}}} +\newcommand{\AnnotationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}} +\newcommand{\CommentVarTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}} +\newcommand{\VariableTok}[1]{\textcolor[rgb]{0.10,0.09,0.49}{{#1}}} +\newcommand{\ControlFlowTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{{#1}}}} +\newcommand{\OperatorTok}[1]{\textcolor[rgb]{0.40,0.40,0.40}{{#1}}} +\newcommand{\BuiltInTok}[1]{{#1}} +\newcommand{\ExtensionTok}[1]{{#1}} +\newcommand{\PreprocessorTok}[1]{\textcolor[rgb]{0.74,0.48,0.00}{{#1}}} +\newcommand{\AttributeTok}[1]{\textcolor[rgb]{0.49,0.56,0.16}{{#1}}} +\newcommand{\InformationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}} +\newcommand{\WarningTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}} + +% Define a nice break command that doesn't care if a line doesn't already +% exist. +\def\br{\hspace*{\fill} \\* } + +% Math Jax compatability definitions +\def\gt{>} +\def\lt{<} + +\setcounter{secnumdepth}{5} + +% Colors for the hyperref package +\definecolor{urlcolor}{rgb}{0,.145,.698} +\definecolor{linkcolor}{rgb}{.71,0.21,0.01} +\definecolor{citecolor}{rgb}{.12,.54,.11} + +\DeclareTranslationFallback{Author}{Author} +\DeclareTranslation{Portuges}{Author}{Autor} + +\DeclareTranslationFallback{List of Codes}{List of Codes} +\DeclareTranslation{Catalan}{List of Codes}{Llista de Codis} +\DeclareTranslation{Danish}{List of Codes}{Liste over Koder} +\DeclareTranslation{German}{List of Codes}{Liste der Codes} +\DeclareTranslation{Spanish}{List of Codes}{Lista de C\'{o}digos} +\DeclareTranslation{French}{List of Codes}{Liste des Codes} +\DeclareTranslation{Italian}{List of Codes}{Elenco dei Codici} +\DeclareTranslation{Dutch}{List of Codes}{Lijst van Codes} +\DeclareTranslation{Portuges}{List of Codes}{Lista de C\'{o}digos} + +\DeclareTranslationFallback{Supervisors}{Supervisors} +\DeclareTranslation{Catalan}{Supervisors}{Supervisors} +\DeclareTranslation{Danish}{Supervisors}{Vejledere} +\DeclareTranslation{German}{Supervisors}{Vorgesetzten} +\DeclareTranslation{Spanish}{Supervisors}{Supervisores} +\DeclareTranslation{French}{Supervisors}{Superviseurs} +\DeclareTranslation{Italian}{Supervisors}{Le autorit\`{a} di vigilanza} +\DeclareTranslation{Dutch}{Supervisors}{supervisors} +\DeclareTranslation{Portuguese}{Supervisors}{Supervisores} + +\definecolor{codegreen}{rgb}{0,0.6,0} +\definecolor{codegray}{rgb}{0.5,0.5,0.5} +\definecolor{codepurple}{rgb}{0.58,0,0.82} +\definecolor{backcolour}{rgb}{0.95,0.95,0.95} + +\lstdefinestyle{mystyle}{ + commentstyle=\color{codegreen}, + keywordstyle=\color{magenta}, + numberstyle=\tiny\color{codegray}, + stringstyle=\color{codepurple}, + basicstyle=\ttfamily, + breakatwhitespace=false, + keepspaces=true, + numbers=left, + numbersep=10pt, + showspaces=false, + showstringspaces=false, + showtabs=false, + tabsize=2, + breaklines=true, + literate={\-}{}{0\discretionary{-}{}{-}}, + postbreak=\mbox{\textcolor{red}{$\hookrightarrow$}\space}, +} + +\lstset{style=mystyle} + +\surroundwithmdframed[ + hidealllines=true, + backgroundcolor=backcolour, + innerleftmargin=0pt, + innerrightmargin=0pt, + innertopmargin=0pt, + innerbottommargin=0pt]{lstlisting} + +%%%%%%%%%%%% + +%%%%%%%%%%%% MARGINS + + % Used to adjust the document margins +\usepackage{geometry} +\geometry{tmargin=1in,bmargin=1in,lmargin=1in,rmargin=1in, +nohead,includefoot,footskip=25pt} +% you can use showframe option to check the margins visually +%%%%%%%%%%%% + +%%%%%%%%%%%% COMMANDS + +% ensure new section starts on new page +\addtokomafont{section}{\clearpage} + +% Prevent overflowing lines due to hard-to-break entities +\sloppy + +% Setup hyperref package +\hypersetup{ + breaklinks=true, % so long urls are correctly broken across lines + colorlinks=true, + urlcolor=urlcolor, + linkcolor=linkcolor, + citecolor=citecolor, + } + +% ensure figures are placed within subsections +\makeatletter +\AtBeginDocument{% + \expandafter\renewcommand\expandafter\subsection\expandafter + {\expandafter\@fb@secFB\subsection}% + \newcommand\@fb@secFB{\FloatBarrier + \gdef\@fb@afterHHook{\@fb@topbarrier \gdef\@fb@afterHHook{}}}% + \g@addto@macro\@afterheading{\@fb@afterHHook}% + \gdef\@fb@afterHHook{}% +} +\makeatother + +% number figures, tables and equations by section +\counterwithout{figure}{section} +\counterwithout{table}{section} +\counterwithout{equation}{section} +\makeatletter +\@addtoreset{table}{section} +\@addtoreset{figure}{section} +\@addtoreset{equation}{section} +\makeatother +\renewcommand\thetable{\thesection.\arabic{table}} +\renewcommand\thefigure{\thesection.\arabic{figure}} +\renewcommand\theequation{\thesection.\arabic{equation}} + + % set global options for float placement + \makeatletter + \providecommand*\setfloatlocations[2]{\@namedef{fps@#1}{#2}} + \makeatother + +% align captions to left (indented) +\captionsetup{justification=raggedright, +singlelinecheck=false,format=hang,labelfont={it,bf}} + +% shift footer down so space between separation line +\ModifyLayer[addvoffset=.6ex]{scrheadings.foot.odd} +\ModifyLayer[addvoffset=.6ex]{scrheadings.foot.even} +\ModifyLayer[addvoffset=.6ex]{scrheadings.foot.oneside} +\ModifyLayer[addvoffset=.6ex]{plain.scrheadings.foot.odd} +\ModifyLayer[addvoffset=.6ex]{plain.scrheadings.foot.even} +\ModifyLayer[addvoffset=.6ex]{plain.scrheadings.foot.oneside} +\pagestyle{scrheadings} +\clearscrheadfoot{} +\ifoot{\leftmark} +\renewcommand{\sectionmark}[1]{\markleft{\thesection\ #1}} +\ofoot{\pagemark} +\cfoot{} + +%%%%%%%%%%%% + +%%%%%%%%%%%% FINAL HEADER MATERIAL + +% clereref must be loaded after anything that changes the referencing system +\usepackage{cleveref} +\creflabelformat{equation}{#2#1#3} + +% make the code float work with cleverref +\crefname{codecell}{code}{codes} +\Crefname{codecell}{code}{codes} +% make the text float work with cleverref +\crefname{textcell}{text}{texts} +\Crefname{textcell}{text}{texts} +% make the text float work with cleverref +\crefname{errorcell}{error}{errors} +\Crefname{errorcell}{error}{errors} +%%%%%%%%%%%% + +\begin{document} + + \title{Notebook} + \date{\today} + \maketitle + + \begingroup + \let\cleardoublepage\relax + \let\clearpage\relax\tableofcontents\listoffigures\listoftables\listof{codecell}{\GetTranslation{List of Codes}} + \endgroup + +\hypertarget{a-title}{% +\section{a title}\label{a-title}} + +some text + +\begin{lstlisting}[language=Python,numbers=left,xleftmargin=20pt,xrightmargin=5pt,belowskip=5pt,aboveskip=5pt] +a=1 +print(a) +\end{lstlisting} + +\begin{lstlisting}[language={},postbreak={},numbers=none,xrightmargin=7pt,belowskip=5pt,aboveskip=5pt,breakindent=0pt] +1 + +\end{lstlisting} + +\end{document} + diff --git a/ipypublish/tests/test_files/ipynb1_converted/latex_ipypublish_all.tex b/ipypublish/tests/test_files/ipynb1_converted/latex_ipypublish_all.tex index a877dae..70d431c 100644 --- a/ipypublish/tests/test_files/ipynb1_converted/latex_ipypublish_all.tex +++ b/ipypublish/tests/test_files/ipynb1_converted/latex_ipypublish_all.tex @@ -1,6 +1,6 @@ -% A latex document created by ipypublish +% A latex document created by ipypublish % outline: ipypublish.templates.outline_schemas/latex_outline.latex.j2 % with segments: % - standard-standard_packages: with standard nbconvert packages diff --git a/ipypublish/tests/test_files/ipynb1_converted/latex_ipypublish_main.tex b/ipypublish/tests/test_files/ipynb1_converted/latex_ipypublish_main.tex index 57fd6de..63b870b 100644 --- a/ipypublish/tests/test_files/ipynb1_converted/latex_ipypublish_main.tex +++ b/ipypublish/tests/test_files/ipynb1_converted/latex_ipypublish_main.tex @@ -1,6 +1,6 @@ -% A latex document created by ipypublish +% A latex document created by ipypublish % outline: ipypublish.templates.outline_schemas/latex_outline.latex.j2 % with segments: % - standard-standard_packages: with standard nbconvert packages diff --git a/ipypublish/tests/test_files/ipynb1_converted/latex_ipypublish_nocode.tex b/ipypublish/tests/test_files/ipynb1_converted/latex_ipypublish_nocode.tex index a18bf69..dc9b947 100644 --- a/ipypublish/tests/test_files/ipynb1_converted/latex_ipypublish_nocode.tex +++ b/ipypublish/tests/test_files/ipynb1_converted/latex_ipypublish_nocode.tex @@ -1,6 +1,6 @@ -% A latex document created by ipypublish +% A latex document created by ipypublish % outline: ipypublish.templates.outline_schemas/latex_outline.latex.j2 % with segments: % - standard-standard_packages: with standard nbconvert packages diff --git a/ipypublish/tests/test_files/ipynb1_converted/latex_standard_article.tex b/ipypublish/tests/test_files/ipynb1_converted/latex_standard_article.tex index f48fd8f..346809d 100644 --- a/ipypublish/tests/test_files/ipynb1_converted/latex_standard_article.tex +++ b/ipypublish/tests/test_files/ipynb1_converted/latex_standard_article.tex @@ -1,6 +1,6 @@ -% A latex document created by ipypublish +% A latex document created by ipypublish % outline: ipypublish.templates.outline_schemas/latex_outline.latex.j2 % with segments: % - standard-standard_packages: with standard nbconvert packages diff --git a/ipypublish/tests/test_files/ipynb1_converted/sphinx_ipypublish_all.exec.rst b/ipypublish/tests/test_files/ipynb1_converted/sphinx_ipypublish_all.exec.rst new file mode 100644 index 0000000..db3f15d --- /dev/null +++ b/ipypublish/tests/test_files/ipynb1_converted/sphinx_ipypublish_all.exec.rst @@ -0,0 +1,31 @@ + +.. An html document created by ipypublish + outline: ipypublish.templates.outline_schemas/rst_outline.rst.j2 + with segments: + - nbsphinx-ipypublish-content: ipypublish sphinx content + +a title +======= + +some text + +.. nbinput:: ipython3 + :execution-count: 1 + :no-output: + + a=1 + print(a) + +.. nboutput:: ansi + + .. rst-class:: highlight + + .. raw:: html + +
+ 1 ++ + .. raw:: latex + + 1 diff --git a/ipypublish/tests/test_files/ipynb1_converted/sphinx_ipypublish_all.rst b/ipypublish/tests/test_files/ipynb1_converted/sphinx_ipypublish_all.rst new file mode 100644 index 0000000..c95cab0 --- /dev/null +++ b/ipypublish/tests/test_files/ipynb1_converted/sphinx_ipypublish_all.rst @@ -0,0 +1,31 @@ + +.. An html document created by ipypublish + outline: ipypublish.templates.outline_schemas/rst_outline.rst.j2 + with segments: + - nbsphinx-ipypublish-content: ipypublish sphinx content + +a title +======= + +some text + +.. nbinput:: ipython3 + :execution-count: 2 + :no-output: + + a=1 + print(a) + +.. nboutput:: ansi + + .. rst-class:: highlight + + .. raw:: html + +
+ 1 ++ + .. raw:: latex + + 1 diff --git a/ipypublish/tests/test_files/ipynb1_converted/sphinx_ipypublish_main.rst b/ipypublish/tests/test_files/ipynb1_converted/sphinx_ipypublish_main.rst new file mode 100644 index 0000000..abae09b --- /dev/null +++ b/ipypublish/tests/test_files/ipynb1_converted/sphinx_ipypublish_main.rst @@ -0,0 +1,10 @@ + +.. An html document created by ipypublish + outline: ipypublish.templates.outline_schemas/rst_outline.rst.j2 + with segments: + - nbsphinx-ipypublish-content: ipypublish sphinx content + +a title +======= + +some text diff --git a/ipypublish/tests/test_files/ipynb1_converted/sphinx_ipypublish_nocode.rst b/ipypublish/tests/test_files/ipynb1_converted/sphinx_ipypublish_nocode.rst new file mode 100644 index 0000000..fa6e72a --- /dev/null +++ b/ipypublish/tests/test_files/ipynb1_converted/sphinx_ipypublish_nocode.rst @@ -0,0 +1,24 @@ + +.. An html document created by ipypublish + outline: ipypublish.templates.outline_schemas/rst_outline.rst.j2 + with segments: + - nbsphinx-ipypublish-content: ipypublish sphinx content + +a title +======= + +some text + +.. nboutput:: ansi + + .. rst-class:: highlight + + .. raw:: html + +
+ 1 ++ + .. raw:: latex + + 1 diff --git a/ipypublish/tests/test_files/ipynb1_converted/sphinx_nbsphinx.rst b/ipypublish/tests/test_files/ipynb1_converted/sphinx_nbsphinx.rst index 94806ad..c71a1d6 100644 --- a/ipypublish/tests/test_files/ipynb1_converted/sphinx_nbsphinx.rst +++ b/ipypublish/tests/test_files/ipynb1_converted/sphinx_nbsphinx.rst @@ -39,4 +39,3 @@ some text % cells and some other stuff (e.g. bullet lists) following ANSI cells. % See https://github.com/sphinx-doc/sphinx/issues/3594 \relax - diff --git a/ipypublish/tests/test_files/ipynb1_converted/sphinx_standard.rst b/ipypublish/tests/test_files/ipynb1_converted/sphinx_standard.rst index e3595c1..fe4ec75 100644 --- a/ipypublish/tests/test_files/ipynb1_converted/sphinx_standard.rst +++ b/ipypublish/tests/test_files/ipynb1_converted/sphinx_standard.rst @@ -17,4 +17,3 @@ some text .. parsed-literal:: 1 - diff --git a/ipypublish/tests/test_files/ipynb_with_external/example.bib b/ipypublish/tests/test_files/ipynb_with_external/example.bib index 50e638d..3f1df55 100644 --- a/ipypublish/tests/test_files/ipynb_with_external/example.bib +++ b/ipypublish/tests/test_files/ipynb_with_external/example.bib @@ -9,10 +9,12 @@ @article{kirkeminde_thermodynamic_2012 langid = {english}, number = {1}, journaltitle = {Journal of Materials Chemistry A}, + journal = {Journal of Materials Chemistry A}, shortjournal = {J. Mater. Chem. A}, author = {Kirkeminde, Alec and Ren, Shenqiang}, urldate = {2017-06-18}, date = {2012-11-29}, + year = {2012}, pages = {49--54}, file = {Kirkeminde_Ren_2012_Thermodynamic control of iron pyrite nanocrystal synthesis with high.pdf:/Users/cjs14/Docear/projects/Corrosion/Zotero_Attachments//2012/Kirkeminde_Ren_2012_Thermodynamic control of iron pyrite nanocrystal synthesis with high.pdf:application/pdf} } @@ -27,10 +29,12 @@ @article{zelenyak_molecular_2016 langid = {english}, number = {5}, journaltitle = {High Energy Chemistry}, + journal = {High Energy Chemistry}, shortjournal = {High Energy Chem}, author = {Zelenyak, T. Yu and Kholmurodov, Kh T. and Tameev, A. R. and Vannikov, A. V. and Gladyshev, P. P.}, urldate = {2017-07-06}, date = {2016-09-01}, + year = {2016}, pages = {400--405}, file = {Zelenyak et al_2016_Molecular dynamics study of perovskite structures with modified interatomic.pdf:/Users/cjs14/Library/Application Support/Firefox/Profiles/gignsb3n.default/zotero/storage/H5NVC2I5/Zelenyak et al_2016_Molecular dynamics study of perovskite structures with modified interatomic.pdf:application/pdf} } diff --git a/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.Rmd b/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.Rmd new file mode 100644 index 0000000..8d0f065 --- /dev/null +++ b/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.Rmd @@ -0,0 +1,161 @@ +--- +jupyter: + ipub: + at_notation: true + bibliography: example.bib + biboptions: + - super + - sort + bibstyle: unsrtnat + language: portuges + listcode: true + listfigures: true + listtables: true + titlepage: + author: Authors Name + email: authors@email.com + institution: + - Institution1 + - Institution2 + logo: logo_example.png + subtitle: Sub-Title + supervisors: + - First Supervisor + - Second Supervisor + tagline: A tagline for the report. + title: Main-Title + toc: + depth: 2 + use_numref: true + jupytext: + metadata_filter: + notebook: ipub + text_representation: + extension: .Rmd + format_name: rmarkdown + format_version: '1.0' + jupytext_version: 0.8.6 + kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +```{python init_cell=TRUE, slideshow={'slide_type': 'skip'}} +from ipypublish.scripts.ipynb_latex_setup import * +``` + +# Markdown + + +## General + + +Some markdown text. + +A list: + +- something +- something else + +A numbered list + +1. something +2. something else + +non-ascii characters TODO + + +This is a long section of text, which we only want in a document (not a presentation) +some text +some more text +some more text +some more text +some more text +some more text +some more text +some more text +some more text + + + +This is an abbreviated section of the document text, which we only want in a presentation + +- summary of document text + + +## References and Citations + + +References to \cref{fig:example}, \cref{tbl:example}, =@eqn:example_sympy and \cref{code:example_mpl}. + +A latex citation.\cite{zelenyak_molecular_2016} + +A html citation.(Kirkeminde, 2012) + + +## Todo notes + + +\todo[inline]{an inline todo} + +Some text.\todo{a todo in the margins} + + +# Text Output + +```{python ipub={'text': {'format': {'backgroundcolor': '\\color{blue!10}'}}}} +print(""" +This is some printed text, +with a nicely formatted output. +""") +``` + +# Images and Figures + +```{python ipub={'figure': {'caption': 'A nice picture.', 'label': 'fig:example', 'placement': '!bh'}}} +Image('example.jpg',height=400) +``` + +## Displaying a plot with its code + + +A matplotlib figure, with the caption set in the markdowncell above the figure. + + +The plotting code for a matplotlib figure (\cref{fig:example_mpl}). + +```{python ipub={'code': {'asfloat': True, 'caption': 'a', 'label': 'code:example_mpl', 'widefigure': False}, 'figure': {'caption': '', 'label': 'fig:example_mpl', 'widefigure': False}}} +plt.scatter(np.random.rand(10), np.random.rand(10), + label='data label') +plt.ylabel(r'a y label with latex $\alpha$') +plt.legend(); +``` + +# Tables (with pandas) + + +The plotting code for a pandas Dataframe table (\cref{tbl:example}). + +```{python ipub={'code': {'asfloat': True, 'caption': '', 'label': 'code:example_pd', 'placement': 'H', 'widefigure': False}, 'table': {'alternate': 'gray!20', 'caption': 'An example of a table created with pandas dataframe.', 'label': 'tbl:example', 'placement': 'H'}}} +df = pd.DataFrame(np.random.rand(3,4),columns=['a','b','c','d']) +df.a = ['$\delta$','x','y'] +df.b = ['l','m','n'] +df.set_index(['a','b']) +df.round(3) +``` + +# Equations (with ipython or sympy) + +```{python ipub={'equation': {'label': 'eqn:example_ipy'}}} +Latex('$$ a = b+c $$') +``` + +The plotting code for a sympy equation (=@eqn:example_sympy). + +```{python ipub={'code': {'asfloat': True, 'caption': '', 'label': 'code:example_sym', 'placement': 'H', 'widefigure': False}, 'equation': {'environment': 'equation', 'label': 'eqn:example_sympy'}}} +y = sym.Function('y') +n = sym.symbols(r'\alpha') +f = y(n)-2*y(n-1/sym.pi)-5*y(n-2) +sym.rsolve(f,y(n),[1,4]) +``` diff --git a/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.html b/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.html index 2b678ce..a6f9421 100644 --- a/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.html +++ b/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.html @@ -1,6 +1,6 @@ - - +- ipypublish-latex_doc: caption and label elements according to ipub meta tags +--> + @@ -8462,15 +8464,15 @@ } /* Flexible box model classes */ /* Taken from Alex Russell http://infrequently.org/2009/08/css-3-progress/ */ -/* This file is a compatability layer. It allows the usage of flexible box +/* This file is a compatability layer. It allows the usage of flexible box model layouts accross multiple browsers, including older browsers. The newest, universal implementation of the flexible box model is used when available (see -`Modern browsers` comments below). Browsers that are known to implement this +`Modern browsers` comments below). Browsers that are known to implement this new spec completely include: Firefox 28.0+ Chrome 29.0+ - Internet Explorer 11+ + Internet Explorer 11+ Opera 17.0+ Browsers not listed, including Safari, are supported via the styling under the @@ -11244,7 +11246,7 @@ background: #f7f7f7; border-top: 1px solid #cfcfcf; border-bottom: 1px solid #cfcfcf; - /* This injects handle bars (a short, wide = symbol) for + /* This injects handle bars (a short, wide = symbol) for the resize handle. */ } div#pager .ui-resizable-handle::after { @@ -11979,7 +11981,7 @@
References to fig. 1, tbl. 1, eqn. 1 and code 3.
+References to fig. 1, tbl. 1, =@eqn:example_sympy and code 3.
A latex citation.[Zelenyak et al, 2016.]
A html citation.(Kirkeminde, 2012)
@@ -13105,7 +13107,7 @@plt.scatter(np.random.rand(10), np.random.rand(10),
+plt.scatter(np.random.rand(10), np.random.rand(10),
label='data label')
plt.ylabel(r'a y label with latex $\alpha$')
plt.legend();
@@ -13134,33 +13136,33 @@ Displaying a plot with its code
-
-
-
@@ -13181,8 +13183,8 @@ Displaying a plot with its code
-
@@ -13192,32 +13194,32 @@ Displaying a plot with its code
-
-
@@ -13237,25 +13239,25 @@ Displaying a plot with its code
-
@@ -13275,28 +13277,28 @@ Displaying a plot with its code
-
@@ -13316,26 +13318,26 @@ Displaying a plot with its code
-
@@ -13355,29 +13357,29 @@ Displaying a plot with its code
-
@@ -13393,8 +13395,8 @@ Displaying a plot with its code
-
@@ -13479,21 +13481,21 @@ Displaying a plot with its code
-
@@ -13507,277 +13509,277 @@ Displaying a plot with its code
-
-
-
-
-
-
-
-
-
-
-
@@ -13803,36 +13805,36 @@ Displaying a plot with its code
-
-
-
-
-
@@ -13844,27 +13846,27 @@ Displaying a plot with its code
-
@@ -14030,15 +14032,15 @@ Equations (with ipython or sympy)
-
Code 8: The plotting code for a sympy equation (eqn. 1).
+
Code 8: The plotting code for a sympy equation (=@eqn:example_sympy).
-f = sym.Function('f')
-y,n = sym.symbols(r'y \alpha')
+y = sym.Function('y')
+n = sym.symbols(r'\alpha')
f = y(n)-2*y(n-1/sym.pi)-5*y(n-2)
sym.rsolve(f,y(n),[1,4])
diff --git a/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.ipynb b/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.ipynb
index 70ab27e..1ab70fa 100644
--- a/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.ipynb
+++ b/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.ipynb
@@ -110,7 +110,7 @@
}
},
"source": [
- "References to \\cref{fig:example}, \\cref{tbl:example}, \\cref{eqn:example_sympy} and \\cref{code:example_mpl}.\n",
+ "References to \\cref{fig:example}, \\cref{tbl:example}, =@eqn:example_sympy and \\cref{code:example_mpl}.\n",
"\n",
"A latex citation.\\cite{zelenyak_molecular_2016}\n",
"\n",
@@ -1225,7 +1225,7 @@
}
},
"source": [
- "The plotting code for a sympy equation (\\cref{eqn:example_sympy})."
+ "The plotting code for a sympy equation (=@eqn:example_sympy)."
]
},
{
@@ -1260,8 +1260,8 @@
}
],
"source": [
- "f = sym.Function('f')\n",
- "y,n = sym.symbols(r'y \\alpha')\n",
+ "y = sym.Function('y')\n",
+ "n = sym.symbols(r'\\alpha')\n",
"f = y(n)-2*y(n-1/sym.pi)-5*y(n-2)\n",
"sym.rsolve(f,y(n),[1,4])"
]
@@ -1297,7 +1297,11 @@
"tagline": "A tagline for the report.",
"title": "Main-Title"
},
- "toc": {"depth": 2}
+ "toc": {"depth": 2},
+ "pandoc": {
+ "use_numref": true,
+ "at_notation": true
+ }
},
"jupytext": {
"metadata_filter": {
diff --git a/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.json b/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.json
new file mode 100644
index 0000000..4af5361
--- /dev/null
+++ b/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.json
@@ -0,0 +1,1882 @@
+{
+ "blocks": [
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Code",
+ "c": [
+ [
+ "",
+ [],
+ []
+ ],
+ "{python init_cell=TRUE, slideshow={'slide_type': 'skip'}} from ipypublish.scripts.ipynb_latex_setup import *"
+ ]
+ }
+ ]
+ },
+ {
+ "t": "Header",
+ "c": [
+ 1,
+ [
+ "markdown",
+ [],
+ []
+ ],
+ [
+ {
+ "t": "Str",
+ "c": "Markdown"
+ }
+ ]
+ ]
+ },
+ {
+ "t": "Header",
+ "c": [
+ 2,
+ [
+ "general",
+ [],
+ []
+ ],
+ [
+ {
+ "t": "Str",
+ "c": "General"
+ }
+ ]
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Str",
+ "c": "Some"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "markdown"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "text."
+ }
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Str",
+ "c": "A"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "list:"
+ }
+ ]
+ },
+ {
+ "t": "BulletList",
+ "c": [
+ [
+ {
+ "t": "Plain",
+ "c": [
+ {
+ "t": "Str",
+ "c": "something"
+ }
+ ]
+ }
+ ],
+ [
+ {
+ "t": "Plain",
+ "c": [
+ {
+ "t": "Str",
+ "c": "something"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "else"
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Str",
+ "c": "A"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "numbered"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "list"
+ }
+ ]
+ },
+ {
+ "t": "OrderedList",
+ "c": [
+ [
+ 1,
+ {
+ "t": "Decimal"
+ },
+ {
+ "t": "Period"
+ }
+ ],
+ [
+ [
+ {
+ "t": "Plain",
+ "c": [
+ {
+ "t": "Str",
+ "c": "something"
+ }
+ ]
+ }
+ ],
+ [
+ {
+ "t": "Plain",
+ "c": [
+ {
+ "t": "Str",
+ "c": "something"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "else"
+ }
+ ]
+ }
+ ]
+ ]
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Str",
+ "c": "non-ascii"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "characters"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "TODO"
+ }
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Str",
+ "c": "This"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "is"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "a"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "long"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "section"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "of"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "text,"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "which"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "we"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "only"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "want"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "in"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "a"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "document"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "(not"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "a"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "presentation)"
+ },
+ {
+ "t": "SoftBreak"
+ },
+ {
+ "t": "Str",
+ "c": "some"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "text"
+ },
+ {
+ "t": "SoftBreak"
+ },
+ {
+ "t": "Str",
+ "c": "some"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "more"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "text"
+ },
+ {
+ "t": "SoftBreak"
+ },
+ {
+ "t": "Str",
+ "c": "some"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "more"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "text"
+ },
+ {
+ "t": "SoftBreak"
+ },
+ {
+ "t": "Str",
+ "c": "some"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "more"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "text"
+ },
+ {
+ "t": "SoftBreak"
+ },
+ {
+ "t": "Str",
+ "c": "some"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "more"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "text"
+ },
+ {
+ "t": "SoftBreak"
+ },
+ {
+ "t": "Str",
+ "c": "some"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "more"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "text"
+ },
+ {
+ "t": "SoftBreak"
+ },
+ {
+ "t": "Str",
+ "c": "some"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "more"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "text"
+ },
+ {
+ "t": "SoftBreak"
+ },
+ {
+ "t": "Str",
+ "c": "some"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "more"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "text"
+ },
+ {
+ "t": "SoftBreak"
+ },
+ {
+ "t": "Str",
+ "c": "some"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "more"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "text"
+ }
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Str",
+ "c": "This"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "is"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "an"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "abbreviated"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "section"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "of"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "the"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "document"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "text,"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "which"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "we"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "only"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "want"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "in"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "a"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "presentation"
+ }
+ ]
+ },
+ {
+ "t": "BulletList",
+ "c": [
+ [
+ {
+ "t": "Plain",
+ "c": [
+ {
+ "t": "Str",
+ "c": "summary"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "of"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "document"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "text"
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ {
+ "t": "Header",
+ "c": [
+ 2,
+ [
+ "references-and-citations",
+ [],
+ []
+ ],
+ [
+ {
+ "t": "Str",
+ "c": "References"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "and"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "Citations"
+ }
+ ]
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Str",
+ "c": "References"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "to"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "RawInline",
+ "c": [
+ "tex",
+ "\\cref{fig:example}"
+ ]
+ },
+ {
+ "t": "Str",
+ "c": ","
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "RawInline",
+ "c": [
+ "tex",
+ "\\cref{tbl:example}"
+ ]
+ },
+ {
+ "t": "Str",
+ "c": ","
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "="
+ },
+ {
+ "t": "Cite",
+ "c": [
+ [
+ {
+ "citationSuffix": [],
+ "citationNoteNum": 0,
+ "citationMode": {
+ "t": "AuthorInText"
+ },
+ "citationPrefix": [],
+ "citationId": "eqn:example_sympy",
+ "citationHash": 0
+ }
+ ],
+ [
+ {
+ "t": "Str",
+ "c": "@eqn:example_sympy"
+ }
+ ]
+ ]
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "and"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "RawInline",
+ "c": [
+ "tex",
+ "\\cref{code:example_mpl}"
+ ]
+ },
+ {
+ "t": "Str",
+ "c": "."
+ }
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Str",
+ "c": "A"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "latex"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "citation."
+ },
+ {
+ "t": "RawInline",
+ "c": [
+ "tex",
+ "\\cite{zelenyak_molecular_2016}"
+ ]
+ }
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Str",
+ "c": "A"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "html"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "citation."
+ },
+ {
+ "t": "RawInline",
+ "c": [
+ "html",
+ ""
+ ]
+ },
+ {
+ "t": "Str",
+ "c": "(Kirkeminde,"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "2012)"
+ },
+ {
+ "t": "RawInline",
+ "c": [
+ "html",
+ ""
+ ]
+ }
+ ]
+ },
+ {
+ "t": "Header",
+ "c": [
+ 2,
+ [
+ "todo-notes",
+ [],
+ []
+ ],
+ [
+ {
+ "t": "Str",
+ "c": "Todo"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "notes"
+ }
+ ]
+ ]
+ },
+ {
+ "t": "RawBlock",
+ "c": [
+ "latex",
+ "\\todo[inline]{an inline todo}"
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Str",
+ "c": "Some"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "text."
+ },
+ {
+ "t": "RawInline",
+ "c": [
+ "tex",
+ "\\todo{a todo in the margins}"
+ ]
+ }
+ ]
+ },
+ {
+ "t": "Header",
+ "c": [
+ 1,
+ [
+ "text-output",
+ [],
+ []
+ ],
+ [
+ {
+ "t": "Str",
+ "c": "Text"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "Output"
+ }
+ ]
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Code",
+ "c": [
+ [
+ "",
+ [],
+ []
+ ],
+ "{python ipub={'text': {'format': {'backgroundcolor': '\\\\color{blue!10}'}}}} print(\"\"\" This is some printed text, with a nicely formatted output. \"\"\")"
+ ]
+ }
+ ]
+ },
+ {
+ "t": "Header",
+ "c": [
+ 1,
+ [
+ "images-and-figures",
+ [],
+ []
+ ],
+ [
+ {
+ "t": "Str",
+ "c": "Images"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "and"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "Figures"
+ }
+ ]
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Code",
+ "c": [
+ [
+ "",
+ [],
+ []
+ ],
+ "{python ipub={'figure': {'caption': 'A nice picture.', 'label': 'fig:example', 'placement': '!bh'}}} Image('example.jpg',height=400)"
+ ]
+ }
+ ]
+ },
+ {
+ "t": "Header",
+ "c": [
+ 2,
+ [
+ "displaying-a-plot-with-its-code",
+ [],
+ []
+ ],
+ [
+ {
+ "t": "Str",
+ "c": "Displaying"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "a"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "plot"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "with"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "its"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "code"
+ }
+ ]
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Str",
+ "c": "A"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "matplotlib"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "figure,"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "with"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "the"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "caption"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "set"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "in"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "the"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "markdowncell"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "above"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "the"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "figure."
+ }
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Str",
+ "c": "The"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "plotting"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "code"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "for"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "a"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "matplotlib"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "figure"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "("
+ },
+ {
+ "t": "RawInline",
+ "c": [
+ "tex",
+ "\\cref{fig:example_mpl}"
+ ]
+ },
+ {
+ "t": "Str",
+ "c": ")."
+ }
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Code",
+ "c": [
+ [
+ "",
+ [],
+ []
+ ],
+ "{python ipub={'code': {'asfloat': True, 'caption': 'a', 'label': 'code:example_mpl', 'widefigure': False}, 'figure': {'caption': '', 'label': 'fig:example_mpl', 'widefigure': False}}} plt.scatter(np.random.rand(10), np.random.rand(10), label='data label') plt.ylabel(r'a y label with latex $\\alpha$') plt.legend();"
+ ]
+ }
+ ]
+ },
+ {
+ "t": "Header",
+ "c": [
+ 1,
+ [
+ "tables-with-pandas",
+ [],
+ []
+ ],
+ [
+ {
+ "t": "Str",
+ "c": "Tables"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "(with"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "pandas)"
+ }
+ ]
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Str",
+ "c": "The"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "plotting"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "code"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "for"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "a"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "pandas"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "Dataframe"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "table"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "("
+ },
+ {
+ "t": "RawInline",
+ "c": [
+ "tex",
+ "\\cref{tbl:example}"
+ ]
+ },
+ {
+ "t": "Str",
+ "c": ")."
+ }
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Code",
+ "c": [
+ [
+ "",
+ [],
+ []
+ ],
+ "{python ipub={'code': {'asfloat': True, 'caption': '', 'label': 'code:example_pd', 'placement': 'H', 'widefigure': False}, 'table': {'alternate': 'gray!20', 'caption': 'An example of a table created with pandas dataframe.', 'label': 'tbl:example', 'placement': 'H'}}} df = pd.DataFrame(np.random.rand(3,4),columns=['a','b','c','d']) df.a = ['$\\delta$','x','y'] df.b = ['l','m','n'] df.set_index(['a','b']) df.round(3)"
+ ]
+ }
+ ]
+ },
+ {
+ "t": "Header",
+ "c": [
+ 1,
+ [
+ "equations-with-ipython-or-sympy",
+ [],
+ []
+ ],
+ [
+ {
+ "t": "Str",
+ "c": "Equations"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "(with"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "ipython"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "or"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "sympy)"
+ }
+ ]
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Code",
+ "c": [
+ [
+ "",
+ [],
+ []
+ ],
+ "{python ipub={'equation': {'label': 'eqn:example_ipy'}}} Latex('$$ a = b+c $$')"
+ ]
+ }
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Str",
+ "c": "The"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "plotting"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "code"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "for"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "a"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "sympy"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "equation"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "(="
+ },
+ {
+ "t": "Cite",
+ "c": [
+ [
+ {
+ "citationSuffix": [],
+ "citationNoteNum": 0,
+ "citationMode": {
+ "t": "AuthorInText"
+ },
+ "citationPrefix": [],
+ "citationId": "eqn:example_sympy",
+ "citationHash": 0
+ }
+ ],
+ [
+ {
+ "t": "Str",
+ "c": "@eqn:example_sympy"
+ }
+ ]
+ ]
+ },
+ {
+ "t": "Str",
+ "c": ")."
+ }
+ ]
+ },
+ {
+ "t": "Para",
+ "c": [
+ {
+ "t": "Code",
+ "c": [
+ [
+ "",
+ [],
+ []
+ ],
+ "{python ipub={'code': {'asfloat': True, 'caption': '', 'label': 'code:example_sym', 'placement': 'H', 'widefigure': False}, 'equation': {'environment': 'equation', 'label': 'eqn:example_sympy'}}} y = sym.Function('y') n = sym.symbols(r'\\alpha') f = y(n)-2*y(n-1/sym.pi)-5*y(n-2) sym.rsolve(f,y(n),[1,4])"
+ ]
+ }
+ ]
+ }
+ ],
+ "pandoc-api-version": [
+ 1,
+ 17,
+ 5,
+ 1
+ ],
+ "meta": {
+ "jupyter": {
+ "t": "MetaMap",
+ "c": {
+ "jupytext": {
+ "t": "MetaMap",
+ "c": {
+ "metadata_filter": {
+ "t": "MetaMap",
+ "c": {
+ "notebook": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "ipub"
+ }
+ ]
+ }
+ }
+ },
+ "text_representation": {
+ "t": "MetaMap",
+ "c": {
+ "format_version": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "1.0"
+ }
+ ]
+ },
+ "jupytext_version": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "0.8.6"
+ }
+ ]
+ },
+ "extension": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": ".Rmd"
+ }
+ ]
+ },
+ "format_name": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "rmarkdown"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "kernelspec": {
+ "t": "MetaMap",
+ "c": {
+ "display_name": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "Python"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "3"
+ }
+ ]
+ },
+ "name": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "python3"
+ }
+ ]
+ },
+ "language": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "python"
+ }
+ ]
+ }
+ }
+ },
+ "ipub": {
+ "t": "MetaMap",
+ "c": {
+ "at_notation": {
+ "t": "MetaBool",
+ "c": true
+ },
+ "toc": {
+ "t": "MetaMap",
+ "c": {
+ "depth": {
+ "t": "MetaString",
+ "c": "2"
+ }
+ }
+ },
+ "listfigures": {
+ "t": "MetaBool",
+ "c": true
+ },
+ "use_numref": {
+ "t": "MetaBool",
+ "c": true
+ },
+ "bibstyle": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "unsrtnat"
+ }
+ ]
+ },
+ "bibliography": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "example.bib"
+ }
+ ]
+ },
+ "biboptions": {
+ "t": "MetaList",
+ "c": [
+ {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "super"
+ }
+ ]
+ },
+ {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "sort"
+ }
+ ]
+ }
+ ]
+ },
+ "listcode": {
+ "t": "MetaBool",
+ "c": true
+ },
+ "listtables": {
+ "t": "MetaBool",
+ "c": true
+ },
+ "language": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "portuges"
+ }
+ ]
+ },
+ "titlepage": {
+ "t": "MetaMap",
+ "c": {
+ "institution": {
+ "t": "MetaList",
+ "c": [
+ {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "Institution1"
+ }
+ ]
+ },
+ {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "Institution2"
+ }
+ ]
+ }
+ ]
+ },
+ "email": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "authors@email.com"
+ }
+ ]
+ },
+ "supervisors": {
+ "t": "MetaList",
+ "c": [
+ {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "First"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "Supervisor"
+ }
+ ]
+ },
+ {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "Second"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "Supervisor"
+ }
+ ]
+ }
+ ]
+ },
+ "subtitle": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "Sub-Title"
+ }
+ ]
+ },
+ "tagline": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "A"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "tagline"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "for"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "the"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "report."
+ }
+ ]
+ },
+ "author": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "Authors"
+ },
+ {
+ "t": "Space"
+ },
+ {
+ "t": "Str",
+ "c": "Name"
+ }
+ ]
+ },
+ "title": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "Main-Title"
+ }
+ ]
+ },
+ "logo": {
+ "t": "MetaInlines",
+ "c": [
+ {
+ "t": "Str",
+ "c": "logo_example.png"
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.slides.html b/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.slides.html
index b8765eb..60178b4 100644
--- a/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.slides.html
+++ b/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.slides.html
@@ -1,14 +1,16 @@
-
-
+- ipypublish-latex_doc: caption and label elements according to ipub meta tags
+- ipypublish-slides_ipypublish: marks up html with slide tags, based on metadata
+-->
+
@@ -8515,15 +8517,15 @@
}
/* Flexible box model classes */
/* Taken from Alex Russell http://infrequently.org/2009/08/css-3-progress/ */
-/* This file is a compatability layer. It allows the usage of flexible box
+/* This file is a compatability layer. It allows the usage of flexible box
model layouts accross multiple browsers, including older browsers. The newest,
universal implementation of the flexible box model is used when available (see
-`Modern browsers` comments below). Browsers that are known to implement this
+`Modern browsers` comments below). Browsers that are known to implement this
new spec completely include:
Firefox 28.0+
Chrome 29.0+
- Internet Explorer 11+
+ Internet Explorer 11+
Opera 17.0+
Browsers not listed, including Safari, are supported via the styling under the
@@ -11297,7 +11299,7 @@
background: #f7f7f7;
border-top: 1px solid #cfcfcf;
border-bottom: 1px solid #cfcfcf;
- /* This injects handle bars (a short, wide = symbol) for
+ /* This injects handle bars (a short, wide = symbol) for
the resize handle. */
}
div#pager .ui-resizable-handle::after {
@@ -11951,7 +11953,7 @@ 1.2. References and Citations
-References to fig. 1, tbl. 1, eqn. 1 and code 3.
+References to fig. 1, tbl. 1, =@eqn:example_sympy and code 3.
A latex citation.[Zelenyak et al, 2016.]
A html citation.(Kirkeminde, 2012)
@@ -13095,7 +13097,7 @@ 3.1. Displaying a plot with its co
-plt.scatter(np.random.rand(10), np.random.rand(10),
+plt.scatter(np.random.rand(10), np.random.rand(10),
label='data label')
plt.ylabel(r'a y label with latex $\alpha$')
plt.legend();
@@ -13124,33 +13126,33 @@ 3.1. Displaying a plot with its co
-
-
-
@@ -13171,8 +13173,8 @@ 3.1. Displaying a plot with its co
-
@@ -13182,32 +13184,32 @@ 3.1. Displaying a plot with its co
-
-
@@ -13227,25 +13229,25 @@ 3.1. Displaying a plot with its co
-
@@ -13265,28 +13267,28 @@ 3.1. Displaying a plot with its co
-
@@ -13306,26 +13308,26 @@ 3.1. Displaying a plot with its co
-
@@ -13345,29 +13347,29 @@ 3.1. Displaying a plot with its co
-
@@ -13383,8 +13385,8 @@ 3.1. Displaying a plot with its co
-
@@ -13469,21 +13471,21 @@ 3.1. Displaying a plot with its co
-
@@ -13497,277 +13499,277 @@ 3.1. Displaying a plot with its co
-
-
-
-
-
-
-
-
-
-
-
@@ -13793,36 +13795,36 @@ 3.1. Displaying a plot with its co
-
-
-
-
-
@@ -13834,27 +13836,27 @@ 3.1. Displaying a plot with its co
-
@@ -14032,15 +14034,15 @@ 5. Equations (with ipython or symp
-
Code 8: The plotting code for a sympy equation (eqn. 1).
+
Code 8: The plotting code for a sympy equation (=@eqn:example_sympy).
-f = sym.Function('f')
-y,n = sym.symbols(r'y \alpha')
+y = sym.Function('y')
+n = sym.symbols(r'\alpha')
f = y(n)-2*y(n-1/sym.pi)-5*y(n-2)
sym.rsolve(f,y(n),[1,4])
diff --git a/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.tex b/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.tex
index 839bafa..afde46f 100644
--- a/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.tex
+++ b/ipypublish/tests/test_files/ipynb_with_external/ipynb_with_external.tex
@@ -1,6 +1,6 @@
-% A latex document created by ipypublish
+% A latex document created by ipypublish
% outline: ipypublish.templates.outline_schemas/latex_outline.latex.j2
% with segments:
% - standard-standard_packages: with standard nbconvert packages
@@ -425,6 +425,7 @@
% make the text float work with cleverref
\crefname{errorcell}{error}{errors}
\Crefname{errorcell}{error}{errors}
+
%%%%%%%%%%%%
\begin{document}
@@ -524,7 +525,7 @@ \subsection{General}\label{general}}
\subsection{References and Citations}\label{references-and-citations}}
References to \cref{fig:example}, \cref{tbl:example},
-\cref{eqn:example_sympy} and \cref{code:example_mpl}.
+\eqref{eqn:example_sympy} and \cref{code:example_mpl}.
A latex citation.\cite{zelenyak_molecular_2016}
@@ -558,23 +559,26 @@ \subsection{Displaying a plot with its
code}\label{displaying-a-plot-with-its-code}}
\begin{codecell}
-
- \caption{The plotting code for a matplotlib figure (\cref{fig:example_mpl}).}\label{code:example_mpl}\begin{lstlisting}[language=Python,numbers=left,xleftmargin=20pt,xrightmargin=5pt,belowskip=5pt,aboveskip=5pt]
-plt.scatter(np.random.rand(10), np.random.rand(10),
+\caption{The plotting code for a matplotlib figure (\cref{fig:example_mpl}).}
+\label{code:example_mpl}
+\begin{lstlisting}[language=Python,numbers=left,xleftmargin=20pt,xrightmargin=5pt,belowskip=5pt,aboveskip=5pt]
+plt.scatter(np.random.rand(10), np.random.rand(10),
label='data label')
plt.ylabel(r'a y label with latex $\alpha$')
plt.legend();
\end{lstlisting}\end{codecell}
-\begin{figure}\begin{center}\adjustimage{max size={0.9\linewidth}{0.9\paperheight}}{ipynb_with_external_files/output_17_0.pdf}\end{center}\caption{A matplotlib figure, with the caption set in the markdowncell above the figure.}\label{fig:example_mpl}
+\begin{figure}\begin{center}\adjustimage{max size={0.9\linewidth}{0.9\paperheight}}{ipynb_with_external_files/output_17_0.pdf}\end{center}\caption{A matplotlib figure, with the caption set in the markdowncell above the
+figure.}\label{fig:example_mpl}
\end{figure}
\hypertarget{tables-with-pandas}{%
\section{Tables (with pandas)}\label{tables-with-pandas}}
\begin{codecell}[H]
-
- \caption{The plotting code for a pandas Dataframe table (\cref{tbl:example}).}\label{code:example_pd}\begin{lstlisting}[language=Python,numbers=left,xleftmargin=20pt,xrightmargin=5pt,belowskip=5pt,aboveskip=5pt]
+\caption{The plotting code for a pandas Dataframe table (\cref{tbl:example}).}
+\label{code:example_pd}
+\begin{lstlisting}[language=Python,numbers=left,xleftmargin=20pt,xrightmargin=5pt,belowskip=5pt,aboveskip=5pt]
df = pd.DataFrame(np.random.rand(3,4),columns=['a','b','c','d'])
df.a = ['$\delta$','x','y']
df.b = ['l','m','n']
@@ -582,8 +586,8 @@ \section{Tables (with pandas)}\label{tables-with-pandas}}
df.round(3)
\end{lstlisting}\end{codecell}
- \begin{table}[H]\caption{An example of a table created with pandas dataframe.}\label{tbl:example}
-
+\begin{table}[H]
+\caption{An example of a table created with pandas dataframe.}\label{tbl:example}
\centering
\begin{adjustbox}{max width=\textwidth}\rowcolors{2}{gray!20}{white}
\begin{tabular}{lllrr}
@@ -606,10 +610,11 @@ \section{Equations (with ipython or
$$ a = b+c $$
\begin{codecell}[H]
-
- \caption{The plotting code for a sympy equation (\cref{eqn:example_sympy}).}\label{code:example_sym}\begin{lstlisting}[language=Python,numbers=left,xleftmargin=20pt,xrightmargin=5pt,belowskip=5pt,aboveskip=5pt]
-f = sym.Function('f')
-y,n = sym.symbols(r'y \alpha')
+\caption{The plotting code for a sympy equation (\eqref{eqn:example_sympy}).}
+\label{code:example_sym}
+\begin{lstlisting}[language=Python,numbers=left,xleftmargin=20pt,xrightmargin=5pt,belowskip=5pt,aboveskip=5pt]
+y = sym.Function('y')
+n = sym.symbols(r'\alpha')
f = y(n)-2*y(n-1/sym.pi)-5*y(n-2)
sym.rsolve(f,y(n),[1,4])
\end{lstlisting}\end{codecell}
@@ -622,4 +627,3 @@ \section{Equations (with ipython or
\bibliography{ipynb_with_external_files/example}
\end{document}
-
diff --git a/ipypublish/tests/test_files/ipynb_with_external/sphinx_ipypublish_all.pandoc.1-12.rst b/ipypublish/tests/test_files/ipynb_with_external/sphinx_ipypublish_all.pandoc.1-12.rst
new file mode 100644
index 0000000..72b151e
--- /dev/null
+++ b/ipypublish/tests/test_files/ipynb_with_external/sphinx_ipypublish_all.pandoc.1-12.rst
@@ -0,0 +1,194 @@
+
+.. An html document created by ipypublish
+ outline: ipypublish.templates.outline_schemas/rst_outline.rst.j2
+ with segments:
+ - nbsphinx-ipypublish-content: ipypublish sphinx content
+
+.. nbinput:: ipython3
+ :no-output:
+
+ from ipypublish.scripts.ipynb_latex_setup import *
+
+Markdown
+========
+
+General
+-------
+
+Some markdown text.
+
+A list:
+
+- something
+- something else
+
+A numbered list
+
+1. something
+2. something else
+
+non-ascii characters TODO
+
+This is a long section of text, which we only want in a document (not a
+presentation) some text some more text some more text some more text
+some more text some more text some more text some more text some more
+text
+
+References and Citations
+------------------------
+
+References to :numref:`fig:example`, :numref:`tbl:example`,
+:eq:`eqn:example_sympy` and :numref:`code:example_mpl`.
+
+A latex citation. :cite:`zelenyak_molecular_2016`
+
+A html citation. :cite:`kirkeminde_thermodynamic_2012`
+
+Todo notes
+----------
+
+.. todo:: an inline todo
+
+Some text.
+
+.. todo:: a todo in the margins
+
+Text Output
+===========
+
+.. nbinput:: ipython3
+ :execution-count: 3
+ :no-output:
+
+ print("""
+ This is some printed text,
+ with a nicely formatted output.
+ """)
+
+.. nboutput:: ansi
+
+ .. rst-class:: highlight
+
+ .. raw:: html
+
+
+
+ This is some printed text,
+ with a nicely formatted output.
+
+
+
+ .. raw:: latex
+
+ This is some printed text,
+ with a nicely formatted output.
+
+Images and Figures
+==================
+
+.. nbinput:: ipython3
+ :execution-count: 3
+ :no-output:
+
+ Image('example.jpg',height=400)
+
+.. nboutput:: rst
+
+ .. figure:: ipynb_with_external_files/output_13_0.jpeg
+ :alt: output_13_0
+ :align: center
+ :height: 400
+ :name: fig:example
+
+ A nice picture.
+
+Displaying a plot with its code
+-------------------------------
+
+.. nbinput:: ipython3
+ :execution-count: 9
+ :no-output:
+ :name: code:example_mpl
+ :caption: The plotting code for a matplotlib figure (:numref:`fig:example_mpl`).
+
+ plt.scatter(np.random.rand(10), np.random.rand(10),
+ label='data label')
+ plt.ylabel(r'a y label with latex $\alpha$')
+ plt.legend();
+
+.. nboutput:: rst
+
+ .. figure:: ipynb_with_external_files/output_17_0.svg
+ :alt: output_17_0
+ :align: center
+ :name: fig:example_mpl
+
+ A matplotlib figure, with the caption set in the markdowncell above the
+ figure.
+
+Tables (with pandas)
+====================
+
+.. nbinput:: ipython3
+ :execution-count: 8
+ :no-output:
+ :name: code:example_pd
+ :caption: The plotting code for a pandas Dataframe table (:numref:`tbl:example`).
+
+ df = pd.DataFrame(np.random.rand(3,4),columns=['a','b','c','d'])
+ df.a = ['$\delta$','x','y']
+ df.b = ['l','m','n']
+ df.set_index(['a','b'])
+ df.round(3)
+
+.. nboutput:: rst
+
+ .. table:: An example of a table created with pandas dataframe.
+ :name: tbl:example
+
+ | lllrr & a & b & c & d
+ | 0 & :math:`\delta` & l & 0.583 & 0.279
+ | 1 & x & m & 0.914 & 0.021
+ | 2 & y & n & 0.333 & 0.116
+
+Equations (with ipython or sympy)
+=================================
+
+.. nbinput:: ipython3
+ :execution-count: 9
+ :no-output:
+
+ Latex('$$ a = b+c $$')
+
+.. nboutput:: rst
+
+ .. math::
+ :nowrap:
+ :label: eqn:example_ipy
+
+ \begin{equation}
+ a = b+c
+ \end{equation}
+
+.. nbinput:: ipython3
+ :execution-count: 10
+ :no-output:
+ :name: code:example_sym
+ :caption: The plotting code for a sympy equation (:eq:`eqn:example_sympy`).
+
+ y = sym.Function('y')
+ n = sym.symbols(r'\alpha')
+ f = y(n)-2*y(n-1/sym.pi)-5*y(n-2)
+ sym.rsolve(f,y(n),[1,4])
+
+.. nboutput:: rst
+
+ .. math::
+ :nowrap:
+ :label: eqn:example_sympy
+
+ \begin{equation}
+ \left(\sqrt{5} i\right)^{\alpha} \left(\frac{1}{2} - \frac{2 i}{5} \sqrt{5}\right) + \left(- \sqrt{5} i\right)^{\alpha} \left(\frac{1}{2} + \frac{2 i}{5} \sqrt{5}\right)
+ \end{equation}
+
+.. bibliography:: ipynb_with_external_files/example.bib
diff --git a/ipypublish/tests/test_files/ipynb_with_external/sphinx_ipypublish_all.pandoc.2-2.rst b/ipypublish/tests/test_files/ipynb_with_external/sphinx_ipypublish_all.pandoc.2-2.rst
new file mode 100644
index 0000000..e66dc44
--- /dev/null
+++ b/ipypublish/tests/test_files/ipynb_with_external/sphinx_ipypublish_all.pandoc.2-2.rst
@@ -0,0 +1,199 @@
+
+.. An html document created by ipypublish
+ outline: ipypublish.templates.outline_schemas/rst_outline.rst.j2
+ with segments:
+ - nbsphinx-ipypublish-content: ipypublish sphinx content
+
+.. nbinput:: ipython3
+ :no-output:
+
+ from ipypublish.scripts.ipynb_latex_setup import *
+
+Markdown
+========
+
+General
+-------
+
+Some markdown text.
+
+A list:
+
+- something
+- something else
+
+A numbered list
+
+1. something
+2. something else
+
+non-ascii characters TODO
+
+This is a long section of text, which we only want in a document (not a
+presentation) some text some more text some more text some more text
+some more text some more text some more text some more text some more
+text
+
+References and Citations
+------------------------
+
+References to :numref:`fig:example`, :numref:`tbl:example`,
+:eq:`eqn:example_sympy` and :numref:`code:example_mpl`.
+
+A latex citation. :cite:`zelenyak_molecular_2016`
+
+A html citation. :cite:`kirkeminde_thermodynamic_2012`
+
+Todo notes
+----------
+
+.. todo:: an inline todo
+
+Some text.
+
+.. todo:: a todo in the margins
+
+Text Output
+===========
+
+.. nbinput:: ipython3
+ :execution-count: 3
+ :no-output:
+
+ print("""
+ This is some printed text,
+ with a nicely formatted output.
+ """)
+
+.. nboutput:: ansi
+
+ .. rst-class:: highlight
+
+ .. raw:: html
+
+
+
+ This is some printed text,
+ with a nicely formatted output.
+
+
+
+ .. raw:: latex
+
+ This is some printed text,
+ with a nicely formatted output.
+
+Images and Figures
+==================
+
+.. nbinput:: ipython3
+ :execution-count: 3
+ :no-output:
+
+ Image('example.jpg',height=400)
+
+.. nboutput:: rst
+
+ .. figure:: ipynb_with_external_files/output_13_0.jpeg
+ :alt: output_13_0
+ :align: center
+ :height: 400
+ :name: fig:example
+
+ A nice picture.
+
+Displaying a plot with its code
+-------------------------------
+
+.. nbinput:: ipython3
+ :execution-count: 9
+ :no-output:
+ :name: code:example_mpl
+ :caption: The plotting code for a matplotlib figure (:numref:`fig:example_mpl`).
+
+ plt.scatter(np.random.rand(10), np.random.rand(10),
+ label='data label')
+ plt.ylabel(r'a y label with latex $\alpha$')
+ plt.legend();
+
+.. nboutput:: rst
+
+ .. figure:: ipynb_with_external_files/output_17_0.svg
+ :alt: output_17_0
+ :align: center
+ :name: fig:example_mpl
+
+ A matplotlib figure, with the caption set in the markdowncell above the
+ figure.
+
+Tables (with pandas)
+====================
+
+.. nbinput:: ipython3
+ :execution-count: 8
+ :no-output:
+ :name: code:example_pd
+ :caption: The plotting code for a pandas Dataframe table (:numref:`tbl:example`).
+
+ df = pd.DataFrame(np.random.rand(3,4),columns=['a','b','c','d'])
+ df.a = ['$\delta$','x','y']
+ df.b = ['l','m','n']
+ df.set_index(['a','b'])
+ df.round(3)
+
+.. nboutput:: rst
+
+ .. table:: An example of a table created with pandas dataframe.
+ :name: tbl:example
+
+ +---+----------------+---+-------+-------+
+ | | a | b | c | d |
+ +===+================+===+=======+=======+
+ | 0 | :math:`\delta` | l | 0.583 | 0.279 |
+ +---+----------------+---+-------+-------+
+ | 1 | x | m | 0.914 | 0.021 |
+ +---+----------------+---+-------+-------+
+ | 2 | y | n | 0.333 | 0.116 |
+ +---+----------------+---+-------+-------+
+
+Equations (with ipython or sympy)
+=================================
+
+.. nbinput:: ipython3
+ :execution-count: 9
+ :no-output:
+
+ Latex('$$ a = b+c $$')
+
+.. nboutput:: rst
+
+ .. math::
+ :nowrap:
+ :label: eqn:example_ipy
+
+ \begin{equation}
+ a = b+c
+ \end{equation}
+
+.. nbinput:: ipython3
+ :execution-count: 10
+ :no-output:
+ :name: code:example_sym
+ :caption: The plotting code for a sympy equation (:eq:`eqn:example_sympy`).
+
+ y = sym.Function('y')
+ n = sym.symbols(r'\alpha')
+ f = y(n)-2*y(n-1/sym.pi)-5*y(n-2)
+ sym.rsolve(f,y(n),[1,4])
+
+.. nboutput:: rst
+
+ .. math::
+ :nowrap:
+ :label: eqn:example_sympy
+
+ \begin{equation}
+ \left(\sqrt{5} i\right)^{\alpha} \left(\frac{1}{2} - \frac{2 i}{5} \sqrt{5}\right) + \left(- \sqrt{5} i\right)^{\alpha} \left(\frac{1}{2} + \frac{2 i}{5} \sqrt{5}\right)
+ \end{equation}
+
+.. bibliography:: ipynb_with_external_files/example.bib
diff --git a/ipypublish/tests/test_files/ipynb_with_external/sphinx_ipypublish_all.pandoc.2-6.rst b/ipypublish/tests/test_files/ipynb_with_external/sphinx_ipypublish_all.pandoc.2-6.rst
new file mode 100644
index 0000000..584cbc1
--- /dev/null
+++ b/ipypublish/tests/test_files/ipynb_with_external/sphinx_ipypublish_all.pandoc.2-6.rst
@@ -0,0 +1,197 @@
+
+.. An html document created by ipypublish
+ outline: ipypublish.templates.outline_schemas/rst_outline.rst.j2
+ with segments:
+ - nbsphinx-ipypublish-content: ipypublish sphinx content
+
+.. nbinput:: ipython3
+ :no-output:
+
+ from ipypublish.scripts.ipynb_latex_setup import *
+
+Markdown
+========
+
+General
+-------
+
+Some markdown text.
+
+A list:
+
+- something
+- something else
+
+A numbered list
+
+1. something
+2. something else
+
+non-ascii characters TODO
+
+This is a long section of text, which we only want in a document (not a
+presentation) some text some more text some more text some more text
+some more text some more text some more text some more text some more
+text
+
+References and Citations
+------------------------
+
+References to :numref:`fig:example`, :numref:`tbl:example`,
+:eq:`eqn:example_sympy` and :numref:`code:example_mpl`.
+
+A latex citation. :cite:`zelenyak_molecular_2016`
+
+A html citation. :cite:`kirkeminde_thermodynamic_2012`
+
+Todo notes
+----------
+
+.. todo:: an inline todo
+
+Some text.
+
+.. todo:: a todo in the margins
+
+Text Output
+===========
+
+.. nbinput:: ipython3
+ :execution-count: 3
+ :no-output:
+
+ print("""
+ This is some printed text,
+ with a nicely formatted output.
+ """)
+
+.. nboutput:: ansi
+
+ .. rst-class:: highlight
+
+ .. raw:: html
+
+
+
+ This is some printed text,
+ with a nicely formatted output.
+
+
+
+ .. raw:: latex
+
+ This is some printed text,
+ with a nicely formatted output.
+
+Images and Figures
+==================
+
+.. nbinput:: ipython3
+ :execution-count: 3
+ :no-output:
+
+ Image('example.jpg',height=400)
+
+.. nboutput:: rst
+
+ .. figure:: ipynb_with_external_files/output_13_0.jpeg
+ :alt: output_13_0
+ :align: center
+ :height: 400
+ :name: fig:example
+
+ A nice picture.
+
+Displaying a plot with its code
+-------------------------------
+
+.. nbinput:: ipython3
+ :execution-count: 9
+ :no-output:
+ :name: code:example_mpl
+ :caption: The plotting code for a matplotlib figure (:numref:`fig:example_mpl`).
+
+ plt.scatter(np.random.rand(10), np.random.rand(10),
+ label='data label')
+ plt.ylabel(r'a y label with latex $\alpha$')
+ plt.legend();
+
+.. nboutput:: rst
+
+ .. figure:: ipynb_with_external_files/output_17_0.svg
+ :alt: output_17_0
+ :align: center
+ :name: fig:example_mpl
+
+ A matplotlib figure, with the caption set in the markdowncell above the
+ figure.
+
+Tables (with pandas)
+====================
+
+.. nbinput:: ipython3
+ :execution-count: 8
+ :no-output:
+ :name: code:example_pd
+ :caption: The plotting code for a pandas Dataframe table (:numref:`tbl:example`).
+
+ df = pd.DataFrame(np.random.rand(3,4),columns=['a','b','c','d'])
+ df.a = ['$\delta$','x','y']
+ df.b = ['l','m','n']
+ df.set_index(['a','b'])
+ df.round(3)
+
+.. nboutput:: rst
+
+ .. table:: An example of a table created with pandas dataframe.
+ :name: tbl:example
+
+ == ============== = ===== =====
+ \ a b c d
+ == ============== = ===== =====
+ 0 :math:`\delta` l 0.583 0.279
+ 1 x m 0.914 0.021
+ 2 y n 0.333 0.116
+ == ============== = ===== =====
+
+Equations (with ipython or sympy)
+=================================
+
+.. nbinput:: ipython3
+ :execution-count: 9
+ :no-output:
+
+ Latex('$$ a = b+c $$')
+
+.. nboutput:: rst
+
+ .. math::
+ :nowrap:
+ :label: eqn:example_ipy
+
+ \begin{equation}
+ a = b+c
+ \end{equation}
+
+.. nbinput:: ipython3
+ :execution-count: 10
+ :no-output:
+ :name: code:example_sym
+ :caption: The plotting code for a sympy equation (:eq:`eqn:example_sympy`).
+
+ y = sym.Function('y')
+ n = sym.symbols(r'\alpha')
+ f = y(n)-2*y(n-1/sym.pi)-5*y(n-2)
+ sym.rsolve(f,y(n),[1,4])
+
+.. nboutput:: rst
+
+ .. math::
+ :nowrap:
+ :label: eqn:example_sympy
+
+ \begin{equation}
+ \left(\sqrt{5} i\right)^{\alpha} \left(\frac{1}{2} - \frac{2 i}{5} \sqrt{5}\right) + \left(- \sqrt{5} i\right)^{\alpha} \left(\frac{1}{2} + \frac{2 i}{5} \sqrt{5}\right)
+ \end{equation}
+
+.. bibliography:: ipynb_with_external_files/example.bib
diff --git a/ipypublish/tests/test_files/ipynb_with_external/sphinx_nbsphinx.rst b/ipypublish/tests/test_files/ipynb_with_external/sphinx_nbsphinx.rst
index dbf5997..598bdd7 100644
--- a/ipypublish/tests/test_files/ipynb_with_external/sphinx_nbsphinx.rst
+++ b/ipypublish/tests/test_files/ipynb_with_external/sphinx_nbsphinx.rst
@@ -248,8 +248,8 @@ The plotting code for a sympy equation (:nbsphinx-math:`\cref{eqn:example_sympy}
.. nbinput:: ipython3
:execution-count: 10
- f = sym.Function('f')
- y,n = sym.symbols(r'y \alpha')
+ y = sym.Function('y')
+ n = sym.symbols(r'\alpha')
f = y(n)-2*y(n-1/sym.pi)-5*y(n-2)
sym.rsolve(f,y(n),[1,4])
diff --git a/ipypublish/tests/test_files/ipynb_with_external/sphinx_standard.rst b/ipypublish/tests/test_files/ipynb_with_external/sphinx_standard.rst
index cb011db..e4392ef 100644
--- a/ipypublish/tests/test_files/ipynb_with_external/sphinx_standard.rst
+++ b/ipypublish/tests/test_files/ipynb_with_external/sphinx_standard.rst
@@ -181,8 +181,8 @@ The plotting code for a sympy equation
.. code:: ipython3
- f = sym.Function('f')
- y,n = sym.symbols(r'y \alpha')
+ y = sym.Function('y')
+ n = sym.symbols(r'\alpha')
f = y(n)-2*y(n-1/sym.pi)-5*y(n-2)
sym.rsolve(f,y(n),[1,4])
diff --git a/ipypublish/tests/test_files/nb_markdown_cells/__init__.py b/ipypublish/tests/test_files/nb_markdown_cells/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/ipypublish/tests/test_files/nb_markdown_cells/latex_ipypublish_main.pandoc.1-12.tex b/ipypublish/tests/test_files/nb_markdown_cells/latex_ipypublish_main.pandoc.1-12.tex
new file mode 100644
index 0000000..0899a4d
--- /dev/null
+++ b/ipypublish/tests/test_files/nb_markdown_cells/latex_ipypublish_main.pandoc.1-12.tex
@@ -0,0 +1,508 @@
+
+
+% A latex document created by ipypublish
+% outline: ipypublish.templates.outline_schemas/latex_outline.latex.j2
+% with segments:
+% - standard-standard_packages: with standard nbconvert packages
+% - standard-standard_definitions: with standard nbconvert definitions
+% - ipypublish-doc_article: with the main ipypublish article setup
+% - ipypublish-front_pages: with the main ipypublish title and contents page setup
+% - ipypublish-biblio_natbib: with the main ipypublish bibliography
+% - ipypublish-contents_output: with the main ipypublish content
+% - ipypublish-contents_framed_code: with the input code wrapped and framed
+%
+%%%%%%%%%%%% DOCCLASS
+
+\documentclass[10pt,parskip=half,
+toc=sectionentrywithdots,
+bibliography=totocnumbered,
+captions=tableheading,numbers=noendperiod]{scrartcl}
+
+%%%%%%%%%%%%
+
+%%%%%%%%%%%% PACKAGES
+
+\usepackage[T1]{fontenc} % Nicer default font (+ math font) than Computer Modern for most use cases
+\usepackage{mathpazo}
+\usepackage{graphicx}
+\usepackage[skip=3pt]{caption}
+\usepackage{adjustbox} % Used to constrain images to a maximum size
+\usepackage[table]{xcolor} % Allow colors to be defined
+\usepackage{enumerate} % Needed for markdown enumerations to work
+\usepackage{amsmath} % Equations
+\usepackage{amssymb} % Equations
+\usepackage{textcomp} % defines textquotesingle
+% Hack from http://tex.stackexchange.com/a/47451/13684:
+\AtBeginDocument{%
+ \def\PYZsq{\textquotesingle}% Upright quotes in Pygmentized code
+}
+\usepackage{upquote} % Upright quotes for verbatim code
+\usepackage{eurosym} % defines \euro
+\usepackage[mathletters]{ucs} % Extended unicode (utf-8) support
+\usepackage[utf8x]{inputenc} % Allow utf-8 characters in the tex document
+\usepackage{fancyvrb} % verbatim replacement that allows latex
+\usepackage{grffile} % extends the file name processing of package graphics
+ % to support a larger range
+% The hyperref package gives us a pdf with properly built
+% internal navigation ('pdf bookmarks' for the table of contents,
+% internal cross-reference links, web links for URLs, etc.)
+\usepackage{hyperref}
+\usepackage{longtable} % longtable support required by pandoc >1.10
+\usepackage{booktabs} % table support for pandoc > 1.12.2
+\usepackage[inline]{enumitem} % IRkernel/repr support (it uses the enumerate* environment)
+\usepackage[normalem]{ulem} % ulem is needed to support strikethroughs (\sout)
+ % normalem makes italics be italics, not underlines
+
+\usepackage{translations}
+\usepackage{microtype} % improves the spacing between words and letters
+\usepackage{placeins} % placement of figures
+% could use \usepackage[section]{placeins} but placing in subsection in command section
+% Places the float at precisely the location in the LaTeX code (with H)
+\usepackage{float}
+\usepackage[colorinlistoftodos,obeyFinal,textwidth=.8in]{todonotes} % to mark to-dos
+% number figures, tables and equations by section
+% fix for new versions of texlive (see https://tex.stackexchange.com/a/425603/107738)
+\let\counterwithout\relax
+\let\counterwithin\relax
+\usepackage{chngcntr}
+% header/footer
+\usepackage[footsepline=0.25pt]{scrlayer-scrpage}
+
+% bibliography formatting
+\usepackage[numbers, square, super, sort&compress]{natbib}
+% hyperlink doi's
+\usepackage{doi}
+
+ % define a code float
+ \usepackage{newfloat} % to define a new float types
+ \DeclareFloatingEnvironment[
+ fileext=frm,placement={!ht},
+ within=section,name=Code]{codecell}
+ \DeclareFloatingEnvironment[
+ fileext=frm,placement={!ht},
+ within=section,name=Text]{textcell}
+ \DeclareFloatingEnvironment[
+ fileext=frm,placement={!ht},
+ within=section,name=Text]{errorcell}
+
+ \usepackage{listings} % a package for wrapping code in a box
+ \usepackage[framemethod=tikz]{mdframed} % to fram code
+
+%%%%%%%%%%%%
+
+%%%%%%%%%%%% DEFINITIONS
+
+% Pygments definitions
+
+\makeatletter
+\def\PY@reset{\let\PY@it=\relax \let\PY@bf=\relax%
+ \let\PY@ul=\relax \let\PY@tc=\relax%
+ \let\PY@bc=\relax \let\PY@ff=\relax}
+\def\PY@tok#1{\csname PY@tok@#1\endcsname}
+\def\PY@toks#1+{\ifx\relax#1\empty\else%
+ \PY@tok{#1}\expandafter\PY@toks\fi}
+\def\PY@do#1{\PY@bc{\PY@tc{\PY@ul{%
+ \PY@it{\PY@bf{\PY@ff{#1}}}}}}}
+\def\PY#1#2{\PY@reset\PY@toks#1+\relax+\PY@do{#2}}
+
+\expandafter\def\csname PY@tok@w\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.73,0.73}{##1}}}
+\expandafter\def\csname PY@tok@c\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
+\expandafter\def\csname PY@tok@cp\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.74,0.48,0.00}{##1}}}
+\expandafter\def\csname PY@tok@k\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@kp\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@kt\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.69,0.00,0.25}{##1}}}
+\expandafter\def\csname PY@tok@o\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@ow\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.67,0.13,1.00}{##1}}}
+\expandafter\def\csname PY@tok@nb\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@nf\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}}
+\expandafter\def\csname PY@tok@nc\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}}
+\expandafter\def\csname PY@tok@nn\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}}
+\expandafter\def\csname PY@tok@ne\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.82,0.25,0.23}{##1}}}
+\expandafter\def\csname PY@tok@nv\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
+\expandafter\def\csname PY@tok@no\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.53,0.00,0.00}{##1}}}
+\expandafter\def\csname PY@tok@nl\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.63,0.63,0.00}{##1}}}
+\expandafter\def\csname PY@tok@ni\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.60,0.60,0.60}{##1}}}
+\expandafter\def\csname PY@tok@na\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.49,0.56,0.16}{##1}}}
+\expandafter\def\csname PY@tok@nt\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@nd\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.67,0.13,1.00}{##1}}}
+\expandafter\def\csname PY@tok@s\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@sd\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@si\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.73,0.40,0.53}{##1}}}
+\expandafter\def\csname PY@tok@se\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.73,0.40,0.13}{##1}}}
+\expandafter\def\csname PY@tok@sr\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.40,0.53}{##1}}}
+\expandafter\def\csname PY@tok@ss\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
+\expandafter\def\csname PY@tok@sx\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@m\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@gh\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.50}{##1}}}
+\expandafter\def\csname PY@tok@gu\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.50,0.00,0.50}{##1}}}
+\expandafter\def\csname PY@tok@gd\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.63,0.00,0.00}{##1}}}
+\expandafter\def\csname PY@tok@gi\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.63,0.00}{##1}}}
+\expandafter\def\csname PY@tok@gr\endcsname{\def\PY@tc##1{\textcolor[rgb]{1.00,0.00,0.00}{##1}}}
+\expandafter\def\csname PY@tok@ge\endcsname{\let\PY@it=\textit}
+\expandafter\def\csname PY@tok@gs\endcsname{\let\PY@bf=\textbf}
+\expandafter\def\csname PY@tok@gp\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.50}{##1}}}
+\expandafter\def\csname PY@tok@go\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.53,0.53,0.53}{##1}}}
+\expandafter\def\csname PY@tok@gt\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.27,0.87}{##1}}}
+\expandafter\def\csname PY@tok@err\endcsname{\def\PY@bc##1{\setlength{\fboxsep}{0pt}\fcolorbox[rgb]{1.00,0.00,0.00}{1,1,1}{\strut ##1}}}
+\expandafter\def\csname PY@tok@kc\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@kd\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@kn\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@kr\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@bp\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@fm\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}}
+\expandafter\def\csname PY@tok@vc\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
+\expandafter\def\csname PY@tok@vg\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
+\expandafter\def\csname PY@tok@vi\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
+\expandafter\def\csname PY@tok@vm\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
+\expandafter\def\csname PY@tok@sa\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@sb\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@sc\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@dl\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@s2\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@sh\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@s1\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@mb\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@mf\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@mh\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@mi\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@il\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@mo\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@ch\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
+\expandafter\def\csname PY@tok@cm\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
+\expandafter\def\csname PY@tok@cpf\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
+\expandafter\def\csname PY@tok@c1\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
+\expandafter\def\csname PY@tok@cs\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
+
+\def\PYZbs{\char`\\}
+\def\PYZus{\char`\_}
+\def\PYZob{\char`\{}
+\def\PYZcb{\char`\}}
+\def\PYZca{\char`\^}
+\def\PYZam{\char`\&}
+\def\PYZlt{\char`\<}
+\def\PYZgt{\char`\>}
+\def\PYZsh{\char`\#}
+\def\PYZpc{\char`\%}
+\def\PYZdl{\char`\$}
+\def\PYZhy{\char`\-}
+\def\PYZsq{\char`\'}
+\def\PYZdq{\char`\"}
+\def\PYZti{\char`\~}
+% for compatibility with earlier versions
+\def\PYZat{@}
+\def\PYZlb{[}
+\def\PYZrb{]}
+\makeatother
+
+% ANSI colors
+\definecolor{ansi-black}{HTML}{3E424D}
+\definecolor{ansi-black-intense}{HTML}{282C36}
+\definecolor{ansi-red}{HTML}{E75C58}
+\definecolor{ansi-red-intense}{HTML}{B22B31}
+\definecolor{ansi-green}{HTML}{00A250}
+\definecolor{ansi-green-intense}{HTML}{007427}
+\definecolor{ansi-yellow}{HTML}{DDB62B}
+\definecolor{ansi-yellow-intense}{HTML}{B27D12}
+\definecolor{ansi-blue}{HTML}{208FFB}
+\definecolor{ansi-blue-intense}{HTML}{0065CA}
+\definecolor{ansi-magenta}{HTML}{D160C4}
+\definecolor{ansi-magenta-intense}{HTML}{A03196}
+\definecolor{ansi-cyan}{HTML}{60C6C8}
+\definecolor{ansi-cyan-intense}{HTML}{258F8F}
+\definecolor{ansi-white}{HTML}{C5C1B4}
+\definecolor{ansi-white-intense}{HTML}{A1A6B2}
+
+% commands and environments needed by pandoc snippets
+% extracted from the output of `pandoc -s`
+\providecommand{\tightlist}{%
+ \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
+\DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}}
+% Add ',fontsize=\small' for more characters per line
+\newenvironment{Shaded}{}{}
+\newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{{#1}}}}
+\newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.56,0.13,0.00}{{#1}}}
+\newcommand{\DecValTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}}
+\newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}}
+\newcommand{\FloatTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}}
+\newcommand{\CharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
+\newcommand{\StringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
+\newcommand{\CommentTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textit{{#1}}}}
+\newcommand{\OtherTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{{#1}}}
+\newcommand{\AlertTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}}
+\newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.02,0.16,0.49}{{#1}}}
+\newcommand{\RegionMarkerTok}[1]{{#1}}
+\newcommand{\ErrorTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}}
+\newcommand{\NormalTok}[1]{{#1}}
+
+% Additional commands for more recent versions of Pandoc
+\newcommand{\ConstantTok}[1]{\textcolor[rgb]{0.53,0.00,0.00}{{#1}}}
+\newcommand{\SpecialCharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
+\newcommand{\VerbatimStringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
+\newcommand{\SpecialStringTok}[1]{\textcolor[rgb]{0.73,0.40,0.53}{{#1}}}
+\newcommand{\ImportTok}[1]{{#1}}
+\newcommand{\DocumentationTok}[1]{\textcolor[rgb]{0.73,0.13,0.13}{\textit{{#1}}}}
+\newcommand{\AnnotationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}}
+\newcommand{\CommentVarTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}}
+\newcommand{\VariableTok}[1]{\textcolor[rgb]{0.10,0.09,0.49}{{#1}}}
+\newcommand{\ControlFlowTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{{#1}}}}
+\newcommand{\OperatorTok}[1]{\textcolor[rgb]{0.40,0.40,0.40}{{#1}}}
+\newcommand{\BuiltInTok}[1]{{#1}}
+\newcommand{\ExtensionTok}[1]{{#1}}
+\newcommand{\PreprocessorTok}[1]{\textcolor[rgb]{0.74,0.48,0.00}{{#1}}}
+\newcommand{\AttributeTok}[1]{\textcolor[rgb]{0.49,0.56,0.16}{{#1}}}
+\newcommand{\InformationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}}
+\newcommand{\WarningTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}}
+
+% Define a nice break command that doesn't care if a line doesn't already
+% exist.
+\def\br{\hspace*{\fill} \\* }
+
+% Math Jax compatability definitions
+\def\gt{>}
+\def\lt{<}
+
+\setcounter{secnumdepth}{5}
+
+% Colors for the hyperref package
+\definecolor{urlcolor}{rgb}{0,.145,.698}
+\definecolor{linkcolor}{rgb}{.71,0.21,0.01}
+\definecolor{citecolor}{rgb}{.12,.54,.11}
+
+\DeclareTranslationFallback{Author}{Author}
+\DeclareTranslation{Portuges}{Author}{Autor}
+
+\DeclareTranslationFallback{List of Codes}{List of Codes}
+\DeclareTranslation{Catalan}{List of Codes}{Llista de Codis}
+\DeclareTranslation{Danish}{List of Codes}{Liste over Koder}
+\DeclareTranslation{German}{List of Codes}{Liste der Codes}
+\DeclareTranslation{Spanish}{List of Codes}{Lista de C\'{o}digos}
+\DeclareTranslation{French}{List of Codes}{Liste des Codes}
+\DeclareTranslation{Italian}{List of Codes}{Elenco dei Codici}
+\DeclareTranslation{Dutch}{List of Codes}{Lijst van Codes}
+\DeclareTranslation{Portuges}{List of Codes}{Lista de C\'{o}digos}
+
+\DeclareTranslationFallback{Supervisors}{Supervisors}
+\DeclareTranslation{Catalan}{Supervisors}{Supervisors}
+\DeclareTranslation{Danish}{Supervisors}{Vejledere}
+\DeclareTranslation{German}{Supervisors}{Vorgesetzten}
+\DeclareTranslation{Spanish}{Supervisors}{Supervisores}
+\DeclareTranslation{French}{Supervisors}{Superviseurs}
+\DeclareTranslation{Italian}{Supervisors}{Le autorit\`{a} di vigilanza}
+\DeclareTranslation{Dutch}{Supervisors}{supervisors}
+\DeclareTranslation{Portuguese}{Supervisors}{Supervisores}
+
+\definecolor{codegreen}{rgb}{0,0.6,0}
+\definecolor{codegray}{rgb}{0.5,0.5,0.5}
+\definecolor{codepurple}{rgb}{0.58,0,0.82}
+\definecolor{backcolour}{rgb}{0.95,0.95,0.95}
+
+\lstdefinestyle{mystyle}{
+ commentstyle=\color{codegreen},
+ keywordstyle=\color{magenta},
+ numberstyle=\tiny\color{codegray},
+ stringstyle=\color{codepurple},
+ basicstyle=\ttfamily,
+ breakatwhitespace=false,
+ keepspaces=true,
+ numbers=left,
+ numbersep=10pt,
+ showspaces=false,
+ showstringspaces=false,
+ showtabs=false,
+ tabsize=2,
+ breaklines=true,
+ literate={\-}{}{0\discretionary{-}{}{-}},
+ postbreak=\mbox{\textcolor{red}{$\hookrightarrow$}\space},
+}
+
+\lstset{style=mystyle}
+
+\surroundwithmdframed[
+ hidealllines=true,
+ backgroundcolor=backcolour,
+ innerleftmargin=0pt,
+ innerrightmargin=0pt,
+ innertopmargin=0pt,
+ innerbottommargin=0pt]{lstlisting}
+
+%%%%%%%%%%%%
+
+%%%%%%%%%%%% MARGINS
+
+ % Used to adjust the document margins
+\usepackage{geometry}
+\geometry{tmargin=1in,bmargin=1in,lmargin=1in,rmargin=1in,
+nohead,includefoot,footskip=25pt}
+% you can use showframe option to check the margins visually
+%%%%%%%%%%%%
+
+%%%%%%%%%%%% COMMANDS
+
+% ensure new section starts on new page
+\addtokomafont{section}{\clearpage}
+
+% Prevent overflowing lines due to hard-to-break entities
+\sloppy
+
+% Setup hyperref package
+\hypersetup{
+ breaklinks=true, % so long urls are correctly broken across lines
+ colorlinks=true,
+ urlcolor=urlcolor,
+ linkcolor=linkcolor,
+ citecolor=citecolor,
+ }
+
+% ensure figures are placed within subsections
+\makeatletter
+\AtBeginDocument{%
+ \expandafter\renewcommand\expandafter\subsection\expandafter
+ {\expandafter\@fb@secFB\subsection}%
+ \newcommand\@fb@secFB{\FloatBarrier
+ \gdef\@fb@afterHHook{\@fb@topbarrier \gdef\@fb@afterHHook{}}}%
+ \g@addto@macro\@afterheading{\@fb@afterHHook}%
+ \gdef\@fb@afterHHook{}%
+}
+\makeatother
+
+% number figures, tables and equations by section
+\counterwithout{figure}{section}
+\counterwithout{table}{section}
+\counterwithout{equation}{section}
+\makeatletter
+\@addtoreset{table}{section}
+\@addtoreset{figure}{section}
+\@addtoreset{equation}{section}
+\makeatother
+\renewcommand\thetable{\thesection.\arabic{table}}
+\renewcommand\thefigure{\thesection.\arabic{figure}}
+\renewcommand\theequation{\thesection.\arabic{equation}}
+
+ % set global options for float placement
+ \makeatletter
+ \providecommand*\setfloatlocations[2]{\@namedef{fps@#1}{#2}}
+ \makeatother
+
+% align captions to left (indented)
+\captionsetup{justification=raggedright,
+singlelinecheck=false,format=hang,labelfont={it,bf}}
+
+% shift footer down so space between separation line
+\ModifyLayer[addvoffset=.6ex]{scrheadings.foot.odd}
+\ModifyLayer[addvoffset=.6ex]{scrheadings.foot.even}
+\ModifyLayer[addvoffset=.6ex]{scrheadings.foot.oneside}
+\ModifyLayer[addvoffset=.6ex]{plain.scrheadings.foot.odd}
+\ModifyLayer[addvoffset=.6ex]{plain.scrheadings.foot.even}
+\ModifyLayer[addvoffset=.6ex]{plain.scrheadings.foot.oneside}
+\pagestyle{scrheadings}
+\clearscrheadfoot{}
+\ifoot{\leftmark}
+\renewcommand{\sectionmark}[1]{\markleft{\thesection\ #1}}
+\ofoot{\pagemark}
+\cfoot{}
+
+%%%%%%%%%%%%
+
+%%%%%%%%%%%% FINAL HEADER MATERIAL
+
+% clereref must be loaded after anything that changes the referencing system
+\usepackage{cleveref}
+\creflabelformat{equation}{#2#1#3}
+
+% make the code float work with cleverref
+\crefname{codecell}{code}{codes}
+\Crefname{codecell}{code}{codes}
+% make the text float work with cleverref
+\crefname{textcell}{text}{texts}
+\Crefname{textcell}{text}{texts}
+% make the text float work with cleverref
+\crefname{errorcell}{error}{errors}
+\Crefname{errorcell}{error}{errors}
+%%%%%%%%%%%%
+
+\begin{document}
+
+ \title{Notebook}
+ \date{\today}
+ \maketitle
+
+ \begingroup
+ \let\cleardoublepage\relax
+ \let\clearpage\relax
+ \endgroup
+
+\hypertarget{notebook-to-test-markdown-cells}{%
+\section{Notebook to Test Markdown
+Cells}\label{notebook-to-test-markdown-cells}}
+
+\hypertarget{cell-with-attached-image}{%
+\subsection{Cell with Attached Image}\label{cell-with-attached-image}}
+
+\begin{figure}[H]
+\hypertarget{fig:id1}{%
+\begin{center}
+\adjustimage{max size={0.9\linewidth}{0.9\paperheight},}{nb_markdown_cells_files/attach_1_output_13_0.jpeg}
+\end{center}
+\caption{output\_13\_0.jpeg}\label{fig:id1}
+}
+\end{figure}
+
+\cref{fig:id1} \cref{fig:id1}
+
+\hypertarget{cell-with-linked-image}{%
+\subsection{Cell with Linked Image}\label{cell-with-linked-image}}
+
+\begin{figure}[]
+\hypertarget{fig:id2}{%
+\begin{center}
+\adjustimage{max size={0.9\linewidth}{0.9\paperheight},width=0.5\linewidth}{nb_markdown_cells_files/logo_example.png}
+\end{center}
+\caption{this is a \textbf{caption}}\label{fig:id2}
+}
+\end{figure}
+
+\hypertarget{cell-with-link-to-header}{%
+\subsection{Cell with Link to Header}\label{cell-with-link-to-header}}
+
+\cref{cell-with-link-to-header}
+
+\hypertarget{cell-with-math}{%
+\subsection{Cell with Math}\label{cell-with-math}}
+
+inline: $a = b$
+
+\begin{equation}a = b\label{eq:id1}\end{equation}
+\begin{align*}c &= d \\ other &= e\label{eq:id2}\end{align*}
+
+\hypertarget{cell-with-table}{%
+\subsection{Cell with Table}\label{cell-with-table}}
+
+\begin{longtable}[c]{@{}lll@{}}
+\toprule\addlinespace
+A & B & A and B
+\\\addlinespace
+\midrule\endhead
+False & False & False
+\\\addlinespace
+True & False & False
+\\\addlinespace
+False & True & False
+\\\addlinespace
+True & True & True
+\\\addlinespace
+\bottomrule
+\addlinespace
+\caption{Caption. \label{tbl:id}}
+\end{longtable}
+
+\cref{tbl:id}
+
+\hypertarget{references-using-notation}{%
+\subsection{References Using @
+Notation}\label{references-using-notation}}
+
+\Cref{cell-with-link-to-header}, and multiple references
+\cref{tbl:id,eq:id1}
+
+\end{document}
+
diff --git a/ipypublish/tests/test_files/nb_markdown_cells/latex_ipypublish_main.pandoc.2-2.tex b/ipypublish/tests/test_files/nb_markdown_cells/latex_ipypublish_main.pandoc.2-2.tex
new file mode 100644
index 0000000..3b80875
--- /dev/null
+++ b/ipypublish/tests/test_files/nb_markdown_cells/latex_ipypublish_main.pandoc.2-2.tex
@@ -0,0 +1,507 @@
+
+
+% A latex document created by ipypublish
+% outline: ipypublish.templates.outline_schemas/latex_outline.latex.j2
+% with segments:
+% - standard-standard_packages: with standard nbconvert packages
+% - standard-standard_definitions: with standard nbconvert definitions
+% - ipypublish-doc_article: with the main ipypublish article setup
+% - ipypublish-front_pages: with the main ipypublish title and contents page setup
+% - ipypublish-biblio_natbib: with the main ipypublish bibliography
+% - ipypublish-contents_output: with the main ipypublish content
+% - ipypublish-contents_framed_code: with the input code wrapped and framed
+%
+%%%%%%%%%%%% DOCCLASS
+
+\documentclass[10pt,parskip=half,
+toc=sectionentrywithdots,
+bibliography=totocnumbered,
+captions=tableheading,numbers=noendperiod]{scrartcl}
+
+%%%%%%%%%%%%
+
+%%%%%%%%%%%% PACKAGES
+
+\usepackage[T1]{fontenc} % Nicer default font (+ math font) than Computer Modern for most use cases
+\usepackage{mathpazo}
+\usepackage{graphicx}
+\usepackage[skip=3pt]{caption}
+\usepackage{adjustbox} % Used to constrain images to a maximum size
+\usepackage[table]{xcolor} % Allow colors to be defined
+\usepackage{enumerate} % Needed for markdown enumerations to work
+\usepackage{amsmath} % Equations
+\usepackage{amssymb} % Equations
+\usepackage{textcomp} % defines textquotesingle
+% Hack from http://tex.stackexchange.com/a/47451/13684:
+\AtBeginDocument{%
+ \def\PYZsq{\textquotesingle}% Upright quotes in Pygmentized code
+}
+\usepackage{upquote} % Upright quotes for verbatim code
+\usepackage{eurosym} % defines \euro
+\usepackage[mathletters]{ucs} % Extended unicode (utf-8) support
+\usepackage[utf8x]{inputenc} % Allow utf-8 characters in the tex document
+\usepackage{fancyvrb} % verbatim replacement that allows latex
+\usepackage{grffile} % extends the file name processing of package graphics
+ % to support a larger range
+% The hyperref package gives us a pdf with properly built
+% internal navigation ('pdf bookmarks' for the table of contents,
+% internal cross-reference links, web links for URLs, etc.)
+\usepackage{hyperref}
+\usepackage{longtable} % longtable support required by pandoc >1.10
+\usepackage{booktabs} % table support for pandoc > 1.12.2
+\usepackage[inline]{enumitem} % IRkernel/repr support (it uses the enumerate* environment)
+\usepackage[normalem]{ulem} % ulem is needed to support strikethroughs (\sout)
+ % normalem makes italics be italics, not underlines
+
+\usepackage{translations}
+\usepackage{microtype} % improves the spacing between words and letters
+\usepackage{placeins} % placement of figures
+% could use \usepackage[section]{placeins} but placing in subsection in command section
+% Places the float at precisely the location in the LaTeX code (with H)
+\usepackage{float}
+\usepackage[colorinlistoftodos,obeyFinal,textwidth=.8in]{todonotes} % to mark to-dos
+% number figures, tables and equations by section
+% fix for new versions of texlive (see https://tex.stackexchange.com/a/425603/107738)
+\let\counterwithout\relax
+\let\counterwithin\relax
+\usepackage{chngcntr}
+% header/footer
+\usepackage[footsepline=0.25pt]{scrlayer-scrpage}
+
+% bibliography formatting
+\usepackage[numbers, square, super, sort&compress]{natbib}
+% hyperlink doi's
+\usepackage{doi}
+
+ % define a code float
+ \usepackage{newfloat} % to define a new float types
+ \DeclareFloatingEnvironment[
+ fileext=frm,placement={!ht},
+ within=section,name=Code]{codecell}
+ \DeclareFloatingEnvironment[
+ fileext=frm,placement={!ht},
+ within=section,name=Text]{textcell}
+ \DeclareFloatingEnvironment[
+ fileext=frm,placement={!ht},
+ within=section,name=Text]{errorcell}
+
+ \usepackage{listings} % a package for wrapping code in a box
+ \usepackage[framemethod=tikz]{mdframed} % to fram code
+
+%%%%%%%%%%%%
+
+%%%%%%%%%%%% DEFINITIONS
+
+% Pygments definitions
+
+\makeatletter
+\def\PY@reset{\let\PY@it=\relax \let\PY@bf=\relax%
+ \let\PY@ul=\relax \let\PY@tc=\relax%
+ \let\PY@bc=\relax \let\PY@ff=\relax}
+\def\PY@tok#1{\csname PY@tok@#1\endcsname}
+\def\PY@toks#1+{\ifx\relax#1\empty\else%
+ \PY@tok{#1}\expandafter\PY@toks\fi}
+\def\PY@do#1{\PY@bc{\PY@tc{\PY@ul{%
+ \PY@it{\PY@bf{\PY@ff{#1}}}}}}}
+\def\PY#1#2{\PY@reset\PY@toks#1+\relax+\PY@do{#2}}
+
+\expandafter\def\csname PY@tok@w\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.73,0.73}{##1}}}
+\expandafter\def\csname PY@tok@c\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
+\expandafter\def\csname PY@tok@cp\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.74,0.48,0.00}{##1}}}
+\expandafter\def\csname PY@tok@k\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@kp\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@kt\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.69,0.00,0.25}{##1}}}
+\expandafter\def\csname PY@tok@o\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@ow\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.67,0.13,1.00}{##1}}}
+\expandafter\def\csname PY@tok@nb\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@nf\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}}
+\expandafter\def\csname PY@tok@nc\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}}
+\expandafter\def\csname PY@tok@nn\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}}
+\expandafter\def\csname PY@tok@ne\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.82,0.25,0.23}{##1}}}
+\expandafter\def\csname PY@tok@nv\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
+\expandafter\def\csname PY@tok@no\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.53,0.00,0.00}{##1}}}
+\expandafter\def\csname PY@tok@nl\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.63,0.63,0.00}{##1}}}
+\expandafter\def\csname PY@tok@ni\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.60,0.60,0.60}{##1}}}
+\expandafter\def\csname PY@tok@na\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.49,0.56,0.16}{##1}}}
+\expandafter\def\csname PY@tok@nt\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@nd\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.67,0.13,1.00}{##1}}}
+\expandafter\def\csname PY@tok@s\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@sd\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@si\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.73,0.40,0.53}{##1}}}
+\expandafter\def\csname PY@tok@se\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.73,0.40,0.13}{##1}}}
+\expandafter\def\csname PY@tok@sr\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.40,0.53}{##1}}}
+\expandafter\def\csname PY@tok@ss\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
+\expandafter\def\csname PY@tok@sx\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@m\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@gh\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.50}{##1}}}
+\expandafter\def\csname PY@tok@gu\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.50,0.00,0.50}{##1}}}
+\expandafter\def\csname PY@tok@gd\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.63,0.00,0.00}{##1}}}
+\expandafter\def\csname PY@tok@gi\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.63,0.00}{##1}}}
+\expandafter\def\csname PY@tok@gr\endcsname{\def\PY@tc##1{\textcolor[rgb]{1.00,0.00,0.00}{##1}}}
+\expandafter\def\csname PY@tok@ge\endcsname{\let\PY@it=\textit}
+\expandafter\def\csname PY@tok@gs\endcsname{\let\PY@bf=\textbf}
+\expandafter\def\csname PY@tok@gp\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,0.50}{##1}}}
+\expandafter\def\csname PY@tok@go\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.53,0.53,0.53}{##1}}}
+\expandafter\def\csname PY@tok@gt\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.27,0.87}{##1}}}
+\expandafter\def\csname PY@tok@err\endcsname{\def\PY@bc##1{\setlength{\fboxsep}{0pt}\fcolorbox[rgb]{1.00,0.00,0.00}{1,1,1}{\strut ##1}}}
+\expandafter\def\csname PY@tok@kc\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@kd\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@kn\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@kr\endcsname{\let\PY@bf=\textbf\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@bp\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.50,0.00}{##1}}}
+\expandafter\def\csname PY@tok@fm\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.00,0.00,1.00}{##1}}}
+\expandafter\def\csname PY@tok@vc\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
+\expandafter\def\csname PY@tok@vg\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
+\expandafter\def\csname PY@tok@vi\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
+\expandafter\def\csname PY@tok@vm\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.10,0.09,0.49}{##1}}}
+\expandafter\def\csname PY@tok@sa\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@sb\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@sc\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@dl\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@s2\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@sh\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@s1\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.73,0.13,0.13}{##1}}}
+\expandafter\def\csname PY@tok@mb\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@mf\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@mh\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@mi\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@il\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@mo\endcsname{\def\PY@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
+\expandafter\def\csname PY@tok@ch\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
+\expandafter\def\csname PY@tok@cm\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
+\expandafter\def\csname PY@tok@cpf\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
+\expandafter\def\csname PY@tok@c1\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
+\expandafter\def\csname PY@tok@cs\endcsname{\let\PY@it=\textit\def\PY@tc##1{\textcolor[rgb]{0.25,0.50,0.50}{##1}}}
+
+\def\PYZbs{\char`\\}
+\def\PYZus{\char`\_}
+\def\PYZob{\char`\{}
+\def\PYZcb{\char`\}}
+\def\PYZca{\char`\^}
+\def\PYZam{\char`\&}
+\def\PYZlt{\char`\<}
+\def\PYZgt{\char`\>}
+\def\PYZsh{\char`\#}
+\def\PYZpc{\char`\%}
+\def\PYZdl{\char`\$}
+\def\PYZhy{\char`\-}
+\def\PYZsq{\char`\'}
+\def\PYZdq{\char`\"}
+\def\PYZti{\char`\~}
+% for compatibility with earlier versions
+\def\PYZat{@}
+\def\PYZlb{[}
+\def\PYZrb{]}
+\makeatother
+
+% ANSI colors
+\definecolor{ansi-black}{HTML}{3E424D}
+\definecolor{ansi-black-intense}{HTML}{282C36}
+\definecolor{ansi-red}{HTML}{E75C58}
+\definecolor{ansi-red-intense}{HTML}{B22B31}
+\definecolor{ansi-green}{HTML}{00A250}
+\definecolor{ansi-green-intense}{HTML}{007427}
+\definecolor{ansi-yellow}{HTML}{DDB62B}
+\definecolor{ansi-yellow-intense}{HTML}{B27D12}
+\definecolor{ansi-blue}{HTML}{208FFB}
+\definecolor{ansi-blue-intense}{HTML}{0065CA}
+\definecolor{ansi-magenta}{HTML}{D160C4}
+\definecolor{ansi-magenta-intense}{HTML}{A03196}
+\definecolor{ansi-cyan}{HTML}{60C6C8}
+\definecolor{ansi-cyan-intense}{HTML}{258F8F}
+\definecolor{ansi-white}{HTML}{C5C1B4}
+\definecolor{ansi-white-intense}{HTML}{A1A6B2}
+
+% commands and environments needed by pandoc snippets
+% extracted from the output of `pandoc -s`
+\providecommand{\tightlist}{%
+ \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
+\DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}}
+% Add ',fontsize=\small' for more characters per line
+\newenvironment{Shaded}{}{}
+\newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{{#1}}}}
+\newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.56,0.13,0.00}{{#1}}}
+\newcommand{\DecValTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}}
+\newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}}
+\newcommand{\FloatTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}}
+\newcommand{\CharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
+\newcommand{\StringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
+\newcommand{\CommentTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textit{{#1}}}}
+\newcommand{\OtherTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{{#1}}}
+\newcommand{\AlertTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}}
+\newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.02,0.16,0.49}{{#1}}}
+\newcommand{\RegionMarkerTok}[1]{{#1}}
+\newcommand{\ErrorTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}}
+\newcommand{\NormalTok}[1]{{#1}}
+
+% Additional commands for more recent versions of Pandoc
+\newcommand{\ConstantTok}[1]{\textcolor[rgb]{0.53,0.00,0.00}{{#1}}}
+\newcommand{\SpecialCharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
+\newcommand{\VerbatimStringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
+\newcommand{\SpecialStringTok}[1]{\textcolor[rgb]{0.73,0.40,0.53}{{#1}}}
+\newcommand{\ImportTok}[1]{{#1}}
+\newcommand{\DocumentationTok}[1]{\textcolor[rgb]{0.73,0.13,0.13}{\textit{{#1}}}}
+\newcommand{\AnnotationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}}
+\newcommand{\CommentVarTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}}
+\newcommand{\VariableTok}[1]{\textcolor[rgb]{0.10,0.09,0.49}{{#1}}}
+\newcommand{\ControlFlowTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{{#1}}}}
+\newcommand{\OperatorTok}[1]{\textcolor[rgb]{0.40,0.40,0.40}{{#1}}}
+\newcommand{\BuiltInTok}[1]{{#1}}
+\newcommand{\ExtensionTok}[1]{{#1}}
+\newcommand{\PreprocessorTok}[1]{\textcolor[rgb]{0.74,0.48,0.00}{{#1}}}
+\newcommand{\AttributeTok}[1]{\textcolor[rgb]{0.49,0.56,0.16}{{#1}}}
+\newcommand{\InformationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}}
+\newcommand{\WarningTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}}
+
+% Define a nice break command that doesn't care if a line doesn't already
+% exist.
+\def\br{\hspace*{\fill} \\* }
+
+% Math Jax compatability definitions
+\def\gt{>}
+\def\lt{<}
+
+\setcounter{secnumdepth}{5}
+
+% Colors for the hyperref package
+\definecolor{urlcolor}{rgb}{0,.145,.698}
+\definecolor{linkcolor}{rgb}{.71,0.21,0.01}
+\definecolor{citecolor}{rgb}{.12,.54,.11}
+
+\DeclareTranslationFallback{Author}{Author}
+\DeclareTranslation{Portuges}{Author}{Autor}
+
+\DeclareTranslationFallback{List of Codes}{List of Codes}
+\DeclareTranslation{Catalan}{List of Codes}{Llista de Codis}
+\DeclareTranslation{Danish}{List of Codes}{Liste over Koder}
+\DeclareTranslation{German}{List of Codes}{Liste der Codes}
+\DeclareTranslation{Spanish}{List of Codes}{Lista de C\'{o}digos}
+\DeclareTranslation{French}{List of Codes}{Liste des Codes}
+\DeclareTranslation{Italian}{List of Codes}{Elenco dei Codici}
+\DeclareTranslation{Dutch}{List of Codes}{Lijst van Codes}
+\DeclareTranslation{Portuges}{List of Codes}{Lista de C\'{o}digos}
+
+\DeclareTranslationFallback{Supervisors}{Supervisors}
+\DeclareTranslation{Catalan}{Supervisors}{Supervisors}
+\DeclareTranslation{Danish}{Supervisors}{Vejledere}
+\DeclareTranslation{German}{Supervisors}{Vorgesetzten}
+\DeclareTranslation{Spanish}{Supervisors}{Supervisores}
+\DeclareTranslation{French}{Supervisors}{Superviseurs}
+\DeclareTranslation{Italian}{Supervisors}{Le autorit\`{a} di vigilanza}
+\DeclareTranslation{Dutch}{Supervisors}{supervisors}
+\DeclareTranslation{Portuguese}{Supervisors}{Supervisores}
+
+\definecolor{codegreen}{rgb}{0,0.6,0}
+\definecolor{codegray}{rgb}{0.5,0.5,0.5}
+\definecolor{codepurple}{rgb}{0.58,0,0.82}
+\definecolor{backcolour}{rgb}{0.95,0.95,0.95}
+
+\lstdefinestyle{mystyle}{
+ commentstyle=\color{codegreen},
+ keywordstyle=\color{magenta},
+ numberstyle=\tiny\color{codegray},
+ stringstyle=\color{codepurple},
+ basicstyle=\ttfamily,
+ breakatwhitespace=false,
+ keepspaces=true,
+ numbers=left,
+ numbersep=10pt,
+ showspaces=false,
+ showstringspaces=false,
+ showtabs=false,
+ tabsize=2,
+ breaklines=true,
+ literate={\-}{}{0\discretionary{-}{}{-}},
+ postbreak=\mbox{\textcolor{red}{$\hookrightarrow$}\space},
+}
+
+\lstset{style=mystyle}
+
+\surroundwithmdframed[
+ hidealllines=true,
+ backgroundcolor=backcolour,
+ innerleftmargin=0pt,
+ innerrightmargin=0pt,
+ innertopmargin=0pt,
+ innerbottommargin=0pt]{lstlisting}
+
+%%%%%%%%%%%%
+
+%%%%%%%%%%%% MARGINS
+
+ % Used to adjust the document margins
+\usepackage{geometry}
+\geometry{tmargin=1in,bmargin=1in,lmargin=1in,rmargin=1in,
+nohead,includefoot,footskip=25pt}
+% you can use showframe option to check the margins visually
+%%%%%%%%%%%%
+
+%%%%%%%%%%%% COMMANDS
+
+% ensure new section starts on new page
+\addtokomafont{section}{\clearpage}
+
+% Prevent overflowing lines due to hard-to-break entities
+\sloppy
+
+% Setup hyperref package
+\hypersetup{
+ breaklinks=true, % so long urls are correctly broken across lines
+ colorlinks=true,
+ urlcolor=urlcolor,
+ linkcolor=linkcolor,
+ citecolor=citecolor,
+ }
+
+% ensure figures are placed within subsections
+\makeatletter
+\AtBeginDocument{%
+ \expandafter\renewcommand\expandafter\subsection\expandafter
+ {\expandafter\@fb@secFB\subsection}%
+ \newcommand\@fb@secFB{\FloatBarrier
+ \gdef\@fb@afterHHook{\@fb@topbarrier \gdef\@fb@afterHHook{}}}%
+ \g@addto@macro\@afterheading{\@fb@afterHHook}%
+ \gdef\@fb@afterHHook{}%
+}
+\makeatother
+
+% number figures, tables and equations by section
+\counterwithout{figure}{section}
+\counterwithout{table}{section}
+\counterwithout{equation}{section}
+\makeatletter
+\@addtoreset{table}{section}
+\@addtoreset{figure}{section}
+\@addtoreset{equation}{section}
+\makeatother
+\renewcommand\thetable{\thesection.\arabic{table}}
+\renewcommand\thefigure{\thesection.\arabic{figure}}
+\renewcommand\theequation{\thesection.\arabic{equation}}
+
+ % set global options for float placement
+ \makeatletter
+ \providecommand*\setfloatlocations[2]{\@namedef{fps@#1}{#2}}
+ \makeatother
+
+% align captions to left (indented)
+\captionsetup{justification=raggedright,
+singlelinecheck=false,format=hang,labelfont={it,bf}}
+
+% shift footer down so space between separation line
+\ModifyLayer[addvoffset=.6ex]{scrheadings.foot.odd}
+\ModifyLayer[addvoffset=.6ex]{scrheadings.foot.even}
+\ModifyLayer[addvoffset=.6ex]{scrheadings.foot.oneside}
+\ModifyLayer[addvoffset=.6ex]{plain.scrheadings.foot.odd}
+\ModifyLayer[addvoffset=.6ex]{plain.scrheadings.foot.even}
+\ModifyLayer[addvoffset=.6ex]{plain.scrheadings.foot.oneside}
+\pagestyle{scrheadings}
+\clearscrheadfoot{}
+\ifoot{\leftmark}
+\renewcommand{\sectionmark}[1]{\markleft{\thesection\ #1}}
+\ofoot{\pagemark}
+\cfoot{}
+
+%%%%%%%%%%%%
+
+%%%%%%%%%%%% FINAL HEADER MATERIAL
+
+% clereref must be loaded after anything that changes the referencing system
+\usepackage{cleveref}
+\creflabelformat{equation}{#2#1#3}
+
+% make the code float work with cleverref
+\crefname{codecell}{code}{codes}
+\Crefname{codecell}{code}{codes}
+% make the text float work with cleverref
+\crefname{textcell}{text}{texts}
+\Crefname{textcell}{text}{texts}
+% make the text float work with cleverref
+\crefname{errorcell}{error}{errors}
+\Crefname{errorcell}{error}{errors}
+%%%%%%%%%%%%
+
+\begin{document}
+
+ \title{Notebook}
+ \date{\today}
+ \maketitle
+
+ \begingroup
+ \let\cleardoublepage\relax
+ \let\clearpage\relax
+ \endgroup
+
+\hypertarget{notebook-to-test-markdown-cells}{%
+\section{Notebook to Test Markdown
+Cells}\label{notebook-to-test-markdown-cells}}
+
+\hypertarget{cell-with-attached-image}{%
+\subsection{Cell with Attached Image}\label{cell-with-attached-image}}
+
+\begin{figure}[H]
+\hypertarget{fig:id1}{%
+\begin{center}
+\adjustimage{max size={0.9\linewidth}{0.9\paperheight},}{nb_markdown_cells_files/attach_1_output_13_0.jpeg}
+\end{center}
+\caption{output\_13\_0.jpeg}\label{fig:id1}
+}
+\end{figure}
+
+\cref{fig:id1} \cref{fig:id1}
+
+\hypertarget{cell-with-linked-image}{%
+\subsection{Cell with Linked Image}\label{cell-with-linked-image}}
+
+\begin{figure}[]
+\hypertarget{fig:id2}{%
+\begin{center}
+\adjustimage{max size={0.9\linewidth}{0.9\paperheight},width=0.5\linewidth}{nb_markdown_cells_files/logo_example.png}
+\end{center}
+\caption{this is a \textbf{caption}}\label{fig:id2}
+}
+\end{figure}
+
+\hypertarget{cell-with-link-to-header}{%
+\subsection{Cell with Link to Header}\label{cell-with-link-to-header}}
+
+\cref{cell-with-link-to-header}
+
+\hypertarget{cell-with-math}{%
+\subsection{Cell with Math}\label{cell-with-math}}
+
+inline: \(a = b\)
+
+\begin{equation}a = b\label{eq:id1}\end{equation}
+\begin{align*}c &= d \\ other &= e\label{eq:id2}\end{align*}
+
+\hypertarget{cell-with-table}{%
+\subsection{Cell with Table}\label{cell-with-table}}
+
+\begin{longtable}[]{@{}lll@{}}
+\caption{Caption. \label{tbl:id}}\tabularnewline
+\toprule
+A & B & A and B\tabularnewline
+\midrule
+\endfirsthead
+\toprule
+A & B & A and B\tabularnewline
+\midrule
+\endhead
+False & False & False\tabularnewline
+True & False & False\tabularnewline
+False & True & False\tabularnewline
+True & True & True\tabularnewline
+\bottomrule
+\end{longtable}
+
+\cref{tbl:id}
+
+\hypertarget{references-using-notation}{%
+\subsection{References Using @
+Notation}\label{references-using-notation}}
+
+\Cref{cell-with-link-to-header}, and multiple references
+\cref{tbl:id,eq:id1}
+
+\end{document}
+
diff --git a/ipypublish/tests/test_files/nb_markdown_cells/logo_example.png b/ipypublish/tests/test_files/nb_markdown_cells/logo_example.png
new file mode 100644
index 0000000..a52d9d4
Binary files /dev/null and b/ipypublish/tests/test_files/nb_markdown_cells/logo_example.png differ
diff --git a/ipypublish/tests/test_files/nb_markdown_cells/nb_markdown_cells.ipynb b/ipypublish/tests/test_files/nb_markdown_cells/nb_markdown_cells.ipynb
new file mode 100644
index 0000000..39b7828
--- /dev/null
+++ b/ipypublish/tests/test_files/nb_markdown_cells/nb_markdown_cells.ipynb
@@ -0,0 +1,135 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Notebook to Test Markdown Cells"
+ ]
+ },
+ {
+ "attachments": {
+ "output_13_0.jpeg": {
+ "image/jpeg": "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////////A+gAAAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAADhCSU0EAAAAAAAAAgApOEJJTQQCAAAAAACGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4QklNBDAAAAAAAEMBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBADhCSU0ELQAAAAAABgABAAAANjhCSU0ECAAAAAAATAAAAAEAAAJAAAACQAAAAAwAAAAAAQAAQgAB//+cAAAAACJAAQAAH8AB///KQAD//84AAP///EAAAAAAAAAAAC5AAP//x4AB///9gAE4QklNBB4AAAAAAAQAAAAAOEJJTQQaAAAAAANjAAAABgAAAAAAAAAAAAAA/gAAAXIAAAAXADEAMgAuADEANQAtAGgAbwBtAGUAcABhAGcAZQAtAGMAdQByAGEAdABpAG8AbgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABcgAAAP4AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAQAAAAAAAG51bGwAAAACAAAABmJvdW5kc09iamMAAAABAAAAAAAAUmN0MQAAAAQAAAAAVG9wIGxvbmcAAAAAAAAAAExlZnRsb25nAAAAAAAAAABCdG9tbG9uZwAAAP4AAAAAUmdodGxvbmcAAAFyAAAABnNsaWNlc1ZsTHMAAAABT2JqYwAAAAEAAAAAAAVzbGljZQAAABIAAAAHc2xpY2VJRGxvbmcAAAAAAAAAB2dyb3VwSURsb25nAAAAAAAAAAZvcmlnaW5lbnVtAAAADEVTbGljZU9yaWdpbgAAAA1hdXRvR2VuZXJhdGVkAAAAAFR5cGVlbnVtAAAACkVTbGljZVR5cGUAAAAASW1nIAAAAAZib3VuZHNP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cAAgAEMAQwAgADIAMAAxADUAAAABADhCSU0EBgAAAAAABwAGAAAAAQEA/+Ea52h0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8APD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMwNjcgNzkuMTU3NzQ3LCAyMDE1LzAzLzMwLTIzOjQwOjQyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdGVEYXRlPSIyMDE1LTEwLTA4VDEyOjM4OjExLTA0OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxNS0xMi0xN1QxMDo1OTo0NS0wNTowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxNS0xMi0xN1QxMDo1OTo0NS0wNTowMCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxNSAoTWFjaW50b3NoKSIgZGM6Zm9ybWF0PSJpbWFnZS9qcGVnIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0iVkEyNzAzIFNlcmllcyBDYWxpYnJhdGVkIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOmUyYmQwYjU5LTU2YjEtNDNiZi1iN2UyLTMyNzQzYjFhOTNjMCIgeG1wTU06RG9jdW1lbnRJRD0iYWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOjk2MWFlZWE0LWU1NjUtMTE3OC04NGExLWVmNTVlNWVmOTVhZiIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjY1MjRlZTYyLTQwNDAtNDQ4Ni05NzMwLWNjNDgyZDBiNmRjNCI+IDxwaG90b3Nob3A6VGV4dExheWVycz4gPHJkZjpCYWc+IDxyZGY6bGkgcGhvdG9zaG9wOkxheWVyTmFtZT0iUG9wdWxhciBJbGx1c3RyYXRpb24gQ2F0ZWdvcmllcyIgcGhvdG9zaG9wOkxheWVyVGV4dD0iUG9wdWxhciBJbGx1c3RyYXRpb24gQ2F0ZWdvcmllcyIvPiA8cmRmOmxpIHBob3Rvc2hvcDpMYXllck5hbWU9IlBvcHVsYXIgVmVjdG9yIENhdGVnb3JpZXMiIHBob3Rvc2hvcDpMYXllclRleHQ9IlBvcHVsYXIgVmVjdG9yIENhdGVnb3JpZXMiLz4gPHJkZjpsaSBwaG90b3Nob3A6TGF5ZXJOYW1lPSJQb3B1bGFyIFBob3RvIENhdGVnb3JpZXMiIHBob3Rvc2hvcDpMYXllclRleHQ9IlBvcHVsYXIgUGhvdG8gQ2F0ZWdvcmllcyIvPiA8cmRmOmxpIHBob3Rvc2hvcDpMYXllck5hbWU9IkJpZ3N0b2NrIFBpY2tzIiBwaG90b3Nob3A6TGF5ZXJUZXh0PSJCaWdzdG9jayBQaWNrcyIvPiA8cmRmOmxpIHBob3Rvc2hvcDpMYXllck5hbWU9IldpbnRlciBDb2xsZWN0aW9uIiBwaG90b3Nob3A6TGF5ZXJUZXh0PSJXaW50ZXIgQ29sbGVjdGlvbiIvPiA8cmRmOmxpIHBob3Rvc2hvcDpMYXllck5hbWU9IkJpZ3N0b2NrIFZpZGVvIiBwaG90b3Nob3A6TGF5ZXJUZXh0PSJCaWdzdG9jayBWaWRlbyIvPiA8cmRmOmxpIHBob3Rvc2hvcDpMYXllck5hbWU9IkltYWdlcyBhbmQgVmlkZW8gZm9yIGV2ZXJ5b25lLiIgcGhvdG9zaG9wOkxheWVyVGV4dD0iSW1hZ2VzIGFuZCBWaWRlbyBmb3IgZXZlcnlvbmUuIi8+IDxyZGY6bGkgcGhvdG9zaG9wOkxheWVyTmFtZT0iT3ZlciAzMCBtaWxsaW9uIHN0b2NrIHBob3RvcywgdmlkZW9zLCBhbmQgdmVjdG9ycy4iIHBob3Rvc2hvcDpMYXllclRleHQ9Ik92ZXIgMzAgbWlsbGlvbiBzdG9jayBwaG90b3MsIHZpZGVvcywgYW5kIHZlY3RvcnMuIi8+IDwvcmRmOkJhZz4gPC9waG90b3Nob3A6VGV4dExheWVycz4gPHBob3Rvc2hvcDpEb2N1bWVudEFuY2VzdG9ycz4gPHJkZjpCYWc+IDxyZGY6bGk+MjMzOEI4RTQxMjc0MDA4QTkwQzhCRDI1NDc5NjBCQjM8L3JkZjpsaT4gPHJkZjpsaT4yREU0NDA2QzEwQjczNDIyQjRFRTZEOEIwRDMyNUZBODwvcmRmOmxpPiA8cmRmOmxpPjMxOTc2NTBFRTkzRjc5OEQ2QTJCQUYyMUFENjIyNzJCPC9yZGY6bGk+IDxyZGY6bGk+M0YyOTgxMzJFRjVERjdCRDFFN0U3OUM1MjVDMENBODY8L3JkZjpsaT4gPHJkZjpsaT41QUFBMDQ2RjFCRUQ1NTA3QjRGRTU4MkVEMTI1OTFBNDwvcmRmOmxpPiA8cmRmOmxpPjY1NjUzQUYxMEE1MUQ5MEZBMDdFQ0U2MzMyNjA4NEFBPC9yZGY6bGk+IDxyZGY6bGk+NzZFNDE3RTVFNDAxN0Q3ODU4MkI3OTFCOTYzQzlGM0I8L3JkZjpsaT4gPHJkZjpsaT44RjQwMDNDMUU1MzE4REU2MzVDODM0OTBENTE0ODMwQTwvcmRmOmxpPiA8cmRmOmxpPkExNDc0Q0I1QTEwRTM2RDQ2ODcwRjA0NDZFMDdEM0UwPC9yZGY6bGk+IDxyZGY6bGk+QTRENUQzQzczOTc4NTBERkZDQThDNjM2QTZEMkFBOUU8L3JkZjpsaT4gPHJkZjpsaT5BODE4NjdBREIyRDIwMzc2Q0FGMjNDNkM0NDU1QTYxRjwvcmRmOmxpPiA8cmRmOmxpPkMzMDkzMjZBRjJEMkUzQTE1QThBMjI0RUUwMjQ2NDQyPC9yZGY6bGk+IDxyZGY6bGk+QzRBQUJERDU3MUY5NkU5MjQ1QUYzMjU1REFDQkU5MDI8L3JkZjpsaT4gPHJkZjpsaT5DNTk3RkREMkRGMjlDRUUzQTA4OTA2REVGODIzNUZBMzwvcmRmOmxpPiA8cmRmOmxpPkQwRTQxMTkzRDBEODdBQkY2OUQzQTI3NDM1RkQ5Q0U2PC9yZGY6bGk+IDxyZGY6bGk+RDQ5M0IzODIwMDhERDAyMDA1ODk0Rjg0QUI4QUNEQTU8L3JkZjpsaT4gPHJkZjpsaT5EQjFBQzlEMjZCMUY0MEM5QTVBMTFCN0E2QURDM0ExMjwvcmRmOmxpPiA8cmRmOmxpPkU2NEU5NTJBQ0UyOTAwMkVCNjhGMUJDRDAxQjg5MTFCPC9yZGY6bGk+IDxyZGY6bGk+RTY4ODU2ODVDQkRGMjMyNEU3MTE1OEJGMjE3NkUxRkU8L3JkZjpsaT4gPHJkZjpsaT5GNUU3NTc3QTZCM0EzNDFBNTFDQUFBQzVFM0E1OUIxMTwvcmRmOmxpPiA8cmRmOmxpPkZEMUQ3RTMxQzc1MTJCRTBBODkxQ0RBQTVDNzdERTk1PC9yZGY6bGk+IDxyZGY6bGk+eG1wLmRpZDo2NDk0NmNiOC00MTFhLTRiMDAtOTk2MS1jODJkZmZjNTQ2NGM8L3JkZjpsaT4gPC9yZGY6QmFnPiA8L3Bob3Rvc2hvcDpEb2N1bWVudEFuY2VzdG9ycz4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NjUyNGVlNjItNDA0MC00NDg2LTk3MzAtY2M0ODJkMGI2ZGM0IiBzdEV2dDp3aGVuPSIyMDE1LTEwLTMwVDE0OjI2OjM1LTA0OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxNSAoTWFjaW50b3NoKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY29udmVydGVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJmcm9tIGltYWdlL3BuZyB0byBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJkZXJpdmVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJjb252ZXJ0ZWQgZnJvbSBpbWFnZS9wbmcgdG8gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NjQ5NDZjYjgtNDExYS00YjAwLTk5NjEtYzgyZGZmYzU0NjRjIiBzdEV2dDp3aGVuPSIyMDE1LTEwLTMwVDE0OjI2OjM1LTA0OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxNSAoTWFjaW50b3NoKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NjM0NGY3MWMtNDhiZC00MGU4LWFhM2YtZjcyYTEwNmJjZTlhIiBzdEV2dDp3aGVuPSIyMDE1LTEyLTE3VDEwOjU5OjQ1LTA1OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxNSAoTWFjaW50b3NoKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY29udmVydGVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJmcm9tIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5waG90b3Nob3AgdG8gaW1hZ2UvanBlZyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iZGVyaXZlZCIgc3RFdnQ6cGFyYW1ldGVycz0iY29udmVydGVkIGZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9qcGVnIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDplMmJkMGI1OS01NmIxLTQzYmYtYjdlMi0zMjc0M2IxYTkzYzAiIHN0RXZ0OndoZW49IjIwMTUtMTItMTdUMTA6NTk6NDUtMDU6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE1IChNYWNpbnRvc2gpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2MzQ0ZjcxYy00OGJkLTQwZTgtYWEzZi1mNzJhMTA2YmNlOWEiIHN0UmVmOmRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDpjYTc1NGM2MC1iZmMwLTExNzgtYjgwYy1lNWFjMmFiZWU0MjgiIHN0UmVmOm9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo2NTI0ZWU2Mi00MDQwLTQ0ODYtOTczMC1jYzQ4MmQwYjZkYzQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPD94cGFja2V0IGVuZD0idyI/Pv/iKWhJQ0NfUFJPRklMRQABAQAAKVhhcHBsAhAAAG1udHJSR0IgWFlaIAffAAkACgAPABcAGGFjc3BBUFBMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD21gABAAAAANMtYXBwbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEWRlc2MAAAFQAAAAc2RzY20AAAHEAAAATGNwcnQAAAIQAAAAI3d0cHQAAAI0AAAAFHJYWVoAAAJIAAAAFGdYWVoAAAJcAAAAFGJYWVoAAAJwAAAAFHJUUkMAAAKEAAAIDGFhcmcAAAqQAAAAIHZjZ3QAAAqwAAAG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"
+ }
+ },
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Cell with Attached Image\n",
+ "\n",
+ "![output_13_0.jpeg](attachment:output_13_0.jpeg){#fig:id1 placement='H'}\n",
+ "\n",
+ "\\cref{fig:id1}\n",
+ "[mkdown_ref](#fig:id1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Cell with Linked Image\n",
+ "\n",
+ "![this is a **caption**](logo_example.png){#fig:id2 width=50%}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Cell with Link to Header"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "[link_to_header](#cell-with-link-to-header)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Cell with Math\n",
+ "\n",
+ "inline: $a = b$\n",
+ "\n",
+ "$$a = b$$ {#eq:id1}\n",
+ "$$c &= d \\\\ other &= e$$ {#eq:id2 env=align .unnumbered}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Cell with Table\n",
+ "\n",
+ "A | B | A and B\n",
+ "------|-------|--------\n",
+ "False | False | False\n",
+ "True | False | False\n",
+ "False | True | False\n",
+ "True | True | True\n",
+ "\n",
+ "Table: Caption. {#tbl:id}\n",
+ "\n",
+ "\\cref{tbl:id}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "ipub": {
+ "at_notation": true
+ }
+ },
+ "source": [
+ "## References Using @ Notation\n",
+ "\n",
+ "?@cell-with-link-to-header, and multiple references +[@tbl:id; @eq:id1]"
+ ]
+ }
+ ],
+ "metadata": {
+ "celltoolbar": "Edit Metadata",
+ "hide_input": false,
+ "ipub": {
+ "pandoc": {
+ "use_numref": true
+ }
+ },
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.8"
+ },
+ "toc": {
+ "base_numbering": 1,
+ "nav_menu": {},
+ "number_sections": true,
+ "sideBar": true,
+ "skip_h1_title": false,
+ "title_cell": "Table of Contents",
+ "title_sidebar": "Contents",
+ "toc_cell": false,
+ "toc_position": {},
+ "toc_section_display": true,
+ "toc_window_display": false
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/ipypublish/tests/test_files/nb_markdown_cells/nbsphinx_markdown.ipynb b/ipypublish/tests/test_files/nb_markdown_cells/nbsphinx_markdown.ipynb
new file mode 100644
index 0000000..991ed9d
--- /dev/null
+++ b/ipypublish/tests/test_files/nb_markdown_cells/nbsphinx_markdown.ipynb
@@ -0,0 +1,513 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "nbsphinx": "hidden"
+ },
+ "source": [
+ "This notebook is part of the `nbsphinx` documentation: https://nbsphinx.readthedocs.io/."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Markdown Cells\n",
+ "\n",
+ "We can use *emphasis*, **boldface**, `preformatted text`.\n",
+ "\n",
+ "> It looks like strike-out text is not supported: ~~strikethrough~~.\n",
+ "\n",
+ "* Red\n",
+ "* Green\n",
+ "* Blue\n",
+ "\n",
+ "***\n",
+ "\n",
+ "1. One\n",
+ "1. Two\n",
+ "1. Three\n",
+ "\n",
+ "Arbitrary Unicode characters should be supported, e.g. łßō.\n",
+ "Note, however, that this only works if your HTML browser and your LaTeX processor provide the appropriate fonts."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Equations\n",
+ "\n",
+ "Inline equations like $\\text{e}^{i\\pi} = -1$\n",
+ "can be created by putting a LaTeX expression between two dollar signs, like this:\n",
+ "`$\\text{e}^{i\\pi} = -1$`."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "**Note:**\n",
+ "\n",
+ "Avoid leading and trailing spaces around math expressions, otherwise errors like the following will occur when Sphinx is running:\n",
+ "\n",
+ " ERROR: Unknown interpreted text role \"raw-latex\".\n",
+ "\n",
+ "See also the [pandoc docs](http://pandoc.org/MANUAL.html#math):\n",
+ "\n",
+ "> Anything between two `$` characters will be treated as TeX math. The opening `$` must have a non-space character immediately to its right, while the closing `$` must have a non-space character immediately to its left, and must not be followed immediately by a digit.\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Equations can also be displayed on their own line like this:\n",
+ "\\begin{equation}\n",
+ "\\int\\limits_{-\\infty}^\\infty f(x) \\delta(x - x_0) dx = f(x_0).\n",
+ "\\end{equation}\n",
+ "\n",
+ "This can be done by simply using one of the LaTeX math environments, like so:\n",
+ "\n",
+ "```\n",
+ "\\begin{equation}\n",
+ "\\int\\limits_{-\\infty}^\\infty f(x) \\delta(x - x_0) dx = f(x_0)\n",
+ "\\end{equation}\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Automatic Equation Numbering\n",
+ "\n",
+ "This is not automatically enabled in Jupyter notebooks,\n",
+ "but you can install a notebook extension in order to enable equation numbering:\n",
+ "https://jupyter-contrib-nbextensions.readthedocs.io/en/latest/nbextensions/equation-numbering/readme.html.\n",
+ "\n",
+ "Automatic Equation Numbering is enabled on http://nbviewer.jupyter.org/,\n",
+ "see e.g. the latest version of this very notebook at the link http://nbviewer.jupyter.org/github/spatialaudio/nbsphinx/blob/master/doc/markdown-cells.ipynb.\n",
+ "\n",
+ "When using `nbsphinx`, you can use the following `mathjax_config` setting in your `conf.py` file\n",
+ "to enable automatic equation numbering in HTML output.\n",
+ "In LaTeX output, the equations are numbered by default.\n",
+ "\n",
+ "```python\n",
+ "mathjax_config = {\n",
+ " 'TeX': {'equationNumbers': {'autoNumber': 'AMS', 'useLabelIds': True}},\n",
+ "}\n",
+ "```\n",
+ "\n",
+ "You can use `\\label{...}` to give a unique label to an equation:\n",
+ "\n",
+ "\\begin{equation}\n",
+ "\\phi = \\frac{1 + \\sqrt{5}}{2}\n",
+ "\\label{golden-mean}\n",
+ "\\end{equation}\n",
+ "\n",
+ "```\n",
+ "\\begin{equation}\n",
+ "\\phi = \\frac{1 + \\sqrt{5}}{2}\n",
+ "\\label{golden-mean}\n",
+ "\\end{equation}\n",
+ "```\n",
+ "\n",
+ "If automatic equation numbering is enabled,\n",
+ "you can later reference that equation using its label.\n",
+ "You can use `\\eqref{golden-mean}` for a reference with parentheses: \\eqref{golden-mean},\n",
+ "or `\\ref{golden-mean}` for a reference without them: \\ref{golden-mean}.\n",
+ "\n",
+ "In HTML output, these equation references only work for equations within a single HTML page.\n",
+ "In LaTeX output, equations from other notebooks can be referenced, e.g. \\eqref{fibonacci-recurrence}."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Manual Equation Numbering\n",
+ "\n",
+ "If you prefer to assign equation numbers (or some kind of names) manually,\n",
+ "you can do so with `\\tag{...}`:\n",
+ "\n",
+ "\\begin{equation}\n",
+ "a^2 + b^2 = c^2\n",
+ "\\tag{99.4}\n",
+ "\\label{pythagoras}\n",
+ "\\end{equation}\n",
+ "\n",
+ "```\n",
+ "\\begin{equation}\n",
+ "a^2 + b^2 = c^2\n",
+ "\\tag{99.4}\n",
+ "\\label{pythagoras}\n",
+ "\\end{equation}\n",
+ "```\n",
+ "\n",
+ "The above equation has the number \\ref{pythagoras}."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Citations\n",
+ "\n",
+ "According to https://nbconvert.readthedocs.io/en/latest/latex_citations.html,\n",
+ "`nbconvert` supports citations using a special HTML-based syntax.\n",
+ "`nbsphinx` supports the same syntax.\n",
+ "\n",
+ "Example: Kluyver et al. (2016).\n",
+ "\n",
+ "```html\n",
+ "Kluyver et al. (2016)\n",
+ "```\n",
+ "\n",
+ "You don't actually have to use ``,\n",
+ "any inline HTML tag can be used, e.g. ``:\n",
+ "Python: An Ecosystem for Scientific Computing.\n",
+ "\n",
+ "```html\n",
+ "Python: An Ecosystem for Scientific Computing\n",
+ "```\n",
+ "\n",
+ "You'll also have to define a list of references,\n",
+ "see [the section about references](a-normal-rst-file.rst#references).\n",
+ "\n",
+ "There is also a Notebook extension which may or may not be useful: https://github.com/takluyver/cite2c."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Code\n",
+ "\n",
+ "We can also write code with nice syntax highlighting:\n",
+ "\n",
+ "```python3\n",
+ "print(\"Hello, world!\")\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Tables\n",
+ "\n",
+ "A | B | A and B\n",
+ "------|-------|--------\n",
+ "False | False | False\n",
+ "True | False | False\n",
+ "False | True | False\n",
+ "True | True | True"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Images\n",
+ "\n",
+ "Local image: ![Jupyter notebook icon](images/notebook_icon.png)\n",
+ "\n",
+ "Remote image: ![Python logo (remote)](https://www.python.org/static/img/python-logo-large.png)\n",
+ "\n",
+ "### SVG support for LaTeX\n",
+ "\n",
+ "LaTeX doesn't support SVG images, but there are Sphinx extensions that can be used for automatically converting SVG images for inclusion in LaTeX output.\n",
+ "\n",
+ "Just include one of the following options in the list of `extensions`\n",
+ "in your `conf.py` file.\n",
+ "\n",
+ "* `'sphinxcontrib.inkscapeconverter'` or `'sphinxcontrib.rsvgconverter'`:\n",
+ " See https://github.com/missinglinkelectronics/sphinxcontrib-svg2pdfconverter\n",
+ " for installation instructions.\n",
+ " \n",
+ " The external programs `inkscape` or `rsvg-convert` (Debian/Ubuntu package `librsvg2-bin`)\n",
+ " are needed, respectively.\n",
+ "\n",
+ "* `'sphinx.ext.imgconverter'`:\n",
+ " This is a built-in Sphinx extension, see\n",
+ " http://www.sphinx-doc.org/en/master/usage/extensions/imgconverter.html.\n",
+ " \n",
+ " This needs the external program `convert` from *ImageMagick*.\n",
+ "\n",
+ " The disadvantage of this extension is that SVGs are converted to bitmap images."
+ ]
+ },
+ {
+ "attachments": {
+ "stickfigure.png": {
+ "image/png": "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"
+ }
+ },
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Cell Attachments\n",
+ "\n",
+ "Images can also be embedded in the notebook itself. Just drag an image file into the Markdown cell you are just editing or copy and paste some image data from an image editor/viewer.\n",
+ "\n",
+ "The generated Markdown code will look just like a \"normal\" image link, except that it will have an `attachment:` prefix:\n",
+ "\n",
+ " ![a stick figure](attachment:stickfigure.png)\n",
+ "\n",
+ "This is a cell attachment: ![a stick figure](attachment:stickfigure.png)\n",
+ "\n",
+ "In the Jupyter Notebook, there is a speciall \"Attachments\" cell toolbar which you can use to see all attachments of a cell and delete them, if needed."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## HTML Elements (HTML only)\n",
+ "\n",
+ "It is allowed to use plain HTML elements within Markdown cells.\n",
+ "Those elements are passed through to the HTML output and are ignored for the LaTeX output.\n",
+ "Below are a few examples.\n",
+ "\n",
+ "HTML5 [audio](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio) elements can be created like this:\n",
+ "\n",
+ "```html\n",
+ "\n",
+ "```\n",
+ "\n",
+ "Example:\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "HTML5 [video](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video) elements can be created like this:\n",
+ "\n",
+ "```html\n",
+ "\n",
+ "```\n",
+ "\n",
+ "Example:\n",
+ "\n",
+ "\n",
+ "\n",
+ "The alternative text is shown in browsers that don't support those elements. The same text is also shown in Sphinx's LaTeX output.\n",
+ "\n",
+ "\n",
+ "\n",
+ "**Note:** You can also use local files for the `"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Info/Warning Boxes\n",
+ "\n",
+ "\n",
+ "\n",
+ "**Warning:**\n",
+ "\n",
+ "This is an *experimental feature*!\n",
+ "Its usage will probably change in the future or it might be removed completely!\n",
+ "\n",
+ "\n",
+ "\n",
+ "Until there is an info/warning extension for Markdown/CommonMark (see [this issue](https://github.com/jupyter/notebook/issues/1292)), such boxes can be created by using HTML `` elements like this:\n",
+ "\n",
+ "```html\n",
+ "\n",
+ "\n",
+ "**Note:** This is a note!\n",
+ "\n",
+ "\n",
+ "```\n",
+ "\n",
+ "For this to work reliably, you should obey the following guidelines:\n",
+ "\n",
+ "* The `class` attribute has to be either `\"alert alert-info\"` or `\"alert alert-warning\"`, other values will not be converted correctly.\n",
+ "* No further attributes are allowed.\n",
+ "* For compatibility with CommonMark, you should add an empty line between the `` start tag and the beginning of the content.\n",
+ "\n",
+ "\n",
+ "\n",
+ "**Note:**\n",
+ "\n",
+ "The text can contain further Markdown formatting.\n",
+ "It is even possible to have nested boxes:\n",
+ "\n",
+ "\n",
+ "\n",
+ "... but please don't *overuse* this!\n",
+ "\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Links to Other Notebooks\n",
+ "\n",
+ "Relative links to local notebooks can be used:\n",
+ "[a link to a notebook in a subdirectory](subdir/a-notebook-in-a-subdir.ipynb),\n",
+ "[a link to an orphan notebook](orphan.ipynb)\n",
+ "(latter won't work in LaTeX output, because orphan pages are not included there).\n",
+ "\n",
+ "This is how a link is created in Markdown:\n",
+ "\n",
+ "```\n",
+ "[a link to a notebook in a subdirectory](subdir/a-notebook-in-a-subdir.ipynb)\n",
+ "```\n",
+ "\n",
+ "Markdown also supports *reference-style* links:\n",
+ "[a reference-style link][mylink],\n",
+ "[another version of the same link][mylink].\n",
+ "\n",
+ "[mylink]: subdir/a-notebook-in-a-subdir.ipynb\n",
+ "\n",
+ "These can be created with this syntax:\n",
+ "\n",
+ "```\n",
+ "[a reference-style link][mylink]\n",
+ "\n",
+ "[mylink]: subdir/a-notebook-in-a-subdir.ipynb\n",
+ "```\n",
+ "\n",
+ "Links to sub-sections are also possible, e.g.\n",
+ "[this subsection](subdir/a-notebook-in-a-subdir.ipynb#A-Sub-Section).\n",
+ "\n",
+ "This link was created with:\n",
+ "\n",
+ "```\n",
+ "[this subsection](subdir/a-notebook-in-a-subdir.ipynb#A-Sub-Section)\n",
+ "```\n",
+ "\n",
+ "You just have to remember to replace spaces with hyphens!\n",
+ "\n",
+ "BTW, links to sections of the current notebook work, too, e.g.\n",
+ "[beginning of this section](#Links-to-Other-Notebooks).\n",
+ "\n",
+ "This can be done, as expected, like this:\n",
+ "\n",
+ "```\n",
+ "[beginning of this section](#Links-to-Other-Notebooks)\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Links to `*.rst` Files (and Other Sphinx Source Files)\n",
+ "\n",
+ "Links to files whose extension is in the configuration value [source_suffix](http://www.sphinx-doc.org/en/master/config.html#confval-source_suffix), will be converted to links to the generated HTML/LaTeX pages. Example: [A reStructuredText file](a-normal-rst-file.rst).\n",
+ "\n",
+ "This was created with:\n",
+ "\n",
+ "```\n",
+ "[A reStructuredText file](a-normal-rst-file.rst)\n",
+ "```\n",
+ "\n",
+ "Links to sub-sections are also possible. Example: [Sphinx Directives](a-normal-rst-file.rst#sphinx-directives-for-info-warning-boxes).\n",
+ "\n",
+ "This was created with:\n",
+ "\n",
+ "```\n",
+ "[Sphinx Directives](a-normal-rst-file.rst#sphinx-directives-for-info-warning-boxes)\n",
+ "```\n",
+ "\n",
+ "\n",
+ "\n",
+ "**Note:**\n",
+ "\n",
+ "Sphinx section anchors are different from Jupyter section anchors!\n",
+ "To create a link to a subsection in an `.rst` file (or another non-notebook source file), you not only have to replace spaces with hyphens, but also slashes and some other characters.\n",
+ "In case of doubt, just check the target HTML page generated by Sphinx.\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Links to Local Files\n",
+ "\n",
+ "Links to local files (other than Jupyter notebooks and other Sphinx source files) are also possible, e.g. [requirements.txt](requirements.txt).\n",
+ "\n",
+ "This was simply created with:\n",
+ "\n",
+ "```\n",
+ "[requirements.txt](requirements.txt)\n",
+ "```\n",
+ "\n",
+ "The linked files are automatically copied to the HTML output directory.\n",
+ "For LaTeX output, links are created,\n",
+ "but the files are not copied to the target directory."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Links to Domain Objects\n",
+ "\n",
+ "Links to [Sphinx domain objects](http://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html) (such as a Python class or JavaScript function) are also possible. For example:\n",
+ "[example_python_function()](a-normal-rst-file.rst#example_python_function).\n",
+ "\n",
+ "This was created with:\n",
+ "\n",
+ "```\n",
+ "[example_python_function()](a-normal-rst-file.rst#example_python_function)\n",
+ "```\n",
+ "\n",
+ "This is especially useful for use with the Sphinx [autodoc](http://www.sphinx-doc.org/en/master/ext/autodoc.html) extension!"
+ ]
+ }
+ ],
+ "metadata": {
+ "hide_input": false,
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.8"
+ },
+ "toc": {
+ "base_numbering": 1,
+ "nav_menu": {},
+ "number_sections": true,
+ "sideBar": true,
+ "skip_h1_title": false,
+ "title_cell": "Table of Contents",
+ "title_sidebar": "Contents",
+ "toc_cell": false,
+ "toc_position": {},
+ "toc_section_display": true,
+ "toc_window_display": false
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/ipypublish/tests/test_files/nb_markdown_cells/sphinx_ipypublish_main.pandoc.1-12.rst b/ipypublish/tests/test_files/nb_markdown_cells/sphinx_ipypublish_main.pandoc.1-12.rst
new file mode 100644
index 0000000..a10be5b
--- /dev/null
+++ b/ipypublish/tests/test_files/nb_markdown_cells/sphinx_ipypublish_main.pandoc.1-12.rst
@@ -0,0 +1,74 @@
+
+.. An html document created by ipypublish
+ outline: ipypublish.templates.outline_schemas/rst_outline.rst.j2
+ with segments:
+ - nbsphinx-ipypublish-content: ipypublish sphinx content
+
+Notebook to Test Markdown Cells
+===============================
+
+Cell with Attached Image
+------------------------
+
+.. figure:: nb_markdown_cells_files/attach_1_output_13_0.jpeg
+ :alt: output\_13\_0.jpeg
+
+ output\_13\_0.jpeg
+:numref:`fig:id1` `mkdown\_ref <#fig:id1>`__
+
+Cell with Linked Image
+----------------------
+
+.. figure:: nb_markdown_cells_files/logo_example.png
+ :alt: this is a **caption**
+
+ this is a **caption**
+
+Cell with Link to Header
+------------------------
+
+`link\_to\_header <#cell-with-link-to-header>`__
+
+Cell with Math
+--------------
+
+inline: :math:`a = b`
+
+.. math::
+ :nowrap:
+ :label: eq:id1
+
+ \begin{equation}a = b\end{equation}
+
+.. math::
+ :nowrap:
+ :label: eq:id2
+
+ \begin{align*}c &= d \\ other &= e\end{align*}
+
+Cell with Table
+---------------
+
+.. _`tbl:id`:
+
++---------+---------+-----------+
+| A | B | A and B |
++=========+=========+===========+
+| False | False | False |
++---------+---------+-----------+
+| True | False | False |
++---------+---------+-----------+
+| False | True | False |
++---------+---------+-----------+
+| True | True | True |
++---------+---------+-----------+
+
+Table: Caption.
+
+:numref:`tbl:id`
+
+References Using @ Notation
+---------------------------
+
+:numref:`cell-with-link-to-header`, and multiple references
+:numref:`tbl:id` and :numref:`eq:id1`
diff --git a/ipypublish/tests/test_files/nb_markdown_cells/sphinx_ipypublish_main.pandoc.2-2.rst b/ipypublish/tests/test_files/nb_markdown_cells/sphinx_ipypublish_main.pandoc.2-2.rst
new file mode 100644
index 0000000..1c6d3cb
--- /dev/null
+++ b/ipypublish/tests/test_files/nb_markdown_cells/sphinx_ipypublish_main.pandoc.2-2.rst
@@ -0,0 +1,78 @@
+
+.. An html document created by ipypublish
+ outline: ipypublish.templates.outline_schemas/rst_outline.rst.j2
+ with segments:
+ - nbsphinx-ipypublish-content: ipypublish sphinx content
+
+Notebook to Test Markdown Cells
+===============================
+
+Cell with Attached Image
+------------------------
+
+.. figure:: nb_markdown_cells_files/attach_1_output_13_0.jpeg
+ :alt: output_13_0.jpeg
+ :name: fig:id1
+
+ output_13_0.jpeg
+
+:numref:`fig:id1` :numref:`fig:id1`
+
+Cell with Linked Image
+----------------------
+
+.. figure:: nb_markdown_cells_files/logo_example.png
+ :alt: this is a **caption**
+ :name: fig:id2
+ :width: 50.0%
+
+ this is a **caption**
+
+Cell with Link to Header
+------------------------
+
+:numref:`cell-with-link-to-header`
+
+Cell with Math
+--------------
+
+inline: :math:`a = b`
+
+.. math::
+ :nowrap:
+ :label: eq:id1
+
+ \begin{equation}a = b\end{equation}
+
+.. math::
+ :nowrap:
+ :label: eq:id2
+
+ \begin{align*}c &= d \\ other &= e\end{align*}
+
+Cell with Table
+---------------
+
+.. _`tbl:id`:
+
+.. table:: Caption.
+
+ +-------+-------+---------+
+ | A | B | A and B |
+ +=======+=======+=========+
+ | False | False | False |
+ +-------+-------+---------+
+ | True | False | False |
+ +-------+-------+---------+
+ | False | True | False |
+ +-------+-------+---------+
+ | True | True | True |
+ +-------+-------+---------+
+
+:numref:`tbl:id`
+
+References Using @ Notation
+---------------------------
+
+:numref:`cell-with-link-to-header`, and multiple references
+:numref:`tbl:id` and :numref:`eq:id1`
diff --git a/ipypublish/tests/test_files/nb_markdown_cells/sphinx_ipypublish_main.pandoc.2-6.rst b/ipypublish/tests/test_files/nb_markdown_cells/sphinx_ipypublish_main.pandoc.2-6.rst
new file mode 100644
index 0000000..ecc21ab
--- /dev/null
+++ b/ipypublish/tests/test_files/nb_markdown_cells/sphinx_ipypublish_main.pandoc.2-6.rst
@@ -0,0 +1,75 @@
+
+.. An html document created by ipypublish
+ outline: ipypublish.templates.outline_schemas/rst_outline.rst.j2
+ with segments:
+ - nbsphinx-ipypublish-content: ipypublish sphinx content
+
+Notebook to Test Markdown Cells
+===============================
+
+Cell with Attached Image
+------------------------
+
+.. figure:: nb_markdown_cells_files/attach_1_output_13_0.jpeg
+ :alt: output_13_0.jpeg
+ :name: fig:id1
+
+ output_13_0.jpeg
+
+:numref:`fig:id1` :numref:`fig:id1`
+
+Cell with Linked Image
+----------------------
+
+.. figure:: nb_markdown_cells_files/logo_example.png
+ :alt: this is a **caption**
+ :name: fig:id2
+ :width: 50.0%
+
+ this is a **caption**
+
+Cell with Link to Header
+------------------------
+
+:numref:`cell-with-link-to-header`
+
+Cell with Math
+--------------
+
+inline: :math:`a = b`
+
+.. math::
+ :nowrap:
+ :label: eq:id1
+
+ \begin{equation}a = b\end{equation}
+
+.. math::
+ :nowrap:
+ :label: eq:id2
+
+ \begin{align*}c &= d \\ other &= e\end{align*}
+
+Cell with Table
+---------------
+
+.. _`tbl:id`:
+
+.. table:: Caption.
+
+ ===== ===== =======
+ A B A and B
+ ===== ===== =======
+ False False False
+ True False False
+ False True False
+ True True True
+ ===== ===== =======
+
+:numref:`tbl:id`
+
+References Using @ Notation
+---------------------------
+
+:numref:`cell-with-link-to-header`, and multiple references
+:numref:`tbl:id` and :numref:`eq:id1`
diff --git a/ipypublish/tests/test_frontend.py b/ipypublish/tests/test_frontend.py
index b684661..7a2c7a4 100644
--- a/ipypublish/tests/test_frontend.py
+++ b/ipypublish/tests/test_frontend.py
@@ -22,13 +22,13 @@ def test_nbpublish_bad_exporter(temp_folder, ipynb1):
def test_nbpresent_dry_run(temp_folder, ipynb1):
# type: (str, pathlib.Path) -> None
assert 0 == nbpresent.run([str(ipynb1), "--outpath", temp_folder,
- "--dry-run", "--log-level", "debug"])
+ "--dry-run", "--log-level", "debug", "-pt"])
def test_nbpublish_dry_run(temp_folder, ipynb1):
# type: (str, pathlib.Path) -> None
assert 0 == nbpublish.run([str(ipynb1), "--outpath", temp_folder,
- "--dry-run", "--log-level", "debug"])
+ "--dry-run", "--log-level", "debug", "-pt"])
def test_nbpublish_dry_run_with_external_plugin(
@@ -37,7 +37,7 @@ def test_nbpublish_dry_run_with_external_plugin(
assert 0 == nbpublish.run([str(ipynb1),
"--outformat", str(external_export_plugin),
"--outpath", temp_folder,
- "--dry-run", "--log-level", "debug"])
+ "--dry-run", "--log-level", "debug", "-pt"])
def test_nbpublish_dry_run_with_external_plugin_key(
@@ -50,7 +50,7 @@ def test_nbpublish_dry_run_with_external_plugin_key(
os.path.splitext(
str(external_export_plugin.name))[0],
"--outpath", temp_folder,
- "--dry-run", "--log-level", "debug"])
+ "--dry-run", "--log-level", "debug", "-pt"])
def test_nbpresent_list_exports():
@@ -71,7 +71,7 @@ def test_nbpublish_write(temp_folder, ipynb1):
# type: (str, pathlib.Path) -> None
assert 0 == nbpublish.run([str(ipynb1),
"--outformat", "latex_ipypublish_main",
- "--outpath", temp_folder])
+ "--outpath", temp_folder, "-pt"])
assert os.path.exists(os.path.join(temp_folder,
ipynb1.name.replace(".ipynb", ".tex")))
@@ -82,6 +82,6 @@ def test_nbpublish_to_pdf(temp_folder, ipynb1):
assert 0 == nbpublish.run([str(ipynb1),
"--outformat", "latex_ipypublish_main",
"--outpath", temp_folder,
- "--create-pdf"])
+ "--create-pdf", "-pt"])
assert os.path.exists(os.path.join(temp_folder,
ipynb1.name.replace(".ipynb", ".pdf")))
diff --git a/ipypublish/tests/test_nbexport.py b/ipypublish/tests/test_nbexport.py
index 531b7d2..794384f 100644
--- a/ipypublish/tests/test_nbexport.py
+++ b/ipypublish/tests/test_nbexport.py
@@ -1,8 +1,8 @@
-from ipypublish.scripts import nbmerge
+from ipypublish.convert import nbmerge
from ipypublish.convert.config_manager import (
create_exporter_cls, str_to_jinja
)
-from ipypublish.convert.main import (dict_to_config, export_notebook)
+from ipypublish.convert.main import dict_to_config, IpyPubMain
def test_nbexport_latex_empty(ipynb1):
@@ -10,8 +10,8 @@ def test_nbexport_latex_empty(ipynb1):
config = dict_to_config({'LatexExporter.template_file': "template_name"})
exporter_cls = create_exporter_cls('nbconvert.exporters.LatexExporter')
nb, path = nbmerge.merge_notebooks(ipynb1)
- exporter, body, resources = export_notebook(nb, exporter_cls,
- config, template)
+ exporter, body, resources = IpyPubMain().export_notebook(nb, exporter_cls,
+ config, template)
assert exporter.output_mimetype == 'text/latex'
assert body == ''
@@ -25,8 +25,8 @@ def test_nbexport_latex_mkdown1(ipynb1):
config = dict_to_config({'LatexExporter.template_file': "template_name"})
nb, path = nbmerge.merge_notebooks(ipynb1)
exporter_cls = create_exporter_cls('nbconvert.exporters.LatexExporter')
- exporter, body, resources = export_notebook(nb, exporter_cls,
- config, template)
+ exporter, body, resources = IpyPubMain().export_notebook(nb, exporter_cls,
+ config, template)
assert exporter.output_mimetype == 'text/latex'
assert body.strip() == 'test123'
@@ -41,8 +41,8 @@ def test_nbexport_latex_mkdown2(ipynb1):
config = dict_to_config({'LatexExporter.template_file': "template_name"})
nb, path = nbmerge.merge_notebooks(ipynb1)
exporter_cls = create_exporter_cls('nbconvert.exporters.LatexExporter')
- exporter, body, resources = export_notebook(nb, exporter_cls,
- config, template)
+ exporter, body, resources = IpyPubMain().export_notebook(nb, exporter_cls,
+ config, template)
assert exporter.output_mimetype == 'text/latex'
assert body.strip() == '# a title\n\nsome text'
@@ -53,8 +53,8 @@ def test_nbexport_html_empty(ipynb1):
config = dict_to_config({'HTMLExporter.template_file': "template_name"})
nb, path = nbmerge.merge_notebooks(ipynb1)
exporter_cls = create_exporter_cls('nbconvert.exporters.HTMLExporter')
- exporter, body, resources = export_notebook(nb, exporter_cls,
- config, template)
+ exporter, body, resources = IpyPubMain().export_notebook(nb, exporter_cls,
+ config, template)
assert exporter.output_mimetype == 'text/html'
assert body == ''
@@ -69,8 +69,8 @@ def test_nbexport_html_mkdown1(ipynb1):
config = dict_to_config({'HTMLExporter.template_file': "template_name"})
nb, path = nbmerge.merge_notebooks(ipynb1)
exporter_cls = create_exporter_cls('nbconvert.exporters.HTMLExporter')
- exporter, body, resources = export_notebook(nb, exporter_cls,
- config, template)
+ exporter, body, resources = IpyPubMain().export_notebook(nb, exporter_cls,
+ config, template)
assert exporter.output_mimetype == 'text/html'
assert body.strip() == 'test123'
@@ -86,8 +86,8 @@ def test_nbexport_html_mkdown2(ipynb1):
config = dict_to_config({'HTMLExporter.template_file': "template_name"})
nb, path = nbmerge.merge_notebooks(ipynb1)
exporter_cls = create_exporter_cls('nbconvert.exporters.HTMLExporter')
- exporter, body, resources = export_notebook(nb, exporter_cls,
- config, template)
+ exporter, body, resources = IpyPubMain().export_notebook(nb, exporter_cls,
+ config, template)
assert exporter.output_mimetype == 'text/html'
assert body.strip() == '# a title\n\nsome text'
diff --git a/ipypublish/tests/test_nbmerge.py b/ipypublish/tests/test_nbmerge.py
index 318d887..465b623 100644
--- a/ipypublish/tests/test_nbmerge.py
+++ b/ipypublish/tests/test_nbmerge.py
@@ -1,4 +1,4 @@
-from ipypublish.scripts import nbmerge
+from ipypublish.convert import nbmerge
def test_nbmerge_one_notebook(ipynb1):
diff --git a/ipypublish/tests/test_nbpublish.py b/ipypublish/tests/test_nbpublish.py
index c3dc9f3..53ae647 100644
--- a/ipypublish/tests/test_nbpublish.py
+++ b/ipypublish/tests/test_nbpublish.py
@@ -1,40 +1,22 @@
import os
import re
import io
+import sys
from difflib import context_diff
import pytest
-from ipypublish.convert.main import publish
-from ipypublish.scripts import pdfexport
+from ipypublish.convert.main import IpyPubMain
from ipypublish.convert.config_manager import iter_all_export_paths
from ipypublish.tests import TEST_FILES_DIR
-def test_pdf_export(temp_folder):
-
- tex_content = """
-\\documentclass{article}
-\\begin{document}
-hallo world
-\\end{document}
-"""
-
- tex_path = os.path.join(temp_folder, 'test.tex')
- pdf_path = os.path.join(temp_folder, 'test.pdf')
-
- with open(tex_path, 'w') as f:
- f.write(tex_content)
- pdfexport.export_pdf(tex_path, temp_folder)
- assert os.path.exists(pdf_path)
-
-
def test_publish_ipynb1_latex(temp_folder, ipynb1):
tex_path = os.path.join(temp_folder,
os.path.splitext(ipynb1.name)[0] + '.tex')
- publish(ipynb1, outpath=temp_folder)
+ IpyPubMain(config={"IpyPubMain": {"outpath": temp_folder}})(ipynb1)
assert os.path.exists(tex_path)
@@ -43,7 +25,7 @@ def test_publish_folder1_latex(ipynb_folder):
tex_path = os.path.join(ipynb_folder,
os.path.basename(ipynb_folder) + '.tex')
- publish(ipynb_folder, outpath=ipynb_folder)
+ IpyPubMain(config={"IpyPubMain": {"outpath": ipynb_folder}})(ipynb_folder)
assert os.path.exists(tex_path)
@@ -55,30 +37,55 @@ def test_publish_ipynb1_pdf(temp_folder, ipynb1):
pdf_path = os.path.join(temp_folder,
os.path.splitext(ipynb1.name)[0] + '.pdf')
- publish(ipynb1, outpath=temp_folder, create_pdf=True)
+ IpyPubMain(config={"IpyPubMain":
+ {"outpath": temp_folder,
+ "default_pporder_kwargs": {"create_pdf": True}}},
+ )(ipynb1)
assert os.path.exists(tex_path)
assert os.path.exists(pdf_path)
@pytest.mark.requires_latexmk
-def test_publish_with_attachments_latex(temp_folder, ipynb_with_attach):
+def test_publish_markdown_cells_latex(temp_folder, nb_markdown_cells):
""" test notebook containing attachments
"""
- ipynb = ipynb_with_attach["input_file"]
- tex_file = ipynb_with_attach["latex_ipypublish_main"]
+ ipynb = nb_markdown_cells["input_file"]
+ tex_file = nb_markdown_cells["latex_ipypublish_main"]
tex_path = os.path.join(temp_folder,
os.path.splitext(ipynb.name)[0] + '.tex')
pdf_path = os.path.join(temp_folder,
os.path.splitext(ipynb.name)[0] + '.pdf')
- publish(ipynb, outpath=temp_folder, create_pdf=True)
+ IpyPubMain(config={"IpyPubMain":
+ {"outpath": temp_folder,
+ "conversion": "latex_ipypublish_main",
+ "default_pporder_kwargs": {"create_pdf": True}}}
+ )(ipynb)
assert os.path.exists(tex_path)
assert os.path.exists(pdf_path)
compare_tex_files(tex_file, tex_path)
+def test_publish_markdown_cells_rst(temp_folder, nb_markdown_cells):
+ """ test notebook containing attachments
+
+ """
+ ipynb = nb_markdown_cells["input_file"]
+ rst_file = nb_markdown_cells["sphinx_ipypublish_main"]
+
+ rst_path = os.path.join(temp_folder,
+ os.path.splitext(ipynb.name)[0] + '.rst')
+
+ IpyPubMain(config={"IpyPubMain": {
+ "outpath": temp_folder,
+ "conversion": "sphinx_ipypublish_main"}}
+ )(ipynb)
+ assert os.path.exists(rst_path)
+ compare_rst_files(rst_file, rst_path)
+
+
@pytest.mark.requires_latexmk
def test_publish_withbib(temp_folder, ipynb_with_bib):
tex_path = os.path.join(temp_folder,
@@ -86,7 +93,10 @@ def test_publish_withbib(temp_folder, ipynb_with_bib):
pdf_path = os.path.join(temp_folder,
os.path.splitext(ipynb_with_bib.name)[0] + '.pdf')
- publish(ipynb_with_bib, outpath=temp_folder, create_pdf=True)
+ IpyPubMain(config={"IpyPubMain": {
+ "outpath": temp_folder,
+ "default_pporder_kwargs": {"create_pdf": True}}}
+ )(ipynb_with_bib)
assert os.path.exists(tex_path)
assert os.path.exists(pdf_path)
@@ -114,10 +124,12 @@ def test_publish_complex_latex(ipynb_folder_with_external):
basename + '.tex')
pdf_path = os.path.join(input_folder,
basename + '.pdf')
- publish(input_folder,
- conversion='latex_ipypublish_main',
- outpath=input_folder,
- create_pdf=True, pdf_debug=True)
+ IpyPubMain(config={"IpyPubMain":
+ {"outpath": input_folder,
+ "conversion": "latex_ipypublish_main",
+ "default_pporder_kwargs": {"create_pdf": True},
+ "default_ppconfig_kwargs": {"pdf_debug": True}}}
+ )(input_folder)
assert os.path.exists(tex_path)
assert os.path.exists(pdf_path)
compare_tex_files(expected, tex_path)
@@ -136,9 +148,9 @@ def test_publish_complex_html(ipynb_folder_with_external):
basename = os.path.basename(input_folder)
html_path = os.path.join(input_folder,
basename + '.html')
- publish(input_folder,
- conversion='html_ipypublish_main',
- outpath=input_folder)
+ IpyPubMain(config={"IpyPubMain": {"outpath": input_folder,
+ "conversion": "html_ipypublish_main"}
+ })(input_folder)
assert os.path.exists(html_path)
compare_html_files(expected, html_path)
@@ -156,19 +168,44 @@ def test_publish_complex_slides(ipynb_folder_with_external):
basename = os.path.basename(input_folder)
html_path = os.path.join(input_folder,
basename + '.slides.html')
- publish(input_folder,
- conversion='slides_ipypublish_main',
- outpath=input_folder)
+ IpyPubMain(config={"IpyPubMain":
+ {"outpath": input_folder,
+ "conversion": "slides_ipypublish_main",
+ "default_pporder_kwargs": {"slides": True}}
+ })(input_folder)
assert os.path.exists(html_path)
compare_html_files(expected, html_path)
+def test_publish_complex_rst(ipynb_folder_with_external):
+ """ includes:
+
+ - internal (image) files
+ - external logo and bib
+
+ """
+ input_folder = ipynb_folder_with_external["input_folder"]
+ expected = ipynb_folder_with_external["sphinx_ipypublish_all"]
+
+ basename = os.path.basename(input_folder)
+ rst_path = os.path.join(input_folder,
+ basename + '.rst')
+
+ IpyPubMain(config={"IpyPubMain": {"outpath": input_folder,
+ "conversion": "sphinx_ipypublish_all"}
+ })(input_folder)
+ assert os.path.exists(rst_path)
+ compare_rst_files(expected, rst_path)
+
+
def test_publish_ipynb1_html(temp_folder, ipynb1):
html_path = os.path.join(temp_folder,
os.path.splitext(ipynb1.name)[0] + '.html')
- publish(ipynb1, conversion='html_ipypublish_main', outpath=temp_folder)
+ IpyPubMain(config={"IpyPubMain": {"outpath": temp_folder,
+ "conversion": "html_ipypublish_main"}
+ })(ipynb1)
assert os.path.exists(html_path)
@@ -177,8 +214,11 @@ def test_publish_ipynb1_slides(temp_folder, ipynb1):
html_path = os.path.join(temp_folder, os.path.splitext(
ipynb1.name)[0] + '.slides.html')
- publish(ipynb1, conversion='slides_ipypublish_main',
- outpath=temp_folder)
+ IpyPubMain(config={"IpyPubMain":
+ {"outpath": temp_folder,
+ "conversion": "slides_ipypublish_main",
+ "default_pporder_kwargs": {"slides": True}}
+ })(ipynb1)
assert os.path.exists(html_path)
@@ -189,12 +229,35 @@ def test_publish_ipynb1_slides(temp_folder, ipynb1):
def test_publish_run_all_plugins(temp_folder, ipynb1,
plugin_name, plugin_path):
- outpath, exporter = publish(
- ipynb1, conversion=plugin_name, outpath=temp_folder)
+ if ((plugin_name in ["sphinx_ipypublish_all.ext"]
+ or "exec" in plugin_name) and sys.version_info[0] < 3):
+ # TODO this fails because the kernel is set as python3 in the notebook
+ # could add a replacement variable e.g. ${pykernel}
+ # and allow parsing of it to main.publish (default = "")
+ return
+
+ # TODO "sphinx_ipypublish_all.run" launches a webbrowser tab
+
+ outdata = IpyPubMain(config={"IpyPubMain": {"outpath": temp_folder,
+ "conversion": plugin_name}}
+ )(ipynb1)
+
+ exporter = outdata["exporter"]
+
outname = os.path.splitext(ipynb1.name)[0] + exporter.file_extension
outfile = os.path.join(temp_folder, outname)
testfile = os.path.join(TEST_FILES_DIR, "ipynb1_converted",
plugin_name + exporter.file_extension)
+
+ if plugin_name in ["python_with_meta_stream", "sphinx_ipypublish_all.ext"]:
+ return
+ if plugin_name in [
+ "sphinx_ipypublish_all.run", "sphinx_ipypublish_main.run"]:
+ assert os.path.exists(os.path.join(
+ temp_folder, "build", "html",
+ os.path.splitext(ipynb1.name)[0] + ".html"))
+ return
+
assert os.path.exists(outfile), "could not find: {} for {}".format(
outfile, plugin_name)
assert os.path.exists(testfile), "could not find: {} for {}".format(
@@ -204,7 +267,32 @@ def test_publish_run_all_plugins(temp_folder, ipynb1,
compare_tex_files(testfile, outfile)
elif exporter.output_mimetype == 'text/html':
compare_html_files(testfile, outfile)
- # TODO test rst output
+ elif exporter.output_mimetype == 'text/restructuredtext':
+ compare_rst_files(testfile, outfile)
+
+
+def compare_rst_files(testpath, outpath):
+ # only compare body of html, since styles differ by
+ # nbconvert/pandoc version (e.g. different versions of font-awesome)
+
+ output = []
+ for path in [testpath, outpath]:
+
+ with io.open(str(path), encoding='utf8') as fobj:
+ content = fobj.read()
+
+ # python 3.5 used .jpg instead of .jpeg
+ content = content.replace(".jpg", ".jpeg")
+
+ output.append(content)
+
+ test_content, out_content = output
+
+ # only report differences
+ if out_content != test_content:
+ raise AssertionError("\n"+"\n".join(context_diff(
+ test_content.splitlines(), out_content.splitlines(),
+ fromfile=str(testpath), tofile=str(outpath))))
def compare_html_files(testpath, outpath):
@@ -229,6 +317,9 @@ def compare_html_files(testpath, outpath):
script_rgx = re.compile("\\", re.DOTALL)
content = script_rgx.sub("", content)
+ # remove trailing whitespace
+ content = "\n".join([l.rstrip() for l in content.splitlines()])
+
output.append(content)
test_content, out_content = output
@@ -274,11 +365,15 @@ def compare_tex_files(testpath, outpath):
("\\\\expandafter\\\\def\\\\csname "
"PY\\@tok\\@[0-9a-zA-Z]*\\\\endcsname[^\n]*"),
re.MULTILINE)
- content = pyg_rgx.sub("\", content)
+ content = pyg_rgx.sub(r"\", content)
# also remove all space from start of lines
- space_rgx = re.compile("^[\s]*", re.MULTILINE)
+ space_rgx = re.compile(r"^[\s]*", re.MULTILINE)
content = space_rgx.sub("", content)
+
+ # remove trailing whitespace
+ content = "\n".join([l.rstrip() for l in content.splitlines()])
+
output.append(content)
test_content, out_content = output
diff --git a/ipypublish/tests/test_postprocessors.py b/ipypublish/tests/test_postprocessors.py
new file mode 100644
index 0000000..e301765
--- /dev/null
+++ b/ipypublish/tests/test_postprocessors.py
@@ -0,0 +1,29 @@
+import os
+from ipypublish.postprocessors.pdfexport import PDFExport
+from ipypublish.postprocessors.reveal_serve import RevealServer
+
+def test_pdf_export(temp_folder):
+
+ tex_content = """
+\\documentclass{article}
+\\begin{document}
+hallo world
+\\end{document}
+"""
+
+ tex_path = os.path.join(temp_folder, 'test.tex')
+ pdf_path = os.path.join(temp_folder, 'test.pdf')
+
+ with open(tex_path, 'w') as f:
+ f.write(tex_content)
+
+ pdfexport = PDFExport()
+ pdfexport.postprocess(tex_content, 'text/latex', tex_path)
+
+ assert os.path.exists(pdf_path)
+
+
+def test_reveal_server():
+ RevealServer()
+ # TODO test reveal server runs correctly,
+ # possibly use https://github.com/eugeniy/pytest-tornado
\ No newline at end of file
diff --git a/ipypublish/utils.py b/ipypublish/utils.py
index 4b9990a..d3ffbcd 100644
--- a/ipypublish/utils.py
+++ b/ipypublish/utils.py
@@ -3,9 +3,10 @@
import inspect
import importlib
import re
+import pkg_resources
from six import string_types
-import yaml # TODO use ruamel.yaml instead?
+import ruamel.yaml as yaml
# python 2/3 compatibility
try:
@@ -83,7 +84,7 @@ def read_file_from_module(module_path, file_name, jtype,
logger, interp_ext=False,
ext_types=(
("json", (".json")),
- ("yaml", (".yaml", ".yaml.j2")))):
+ ("yaml", (".yaml", ".yaml.j2", "yaml.tex.j2")))):
"""load a file situated in a python module
if ``interp_ext=True``:
@@ -116,3 +117,43 @@ def get_valid_filename(s):
"""
s = str(s).strip().replace(' ', '_')
return re.sub(r'(?u)[^-\w.]', '', s)
+
+
+def find_entry_point(name, group, logger, preferred=None):
+ """find an entry point by name and group
+
+ Parameters
+ ----------
+ name: str
+ name of entry point
+ group: str
+ group of entry point
+ preferred: str
+ if multiple matches are found, prefer one from this module
+
+ """
+ entry_points = list(pkg_resources.iter_entry_points(
+ group, name))
+ if len(entry_points) == 0:
+ handle_error(
+ "The {0} entry point "
+ "{1} could not be found".format(group, name),
+ pkg_resources.ResolutionError, logger)
+ elif len(entry_points) != 1:
+ # default to the preferred package
+ oentry_points = []
+ if preferred:
+ oentry_points = [ep for ep in entry_points
+ if ep.module_name.startswith(preferred)]
+ if len(oentry_points) != 1:
+ handle_error(
+ "Multiple {0} plugins found for "
+ "{1}: {2}".format(group, name, entry_points),
+ pkg_resources.ResolutionError, logger)
+ logger.info(
+ "Multiple {0} plugins found for {1}, "
+ "defaulting to the {2} version".format(group, name, preferred))
+ entry_point = oentry_points[0]
+ else:
+ entry_point = entry_points[0]
+ return entry_point.load()
diff --git a/requirements-lock.txt b/requirements-lock.txt
index 4914528..a066365 100644
--- a/requirements-lock.txt
+++ b/requirements-lock.txt
@@ -6,25 +6,34 @@
#
bibtexparser==1.1.0
bleach==3.1.0 # via nbconvert
+click==7.0 # via panflute
decorator==4.3.2 # via traitlets
defusedxml==0.5.0 # via nbconvert
+docutils==0.14
entrypoints==0.3 # via nbconvert
-future==0.17.1 # via bibtexparser
+future==0.17.1 # via bibtexparser, panflute
ipython-genutils==0.2.0 # via nbformat, traitlets
jinja2==2.10
jsonextended==0.7.7
jsonschema==2.6.0
jupyter-core==4.4.0 # via nbconvert, nbformat
+jupytext==0.8.6
markupsafe==1.1.0 # via jinja2
mistune==0.8.4 # via nbconvert
+mock==2.0.0 # via jupytext
nbconvert==5.4.0
nbformat==4.4.0
pandocfilters==1.4.2 # via nbconvert
+panflute==1.11.2
pathlib2==2.3.3
+pbr==5.1.2 # via mock
pygments==2.3.1 # via nbconvert
pyparsing==2.3.1 # via bibtexparser
-pyyaml==4.2b1
+pyyaml==3.13 # via jupytext, panflute
+ruamel.yaml==0.15.87
+shutilwhich==1.1.0 # via panflute
six==1.12.0
+testfixtures==6.5.0 # via jupytext
testpath==0.4.2 # via nbconvert
tornado==5.1.1
traitlets==4.3.2
diff --git a/requirements.txt b/requirements.txt
index 3cdb30b..3446f23 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,4 +9,8 @@ bibtexparser
jsonextended>=0.7
six
jsonschema
-pyyaml
\ No newline at end of file
+ruamel.yaml
+panflute
+docutils
+jupytext
+shutilwhich
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 489e86b..a9405e9 100755
--- a/setup.py
+++ b/setup.py
@@ -10,8 +10,6 @@
with open('requirements.txt') as f:
requirements = f.read().splitlines()
-with open('test_requirements.txt') as f:
- test_requirements = f.read().splitlines()
with io.open('README.md') as readme:
readme_str = readme.read()
@@ -25,10 +23,24 @@
long_description=readme_str,
long_description_content_type='text/markdown',
install_requires=requirements,
- tests_require=test_requirements,
extras_require={
- "docs": {
- "sphinx"
+ "sphinx": {
+ "sphinx>=1.6",
+ "sphinxcontrib-bibtex"
+ },
+ "tests": {
+ "pytest>=3.6",
+ "pytest-cov",
+ "coverage",
+ "pillow",
+ "nbsphinx",
+ "ipykernel"
+ },
+ "science": {
+ "matplotlib",
+ "numpy",
+ "pandas",
+ "sympy"
}
},
license='MIT',
@@ -64,7 +76,22 @@
entry_points={
'console_scripts': [
'nbpublish = ipypublish.frontend.nbpublish:run',
- 'nbpresent = ipypublish.frontend.nbpresent:run'
+ 'nbpresent = ipypublish.frontend.nbpresent:run',
+ 'ipubpandoc = ipypublish.filters_pandoc.main:pandoc_filters'
+ ],
+ 'ipypublish.postprocessors': [
+ 'remove-blank-lines = ipypublish.postprocessors.stream_modify:RemoveBlankLines',
+ 'remove-trailing-space = ipypublish.postprocessors.stream_modify:RemoveTrailingSpace',
+ 'filter-output-files = ipypublish.postprocessors.stream_modify:FilterOutputFiles',
+ 'fix-slide-refs = ipypublish.postprocessors.stream_modify:FixSlideReferences',
+ 'pdf-export = ipypublish.postprocessors.pdfexport:PDFExport',
+ 'write-stream = ipypublish.postprocessors.to_stream:WriteStream',
+ 'write-text-file = ipypublish.postprocessors.file_actions:WriteTextFile',
+ 'remove-folder = ipypublish.postprocessors.file_actions:RemoveFolder',
+ 'write-resource-files = ipypublish.postprocessors.file_actions:WriteResourceFiles',
+ 'copy-resource-paths = ipypublish.postprocessors.file_actions:CopyResourcePaths',
+ 'reveal-server = ipypublish.postprocessors.reveal_serve:RevealServer',
+ 'run-sphinx = ipypublish.postprocessors.sphinx:RunSphinx [sphinx]'
]
}
)
diff --git a/test_requirements.txt b/test_requirements.txt
deleted file mode 100644
index 5387a4e..0000000
--- a/test_requirements.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-pytest>=3.6
-pytest-cov
-coverage
-pillow
-nbsphinx
\ No newline at end of file