diff --git a/liquid_tags/Readme.md b/liquid_tags/Readme.md index bb2203c3c..4cc37864d 100644 --- a/liquid_tags/Readme.md +++ b/liquid_tags/Readme.md @@ -74,7 +74,7 @@ filename. The script must be in the ``code`` subdirectory of your content folder: this default location can be changed by specifying - CODE_DIR = 'code' + CODE_DIR = 'code' within your configuration file. Additionally, in order for the resulting hyperlink to work, this directory must be listed under the STATIC_PATHS @@ -97,7 +97,7 @@ config file: Because the conversion and rendering of notebooks is rather involved, there are a few extra steps required for this plugin: -- First, you will need to install IPython >= 1.0 [1]_ +- First, you will need to install IPython >= 1.0 [[1](#1)] - After typing "make html" when using the notebook tag, a file called ``_nb_header.html`` will be produced in the main directory. The content @@ -115,6 +115,31 @@ are a few extra steps required for this plugin: this will insert the proper css formatting into your document. +### Optional Arguments for Notebook Tags + +The notebook tag also has two optional arguments: ``cells`` and ``language``. + +- You can specify a slice of cells to include: + + ``{% notebook filename.ipynb cells[2:8] %}`` + +- You can also specify the name of a language which Pygments should use for + highlighting code cells. A list of the short names for languages that Pygments + will highlight can be found [here](http://www.pygments.org/docs/lexers/). + + ``{% notebook filename.ipynb language[julia] %}`` + + This may be helpful for those using [IJulia](https://github.com/JuliaLang/IJulia.jl) + or notebooks in any other language, especially as the IPython project [broadens its + scope](https://github.com/ipython/ipython/wiki/Roadmap:-IPython) of [language + compatibility](http://jupyter.org/). By default, the language for highlighting + will be ``ipython``. + +- These options can be used separately, together, or not at all. However, + if both tags are used then ``cells`` must come before ``language``: + + ``{% notebook filename.ipynb cells[2:8] language[julia] %}`` + ### Collapsible Code in IPython Notebooks The plugin also enables collapsible code input boxes. For this to work @@ -127,4 +152,4 @@ comment line ``# `` will be open on load but can be collapsed by clicking on their header. Cells without collapse comments are rendered as standard code input cells. -[1] http://ipython.org/ +[1] http://ipython.org/ diff --git a/liquid_tags/notebook.py b/liquid_tags/notebook.py index 1208f1e13..7f58fab75 100644 --- a/liquid_tags/notebook.py +++ b/liquid_tags/notebook.py @@ -46,6 +46,8 @@ """ import re import os +from functools import partial + from .mdx_liquid_tags import LiquidTags from distutils.version import LooseVersion @@ -230,8 +232,8 @@ def custom_highlighter(source, language='ipython', metadata=None): #---------------------------------------------------------------------- # Below is the pelican plugin code. # -SYNTAX = "{% notebook /path/to/notebook.ipynb [ cells[start:end] ] %}" -FORMAT = re.compile(r"""^(\s+)?(?P\S+)(\s+)?((cells\[)(?P-?[0-9]*):(?P-?[0-9]*)(\]))?(\s+)?$""") +SYNTAX = "{% notebook /path/to/notebook.ipynb [ cells[start:end] ] [ language[language] ] %}" +FORMAT = re.compile(r"""^(\s+)?(?P\S+)(\s+)?((cells\[)(?P-?[0-9]*):(?P-?[0-9]*)(\]))?(\s+)?((language\[)(?P-?[a-z0-9\+\-]*)(\]))?(\s+)?$""") @LiquidTags.register('notebook') @@ -242,6 +244,7 @@ def notebook(preprocessor, tag, markup): src = argdict['src'] start = argdict['start'] end = argdict['end'] + language = argdict['language'] else: raise ValueError("Error processing input, " "expected syntax: {0}".format(SYNTAX)) @@ -256,6 +259,8 @@ def notebook(preprocessor, tag, markup): else: end = None + language_applied_highlighter = partial(custom_highlighter, language=language) + settings = preprocessor.configs.config['settings'] nb_dir = settings.get('NOTEBOOK_DIR', 'notebooks') nb_path = os.path.join('content', nb_dir, src) @@ -284,7 +289,7 @@ def notebook(preprocessor, tag, markup): exporter = HTMLExporter(config=c, template_file=template_file, - filters={'highlight2html': custom_highlighter}, + filters={'highlight2html': language_applied_highlighter}, **subcell_kwarg) # read and parse the notebook diff --git a/liquid_tags/test_notebook.py b/liquid_tags/test_notebook.py new file mode 100644 index 000000000..042d6d1cc --- /dev/null +++ b/liquid_tags/test_notebook.py @@ -0,0 +1,92 @@ +import re + +from pelican.tests.support import unittest + +import notebook + + +class TestNotebookTagRegex(unittest.TestCase): + + def get_argdict(self, markup): + + match = notebook.FORMAT.search(markup) + + if match: + argdict = match.groupdict() + + src = argdict['src'] + start = argdict['start'] + end = argdict['end'] + language = argdict['language'] + + return src, start, end, language + + return None + + def test_basic_notebook_tag(self): + markup = u'path/to/thing.ipynb' + src, start, end, language = self.get_argdict(markup) + + self.assertEqual(src, u'path/to/thing.ipynb') + self.assertIsNone(start) + self.assertIsNone(end) + self.assertIsNone(language) + + def test_basic_notebook_tag_insensitive_to_whitespace(self): + markup = u' path/to/thing.ipynb ' + src, start, end, language = self.get_argdict(markup) + + self.assertEqual(src, u'path/to/thing.ipynb') + self.assertIsNone(start) + self.assertIsNone(end) + self.assertIsNone(language) + + def test_notebook_tag_with_cells(self): + markup = u'path/to/thing.ipynb cells[1:5]' + src, start, end, language = self.get_argdict(markup) + + self.assertEqual(src, u'path/to/thing.ipynb') + self.assertEqual(start, u'1') + self.assertEqual(end, u'5') + self.assertIsNone(language) + + def test_notebook_tag_with_alphanumeric_language(self): + markup = u'path/to/thing.ipynb language[python3]' + src, start, end, language = self.get_argdict(markup) + + self.assertEqual(src, u'path/to/thing.ipynb') + self.assertIsNone(start) + self.assertIsNone(end) + self.assertEqual(language, u'python3') + + def test_notebook_tag_with_symbol_in_name_language(self): + for short_name in [u'c++', u'cpp-objdump', u'c++-objdumb', u'cxx-objdump']: + markup = u'path/to/thing.ipynb language[{}]'.format(short_name) + src, start, end, language = self.get_argdict(markup) + + self.assertEqual(src, u'path/to/thing.ipynb') + self.assertIsNone(start) + self.assertIsNone(end) + self.assertEqual(language, short_name) + + def test_notebook_tag_with_language_and_cells(self): + markup = u'path/to/thing.ipynb cells[1:5] language[julia]' + src, start, end, language = self.get_argdict(markup) + + self.assertEqual(src, u'path/to/thing.ipynb') + self.assertEqual(start, u'1') + self.assertEqual(end, u'5') + self.assertEqual(language, u'julia') + + def test_notebook_tag_with_language_and_cells_and_weird_spaces(self): + markup = u' path/to/thing.ipynb cells[1:5] language[julia] ' + src, start, end, language = self.get_argdict(markup) + + self.assertEqual(src, u'path/to/thing.ipynb') + self.assertEqual(start, u'1') + self.assertEqual(end, u'5') + self.assertEqual(language, u'julia') + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file