From 9124074d6200c4023b8bf8203b34adfd9031c926 Mon Sep 17 00:00:00 2001 From: Ben Date: Thu, 10 Dec 2020 20:43:58 +0100 Subject: [PATCH 1/3] feat(multiple includes): add support for multiple includes on single line - added tests to verify changes --- README.md | 5 +++ markdown_include/include.py | 15 ++++----- unittests/resources/header.md | 3 ++ unittests/resources/simple.md | 1 + unittests/resources/simple_2.md | 1 + unittests/test_include.py | 45 +++++++++++++++++++++++++ unittests/test_include_header_indent.py | 45 +++++++++++++++++++++++++ 7 files changed, 107 insertions(+), 8 deletions(-) create mode 100644 unittests/resources/header.md create mode 100644 unittests/resources/simple.md create mode 100644 unittests/resources/simple_2.md create mode 100644 unittests/test_include.py create mode 100644 unittests/test_include_header_indent.py diff --git a/README.md b/README.md index ea9cc54..e502205 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,11 @@ This module can now be installed using ``pip``. pip install markdown-include +## Tests +Use the unittest module +```bash +python -m unittest discover unittests/ +``` ## Usage This module can be used in a program in the following way: diff --git a/markdown_include/include.py b/markdown_include/include.py index 5463cd5..0022faa 100644 --- a/markdown_include/include.py +++ b/markdown_include/include.py @@ -82,7 +82,7 @@ def run(self, lines): for loc, line in enumerate(lines): m = INC_SYNTAX.search(line) - if m: + while m: filename = m.group(1) filename = os.path.expanduser(filename) if not os.path.isabs(filename): @@ -102,7 +102,6 @@ def run(self, lines): else: raise e - line_split = INC_SYNTAX.split(line) if len(text) == 0: text.append('') for i in range(len(text)): @@ -116,12 +115,12 @@ def run(self, lines): text[i] = '#' * self.headingOffset + text[i] else: text[i] = text[i].rstrip('\r\n') - - text[0] = line_split[0] + text[0] - text[-1] = text[-1] + line_split[2] - lines = lines[:loc] + text + lines[loc+1:] - break - + text_to_insert = '\r\n'.join(text) + line = line[:m.start()] + text_to_insert.strip() + line[m.end():] + lines[loc] = line + + m = INC_SYNTAX.search(line) + else: h = HEADING_SYNTAX.search(line) if h: diff --git a/unittests/resources/header.md b/unittests/resources/header.md new file mode 100644 index 0000000..d5d88ac --- /dev/null +++ b/unittests/resources/header.md @@ -0,0 +1,3 @@ +# This heading will be one level deeper from the previous heading +More included file content. +End of included content. diff --git a/unittests/resources/simple.md b/unittests/resources/simple.md new file mode 100644 index 0000000..9bfaa99 --- /dev/null +++ b/unittests/resources/simple.md @@ -0,0 +1 @@ +This is a simple template diff --git a/unittests/resources/simple_2.md b/unittests/resources/simple_2.md new file mode 100644 index 0000000..951e815 --- /dev/null +++ b/unittests/resources/simple_2.md @@ -0,0 +1 @@ +This is another simple template diff --git a/unittests/test_include.py b/unittests/test_include.py new file mode 100644 index 0000000..62bb6c7 --- /dev/null +++ b/unittests/test_include.py @@ -0,0 +1,45 @@ +import os +from unittest import TestCase + +import markdown + +from markdown_include.include import MarkdownInclude + + +class TestInclude(TestCase): + def setUp(self) -> None: + self.maxDiff = None + self.markdown_include = MarkdownInclude( + configs={'base_path': os.path.dirname(os.path.realpath(__file__))} + ) + + def test_single_include(self): + source = "{!resources/simple.md!}" + html = markdown.markdown(source, extensions=[self.markdown_include]) + + self.assertEqual(html, '

This is a simple template

') + + def test_double_include(self): + source = "{!resources/simple.md!} and {!resources/simple_2.md!}" + html = markdown.markdown(source, extensions=[self.markdown_include]) + + self.assertEqual(html, '

This is a simple template and This is another simple template

') + + def test_headers(self): + source = "Source file\n" \ + "# Heading Level 1 of main file\n" \ + "{!resources/header.md!}\n" \ + "## Heading Level 2 of main file\n" \ + "{!resources/header.md!}" + + html = markdown.markdown(source, extensions=[self.markdown_include]) + + self.assertEqual(html, "

Source file

\n" + "

Heading Level 1 of main file

\n" + "

This heading will be one level deeper from the previous heading

\n" + "

More included file content.\n" + "End of included content.

\n" + "

Heading Level 2 of main file

\n" + "

This heading will be one level deeper from the previous heading

\n" + "

More included file content.\n" + "End of included content.

") diff --git a/unittests/test_include_header_indent.py b/unittests/test_include_header_indent.py new file mode 100644 index 0000000..35f651d --- /dev/null +++ b/unittests/test_include_header_indent.py @@ -0,0 +1,45 @@ +import os +from unittest import TestCase + +import markdown + +from markdown_include.include import MarkdownInclude + + +class TestInclude(TestCase): + def setUp(self) -> None: + self.maxDiff = None + self.markdown_include = MarkdownInclude( + configs={'base_path': os.path.dirname(os.path.realpath(__file__)), 'inheritHeadingDepth': True} + ) + + def test_single_include(self): + source = "{!resources/simple.md!}" + html = markdown.markdown(source, extensions=[self.markdown_include]) + + self.assertEqual(html, '

This is a simple template

') + + def test_double_include(self): + source = "{!resources/simple.md!} and {!resources/simple_2.md!}" + html = markdown.markdown(source, extensions=[self.markdown_include]) + + self.assertEqual(html, '

This is a simple template and This is another simple template

') + + def test_headers(self): + source = "Source file\n" \ + "# Heading Level 1 of main file\n" \ + "{!resources/header.md!}\n" \ + "## Heading Level 2 of main file\n" \ + "{!resources/header.md!}" + + html = markdown.markdown(source, extensions=[self.markdown_include]) + + self.assertEqual(html, "

Source file

\n" + "

Heading Level 1 of main file

\n" + "

This heading will be one level deeper from the previous heading

\n" + "

More included file content.

\n" + "

End of included content.

\n" + "

Heading Level 2 of main file

\n" + "

This heading will be one level deeper from the previous heading

\n" + "

More included file content.

\n" + "

End of included content.

") From 68de05db7b06d0ed15b3f5df20632769b1630a12 Mon Sep 17 00:00:00 2001 From: Ben Date: Thu, 10 Dec 2020 20:57:44 +0100 Subject: [PATCH 2/3] feat(multiple includes): ensure lines are modified correctly --- markdown_include/include.py | 4 ++-- unittests/test_lines.py | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 unittests/test_lines.py diff --git a/markdown_include/include.py b/markdown_include/include.py index 0022faa..2d922c6 100644 --- a/markdown_include/include.py +++ b/markdown_include/include.py @@ -117,8 +117,8 @@ def run(self, lines): text[i] = text[i].rstrip('\r\n') text_to_insert = '\r\n'.join(text) line = line[:m.start()] + text_to_insert.strip() + line[m.end():] - lines[loc] = line - + del lines[loc] + lines[loc:loc] = line.split('\r\n') m = INC_SYNTAX.search(line) else: diff --git a/unittests/test_lines.py b/unittests/test_lines.py new file mode 100644 index 0000000..a97f1fe --- /dev/null +++ b/unittests/test_lines.py @@ -0,0 +1,26 @@ +import os +from unittest import TestCase + +from markdown_include.include import IncludePreprocessor + + +class TestProcessor(TestCase): + def setUp(self) -> None: + self.maxDiff = None + self.processor = IncludePreprocessor(None, { + "base_path": os.path.dirname(os.path.realpath(__file__)), + "encoding": "utf-8", + "inheritHeadingDepth": False, + "headingOffset": 0, + "throwException": False, + }) + + def test_lines(self): + source = ["Source file", + "# Heading Level 1 of main file", + "{!resources/header.md!}", + "## Heading Level 2 of main file", + "{!resources/header.md!}"] + result_lines = self.processor.run(source) + + self.assertEqual(9, len(result_lines)) From 4007bf3bf46dab74f1a32214ee87632e5d11db38 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 15 Dec 2020 15:15:41 +0100 Subject: [PATCH 3/3] feat(embedded templates): fixed issue when using templates inside templates --- markdown_include/include.py | 2 +- unittests/resources/template_inside.md | 3 +++ unittests/test_embedded.py | 20 ++++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 unittests/resources/template_inside.md create mode 100644 unittests/test_embedded.py diff --git a/markdown_include/include.py b/markdown_include/include.py index 2d922c6..4b53db5 100644 --- a/markdown_include/include.py +++ b/markdown_include/include.py @@ -91,7 +91,7 @@ def run(self, lines): ) try: with open(filename, 'r', encoding=self.encoding) as r: - text = r.readlines() + text = self.run(r.readlines()) except Exception as e: if not self.throwException: diff --git a/unittests/resources/template_inside.md b/unittests/resources/template_inside.md new file mode 100644 index 0000000..a20a14c --- /dev/null +++ b/unittests/resources/template_inside.md @@ -0,0 +1,3 @@ +{!resources/simple.md!} + +This is a template with a template. diff --git a/unittests/test_embedded.py b/unittests/test_embedded.py new file mode 100644 index 0000000..a5e7d94 --- /dev/null +++ b/unittests/test_embedded.py @@ -0,0 +1,20 @@ +import os +from unittest import TestCase + +import markdown + +from markdown_include.include import IncludePreprocessor, MarkdownInclude + + +class TestEmbedded(TestCase): + def setUp(self) -> None: + self.maxDiff = None + self.markdown_include = MarkdownInclude( + configs={'base_path': os.path.dirname(os.path.realpath(__file__))} + ) + + def test_embedded_template(self): + source = "{!resources/template_inside.md!}" + html = markdown.markdown(source, extensions=[self.markdown_include]) + + self.assertEqual(html, "

This is a simple template

\n

This is a template with a template.

")