From 4c73429821982defa8818eea244f0aafc6398b37 Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Fri, 12 Jun 2020 16:45:13 +0200 Subject: [PATCH 01/15] liquid_tags: Text files should not be marked executable. --- liquid_tags/requirements.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 liquid_tags/requirements.txt diff --git a/liquid_tags/requirements.txt b/liquid_tags/requirements.txt old mode 100755 new mode 100644 From 32ce3a3618a82d1d3f44af33766be65c326a035f Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Fri, 12 Jun 2020 20:46:41 +0200 Subject: [PATCH 02/15] liquid_tags: Added python3.6 and python3.7 to testing. --- liquid_tags/tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/liquid_tags/tox.ini b/liquid_tags/tox.ini index e2e22bdc3..3f093ab4d 100644 --- a/liquid_tags/tox.ini +++ b/liquid_tags/tox.ini @@ -2,8 +2,8 @@ skipsdist = True minversion = 1.8 envlist = - py{27,34}-ipython2, - py{27,34}-ipython3, + py{27,34,36,37}-ipython2, + py{27,34,36,37}-ipython3, [testenv] commands = py.test From 5760d1a3af3d64350ddf66e3a36586981b88b960 Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Fri, 12 Jun 2020 15:40:02 +0200 Subject: [PATCH 03/15] liquid_tags: Only run preprocessor again if liquid_tags.include_code is enabled. --- liquid_tags/mdx_liquid_tags.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/liquid_tags/mdx_liquid_tags.py b/liquid_tags/mdx_liquid_tags.py index 60edf5e21..55fc623f6 100644 --- a/liquid_tags/mdx_liquid_tags.py +++ b/liquid_tags/mdx_liquid_tags.py @@ -85,12 +85,13 @@ def dec(func): def extendMarkdown(self, md, md_globals): self.htmlStash = md.htmlStash md.registerExtension(self) - # for the include_code preprocessor, we need to re-run the - # fenced code block preprocessor after substituting the code. - # Because the fenced code processor is run before, {% %} tags - # within equations will not be parsed as an include. - md.preprocessors.add('mdincludes', - _LiquidTagsPreprocessor(self), ">html_block") + if 'include_code' in _LiquidTagsPreprocessor._tags: + # For the include_code preprocessor, we need to re-run the + # fenced code block preprocessor after substituting the code. + # Because the fenced code processor is run before, {% %} tags + # within equations will not be parsed as an include. + md.preprocessors.add('mdincludes', + _LiquidTagsPreprocessor(self), ">html_block") def makeExtension(configs=None): From 6c8d236d8114f974c6de35f369c8d7a5b2ce8e64 Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Fri, 12 Jun 2020 16:37:07 +0200 Subject: [PATCH 04/15] liquid_tags: Simplified tag expansion logic. Support for custom tag delimiters. Previous tag expansion logic: 2 regexes, 4 calls to regex functions, plus string concatenations. Simplified tag expansion logic: 1 regex + 1 call to re.sub. Support for customizing tag delimiters comes handy when used with plugins with similar tag syntax. E.g. jinja2content. --- liquid_tags/mdx_liquid_tags.py | 44 ++++++++++++++++------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/liquid_tags/mdx_liquid_tags.py b/liquid_tags/mdx_liquid_tags.py index 55fc623f6..2a5e6eec7 100644 --- a/liquid_tags/mdx_liquid_tags.py +++ b/liquid_tags/mdx_liquid_tags.py @@ -16,46 +16,42 @@ import os from functools import wraps -# Define some regular expressions -LIQUID_TAG = re.compile(r'\{%.*?%\}', re.MULTILINE | re.DOTALL) -EXTRACT_TAG = re.compile(r'(?:\s*)(\S+)(?:\s*)') LT_CONFIG = { 'CODE_DIR': 'code', 'NOTEBOOK_DIR': 'notebooks', 'FLICKR_API_KEY': 'flickr', - 'GIPHY_API_KEY': 'giphy' + 'GIPHY_API_KEY': 'giphy', + 'LT_DELIMITERS': ('{%', '%}'), } LT_HELP = { 'CODE_DIR' : 'Code directory for include_code subplugin', 'NOTEBOOK_DIR' : 'Notebook directory for notebook subplugin', 'FLICKR_API_KEY': 'Flickr key for accessing the API', - 'GIPHY_API_KEY': 'Giphy key for accessing the API' + 'GIPHY_API_KEY': 'Giphy key for accessing the API', + 'LT_DELIMITERS': 'Alternative set of Liquid Tags block delimiters', } class _LiquidTagsPreprocessor(markdown.preprocessors.Preprocessor): + LT_FMT = r'{0}(?:\s*)(?P\S+)(?:\s*)(?P.*?)(?:\s*){1}' + LT_RE_FLAGS = re.MULTILINE | re.DOTALL | re.UNICODE _tags = {} + def __init__(self, configs): + cls = self.__class__ + liquid_tag_re = cls.LT_FMT.format( + *map(re.escape, configs.getConfig('LT_DELIMITERS'))) + self.liquid_tag = re.compile(liquid_tag_re, cls.LT_RE_FLAGS) self.configs = configs + def expand_tag(self, match): + tag, markup = match.groups() + if tag in self.__class__._tags: + return self.__class__._tags[tag](self, tag, markup) + else: + return match[0] + def run(self, lines): page = '\n'.join(lines) - liquid_tags = LIQUID_TAG.findall(page) - - for i, markup in enumerate(liquid_tags): - # remove {% %} - markup = markup[2:-2] - tag = EXTRACT_TAG.match(markup).groups()[0] - markup = EXTRACT_TAG.sub('', markup, 1) - if tag in self._tags: - liquid_tags[i] = self._tags[tag](self, tag, markup.strip()) - - # add an empty string to liquid_tags so that chaining works - liquid_tags.append('') - - # reconstruct string - page = ''.join(itertools.chain(*zip(LIQUID_TAG.split(page), - liquid_tags))) - - # resplit the lines - return page.split("\n") + page = self.liquid_tag.sub(self.expand_tag, page) + return page.splitlines() class LiquidTags(markdown.Extension): From 9bb8f1f936cf02a51fe86e6481a76f44d6729630 Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Sat, 13 Jun 2020 21:13:33 +0200 Subject: [PATCH 05/15] liquid_tags: Added test for customized tag delimiters. --- .../content/test-generic-config-alt-delim.md | 7 ++ liquid_tags/test_generic.py | 64 +++++++++++++------ 2 files changed, 52 insertions(+), 19 deletions(-) create mode 100644 liquid_tags/test_data/content/test-generic-config-alt-delim.md diff --git a/liquid_tags/test_data/content/test-generic-config-alt-delim.md b/liquid_tags/test_data/content/test-generic-config-alt-delim.md new file mode 100644 index 000000000..bc457e95b --- /dev/null +++ b/liquid_tags/test_data/content/test-generic-config-alt-delim.md @@ -0,0 +1,7 @@ +Title: test alternate tag delimiters +Date: 2020-06-13 +Authors: M. Stamatogiannakis + +Regular tag is not expanded: {% generic config author %} is stupid + +Alternate tag is expanded: <+ generic config author +> is smart diff --git a/liquid_tags/test_generic.py b/liquid_tags/test_generic.py index 4960219d7..0f3784754 100644 --- a/liquid_tags/test_generic.py +++ b/liquid_tags/test_generic.py @@ -34,28 +34,54 @@ def tearDown(self): def test_generic_tag_with_config(self): '''Test generation of site with a generic tag that reads in a config file.''' - base_path = os.path.dirname(os.path.abspath(__file__)) - base_path = os.path.join(base_path, 'test_data') - content_path = os.path.join(base_path, 'content') - output_path = os.path.join(base_path, 'output') - settings_path = os.path.join(base_path, 'pelicanconf.py') - settings = read_settings(path=settings_path, - override={'PATH': content_path, - 'OUTPUT_PATH': self.temp_path, - 'CACHE_PATH': self.temp_cache, - } - ) + _pj = os.path.join + base_path = _pj(os.path.dirname(os.path.abspath(__file__)), 'test_data') + content_path = _pj(base_path, 'content') + output_path = _pj(base_path, 'output') + settings_path = _pj(base_path, 'pelicanconf.py') + override = { + 'PATH': content_path, + 'OUTPUT_PATH': self.temp_path, + 'CACHE_PATH': self.temp_cache, + } + settings = read_settings(path=settings_path, override=override) pelican = Pelican(settings) pelican.run() - assert os.path.exists(os.path.join(self.temp_path, - 'test-generic-config-tag.html')) + # test normal tags + f = _pj(self.temp_path, 'test-generic-config-tag.html') + assert os.path.exists(f) + assert "Tester" in open(f).read() - assert "Tester" in open(os.path.join(self.temp_path, - 'test-generic-config-tag.html')).read() # test differences - #assert filecmp.cmp(os.path.join(output_path, - # 'test-ipython-notebook-v3.html'), - # os.path.join(self.temp_path, - # 'test-ipython-notebook.html')) + f1 = _pj(output_path, 'test-ipython-notebook-v3.html') + f2 = _pj(self.temp_path, 'test-ipython-notebook.html') + #assert filecmp.cmp(f1, f2) + + def test_generic_alt_delimiters(self): + '''Test generation of site with alternatively delimited tags.''' + + _pj = os.path.join + base_path = _pj(os.path.dirname(os.path.abspath(__file__)), 'test_data') + content_path = _pj(base_path, 'content') + output_path = _pj(base_path, 'output') + settings_path = _pj(base_path, 'pelicanconf.py') + override = { + 'PATH': content_path, + 'OUTPUT_PATH': self.temp_path, + 'CACHE_PATH': self.temp_cache, + 'LT_DELIMITERS': ('<+', '+>'), + } + settings = read_settings(path=settings_path, override=override) + + pelican = Pelican(settings) + pelican.run() + + # test alternate delimiters + f = _pj(self.temp_path, 'test-alternate-tag-delimiters.html') + fc = open(f).read() + assert '{% generic config author %} is stupid' in fc + assert 'The Tester is smart' in fc + assert 'The Tester is stupid' not in fc + From dc744e2eed48070a7ba59095ab722d47373bdbcd Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Fri, 12 Jun 2020 18:09:13 +0200 Subject: [PATCH 06/15] liquid_tags: Registering md preprocessor with register() rather than the deprecated add(). The semantics of add() were inverse to the intuition because they were implicitly exposing the internals of markdown.util.Registry. E.g. a priority of ">htmlblock" did not translate to "have greater priority than htmlblock processor", as one would expect. Instead it means "when the interal processors array is sorted by priority, the new processor should have a bigger *index* number than htmlblock". The tricky point here is that the internal array is sorted in reverse. So ">htmlblock" actually translates to "use a smaller priority than htmlblock". Madness! And instead of fixing the semantics to make sense, it was chosen to deprecate add() and force us to directly supply the priority to register(). This is also bad, because we have to grep outside our codebase to determine the proper priority to achieve the desired effect. Double the madness! --- liquid_tags/mdx_liquid_tags.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/liquid_tags/mdx_liquid_tags.py b/liquid_tags/mdx_liquid_tags.py index 2a5e6eec7..f6c5c11e1 100644 --- a/liquid_tags/mdx_liquid_tags.py +++ b/liquid_tags/mdx_liquid_tags.py @@ -86,8 +86,11 @@ def extendMarkdown(self, md, md_globals): # fenced code block preprocessor after substituting the code. # Because the fenced code processor is run before, {% %} tags # within equations will not be parsed as an include. - md.preprocessors.add('mdincludes', - _LiquidTagsPreprocessor(self), ">html_block") + # + # The now deprecated add() function, with ">htmlblock" argument + # resulted in a priority of 15. Which is what we use here. + md.preprocessors.register(_LiquidTagsPreprocessor(self), + 'mdincludes', 15) def makeExtension(configs=None): From 289170e17520f14ce66c3798e641359a89cced9e Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Fri, 12 Jun 2020 18:10:22 +0200 Subject: [PATCH 07/15] liquid_tags: python2.7 fixes for include_code tag test. --- liquid_tags/test_include_code.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/liquid_tags/test_include_code.py b/liquid_tags/test_include_code.py index a5321c67f..2b0594a25 100644 --- a/liquid_tags/test_include_code.py +++ b/liquid_tags/test_include_code.py @@ -1,5 +1,7 @@ +# -*- coding: utf-8 -*- import re import sys +import six import unittest import pytest @@ -10,7 +12,7 @@ raise unittest.SkipTest('Those tests are pytest-compatible only') @pytest.mark.parametrize( - 'input,expected', [ + 'input, expected', [ ( 'test_data/main.c', ('test_data/main.c', None, None, None, None, None, None, None) @@ -62,8 +64,10 @@ class Object: class preprocessor: @classmethod - def func(*x, safe=False): - return ''.join([str(s) for s in x]) + def func(cls, *x, **kwargs): + safe = kwargs.get('safe', False) + cls_s = "" % (cls.__module__, cls.__name__) + return '%s%s' % (cls_s, ''.join([str(s) for s in x])) def __init__(self): self.configs = Object() From 430135f60a06c9280e541206269b0b5a370d98e0 Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Sat, 13 Jun 2020 18:36:53 +0200 Subject: [PATCH 08/15] liquid_tags: python2.7 compatibility fixes for include_code. --- liquid_tags/include_code.py | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/liquid_tags/include_code.py b/liquid_tags/include_code.py index 185a62ee0..a70917b8f 100644 --- a/liquid_tags/include_code.py +++ b/liquid_tags/include_code.py @@ -39,9 +39,11 @@ """ import re import os -import sys +import six from .mdx_liquid_tags import LiquidTags +if six.PY2: + from io import open SYNTAX = "{% include_code /path/to/code.py [lang:python] [lines:X-Y] "\ "[:hidefilename:] [:hidelink:] [:hideall:] [title] %}" @@ -77,7 +79,7 @@ def include_code(preprocessor, tag, markup): argdict = match.groupdict() title = argdict['title'] or "" lang = argdict['lang'] - codec = argdict['codec'] or "utf8" + codec = argdict['codec'] or "utf-8" lines = argdict['lines'] hide_filename = bool(argdict['hidefilename']) hide_link = bool(argdict['hidelink']) @@ -86,6 +88,9 @@ def include_code(preprocessor, tag, markup): first_line, last_line = map(int, lines.split("-")) src = argdict['src'] + if not codec: + codec = 'utf-8' + if not src: raise ValueError("Error processing input, " "expected syntax: {0}".format(SYNTAX)) @@ -96,9 +101,6 @@ def include_code(preprocessor, tag, markup): if not os.path.exists(code_path): raise ValueError("File {0} could not be found".format(code_path)) - if not codec: - codec = 'utf-8' - with open(code_path, encoding=codec) as fh: if lines: code = fh.readlines()[first_line - 1: last_line] @@ -145,18 +147,11 @@ def include_code(preprocessor, tag, markup): else: lang_include = '' - if sys.version_info[0] < 3: - source = (open_tag - + '\n\n ' - + lang_include - + '\n '.join(code.decode(codec).split('\n')) + '\n\n' - + close_tag + '\n') - else: - source = (open_tag - + '\n\n ' - + lang_include - + '\n '.join(code.split('\n')) + '\n\n' - + close_tag + '\n') + source = (open_tag + + '\n\n ' + + lang_include + + '\n '.join(code.split('\n')) + '\n\n' + + close_tag + '\n') return source From ff414203c1926f17344d5ebee352a8c9b98dfcb5 Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Fri, 12 Jun 2020 20:44:49 +0200 Subject: [PATCH 09/15] liquid_tags: Updated expected results for include_code tests. Tests hadn't been updated after 076086cdc13. --- liquid_tags/test_include_code.py | 52 +++++++++++++++++++------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/liquid_tags/test_include_code.py b/liquid_tags/test_include_code.py index 2b0594a25..8af92e6bd 100644 --- a/liquid_tags/test_include_code.py +++ b/liquid_tags/test_include_code.py @@ -81,10 +81,11 @@ def __init__(self): 'test_data/main.c', ( '' - '
\n
' - 'main.c ' + '
\n' + '
' + 'main.c' 'download' - '\n' + '
\n' '\n' ' #include \n' ' \n' @@ -103,7 +104,7 @@ def __init__(self): 'test_data/main.c :hideall:', ( '' - '
\n
' + '
\n' '\n' '\n' ' #include \n' @@ -123,9 +124,11 @@ def __init__(self): 'test_data/main.c :hidefilename: C application', ( '' - '
\n
' + '
\n' + '
' + 'C application' 'download' - '\n' + '
\n' '\n' ' #include \n' ' \n' @@ -144,9 +147,10 @@ def __init__(self): 'test_data/main.c :hidelink:', ( '' - '
\n
' - 'main.c ' - '\n' + '
\n' + '
' + 'main.c' + '
\n' '\n' ' #include \n' ' \n' @@ -165,10 +169,11 @@ def __init__(self): 'test_data/main.c lang:c', ( '' - '
\n
' - 'main.c ' + '
\n' + '
' + 'main.c' 'download' - '\n' + '
\n' '\n' ' :::c\n' ' #include \n' @@ -188,10 +193,12 @@ def __init__(self): 'test_data/main.c lines:4-6', ( '' - '
\n
' - 'main.c [Lines 4-6] ' + '
\n' + '
' + 'main.c' + '[Lines 4-6]' 'download' - '\n' + '
\n' '\n' ' printf("Hello world!");\n' ' \n' @@ -205,10 +212,11 @@ def __init__(self): 'test_data/main_cz.c codec:iso-8859-1', ( '' - '
\n
' - 'main_cz.c ' + '
\n' + '
' + 'main_cz.c' 'download' - '\n' + '
\n' '\n' ' #include \n' ' \n' @@ -227,10 +235,12 @@ def __init__(self): 'test_data/main.c C Application', ( '' - '
\n
' - 'C Application main.c ' + '
\n' + '
' + 'C Application' + 'main.c' 'download' - '\n' + '
\n' '\n' ' #include \n' ' \n' From c067b3db90872d98f27c21c840dd6841bb69156a Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Fri, 12 Jun 2020 18:27:29 +0200 Subject: [PATCH 10/15] liquid_tags: Fixed deprecation warning occuring in test_generic. --- liquid_tags/mdx_liquid_tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/liquid_tags/mdx_liquid_tags.py b/liquid_tags/mdx_liquid_tags.py index f6c5c11e1..ca20514a4 100644 --- a/liquid_tags/mdx_liquid_tags.py +++ b/liquid_tags/mdx_liquid_tags.py @@ -78,7 +78,7 @@ def dec(func): return func return dec - def extendMarkdown(self, md, md_globals): + def extendMarkdown(self, md): self.htmlStash = md.htmlStash md.registerExtension(self) if 'include_code' in _LiquidTagsPreprocessor._tags: From dd14c7fab087456d40dbe3260d2db6aa43558b49 Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Sat, 13 Jun 2020 18:38:55 +0200 Subject: [PATCH 11/15] liquid_tags: Fixed include_code test to properly compare non utf-8 values. --- liquid_tags/test_include_code.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/liquid_tags/test_include_code.py b/liquid_tags/test_include_code.py index 8af92e6bd..b25190784 100644 --- a/liquid_tags/test_include_code.py +++ b/liquid_tags/test_include_code.py @@ -257,5 +257,13 @@ def __init__(self): ), ] ) + def test_create_html(input, expected): - assert include_code.include_code(preprocessor(), 'include_code', input) == expected + # output is returned as utf-8 + output = include_code.include_code(preprocessor(), 'include_code', input) + + # expected needs to be interpreted as utf-8 in python2 + if six.PY2: + expected = expected.decode('utf-8') + + assert output == expected From 9711b8ce2ad2eb722123a8b5670aac69c1e60584 Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Sat, 13 Jun 2020 20:27:45 +0200 Subject: [PATCH 12/15] liquid_tags: Fixed use of non-existent global variable. --- liquid_tags/notebook.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/liquid_tags/notebook.py b/liquid_tags/notebook.py index c310e6d5e..597755e63 100644 --- a/liquid_tags/notebook.py +++ b/liquid_tags/notebook.py @@ -283,8 +283,9 @@ def notebook(preprocessor, tag, markup): language_applied_highlighter = partial(custom_highlighter, language=language) + content_root = preprocessor.configs.getConfig('PATH', default='content') nb_dir = preprocessor.configs.getConfig('NOTEBOOK_DIR') - nb_path = os.path.join(settings.get('PATH', 'content'), nb_dir, src) + nb_path = os.path.join(content_root, nb_dir, src) if not os.path.exists(nb_path): raise ValueError("File {0} could not be found".format(nb_path)) From d8ab315ec3bd951829ca2bc26a18aff1002b711e Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Sat, 13 Jun 2020 19:57:54 +0200 Subject: [PATCH 13/15] liquid_tags: Consolidated tests for iPython2/iPython3 in test_generation. --- liquid_tags/test_generation.py | 88 ++++++++++++++-------------------- 1 file changed, 35 insertions(+), 53 deletions(-) diff --git a/liquid_tags/test_generation.py b/liquid_tags/test_generation.py index 169034ad2..42b81f2d1 100644 --- a/liquid_tags/test_generation.py +++ b/liquid_tags/test_generation.py @@ -2,6 +2,7 @@ from __future__ import print_function import filecmp +import logging import os import unittest from shutil import rmtree @@ -32,65 +33,46 @@ def tearDown(self): rmtree(self.temp_cache) os.chdir(PLUGIN_DIR) - @unittest.skipIf(IPYTHON_VERSION != 3, - reason="output must be created with ipython version 3") - def test_generate_with_ipython3(self): + @unittest.skipIf(IPYTHON_VERSION not in (2, 3), + reason="iPython v%d is not supported" % IPYTHON_VERSION) + def test_generate(self): '''Test generation of site with the plugin.''' - base_path = os.path.dirname(os.path.abspath(__file__)) - base_path = os.path.join(base_path, 'test_data') - content_path = os.path.join(base_path, 'content') - output_path = os.path.join(base_path, 'output') - settings_path = os.path.join(base_path, 'pelicanconf.py') - settings = read_settings(path=settings_path, - override={'PATH': content_path, - 'OUTPUT_PATH': self.temp_path, - 'CACHE_PATH': self.temp_cache, - } - ) - + # set paths + _pj = os.path.join + base_path = _pj(os.path.dirname(os.path.abspath(__file__)), 'test_data') + content_path = _pj(base_path, 'content') + output_path = _pj(base_path, 'output') + settings_path = _pj(base_path, 'pelicanconf.py') + + # read settings + override = { + 'PATH': content_path, + 'OUTPUT_PATH': self.temp_path, + 'CACHE_PATH': self.temp_cache, + } + settings = read_settings(path=settings_path, override=override) + + # run and test created files pelican = Pelican(settings) pelican.run() # test existence - assert os.path.exists(os.path.join(self.temp_path, - 'test-ipython-notebook-nb-format-3.html')) - assert os.path.exists(os.path.join(self.temp_path, - 'test-ipython-notebook-nb-format-4.html')) + assert os.path.exists(_pj(self.temp_path, + 'test-ipython-notebook-nb-format-3.html')) + assert os.path.exists(_pj(self.temp_path, + 'test-ipython-notebook-nb-format-4.html')) # test differences - #assert filecmp.cmp(os.path.join(output_path, - # 'test-ipython-notebook-v2.html'), - # os.path.join(self.temp_path, - # 'test-ipython-notebook.html')) - - @unittest.skipIf(IPYTHON_VERSION != 2, - reason="output must be created with ipython version 2") - def test_generate_with_ipython2(self): - '''Test generation of site with the plugin.''' - - base_path = os.path.dirname(os.path.abspath(__file__)) - base_path = os.path.join(base_path, 'test_data') - content_path = os.path.join(base_path, 'content') - settings_path = os.path.join(base_path, 'pelicanconf.py') - settings = read_settings(path=settings_path, - override={'PATH': content_path, - 'OUTPUT_PATH': self.temp_path, - 'CACHE_PATH': self.temp_cache, - } - ) - - pelican = Pelican(settings) - pelican.run() + if IPYTHON_VERSION == 3: + f1 = _pj(output_path, 'test-ipython-notebook-v2.html') + f2 = _pj(self.temp_path, 'test-ipython-notebook.html') + #assert filecmp.cmp(f1, f2) + elif IPYTHON_VERSION == 2: + f1 = _pj(output_path, 'test-ipython-notebook-v3.html') + f2 = _pj(self.temp_path, 'test-ipython-notebook.html') + #assert filecmp.cmp(f1, f2) + else: + logging.error('Unexpected IPYTHON_VERSION: %s', IPYTHON_VERSION) + assert False - # test existence - assert os.path.exists(os.path.join(self.temp_path, - 'test-ipython-notebook-nb-format-3.html')) - assert os.path.exists(os.path.join(self.temp_path, - 'test-ipython-notebook-nb-format-4.html')) - - # test differences - #assert filecmp.cmp(os.path.join(output_path, - # 'test-ipython-notebook-v3.html'), - # os.path.join(self.temp_path, - # 'test-ipython-notebook.html')) From fa9795ec3d1d4e2fc0bddeeda921d7b90ec521ec Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Sun, 14 Jun 2020 00:12:01 +0200 Subject: [PATCH 14/15] liquid_tags: Prepend SITEURL to src when it is an absolute path. This is useful when the live site is hosted in a subdirectory (e.g. http://www.foo.bar/mysite) to avoid having to repeat /mysite every time. --- liquid_tags/img.py | 21 +++++++++++++++------ liquid_tags/mdx_liquid_tags.py | 3 +++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/liquid_tags/img.py b/liquid_tags/img.py index 22d83e436..f38e2b052 100644 --- a/liquid_tags/img.py +++ b/liquid_tags/img.py @@ -22,6 +22,7 @@ [1] https://github.com/imathis/octopress/blob/master/plugins/image_tag.rb """ +import os import re from .mdx_liquid_tags import LiquidTags import six @@ -29,11 +30,13 @@ SYNTAX = '{% img [class name(s)] [http[s]:/]/path/to/image [width [height]] [title text | "title text" ["alt text"]] %}' # Regular expression to match the entire syntax -ReImg = re.compile("""(?P\S.*\s+)?(?P(?:https?:\/\/|\/|\S+\/)\S+)(?:\s+(?P\d+))?(?:\s+(?P\d+))?(?P\s+.+)?""") +ReImg = re.compile(r'(?P<class>[-\w\s]+\s+)?(?P<src>(?P<scheme>[a-zA-Z]+://)?(?P<path>\S+))(?:\s+(?P<width>\d+))?(?:\s+(?P<height>\d+))?(?P<title>\s+.+)?') # Regular expression to split the title and alt text ReTitleAlt = re.compile("""(?:"|')(?P<title>[^"']+)?(?:"|')\s+(?:"|')(?P<alt>[^"']+)?(?:"|')""") +# Attributes to keep in the emmitted img tag +IMG_ATTRS = ['class', 'src', 'width', 'height', 'title',] @LiquidTags.register('img') def img(preprocessor, tag, markup): @@ -42,8 +45,7 @@ def img(preprocessor, tag, markup): # Parse the markup string match = ReImg.search(markup) if match: - attrs = dict([(key, val.strip()) - for (key, val) in six.iteritems(match.groupdict()) if val]) + attrs = {k: v.strip() for k, v in match.groupdict().items() if v} else: raise ValueError('Error processing input. ' 'Expected syntax: {0}'.format(SYNTAX)) @@ -56,9 +58,16 @@ def img(preprocessor, tag, markup): if not attrs.get('alt'): attrs['alt'] = attrs['title'] - # Return the formatted text - return "<img {0}>".format(' '.join('{0}="{1}"'.format(key, val) - for (key, val) in six.iteritems(attrs))) + # prepend site url to absolute paths + if 'scheme' not in attrs and os.path.isabs(attrs['src']): + siteurl = preprocessor.configs.getConfig('SITEURL') + attrs['src'] = siteurl + attrs['path'] + + # create tag + img_attrs = ['{0!s}={1!r}'.format(k, attrs[k]) + for k in IMG_ATTRS if attrs.get(k)] + s = "<img {0}>".format(' '.join(img_attrs)) + return s #---------------------------------------------------------------------- # This import allows image tag to be a Pelican plugin diff --git a/liquid_tags/mdx_liquid_tags.py b/liquid_tags/mdx_liquid_tags.py index ca20514a4..a7e97e97e 100644 --- a/liquid_tags/mdx_liquid_tags.py +++ b/liquid_tags/mdx_liquid_tags.py @@ -21,12 +21,15 @@ 'FLICKR_API_KEY': 'flickr', 'GIPHY_API_KEY': 'giphy', 'LT_DELIMITERS': ('{%', '%}'), + 'SITEURL': '', } LT_HELP = { 'CODE_DIR' : 'Code directory for include_code subplugin', 'NOTEBOOK_DIR' : 'Notebook directory for notebook subplugin', 'FLICKR_API_KEY': 'Flickr key for accessing the API', 'GIPHY_API_KEY': 'Giphy key for accessing the API', 'LT_DELIMITERS': 'Alternative set of Liquid Tags block delimiters', + 'SITEURL': 'Base URL of your web site. ' + 'Inserted before absolute media paths.', } class _LiquidTagsPreprocessor(markdown.preprocessors.Preprocessor): From 06bc3b0feb1d8e116464ac758e9739f00b9d98c0 Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis <mstamat@gmail.com> Date: Sun, 14 Jun 2020 01:15:23 +0200 Subject: [PATCH 15/15] liquid_tags: Added documentation for custom tag delimiters. --- liquid_tags/Readme.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/liquid_tags/Readme.md b/liquid_tags/Readme.md index 6616c91b1..bf27b5e2a 100644 --- a/liquid_tags/Readme.md +++ b/liquid_tags/Readme.md @@ -258,8 +258,10 @@ comment line `# <!-- collapse=False -->` will be expanded on load but can be collapsed by tapping on their header. Cells without collapsed comments are rendered as standard code input cells. -## Configuration settings in custom tags +## Advanced features + +### Configuration settings in custom tags Tags do not have access to the full Pelicans settings, and instead arrange for the variables to be passed to the tag. For tag authors who plan to add their tag as in-tree tags, they can just add the variables they need to an array in @@ -269,6 +271,15 @@ user's `pelicanconf.py` settings: LIQUID_CONFIGS = (('PATH', '.', "The default path"), ('SITENAME', 'Default Sitename', 'The name of the site')) +### Custom delimiters +If you are using Liquid Tags in conjunction with some other plugin that also +uses the `{%` and `%}` delimiters to mark its blocks, then chaos will occur. +You can avoid the chaos by defining an alternative set of delimiters for +Liquid Tags. Just add them as a tuple in your `pelicanconf.py` settings: + + LT_DELIMITERS = ('<+', '+>') + + ## Testing To test the plugin in multiple environments we use [tox](http://tox.readthedocs.org/en/latest/). To run the entire test suite: