From f1339cb20d7688325b63c2186148123d60b9e5d7 Mon Sep 17 00:00:00 2001 From: courtneycb Date: Mon, 21 Oct 2019 13:50:47 +1300 Subject: [PATCH 01/26] WIP. --- verto/html-templates/external-link.html | 1 + verto/processors/ExternalLinkPattern.py | 49 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 verto/html-templates/external-link.html create mode 100644 verto/processors/ExternalLinkPattern.py diff --git a/verto/html-templates/external-link.html b/verto/html-templates/external-link.html new file mode 100644 index 00000000..1c7d83a0 --- /dev/null +++ b/verto/html-templates/external-link.html @@ -0,0 +1 @@ +{{ text }} diff --git a/verto/processors/ExternalLinkPattern.py b/verto/processors/ExternalLinkPattern.py new file mode 100644 index 00000000..e1bf3b6c --- /dev/null +++ b/verto/processors/ExternalLinkPattern.py @@ -0,0 +1,49 @@ +from verto.utils.HtmlParser import HtmlParser +from markdown.inlinepatterns import Pattern +from html import escape +import re + + +class ExternalLinkPattern(Pattern): + '''Return a link element from the given match. + + Only matches: + - Markdown links using []() syntax. + - Links that start with: + - http: + - https: + - ftp: + - ftps: + - mailto: + - news: + ''' + + def __init__(self, ext, *args, **kwargs): + ''' + Args: + ext: An instance of the Markdown class. + ''' + self.processor = 'relative-link' + self.pattern = ext.processor_info[self.processor]['pattern'] + self.compiled_re = re.compile('^(.*?){}(.*)$'.format(self.pattern), re.DOTALL | re.UNICODE) + self.template = ext.jinja_templates[self.processor] + + def handleMatch(self, match): + ''' Inherited from Pattern. Accepts a match and returns an + ElementTree element of a internal link. + Args: + match: The string of text where the match was found. + Returns: + An element tree node to be appended to the html tree. + ''' + context = dict() + context['link_path'] = escape(match.group('link_url')) + link_query = match.group('link_query') + if link_query: + context['link_query'] = link_query + context['text'] = match.group('link_text') + + html_string = self.template.render(context) + parser = HtmlParser() + parser.feed(html_string).close() + return parser.get_root() From fa2a081171987fd1dccfb313b69b43df9a49dfa2 Mon Sep 17 00:00:00 2001 From: courtneycb Date: Wed, 23 Oct 2019 13:08:17 +1300 Subject: [PATCH 02/26] Add external link processor and tests. --- verto/Verto.py | 1 + verto/VertoExtension.py | 2 + verto/html-templates/external-link.html | 2 +- verto/processor-info.json | 4 + verto/processors/ExternalLinkPattern.py | 4 +- verto/tests/ExternalLinkTest.py | 218 ++++++++++++++++++ .../tests/assets/external-link/ftp_schema.md | 1 + .../external-link/ftp_schema_expected.html | 1 + verto/tests/assets/external-link/ftp_text.md | 1 + .../external-link/ftp_text_expected.html | 1 + .../tests/assets/external-link/ftps_schema.md | 1 + .../external-link/ftps_schema_expected.html | 1 + verto/tests/assets/external-link/ftps_text.md | 1 + .../external-link/ftps_text_expected.html | 1 + .../tests/assets/external-link/http_schema.md | 1 + .../external-link/http_schema_expected.html | 1 + verto/tests/assets/external-link/http_text.md | 1 + .../external-link/http_text_expected.html | 1 + .../assets/external-link/https_schema.md | 1 + .../external-link/https_schema_expected.html | 1 + .../tests/assets/external-link/https_text.md | 1 + .../external-link/https_text_expected.html | 1 + verto/tests/assets/external-link/long_path.md | 1 + .../external-link/long_path_expected.html | 1 + .../assets/external-link/mailto_schema.md | 1 + .../external-link/mailto_schema_expected.html | 1 + .../tests/assets/external-link/mailto_text.md | 1 + .../external-link/mailto_text_expected.html | 1 + .../assets/external-link/multiple_links.md | 3 + .../multiple_links_expected.html | 2 + .../multiple_query_parameters.md | 1 + .../multiple_query_parameters_expected.html | 1 + .../tests/assets/external-link/news_schema.md | 1 + .../external-link/news_schema_expected.html | 1 + verto/tests/assets/external-link/news_text.md | 1 + .../external-link/news_text_expected.html | 1 + .../assets/external-link/query_parameter.md | 1 + .../query_parameter_expected.html | 1 + .../external-link/trailing_question_mark.md | 1 + .../trailing_question_mark_expected.html | 1 + verto/tests/assets/external-link/www_text.md | 1 + .../external-link/www_text_expected.html | 1 + verto/tests/start_tests.py | 2 + 43 files changed, 269 insertions(+), 3 deletions(-) create mode 100644 verto/tests/ExternalLinkTest.py create mode 100644 verto/tests/assets/external-link/ftp_schema.md create mode 100644 verto/tests/assets/external-link/ftp_schema_expected.html create mode 100644 verto/tests/assets/external-link/ftp_text.md create mode 100644 verto/tests/assets/external-link/ftp_text_expected.html create mode 100644 verto/tests/assets/external-link/ftps_schema.md create mode 100644 verto/tests/assets/external-link/ftps_schema_expected.html create mode 100644 verto/tests/assets/external-link/ftps_text.md create mode 100644 verto/tests/assets/external-link/ftps_text_expected.html create mode 100644 verto/tests/assets/external-link/http_schema.md create mode 100644 verto/tests/assets/external-link/http_schema_expected.html create mode 100644 verto/tests/assets/external-link/http_text.md create mode 100644 verto/tests/assets/external-link/http_text_expected.html create mode 100644 verto/tests/assets/external-link/https_schema.md create mode 100644 verto/tests/assets/external-link/https_schema_expected.html create mode 100644 verto/tests/assets/external-link/https_text.md create mode 100644 verto/tests/assets/external-link/https_text_expected.html create mode 100644 verto/tests/assets/external-link/long_path.md create mode 100644 verto/tests/assets/external-link/long_path_expected.html create mode 100644 verto/tests/assets/external-link/mailto_schema.md create mode 100644 verto/tests/assets/external-link/mailto_schema_expected.html create mode 100644 verto/tests/assets/external-link/mailto_text.md create mode 100644 verto/tests/assets/external-link/mailto_text_expected.html create mode 100644 verto/tests/assets/external-link/multiple_links.md create mode 100644 verto/tests/assets/external-link/multiple_links_expected.html create mode 100644 verto/tests/assets/external-link/multiple_query_parameters.md create mode 100644 verto/tests/assets/external-link/multiple_query_parameters_expected.html create mode 100644 verto/tests/assets/external-link/news_schema.md create mode 100644 verto/tests/assets/external-link/news_schema_expected.html create mode 100644 verto/tests/assets/external-link/news_text.md create mode 100644 verto/tests/assets/external-link/news_text_expected.html create mode 100644 verto/tests/assets/external-link/query_parameter.md create mode 100644 verto/tests/assets/external-link/query_parameter_expected.html create mode 100644 verto/tests/assets/external-link/trailing_question_mark.md create mode 100644 verto/tests/assets/external-link/trailing_question_mark_expected.html create mode 100644 verto/tests/assets/external-link/www_text.md create mode 100644 verto/tests/assets/external-link/www_text_expected.html diff --git a/verto/Verto.py b/verto/Verto.py index a9027650..ccf9d3fe 100644 --- a/verto/Verto.py +++ b/verto/Verto.py @@ -7,6 +7,7 @@ 'button-link', 'comment', 'conditional', + 'external-link', 'glossary-link', 'style', 'heading', diff --git a/verto/VertoExtension.py b/verto/VertoExtension.py index d15dadac..353fb741 100644 --- a/verto/VertoExtension.py +++ b/verto/VertoExtension.py @@ -10,6 +10,7 @@ from verto.processors.InteractiveTagBlockProcessor import InteractiveTagBlockProcessor from verto.processors.InteractiveContainerBlockProcessor import InteractiveContainerBlockProcessor from verto.processors.RelativeLinkPattern import RelativeLinkPattern +from verto.processors.ExternalLinkPattern import ExternalLinkPattern from verto.processors.RemoveTitlePreprocessor import RemoveTitlePreprocessor from verto.processors.SaveTitlePreprocessor import SaveTitlePreprocessor from verto.processors.GlossaryLinkPattern import GlossaryLinkPattern @@ -192,6 +193,7 @@ def buildProcessors(self, md, md_globals): ] self.inlinepatterns = [ # A special treeprocessor ['relative-link', RelativeLinkPattern(self, md), '_begin'], + ['external-link', ExternalLinkPattern(self, md), '_begin'], ['glossary-link', GlossaryLinkPattern(self, md), '_begin'], ['image-inline', ImageInlinePattern(self, md), '_begin'] ] diff --git a/verto/html-templates/external-link.html b/verto/html-templates/external-link.html index 1c7d83a0..066d2822 100644 --- a/verto/html-templates/external-link.html +++ b/verto/html-templates/external-link.html @@ -1 +1 @@ -{{ text }} +{{ text }} diff --git a/verto/processor-info.json b/verto/processor-info.json index ec7fce7c..36fbaf62 100644 --- a/verto/processor-info.json +++ b/verto/processor-info.json @@ -519,5 +519,9 @@ "argument": "title" } } + }, + "external-link": { + "class": "custom", + "pattern": "\\[(?P[^\\]]+)\\]\\((?=(https?|ftps?|mailto|news):)(?P[^\\?\\)]+)(?P\\?[^\\)]*)?\\)" } } diff --git a/verto/processors/ExternalLinkPattern.py b/verto/processors/ExternalLinkPattern.py index e1bf3b6c..4295f8c3 100644 --- a/verto/processors/ExternalLinkPattern.py +++ b/verto/processors/ExternalLinkPattern.py @@ -23,14 +23,14 @@ def __init__(self, ext, *args, **kwargs): Args: ext: An instance of the Markdown class. ''' - self.processor = 'relative-link' + self.processor = 'external-link' self.pattern = ext.processor_info[self.processor]['pattern'] self.compiled_re = re.compile('^(.*?){}(.*)$'.format(self.pattern), re.DOTALL | re.UNICODE) self.template = ext.jinja_templates[self.processor] def handleMatch(self, match): ''' Inherited from Pattern. Accepts a match and returns an - ElementTree element of a internal link. + ElementTree element of an external link. Args: match: The string of text where the match was found. Returns: diff --git a/verto/tests/ExternalLinkTest.py b/verto/tests/ExternalLinkTest.py new file mode 100644 index 00000000..8f300e5d --- /dev/null +++ b/verto/tests/ExternalLinkTest.py @@ -0,0 +1,218 @@ +import markdown +import re +from unittest.mock import Mock +from verto.processors.ExternalLinkPattern import ExternalLinkPattern +from verto.tests.ProcessorTest import ProcessorTest + + +class ExternalLinkTest(ProcessorTest): + '''Tests to check the 'external-link' pattern works as intended. + This class is unique to other processors as it overrides + default markdown behaviour in certain situations. + ''' + + def __init__(self, *args, **kwargs): + '''Set processor name in class for asset file retrieval.''' + ProcessorTest.__init__(self, *args, **kwargs) + self.processor_name = 'external-link' + self.ext = Mock() + self.ext.processor_info = ProcessorTest.loadProcessorInfo(self) + self.ext.jinja_templates = {self.processor_name: ProcessorTest.loadJinjaTemplate(self, self.processor_name)} + + def test_ignore_http_schema(self): + '''Tests that external links starting with http are matched.''' + test_string = self.read_test_file(self.processor_name, 'http_schema.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNotNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'http_schema_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_http_text(self): + '''Tests that relative links are not matched.''' + test_string = self.read_test_file(self.processor_name, 'http_text.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'http_text_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_https_schema(self): + '''Tests that external links starting with https are matched.''' + test_string = self.read_test_file(self.processor_name, 'https_schema.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNotNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'https_schema_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_ignore_https_text(self): + '''Tests that relative links are not matched.''' + test_string = self.read_test_file(self.processor_name, 'https_text.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'https_text_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_ftp_schema(self): + '''Tests that external links starting with ftp are matched.''' + test_string = self.read_test_file(self.processor_name, 'ftp_schema.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNotNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'ftp_schema_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_ignore_ftp_text(self): + '''Tests that relative links are not matched.''' + test_string = self.read_test_file(self.processor_name, 'ftp_text.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'ftp_text_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_ftps_schema(self): + '''Tests that external links starting with ftps are matched.''' + test_string = self.read_test_file(self.processor_name, 'ftps_schema.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNotNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'ftps_schema_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_ignore_ftps_text(self): + '''Tests that relative links are not matched.''' + test_string = self.read_test_file(self.processor_name, 'ftps_text.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'ftps_text_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_mailto_schema(self): + '''Tests that external links starting with mailto are matched.''' + test_string = self.read_test_file(self.processor_name, 'mailto_schema.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNotNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'mailto_schema_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_ignore_mailto_text(self): + '''Tests that relative links are not matched.''' + test_string = self.read_test_file(self.processor_name, 'mailto_text.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'mailto_text_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_news_schema(self): + '''Tests that external links starting with news are matched.''' + test_string = self.read_test_file(self.processor_name, 'news_schema.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNotNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'news_schema_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_ignore_news_text(self): + '''Tests that relative links are not matched.''' + test_string = self.read_test_file(self.processor_name, 'news_text.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'news_text_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_ignore_www_text(self): + '''Tests that links similar to a match are not matched.''' + test_string = self.read_test_file(self.processor_name, 'www_text.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'www_text_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_long_path(self): + '''Tests that long paths with less than 31 characters work.''' + test_string = self.read_test_file(self.processor_name, 'long_path.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNotNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'long_path_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_query_parameter(self): + '''Tests that paths with query parameter work.''' + test_string = self.read_test_file(self.processor_name, 'query_parameter.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNotNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'query_parameter_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_multiple_query_parameters(self): + '''Tests that paths with multiple query parameters work.''' + test_string = self.read_test_file(self.processor_name, 'multiple_query_parameters.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNotNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'multiple_query_parameters_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_trailing_question_mark(self): + '''Tests paths with trailing question marks.''' + test_string = self.read_test_file(self.processor_name, 'trailing_question_mark.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNotNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'trailing_question_mark_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) + + def test_multiple_links(self): + '''Tests that multiple links are processed.''' + test_string = self.read_test_file(self.processor_name, 'multiple_links.md') + + processor = ExternalLinkPattern(self.ext, self.md.parser) + self.assertIsNotNone(re.search(processor.compiled_re, test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + expected_string = self.read_test_file(self.processor_name, 'multiple_links_expected.html', strip=True).strip() + self.assertEqual(expected_string, converted_test_string) diff --git a/verto/tests/assets/external-link/ftp_schema.md b/verto/tests/assets/external-link/ftp_schema.md new file mode 100644 index 00000000..e5cebfe2 --- /dev/null +++ b/verto/tests/assets/external-link/ftp_schema.md @@ -0,0 +1 @@ +Check out this [website](ftp://ftp.fakesite.org:21). diff --git a/verto/tests/assets/external-link/ftp_schema_expected.html b/verto/tests/assets/external-link/ftp_schema_expected.html new file mode 100644 index 00000000..35c3a1e5 --- /dev/null +++ b/verto/tests/assets/external-link/ftp_schema_expected.html @@ -0,0 +1 @@ +

Check out this website.

diff --git a/verto/tests/assets/external-link/ftp_text.md b/verto/tests/assets/external-link/ftp_text.md new file mode 100644 index 00000000..a8ccbd27 --- /dev/null +++ b/verto/tests/assets/external-link/ftp_text.md @@ -0,0 +1 @@ +Check out this [item](ftp/item.html). diff --git a/verto/tests/assets/external-link/ftp_text_expected.html b/verto/tests/assets/external-link/ftp_text_expected.html new file mode 100644 index 00000000..d15f1f10 --- /dev/null +++ b/verto/tests/assets/external-link/ftp_text_expected.html @@ -0,0 +1 @@ +

Check out this item.

diff --git a/verto/tests/assets/external-link/ftps_schema.md b/verto/tests/assets/external-link/ftps_schema.md new file mode 100644 index 00000000..ec6b87e0 --- /dev/null +++ b/verto/tests/assets/external-link/ftps_schema.md @@ -0,0 +1 @@ +Check out this [website](ftps://ftp.fakesite.org:21). diff --git a/verto/tests/assets/external-link/ftps_schema_expected.html b/verto/tests/assets/external-link/ftps_schema_expected.html new file mode 100644 index 00000000..2311d14c --- /dev/null +++ b/verto/tests/assets/external-link/ftps_schema_expected.html @@ -0,0 +1 @@ +

Check out this website.

diff --git a/verto/tests/assets/external-link/ftps_text.md b/verto/tests/assets/external-link/ftps_text.md new file mode 100644 index 00000000..e9232b23 --- /dev/null +++ b/verto/tests/assets/external-link/ftps_text.md @@ -0,0 +1 @@ +Check out this [item](ftps/item.html). diff --git a/verto/tests/assets/external-link/ftps_text_expected.html b/verto/tests/assets/external-link/ftps_text_expected.html new file mode 100644 index 00000000..03d5fea4 --- /dev/null +++ b/verto/tests/assets/external-link/ftps_text_expected.html @@ -0,0 +1 @@ +

Check out this item.

diff --git a/verto/tests/assets/external-link/http_schema.md b/verto/tests/assets/external-link/http_schema.md new file mode 100644 index 00000000..3ed44eb8 --- /dev/null +++ b/verto/tests/assets/external-link/http_schema.md @@ -0,0 +1 @@ +Check out this [website](http://www.google.com). diff --git a/verto/tests/assets/external-link/http_schema_expected.html b/verto/tests/assets/external-link/http_schema_expected.html new file mode 100644 index 00000000..6c05a4fc --- /dev/null +++ b/verto/tests/assets/external-link/http_schema_expected.html @@ -0,0 +1 @@ +

Check out this website.

diff --git a/verto/tests/assets/external-link/http_text.md b/verto/tests/assets/external-link/http_text.md new file mode 100644 index 00000000..d037e73b --- /dev/null +++ b/verto/tests/assets/external-link/http_text.md @@ -0,0 +1 @@ +Check out this [website](http.html). diff --git a/verto/tests/assets/external-link/http_text_expected.html b/verto/tests/assets/external-link/http_text_expected.html new file mode 100644 index 00000000..bba3c72a --- /dev/null +++ b/verto/tests/assets/external-link/http_text_expected.html @@ -0,0 +1 @@ +

Check out this website.

diff --git a/verto/tests/assets/external-link/https_schema.md b/verto/tests/assets/external-link/https_schema.md new file mode 100644 index 00000000..4ab347cd --- /dev/null +++ b/verto/tests/assets/external-link/https_schema.md @@ -0,0 +1 @@ +Check out this [website](https://www.google.com). diff --git a/verto/tests/assets/external-link/https_schema_expected.html b/verto/tests/assets/external-link/https_schema_expected.html new file mode 100644 index 00000000..0ceb6ec1 --- /dev/null +++ b/verto/tests/assets/external-link/https_schema_expected.html @@ -0,0 +1 @@ +

Check out this website.

diff --git a/verto/tests/assets/external-link/https_text.md b/verto/tests/assets/external-link/https_text.md new file mode 100644 index 00000000..a765c853 --- /dev/null +++ b/verto/tests/assets/external-link/https_text.md @@ -0,0 +1 @@ +Check out this [website](https.html). diff --git a/verto/tests/assets/external-link/https_text_expected.html b/verto/tests/assets/external-link/https_text_expected.html new file mode 100644 index 00000000..4aaeb2a5 --- /dev/null +++ b/verto/tests/assets/external-link/https_text_expected.html @@ -0,0 +1 @@ +

Check out this website.

diff --git a/verto/tests/assets/external-link/long_path.md b/verto/tests/assets/external-link/long_path.md new file mode 100644 index 00000000..d207ec83 --- /dev/null +++ b/verto/tests/assets/external-link/long_path.md @@ -0,0 +1 @@ +Check out this [website](https://www.google.com/binary/). diff --git a/verto/tests/assets/external-link/long_path_expected.html b/verto/tests/assets/external-link/long_path_expected.html new file mode 100644 index 00000000..604683c0 --- /dev/null +++ b/verto/tests/assets/external-link/long_path_expected.html @@ -0,0 +1 @@ +

Check out this website.

diff --git a/verto/tests/assets/external-link/mailto_schema.md b/verto/tests/assets/external-link/mailto_schema.md new file mode 100644 index 00000000..99995c79 --- /dev/null +++ b/verto/tests/assets/external-link/mailto_schema.md @@ -0,0 +1 @@ +Check out this [email](mailto:bob@example.com). diff --git a/verto/tests/assets/external-link/mailto_schema_expected.html b/verto/tests/assets/external-link/mailto_schema_expected.html new file mode 100644 index 00000000..addf2e32 --- /dev/null +++ b/verto/tests/assets/external-link/mailto_schema_expected.html @@ -0,0 +1 @@ +

Check out this email.

diff --git a/verto/tests/assets/external-link/mailto_text.md b/verto/tests/assets/external-link/mailto_text.md new file mode 100644 index 00000000..21e15145 --- /dev/null +++ b/verto/tests/assets/external-link/mailto_text.md @@ -0,0 +1 @@ +Check out this [page](mailto.html). diff --git a/verto/tests/assets/external-link/mailto_text_expected.html b/verto/tests/assets/external-link/mailto_text_expected.html new file mode 100644 index 00000000..602ff641 --- /dev/null +++ b/verto/tests/assets/external-link/mailto_text_expected.html @@ -0,0 +1 @@ +

Check out this page.

diff --git a/verto/tests/assets/external-link/multiple_links.md b/verto/tests/assets/external-link/multiple_links.md new file mode 100644 index 00000000..7cf3680c --- /dev/null +++ b/verto/tests/assets/external-link/multiple_links.md @@ -0,0 +1,3 @@ +This is the [first link](https://www.link1.com) and this is the [second link](https://www.link2.com). + +This is the [third link](https://www.link3.com). diff --git a/verto/tests/assets/external-link/multiple_links_expected.html b/verto/tests/assets/external-link/multiple_links_expected.html new file mode 100644 index 00000000..1b533e1d --- /dev/null +++ b/verto/tests/assets/external-link/multiple_links_expected.html @@ -0,0 +1,2 @@ +

This is the first link and this is the second link.

+

This is the third link.

diff --git a/verto/tests/assets/external-link/multiple_query_parameters.md b/verto/tests/assets/external-link/multiple_query_parameters.md new file mode 100644 index 00000000..a8509eea --- /dev/null +++ b/verto/tests/assets/external-link/multiple_query_parameters.md @@ -0,0 +1 @@ +Check out this [website](https://www.google.com?key1=value1&key2=value2). diff --git a/verto/tests/assets/external-link/multiple_query_parameters_expected.html b/verto/tests/assets/external-link/multiple_query_parameters_expected.html new file mode 100644 index 00000000..40337762 --- /dev/null +++ b/verto/tests/assets/external-link/multiple_query_parameters_expected.html @@ -0,0 +1 @@ +

Check out this website.

diff --git a/verto/tests/assets/external-link/news_schema.md b/verto/tests/assets/external-link/news_schema.md new file mode 100644 index 00000000..20a0c03a --- /dev/null +++ b/verto/tests/assets/external-link/news_schema.md @@ -0,0 +1 @@ +Check out this [news](news://feed.news.com). diff --git a/verto/tests/assets/external-link/news_schema_expected.html b/verto/tests/assets/external-link/news_schema_expected.html new file mode 100644 index 00000000..a10dc67c --- /dev/null +++ b/verto/tests/assets/external-link/news_schema_expected.html @@ -0,0 +1 @@ +

Check out this news.

diff --git a/verto/tests/assets/external-link/news_text.md b/verto/tests/assets/external-link/news_text.md new file mode 100644 index 00000000..0e47d0d9 --- /dev/null +++ b/verto/tests/assets/external-link/news_text.md @@ -0,0 +1 @@ +Check out this [news](news). diff --git a/verto/tests/assets/external-link/news_text_expected.html b/verto/tests/assets/external-link/news_text_expected.html new file mode 100644 index 00000000..a6635548 --- /dev/null +++ b/verto/tests/assets/external-link/news_text_expected.html @@ -0,0 +1 @@ +

Check out this news.

diff --git a/verto/tests/assets/external-link/query_parameter.md b/verto/tests/assets/external-link/query_parameter.md new file mode 100644 index 00000000..4a486141 --- /dev/null +++ b/verto/tests/assets/external-link/query_parameter.md @@ -0,0 +1 @@ +Check out this [website](https://www.google.com?key=value). diff --git a/verto/tests/assets/external-link/query_parameter_expected.html b/verto/tests/assets/external-link/query_parameter_expected.html new file mode 100644 index 00000000..b9d472c7 --- /dev/null +++ b/verto/tests/assets/external-link/query_parameter_expected.html @@ -0,0 +1 @@ +

Check out this website.

diff --git a/verto/tests/assets/external-link/trailing_question_mark.md b/verto/tests/assets/external-link/trailing_question_mark.md new file mode 100644 index 00000000..b45b94b1 --- /dev/null +++ b/verto/tests/assets/external-link/trailing_question_mark.md @@ -0,0 +1 @@ +Check out this [website](https://www.google.com?). diff --git a/verto/tests/assets/external-link/trailing_question_mark_expected.html b/verto/tests/assets/external-link/trailing_question_mark_expected.html new file mode 100644 index 00000000..f0b143b3 --- /dev/null +++ b/verto/tests/assets/external-link/trailing_question_mark_expected.html @@ -0,0 +1 @@ +

Check out this website.

diff --git a/verto/tests/assets/external-link/www_text.md b/verto/tests/assets/external-link/www_text.md new file mode 100644 index 00000000..6ddd498c --- /dev/null +++ b/verto/tests/assets/external-link/www_text.md @@ -0,0 +1 @@ +Check out this [website](www.google.com). diff --git a/verto/tests/assets/external-link/www_text_expected.html b/verto/tests/assets/external-link/www_text_expected.html new file mode 100644 index 00000000..5c832bf4 --- /dev/null +++ b/verto/tests/assets/external-link/www_text_expected.html @@ -0,0 +1 @@ +

Check out this website.

diff --git a/verto/tests/start_tests.py b/verto/tests/start_tests.py index 9f8374e0..8417f4a2 100644 --- a/verto/tests/start_tests.py +++ b/verto/tests/start_tests.py @@ -19,6 +19,7 @@ from verto.tests.InteractiveContainerTest import InteractiveContainerTest from verto.tests.PanelTest import PanelTest from verto.tests.RelativeLinkTest import RelativeLinkTest +from verto.tests.ExternalLinkTest import ExternalLinkTest from verto.tests.RemoveTest import RemoveTest from verto.tests.RemoveTitleTest import RemoveTitleTest from verto.tests.SaveTitleTest import SaveTitleTest @@ -107,6 +108,7 @@ def unit_suite(): unittest.makeSuite(ScratchInlineTest), unittest.makeSuite(StyleTest), unittest.makeSuite(RelativeLinkTest), + unittest.makeSuite(ExternalLinkTest), unittest.makeSuite(RemoveTest), unittest.makeSuite(RemoveTitleTest), unittest.makeSuite(TableOfContentsTest), From 4a135e9ef40310bbe1273918d6fd687ea0bc2424 Mon Sep 17 00:00:00 2001 From: courtneycb Date: Wed, 23 Oct 2019 13:33:10 +1300 Subject: [PATCH 03/26] Add basic documentation. --- docs/source/processors/external-link.rst | 22 ++++++++++++++++++++++ docs/source/processors/index.rst | 1 + 2 files changed, 23 insertions(+) create mode 100644 docs/source/processors/external-link.rst diff --git a/docs/source/processors/external-link.rst b/docs/source/processors/external-link.rst new file mode 100644 index 00000000..64d6531d --- /dev/null +++ b/docs/source/processors/external-link.rst @@ -0,0 +1,22 @@ +External Link +####################################### + +**Processor name:** ``external-link`` + +This processor will find any external links (links that start with ``http:``, ``https:``, ``mailto:``, etc.), and will create a HTML link with the ``target`` attribute set to ``"_blank"``. +This allows external links in Markdown to be opened in a new tab. + +The default HTML for external links is: + +.. literalinclude:: ../../../verto/html-templates/external-link.html + :language: css+jinja + +Using the following example tag: + +.. literalinclude:: ../../../verto/tests/assets/external-link/https_schema.md + :language: none + +The resulting HTML would be: + +.. literalinclude:: ../../../verto/tests/assets/external-link/https_schema_expected.html + :language: html diff --git a/docs/source/processors/index.rst b/docs/source/processors/index.rst index 87d30205..4b172187 100644 --- a/docs/source/processors/index.rst +++ b/docs/source/processors/index.rst @@ -18,6 +18,7 @@ The following pages covers how to use the available processors within Markdown t button-link comment conditional + external-link iframe glossary-link heading From cf1e130bc7fd8e5d461a5aa7fa5912d278398cc4 Mon Sep 17 00:00:00 2001 From: courtneycb Date: Wed, 23 Oct 2019 13:49:37 +1300 Subject: [PATCH 04/26] Change custom_settings parameter to settings. --- verto/Verto.py | 8 ++++---- verto/VertoExtension.py | 6 +++--- verto/tests/BlockquoteTest.py | 8 ++++---- verto/tests/BoxedTextTest.py | 10 +++++----- verto/tests/ButtonLinkTest.py | 10 +++++----- verto/tests/ConfigurationTest.py | 10 +++++----- verto/tests/FrameTest.py | 2 +- verto/tests/GlossaryLinkTest.py | 2 +- verto/tests/ImageContainerTest.py | 8 ++++---- verto/tests/ImageInlineTest.py | 8 ++++---- verto/tests/ImageTagTest.py | 8 ++++---- verto/tests/InteractiveContainerTest.py | 12 ++++++------ verto/tests/InteractiveTagTest.py | 10 +++++----- verto/tests/PanelTest.py | 8 ++++---- verto/tests/VideoTest.py | 4 ++-- 15 files changed, 57 insertions(+), 57 deletions(-) diff --git a/verto/Verto.py b/verto/Verto.py index a9027650..b02acb3f 100644 --- a/verto/Verto.py +++ b/verto/Verto.py @@ -31,7 +31,7 @@ class Verto(object): to HTML. ''' - def __init__(self, processors=DEFAULT_PROCESSORS, html_templates={}, extensions=[], custom_settings={}): + def __init__(self, processors=DEFAULT_PROCESSORS, html_templates={}, extensions=[], settings={}): '''Creates a Verto object. Args: @@ -45,12 +45,12 @@ def __init__(self, processors=DEFAULT_PROCESSORS, html_templates={}, extensions= eg: {'image': ''} extensions: A list of extra extensions to run on the markdown package. - custom_settings: A dictionary of settings to override default settings. + settings: A dictionary of settings to override default settings. ''' self.processors = set(processors) self.html_templates = dict(html_templates) self.extensions = list(extensions) - self.custom_settings = custom_settings + self.settings = settings self.create_converter() def create_converter(self): @@ -59,7 +59,7 @@ def create_converter(self): processors=self.processors, html_templates=self.html_templates, extensions=self.extensions, - custom_settings=self.custom_settings, + settings=self.settings, ) all_extensions = self.extensions + [self.verto_extension] self.converter = markdown.Markdown(extensions=all_extensions) diff --git a/verto/VertoExtension.py b/verto/VertoExtension.py index d15dadac..f7f8abc4 100644 --- a/verto/VertoExtension.py +++ b/verto/VertoExtension.py @@ -50,7 +50,7 @@ class VertoExtension(Extension): the Verto converter. ''' - def __init__(self, processors=[], html_templates={}, extensions=[], custom_settings={}, *args, **kwargs): + def __init__(self, processors=[], html_templates={}, extensions=[], settings={}, *args, **kwargs): ''' Args: processors: A set of processor names given as strings for which @@ -62,12 +62,12 @@ def __init__(self, processors=[], html_templates={}, extensions=[], custom_setti as values. eg: {'image': ''} extensions: A list of extra extensions for compatibility. - custom_settings: A dictionary of user settings to override defaults. + settings: A dictionary of user settings to override defaults. ''' super().__init__(*args, **kwargs) self.jinja_templates = self.loadJinjaTemplates(html_templates) self.processors = processors - self.settings = self.get_settings(custom_settings) + self.settings = self.get_settings(settings) self.processor_info = self.loadProcessorInfo() self.title = None self.heading_tree = None diff --git a/verto/tests/BlockquoteTest.py b/verto/tests/BlockquoteTest.py index 6a03cbd7..2cf4f2aa 100644 --- a/verto/tests/BlockquoteTest.py +++ b/verto/tests/BlockquoteTest.py @@ -187,7 +187,7 @@ def test_custom_arguments_source_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'source_true.md') @@ -211,7 +211,7 @@ def test_custom_arguments_source_true_missing_argument(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'source_true_missing_argument.md') @@ -233,7 +233,7 @@ def test_custom_arguments_alignment_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'alignment_true.md') @@ -257,7 +257,7 @@ def test_custom_arguments_alignment_true_missing_argument(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'alignment_true_missing_argument.md') diff --git a/verto/tests/BoxedTextTest.py b/verto/tests/BoxedTextTest.py index 5fb2556e..f8b22c82 100644 --- a/verto/tests/BoxedTextTest.py +++ b/verto/tests/BoxedTextTest.py @@ -132,7 +132,7 @@ def test_custom_arguments_indented_required(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'indented_required.md') @@ -156,7 +156,7 @@ def test_custom_arguments_type_required(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'type_required.md') @@ -181,7 +181,7 @@ def test_custom_arguments_indented_and_type_required(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'indented_and_type_required.md') @@ -205,7 +205,7 @@ def test_custom_arguments_indented_required_not_provided(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'indented_required_not_provided.md') @@ -228,7 +228,7 @@ def test_custom_arguments_indented_and_type_required_type_not_provided(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'indented_and_type_required_type_not_provided.md') diff --git a/verto/tests/ButtonLinkTest.py b/verto/tests/ButtonLinkTest.py index 3b8302cb..1fd1f6c9 100644 --- a/verto/tests/ButtonLinkTest.py +++ b/verto/tests/ButtonLinkTest.py @@ -97,7 +97,7 @@ def test_custom_arguments_link_false(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'link_false.md') @@ -121,7 +121,7 @@ def test_custom_arguments_text_false(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'text_false.md') @@ -145,7 +145,7 @@ def test_custom_arguments_file_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'file_true.md') @@ -170,7 +170,7 @@ def test_custom_arguments_text_false_file_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'text_false_file_true.md') @@ -194,7 +194,7 @@ def test_custom_arguments_file_true_not_provided(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'file_true_not_provided.md') diff --git a/verto/tests/ConfigurationTest.py b/verto/tests/ConfigurationTest.py index 53e89f10..43092c48 100644 --- a/verto/tests/ConfigurationTest.py +++ b/verto/tests/ConfigurationTest.py @@ -376,7 +376,7 @@ def test_custom_arguments_rules_on_creation(self): } } } - verto = Verto(custom_settings=settings) + verto = Verto(settings=settings) self.assertEqual( verto.verto_extension.settings['processor_argument_overrides'], dict(settings['processor_argument_overrides']) @@ -395,7 +395,7 @@ def test_custom_argument_rules_for_multiple_tags(self): }, } } - verto = Verto(custom_settings=settings) + verto = Verto(settings=settings) self.assertEqual( verto.verto_extension.settings['processor_argument_overrides'], dict(settings['processor_argument_overrides']) @@ -419,7 +419,7 @@ def test_custom_argument_rules_for_multiple_tags_error(self): } } processors = {'image-tag', 'panel', 'comment'} - verto = VertoExtension(processors=processors, custom_settings=settings) + verto = VertoExtension(processors=processors, settings=settings) test_string = self.read_test_file(self.test_name, 'custom_argument_rules_multiple_tags_error.md') self.assertRaises(ArgumentMissingError, lambda x: markdown.markdown(x, extensions=[verto]), test_string) @@ -441,7 +441,7 @@ def test_custom_argument_rules_incorrect_processor_error(self): self.assertRaises( CustomArgumentRulesError, - lambda: VertoExtension(processors=processors, custom_settings=settings) + lambda: VertoExtension(processors=processors, settings=settings) ) def test_custom_argument_rules_incorrect_processor_argument_error(self): @@ -461,5 +461,5 @@ def test_custom_argument_rules_incorrect_processor_argument_error(self): self.assertRaises( CustomArgumentRulesError, - lambda: VertoExtension(processors=processors, custom_settings=settings) + lambda: VertoExtension(processors=processors, settings=settings) ) diff --git a/verto/tests/FrameTest.py b/verto/tests/FrameTest.py index 561eb419..3ee70f10 100644 --- a/verto/tests/FrameTest.py +++ b/verto/tests/FrameTest.py @@ -60,7 +60,7 @@ def test_custom_argument_rules_link_false(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'link_false.md') diff --git a/verto/tests/GlossaryLinkTest.py b/verto/tests/GlossaryLinkTest.py index 740228bc..32285edc 100644 --- a/verto/tests/GlossaryLinkTest.py +++ b/verto/tests/GlossaryLinkTest.py @@ -207,7 +207,7 @@ def test_custom_arguments_reference_text_true_not_provided(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'reference_text_true_not_provided.md') diff --git a/verto/tests/ImageContainerTest.py b/verto/tests/ImageContainerTest.py index e61c7843..b349bee5 100644 --- a/verto/tests/ImageContainerTest.py +++ b/verto/tests/ImageContainerTest.py @@ -460,7 +460,7 @@ def test_custom_arguments_alt_false(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'alt_false.md') @@ -490,7 +490,7 @@ def test_custom_arguments_hover_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'hover_true.md') @@ -521,7 +521,7 @@ def test_custom_arguments_alt_false_source_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'alt_false_source_true.md') @@ -551,7 +551,7 @@ def test_custom_arguments_hover_true_not_provided(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'hover_true_not_provided.md') diff --git a/verto/tests/ImageInlineTest.py b/verto/tests/ImageInlineTest.py index 827b649b..3aadf577 100644 --- a/verto/tests/ImageInlineTest.py +++ b/verto/tests/ImageInlineTest.py @@ -333,7 +333,7 @@ def test_custom_arguments_alt_false(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'alt_false.md') @@ -362,7 +362,7 @@ def test_custom_arguments_hover_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) @@ -393,7 +393,7 @@ def test_custom_arguments_alt_false_source_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'alt_false_source_true.md') @@ -422,7 +422,7 @@ def test_custom_arguments_hover_true_not_provided(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'hover_true_not_provided.md') diff --git a/verto/tests/ImageTagTest.py b/verto/tests/ImageTagTest.py index ed0deb64..00cc9c3a 100644 --- a/verto/tests/ImageTagTest.py +++ b/verto/tests/ImageTagTest.py @@ -401,7 +401,7 @@ def test_custom_arguments_alt_false(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'alt_false.md') @@ -431,7 +431,7 @@ def test_custom_arguments_hover_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'hover_true.md') @@ -462,7 +462,7 @@ def test_custom_arguments_alt_false_source_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'alt_false_source_true.md') @@ -493,7 +493,7 @@ def test_custom_arguments_hover_true_not_provided(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'hover_true_not_provided.md') diff --git a/verto/tests/InteractiveContainerTest.py b/verto/tests/InteractiveContainerTest.py index f601afa7..78f69fd6 100644 --- a/verto/tests/InteractiveContainerTest.py +++ b/verto/tests/InteractiveContainerTest.py @@ -327,7 +327,7 @@ def test_custom_arguments_parameters_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'parameters_true.md') @@ -351,7 +351,7 @@ def test_custom_arguments_thumbnail_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'thumbnail_true.md') @@ -375,7 +375,7 @@ def test_custom_arguments_text_true_not_provided(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'text_true_not_provided.md') @@ -398,7 +398,7 @@ def test_custom_arguments_parameters_and_thumbnail_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'parameters_and_thumbnail_true.md') @@ -426,7 +426,7 @@ def test_default_thumbnail_not_in_required_files_with_override(self): '''Test the thumbnail for a whole page interactive is not required when overriden.''' verto_extension_default_thumbnail_override = VertoExtension( processors=[self.processor_name], - custom_settings={ + settings={ 'add_default_interactive_thumbnails_to_required_files': False} ) test_string = self.read_test_file(self.processor_name, 'whole_page_without_thumbnail_parameter.md') @@ -452,7 +452,7 @@ def test_custom_thumbnail_not_in_required_files_with_override(self): '''Test the custom thumbnail for a whole page interactive is not required when overriden.''' verto_extension_custom_thumbnail_override = VertoExtension( processors=[self.processor_name], - custom_settings={ + settings={ 'add_custom_interactive_thumbnails_to_required_files': False} ) test_string = self.read_test_file(self.processor_name, 'whole_page_with_thumbnail_parameter.md') diff --git a/verto/tests/InteractiveTagTest.py b/verto/tests/InteractiveTagTest.py index fc5e5b5f..2fd2cbd5 100644 --- a/verto/tests/InteractiveTagTest.py +++ b/verto/tests/InteractiveTagTest.py @@ -145,7 +145,7 @@ def test_default_thumbnail_not_in_required_files_with_override(self): '''Test the thumbnail for a whole page interactive is not required when overriden.''' verto_extension_default_thumbnail_override = VertoExtension( processors=[self.processor_name], - custom_settings={'add_default_interactive_thumbnails_to_required_files': False} + settings={'add_default_interactive_thumbnails_to_required_files': False} ) test_string = self.read_test_file(self.processor_name, 'whole_page_without_thumbnail_parameter.md') converted_test_string = markdown.markdown(test_string, extensions=[verto_extension_default_thumbnail_override]) @@ -170,7 +170,7 @@ def test_custom_thumbnail_not_in_required_files_with_override(self): '''Test the custom thumbnail for a whole page interactive is not required when overriden.''' verto_extension_custom_thumbnail_override = VertoExtension( processors=[self.processor_name], - custom_settings={'add_custom_interactive_thumbnails_to_required_files': False} + settings={'add_custom_interactive_thumbnails_to_required_files': False} ) test_string = self.read_test_file(self.processor_name, 'whole_page_with_thumbnail_parameter.md') converted_test_string = markdown.markdown(test_string, extensions=[verto_extension_custom_thumbnail_override]) @@ -191,7 +191,7 @@ def test_custom_arguments_parameters_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'parameters_true.md') @@ -215,7 +215,7 @@ def test_custom_arguments_thumbnail_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) @@ -241,7 +241,7 @@ def test_custom_arguments_parameters_and_thumbnail_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'parameters_and_thumbnail_true.md') diff --git a/verto/tests/PanelTest.py b/verto/tests/PanelTest.py index 6463ee67..9ca77847 100644 --- a/verto/tests/PanelTest.py +++ b/verto/tests/PanelTest.py @@ -380,7 +380,7 @@ def test_custom_arguments_type_false(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'type_false.md') @@ -404,7 +404,7 @@ def test_custom_arguments_subtitle_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'subtitle_true.md') @@ -428,7 +428,7 @@ def test_custom_arguments_expanded_true(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'expanded_true.md') @@ -452,7 +452,7 @@ def test_custom_arguments_subtitle_true_not_provided(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'subtitle_true_not_provided.md') diff --git a/verto/tests/VideoTest.py b/verto/tests/VideoTest.py index 426c1675..7354eb56 100644 --- a/verto/tests/VideoTest.py +++ b/verto/tests/VideoTest.py @@ -198,7 +198,7 @@ def test_url_false_custom_argument_rules(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'url_false.md') @@ -222,7 +222,7 @@ def test_custom_argument_rules_title_true_not_provided(self): } verto_extension_custom_rules = VertoExtension( processors=[self.processor_name], - custom_settings=settings + settings=settings ) test_string = self.read_test_file(self.processor_name, 'title_true_not_provided.md') From 8e3ae68432240173e65369500e1d5278472513f9 Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Thu, 20 May 2021 12:37:11 +1200 Subject: [PATCH 05/26] Update dependencies --- requirements-dev.txt | 10 +++++----- requirements.txt | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 7d4e370c..5afa740c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,5 +1,5 @@ -setuptools==41.0.1 -sphinx==1.8.1 -sphinx_rtd_theme==0.4.3 -coverage==4.5.3 -flake8==3.5.0 +setuptools==53.0.0 +sphinx==3.4.3 +sphinx_rtd_theme==0.5.1 +coverage==5.4 +flake8==3.8.4 diff --git a/requirements.txt b/requirements.txt index 1730a8be..3ff25dcf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ markdown==2.6.11 -Jinja2==2.10.1 -python-slugify==3.0.2 +Jinja2==2.11.3 +python-slugify==4.0.1 From 27ced4f29fd7f08af3b3898ded31acd08f77165d Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Thu, 20 May 2021 12:46:04 +1200 Subject: [PATCH 06/26] Switch to dependabot --- .github/dependabot.yml | 15 +++++++++++++++ .pyup.yml | 3 --- 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 .github/dependabot.yml delete mode 100644 .pyup.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..d4f5c62d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.pyup.yml b/.pyup.yml deleted file mode 100644 index 357fb976..00000000 --- a/.pyup.yml +++ /dev/null @@ -1,3 +0,0 @@ -update: all -branch: develop -label_prs: update From a38fb9405b54acd2590303a6ffbfdea8ef0d61bf Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Thu, 20 May 2021 13:46:27 +1200 Subject: [PATCH 07/26] Update dependencies --- requirements-dev.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 5afa740c..810e86d3 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,5 +1,5 @@ -setuptools==53.0.0 -sphinx==3.4.3 -sphinx_rtd_theme==0.5.1 -coverage==5.4 +setuptools==56.2.0 +sphinx==4.0.1 +sphinx_rtd_theme==0.5.2 +coverage==5.5 flake8==3.8.4 From 7bafeb77ad868f1783d122d16b70e6e263c268a2 Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Thu, 20 May 2021 14:21:53 +1200 Subject: [PATCH 08/26] Style fixes --- verto/processors/StylePreprocessor.py | 6 ++--- verto/processors/VideoBlockProcessor.py | 2 +- verto/processors/utils.py | 4 ++-- verto/utils/UniqueSlugify.py | 30 ++++++++++++------------- verto/utils/overrides.py | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/verto/processors/StylePreprocessor.py b/verto/processors/StylePreprocessor.py index bd7da521..8c1f7b6c 100644 --- a/verto/processors/StylePreprocessor.py +++ b/verto/processors/StylePreprocessor.py @@ -24,7 +24,7 @@ def __init__(self, ext, *args, **kwargs): self.block_strings = ext.processor_info[self.processor]['strings']['block'] self.inline_strings = ext.processor_info[self.processor]['strings']['inline'] - self.LIST_RE = re.compile('^[ ]*(\d+\.|[*+-])[ ]+(.*)') + self.LIST_RE = re.compile(r'^[ ]*(\d+\.|[*+-])[ ]+(.*)') def run(self, lines): ''' @@ -52,9 +52,9 @@ def run(self, lines): if (self.LIST_RE.match(line[:start_index]) and not all(map(lambda char: char.isspace(), line[end_index+1:]))): - raise StyleError(line_nums, error_lines, 'Content after block in list.') + raise StyleError(line_nums, error_lines, 'Content after block in list.') elif (not self.LIST_RE.match(line[:start_index]) and not all(map(lambda char: char.isspace(), rest))): - raise StyleError(line_nums, error_lines, 'Blocks must be the only thing on the line.') + raise StyleError(line_nums, error_lines, 'Blocks must be the only thing on the line.') return lines diff --git a/verto/processors/VideoBlockProcessor.py b/verto/processors/VideoBlockProcessor.py index e60d4c76..6c1b6c2a 100644 --- a/verto/processors/VideoBlockProcessor.py +++ b/verto/processors/VideoBlockProcessor.py @@ -87,7 +87,7 @@ def extract_video_identifier(self, video_url): A tuple of the service and video identifier. ''' - if re.match('.*?youtu\.{0,1}be(.com){0,1}', video_url) is not None: # is a youtube url + if re.match(r'.*?youtu\.{0,1}be(.com){0,1}', video_url) is not None: # is a youtube url video_url = re.sub(r'(.*?)(\?rel=0)', r'\g<1>', video_url) if 'youtu.be' in video_url or 'youtube.com/embed' in video_url: video_query = video_url.split('/')[-1] diff --git a/verto/processors/utils.py b/verto/processors/utils.py index 347c0341..28fe4230 100644 --- a/verto/processors/utils.py +++ b/verto/processors/utils.py @@ -77,8 +77,8 @@ def parse_arguments(processor, inputs, arguments): for other_argument in dependencies: if (parse_argument(other_argument, inputs, None) is None and parse_flag(other_argument, inputs, None) is None): - message = '{} is a required argument because {} exists.'.format(other_argument, argument) - raise ArgumentMissingError(processor, argument, message) + message = '{} is a required argument because {} exists.'.format(other_argument, argument) + raise ArgumentMissingError(processor, argument, message) if is_arg: value = parse_argument(argument, inputs, None) diff --git a/verto/utils/UniqueSlugify.py b/verto/utils/UniqueSlugify.py index 12179a0a..94f1e257 100644 --- a/verto/utils/UniqueSlugify.py +++ b/verto/utils/UniqueSlugify.py @@ -10,21 +10,21 @@ class UniqueSlugify(object): def __init__(self, uids=set(), occurance_separator='-', entities=True, decimal=True, hexadecimal=True, max_length=0, word_boundary=False, separator='-', save_order=False, stopwords=()): - ''' - Args: - uids: A set of strings which are already taken as slugs. - Others: Passed directly to slugify. - ''' - self.uids = set(uids) - self.occurance_separator = str(occurance_separator) - self.entities = bool(entities) - self.decimal = bool(decimal) - self.hexadecimal = bool(hexadecimal) - self.max_length = int(max_length) - self.word_boundary = bool(word_boundary) - self.separator = str(separator) - self.save_order = bool(save_order) - self.stopwords = tuple(stopwords) + ''' + Args: + uids: A set of strings which are already taken as slugs. + Others: Passed directly to slugify. + ''' + self.uids = set(uids) + self.occurance_separator = str(occurance_separator) + self.entities = bool(entities) + self.decimal = bool(decimal) + self.hexadecimal = bool(hexadecimal) + self.max_length = int(max_length) + self.word_boundary = bool(word_boundary) + self.separator = str(separator) + self.save_order = bool(save_order) + self.stopwords = tuple(stopwords) def __call__(self, text): ''' diff --git a/verto/utils/overrides.py b/verto/utils/overrides.py index b07e771a..becd06c8 100644 --- a/verto/utils/overrides.py +++ b/verto/utils/overrides.py @@ -150,7 +150,7 @@ def get_items(self, blocks): match = self.CHILD_RE.match(line) if match is not None: if not item_groups and self.TAG == 'ol': - INTEGER_RE = re.compile('(\d+)') + INTEGER_RE = re.compile(r'(\d+)') self.STARTSWITH = INTEGER_RE.match(match.group(1)).group() item_groups.append([match.group(3)]) elif (self.INDENT_RE.match(line) and not self.INDENT_CONT_RE.match(item_groups[-1][-1])): From 1825dc71346d12cbdb68e3709ef50c96933ef59c Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Fri, 21 May 2021 14:34:49 +1200 Subject: [PATCH 09/26] Modify Scratch processors to use JS library This removes the image method previously used, along with the random and split options. --- docs/source/images/scratch_blocks_example.png | Bin 29441 -> 105207 bytes docs/source/images/scratch_inline_example.png | Bin 2492 -> 20560 bytes docs/source/processors/scratch-inline.rst | 20 +- docs/source/processors/scratch.rst | 76 ++----- verto/html-templates/scratch-inline.html | 2 +- verto/html-templates/scratch.html | 7 +- verto/processor-info.json | 2 +- .../processors/ScratchInlineTreeprocessor.py | 7 +- verto/processors/ScratchTreeprocessor.py | 57 ++---- verto/tests/ConfigurationTest.py | 24 --- verto/tests/InteractiveContainerTest.py | 12 -- verto/tests/InteractiveTagTest.py | 6 - verto/tests/ScratchInlineTest.py | 63 ------ verto/tests/ScratchTest.py | 190 ------------------ .../all_processors_custom_html_expected.html | 17 +- ...ll_processors_except_comment_expected.html | 17 +- .../all_processors_expected.html | 17 +- .../multiline_templates_expected.html | 17 +- .../doc_example_basic_usage_expected.html | 2 +- .../doc_example_override_html_expected.html | 2 +- .../doc_example_override_html_template.html | 2 +- .../mixed_codeblocks_expected.html | 2 +- .../multiple_codeblocks_expected.html | 2 +- .../doc_example_basic_usage_expected.html | 15 +- .../doc_example_override_html_expected.html | 7 +- .../doc_example_override_html_template.html | 8 +- .../example_multiple_codeblocks_expected.html | 31 +-- ...xample_multiple_codeblocks_expected_2.html | 31 +-- .../scratch/example_other_code_expected.html | 15 +- .../scratch/example_random_codeblocks.md | 23 --- .../example_random_split_codeblocks.md | 23 --- .../example_separate_blocks_expected.html | 17 +- .../scratch/example_split_codeblocks.md | 23 --- .../example_split_codeblocks_default.md | 22 -- .../example_split_codeblocks_expected.html | 9 - ...mple_standard_markdown_block_expected.html | 17 +- 36 files changed, 187 insertions(+), 598 deletions(-) delete mode 100644 verto/tests/assets/scratch/example_random_codeblocks.md delete mode 100644 verto/tests/assets/scratch/example_random_split_codeblocks.md delete mode 100644 verto/tests/assets/scratch/example_split_codeblocks.md delete mode 100644 verto/tests/assets/scratch/example_split_codeblocks_default.md delete mode 100644 verto/tests/assets/scratch/example_split_codeblocks_expected.html diff --git a/docs/source/images/scratch_blocks_example.png b/docs/source/images/scratch_blocks_example.png index 60b005d0f79f74a3545346062a6d2f9c38344992..94719a95d04139d7d6f082463696efe3e0418620 100644 GIT binary patch literal 105207 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 literal 29441 zcmZs?WmH^U&?btzdvJG&5L_CkvEZ)3-5PgyYk~xqh7cTry9D<}gF_%daCex_`_0Un zyVm{DfBLLbdzaT!RVPMOMGhN-90Lvx4jU*htqunVZwvdqK|_K4qop^O1P4b82b7l3 z^fo@qMfE3=c^nFAZ`PURphK2CRX&K7Cnh2)S@AnHG9mtX(X7L{M2w7#e-Mg>h6YW+ zDg1V8$g}d2|J8+VSCX4$ZcMLr)QKDoTKo1z5o#z6Qd?>^O}xS zB2B9dZO_LM7r?Ed@$0wYkS#CeGaV0rO{gww7J26Nk2jUqxrX8blIpCk78$&3Fn$?+ z$mfyy-%Za|b)>df`2Cv3v#E%Sl4`9^1aoi8Fa**B^x!p#DW7l0N$0jtM@rdM1@oSe zD2KZ#?;|s_mRh|@&ytCI$_9+fph4x8Ihqb^6^#l@L7k;F9OXlQ>NVaW#KSST7$g1F zgtnKOP*+Ft)0AR7#0eM+>w?o1<)z2Jzb_aLW=Dtx$#xOUsnc_(*CV7I8C+bd&+vX@ zOL;HX#e?(xV9G{Nb4Pj^A)!IbrXV;<1yAKNr(Q0tWG!c<{&IWoMc3OH=~pl8q#m?6 zx)A-0tH~s%Ot^KIs!`jvvDmq^;+a|`R_b63oly4FQ>L<5`5bX$$PU!uf5t!m}r7|5I&|~rR&HxK_do~RU1pAEcBGNHE}g#qL-8zb_v*0zeLus z3aUPY$!9O-0@KK1BPI?qYY|I=bVbQRFmnKnjLL4~(ZIa2i!9grcn({!uhPTs@qfg{ zw(3q=t5YOkSL2!~mcwZgbE5QK7cMvjC6!2#8+@yOc#n{f9c%(F<%ct05t(pZeq{PZ zi1JG-XO#ByP2fy+aNeMDG3a;-BBQB-NsK~n#8Gbgj=WaBKF8O#=W2~5Tg6;Y5oSQN zs_2?*2Sy*9gD}X~UM)ssb}L6!%E0_~%=J!^pQ|Am!yxf2f-U9b!l<&pcn&=d%!dG~ zg-YXiz$~5WcZgSj+o2J=v$tA`C@`7QdgmyZUYOij=(ot@1c!av2f%JTo*AH4Vu^NH zrGs~K;P`OzhqtEyObKrhh|x5Yud0)rbIULWy@-G1N~^y~mfum@acDQ)J+fa-rikCf zf^$aV-7yi(8KWlh2N#1$dUAdK&TRCLgz=YS$YYqgb4(B4 z-1l2o=I@-IJBY(P%4Qi!f${lt{85uDM>RS}hC*|MMAgl>lB-8tUwF{F@0~mbdWZ43 zn7qbI2zij50?j`BDi{SBhijGkGWI*oQ7bfG>X+ERdo`fvq+Jbpm4!M)Y;%Xx>mi;* zZgK|jCEAO4|NMn@&i-|AwSiA7jdm1Jh&ar9=z2=JQr_`>r2(yW;q8C6WzF=wRaGv_ z9)2{5Xkpzm<2(38;c!moea{Hn+j0@1Fg_c? z^TFUsTIHX3Ko!0X5%@*Je$cL}WK?#DL!V3&r-~TSP&K)ibZTpIM@GquS=+~7>a>S( zZCbQvataNJIz*Pv)>*8r^e&4-U*vCW#lhCKCuJ(Av(Sp=GZHyA?D2u^Aa9Gn11m70 zX`vqHwk3Ohf9XLa8rUXg`@{VmLP8jzM^Py3a#PCu#%IO?EXL!1Wcp7Z0E9iR1Co9k z8Sm_nr4JQOdEHC2x^;Vm*cV!PH%E#)Yl6i z2jvy&oM~($r$?OE06yyKryr-bpHmu4jDC84M&f2gfaf_l^=K8KZJDglh>R;Fql>)P ziqwI!ym}KpL`z3EiLe%(UVZ>RMtnK`2{YO~i2?UBmq7y zH#b055`r+7H(4oj0&wYtvE|~-a6@KoQhu1jLl>q(xjAu;S-KFVqzNu=Yb1|k7VG5O zvYv-Mt&zB;5wsNAo_~66u`9`}ukYIU9Uo4k$e0eb_fOxa*QmMJV1wx1MIU}Z9!l@P zG6!)m8v3GoPEp1cv?SVydXjrib)e7z*A8xl#mOSLn*%X>@j{IWIO`wlx&*lF0=4Z;6do=;Kq{2PKIG4>R z;qPDi4RC*UojS?%F*O(KodT7hq}wKx_8%BjmH+X0ADsO?IyyN)Z3GSYH>5bOwD9nF zV{7xs5C4~s0KG6y@n_}(c={69qw0-txsGj4Mec%fSv!ekqM~~)cti5-xDDZvp7_in*ue+{Sq@#sRKY>{ZsOAz1}JM z(#wJ=BX&UT&S0TfrJ%1^0}*OhHzNKq>g-q`{VCMoAcqGS(Lnu3-_)_N$nxmZ=6{4o zdB&u73NO8|V@7&$Q8LPBa{5RcTC$z%^HGfr$()RsqqR`yWst6QX3yRPdb4D_SoGFX zv`_!KSO>e1i$^w!jpp;>kWR0;m>)4<`FLD7(LBz$=n>R*fXRG-dCrsA_!Ym5IfR`_ z`Jy}^&lp#RgR4Or zNoXx+d=8^Y5NpuU@?QP}!?? zu{I1U<{(uGXnE1yYO~KPh3(31fcpnuu@)pj;Xs+2N#y9fFJ;-?Up2j~}sx z3B6k%gV}U$^nvTgR8U&ysHZ6s*}psEd9+?r?Du7vFGdwBs*}H==$81~_K7{M;iCtC zXDiw4Gy5<#i%QK4+&!vx+G=Kn0+dlQ&uJ83B*wM$`OZB0;2lcrzAWsOlxAz&5`LV3 zV}l1o_UcnjMr@y8*;%uy$Jx`5LWFLfTt5%G#UQK0#4+3gkuUL(l$-G^EbEgQu-b6x zW}Ub^Eb6g->fr(MBQ*t(qgowas^tn!VyjIpi?F1E9HADL?+}z>(NbagQJu-;!-p)C zhuA7puv59{*zy3{T+aVIDLF{IW4`R#FK>$hwy{ed-NKAXj@Fb(*@+yym>_l-+imI_ z0elEOuv<`-?Quq60D z@*kDFzRa5Yy+=^a0K`D}JN#11(=g#a;TXK>$a~C2%j$@pXF`b3CN&Z}EIiGG9JW#{ z9gu|tGpf=bq}3>^C3FynenC|62>Tr#T8pj78y)Qsi&18G-t8c)2vCR1 zkPH3AO*h3Jg32dy_Iy4@#sCwgDblF4eYUkB$Uc&5-vHhdaP#b|;s#d(4`;`8rN%!SCW!u`8PUsvG`yF_sOZuH|3fOY$Lu*^gNkN+AC{Ei7yxLREfC`y z%|}#~?0zfBMnnZyBtu^YRGUUXvI?M94Nyxxtxf+I8tU1?q-#iUgoEycPMcWGj?j(Q z7Hz0EY)x;Qnl3X)ji9n5z5pP!c3lIQh`=%tuZ*t%0d5k&wuKfH4NW)-o{ z;u;`}RPf54k0SRj6~RRnLH!Cy+`r!A6h~}~N2|%8c>M8qbu+Whw|5RE|1q0I9`YWX zcX1itj+~ZnnI_Xh^u~$a&Q~JPQ)4nZo8`tM?(M~m@@+Z|1Z(}4M8ZKK9N7IIbMZ@j|I_MIxGpu|1hM7>E)wpLj>WTlnfaXCqc z5BN~21|!;orYW&m2?_GmYAmC_kS2Z4#P2pWK3sO>efU*4sBSZ5_z-X4&~zGY`kef% zL}Sf@9IaIlg&0RGRPTmX?jq-hzkX90?ZO{P?+`?}^{k=N;=00dSe7Pb3?aBz{`y?6 z4?_yXRPt$}^P%{I=V-gg4<)+Tabbe^I;3B!Sb#&xf`zi{6P)+${fi0xZvtw1KUVn_4NdW6Z0#mMUMB@Y^JQ1j z{r_-sS&HUX0Gl8-$>C<>q?gN5ey;WY6pbp;e|M}r& z6vX71A4jM8Z_J7KCsb4%d|yINYL*xBTO=4^CDGvf;uD#SRvx-}ZQZ`BFh!PGO}Xy- zn%_a4HGOlQ0W;_EkmuH|VaAC_mjCcbpuDe=n-@7-lKutVa^%2vzl6rL&!pnrZfyH^ z$i{jj!DCI(8|R}Z#Gstzs9T=g_$dDI0YXu^B5M$VEO#L8*pOJLfQEqnR3M4{km$i; zB_2!wBL4~CObUtwwSTS|z&?KLWsC8)Tp<_-{?h+5NEZV(`TK!H0;WFk26P^$dn&~3 zWz(B8VVlYO`=Fry@iC{Kr{b0AW<3rVv5Wrz|5+*^jUVTk^V@=#c?zhC!4erJ4gdqA zi#BxQlg{M$T2Zak59a`7nI z_Z>%1k6+~k5~;|@In+H4GV&qV3!ik}0vDOQwfSJeMB;?`ANJkN`3iE}l}D3oFTT8( zwm9cJN}HyD5hVG=AZ@zyG>_YuJEyWsf5dHTX9z>@Tn51br^f+Rz!GuYWKeq&XNm47 z`yk8_Jb(ob;SU4P&7M=F-CUa%kni=Um(bn5*6n%gk=O==AQiO?=^=|oEj1Kr{N$Vad^Qu&3(zE4u)slYWp|&#@ zc(VDd8Z|mvlO(&iAgJ);Ek?BuRVlZ5MfM_zp*9XocB%-LjJb87(KT>U{=j!WfGa$^ z&%N5OhNyCO)#xs!Je0vV_XUy5n_?qQyP<$wU~TQKdED#4HpWG z01c>DX4~?oh(^9%4JaR9vrRSO6oyupKfzgRm--r$aL)vb{D7zaG!tuF5Q*eW+0V*cZBrJMm*bIg2zFIEz!u7MAcGQP1d22pqF2ed=#aXU#^| zaCS>cEw^$V%Sog}Oq9EV&%np{E*XFad~7EWeR)MQXkQ?{d<@j!^$x^+&iqnKT;{Tr&2Cfm7nMQ@l3&1{h_c} z`ZpAi2L6LY2(A`ZLOvFF_A{C*1b!J|Tw`oY`520iCh#9DDVv{;^eiBrT6u!g{1p;S z%>yuZK=E4l+;I*dsOO-VsJSD|>kD}M(eZkWmw9I0M1S~|^VVppD^ck&e0FDg z(*!z_R*KW$?K;}PE4v+s7VM(?x7#(#(MKN%O&tOSLswSAub2W%?Od^o9=qb^HvDLv zmQG!)o??ogPZ^ws5d@&=5)G6x;{~Utf&zpK#o_=@D->P}=7Zo9YHdN;f*Ar>`pMxV z0xq7&orrrO#71XIY%m1a1`Q{I!aV{AdaJ(C2b>RB7wz;9sJZmn{4~5k)|^o=_CY-p zB09-}$qgrYSmZLv4DHyPCZY7QSuFCWt6$-$ioTcteBxD_OOCNLQ*IXs&O%PV2hj?Q zbI1Le*aC^1DZ~z_uO$NGR4NA2-!7U^uoJ`ko;jsKIEV$qt4rSbeR{f&?fY{br{L=) zhj7mpR2jeZUeJ;=J8rJ9Fhf!b7 zZ6`)Ie-TYRxqDNWF%kLAls_R)Q85c5N-*dkJM)6OIj);9y#5*$>No{xpp^AaBE|c{ z8(As~CAkiz&$1OWsQ*@II^-VRaraR`g(reuKNCW6yY#uy8WzI!X;ry^!m~PkWa1rn zgN1Y?)j7(;8#hD=AlM0W9A&%S;a))~7M^G$CZx}|**lv73TYT@PjD#^ARkqrpPE zq;p1x=?E6&PyJAzJva?}NlJz`*fz&Fr2{YDxWf-(6=J=2^@b460} zZzekvK55P$1?4(DxQy=LTv|dT73&}$5%`q8npwhPr2$JVAq)a#!>TDG0-4cZ1I`zE z{9Qqr33zhqX?ysv#A<6l*`+QSqhj|t^PrR_F!Hpc3QJmpcFzOwL#2bqrSB1lZCjkh@8VxmfkuS4vE484I4!=o_fClMoB0Qu%OOakEks^ zskT8S%XsXDC?U%dS8zxnCQQTN0*?oyWI2Esg$epd;P#aVO}DxB`G-4Q#Sdwj$RiGj zHc($WWaoxf!KCHd*wuZ*v=bA-L|TK!vPu1WI6X(Q#?H_0R){#KNiCI9CA*8BQEBBh z|GTtbvfFH&$V?l8<-$EiRdZk*I7)W)oz{4JKXz#xAi~hcIE=ZJbTP@+TqxKLc|Rk z)JCjvoURo47c@l>x1J}?BP{MYUv;bsah-L88z@;wJp6B{wY03iGT|eGF(YEp;^^;1 zzDGqHAcqpu8vem6p7`Y^_a`q9^xW@ObW=(IC2T99EDB98=j?8JY=d-Bzv<<}M|Rqa zZLk%upYO4!;N?jASA!CixiT6(ptmy}(?rS;r?9jov$dvFJdiXrqiAatZVZOX(bq^3 z)r3hf0EX;)@^f9(MV=9Zk^V0R(9{cby!}{J^Z&wtg}0TC!~esJFz|KZ2A-&#UR?%N z-SShTYLu&pq)$kot>F4zT~T>Yp?ocyLMLY1PM8d59u}2>snp~OCam`|KjvWlPZn$; z`Z18b=2n{4SPD5A;c-|r`l~%W>^hy6Sfoe{P{&aTVm8ych0HH)_{#oYFkpo3>7euP zb-@t*R8abMANq`%IdHK9{o0)|74+<4Wo-uYaj-LvQ{|5rOK|mv zhRT0UPXSbTW?S(n)YOLjf+Z(d9j03GZvD!NVQroOI`$|8qax z=-p-g;rUr)Yo_QEj?zjS*{56b2+@1n%)6nz+SqEa`v>6S-xl+Tf5Vade^>s8FgiF+ z1`rSTOm`0gmPCEX*J0K45U1cB=qzDh%uDEDsB!RHm^0v!#-v9vU~u!rN$RcJjNd*% zT5uAovdm)Ztjn^tYN;UM%2g?ty7exA5k+ourLcKxCZU^lLOa+*ZY}CO$UoBX8*xQ- zAl8)AOM=QN13gX0nPX1JJ+_4~XN&ckL%i}y2n^xeolJ{2TCQ|5e7T;fOr!^~=?3Z%lz+D@-;n1arNIiwbqKeCK5U zdJL-pBW5s2qtxu@_H8ZGqx9E>Zm2V5wS547+jsyvrNGX{J$&AiwU~Z{thr%D-u}%c zsO@#ME{T54IQ*;MqUr9^(A%9`ud>xe2-P6EBDZYgek}G^HUZ5{Ak*5`H`3&Tx4$>9 zYc?woDb7w#w3MJ8A5L_?{{ufPA-*Y~cAD2Hhi}OCgQ79N{}{6OLEm35q(K0(j2^Px zCMI%moAO855APGwUnj(jO9d^u50?$YC*6$^rd)@+eZb#r-{+zV?>0j=|~fk|X>uK@&P6E)s{(oSS$1D3xt9ce%-M(d zYelHW%Jo3ym~&s6qPXPYv`v-{^FiY5g8viWL!e>vwno;ivCnm}w?+RHuVbD6IKw`E zZuGa8uSwk>5>03C_Dl&t@^>d}SjtB|j7AmxvBdv0*C+$ioU#+;`uYJuR#VIQRECRm+J8_6OSSMgwHXMYjSvTtZu}x-z(-fTN9Z}O}H=4LvG{Cul$|o zUe^gN-Dtffx<&k8#4NU52^A*p>emo7v0N`+h)3 zNCs5NKV*>H(#E+n$awPI3G>;td8?--Z`1mXL6$vK8u?f!GFPY8|l z2fyAm7Xerpkg0dd-b=FkWE+_uhQV-|495Qlm+?1ET3lNqk;9@{%GKit|2my6q~^y* zj6?u?BT6eSJ1EAbUd89UTMK>d@x+#OAP)Jik}q*kIJw_$M$U=n)w&5#cjL=LY#;|zAS1ox6miE`SYAK_ z-r&gq#25~J4|I`}HG7Ux9Jm3+l|$`gu;g~#mzNt3%LQm5%c;C<$7=@EHu=Xn2f-LW zj?6tsE>waff@cb%W+7qov~c>p-^#`y$HE(!NOQi;Q2AxViacw4 zP*wl`AYv^fJ1yuN4yU%2gN5CGPx|FslViD5@H2oar?TLvbrc&S`a z>u`X(8eWNS<>|%aG`LhtBms2*uI7v8+wgMs8NVR#=U_RU0ieqA#ZunFvwx}lB!t|_ zuI7_ZlLs0xNNYDAb67$HYvFK3G6Zcv4q`&AbmIq0DmI2l(e^~Zi2d~Gys-h@PbvVu zoa({UsQ_;kly3qB>?DB6ntFc|7I9ODNbKI+tw`+pzoC#8HOj>w2{6TGvBRes zP7p52lMkyDFl0ocm#h=g$R9HsGrBWea0)^GM0|!eAo506r^&Z@O{Gj1;gx?u*ZTg4 zh1eQl2pQ2|wGI;CP|l7}j;VUI$7GXX7ox!ytOYg$Zv^kC6s5`xA9Z2+6lWL|p%$^= z+KqFd5hU`lQ&KaL(TyrCCJ5za+q5Jk(jjZJeg9SuYg~>>qzLui zY7lUmw&)>Y!gKy{_YKWT%ZKvYCXHpniBIO)jj# zaiv{64vHL%bIFzfw=nm;-lZcwBy_oQ+;;fHGgdk@tuCwQUvNi=_g{908t87`Wrj;_ zmb`VT)&&vPBdX6afhXbj=l(3mL1O+7-lV$nwhZ-DbTmy7%(Nu-lqs3His(wgWtT`P zOkI5&q(mrtn zJ%g?%gWI#h!yVmc;Y{7F>;4e;omW5Kc6KcestFg$Km}>9_yL z#RQXFBQw}C+jI}sOy!b?m1TnqfGj(Xci3nNC`yIXw(N@c^BteEM^mJs6OAH8A2HOk zysq2z5`c50;gGKd&(!T{CuGA#PIjTpxu(DBDf5QC_e1;Pdv7N$FHh$OO+sV#lI5AW z%uQ4!8_DN%rPp?t*5;5p?G*@Koc-wjP&I1V10H@{9_LEBXbj=)d*g7Z2%bG8_PzgM z_*Y}jv5$N33V!VTDpE1ow#MHoMm)5uS{ZKvBB-`goqLcLMu>F>a>3%(OExZ5O6@UQ zfk=xq(cxC8=f2R^fM~{=(g2zWcm(jd0H*@f8$M3Kc+e-;s*3c5n zEYpZal6?4OOJquTDnS{#*SEyi7tFC7{yX(p?_)v0iPR+1K~~~HRymct`}jcF4sllU z{G)fjC%FrCGfsX6`B00@iDCtP6F%P&zrP~7^}rs0c=k?TP-^FSZYEGgw6F`J)m$e@ zX9#`=(bTABwRpGD|_k#i5OGh#jMw%bAFe7?AYav{(GDTXB)D#6@^H+$5Y;3L#MFihvLD8p_LWs&W$Sm%xey{wpYI(?B}9F%p;*q*y>=Y8GCn&lSa z(3?*;S+3T5s=hMs?wUajn6ukyFDW*Jr2~_O{Kv)AGeYFR?)D0_TM)KXtlrN~d-r{< zD1I%Vef8qB=i-Pk)P)3i(=T8y&6#5==<2@A|36OT#zjh*}3pKn4P=C}9 zuO5}Xq=i2Oj5Q8xC_JtgZa-J9vdZt#fA6@9Kv82?CWp1g zExdvBfyzFFslrdVBZX`494}eN$yzWZmR-h|{E16JIgyF@&*w`UovwZvUelshXvXXQ z#Dh&fNDTU`CmK-c>8-zuf!8efe{)hMT#hd|*?(&-{`~zYrOhc|*KaNL*`+}qLer53 z^j$Br8g3Z#4)CMvA|nq=_{!}t;i(q6LD`@_6XdVQn3EbFhmdM*T582{m`m$72S3nj)z#4agp|GoBN1^*0*IMX#91va*J!8#UR7 z!deSA7DLff+BCuMj~?CBeOVOk(+~QhY2S)RRxzw z{XHuTGt~DjG8$@g=;nM<<_eH+qlO>JC*-PwcQ=)gn37O6kzw7;@NYIW4O>Qd^S4xJ z5n-9tS?Wu< zff>bJ|BTSa#lhb<-EKBSy!8?245XIR^j1mHGU-x-;$OM*!D71mg+)syo4ut0)vM9TNLdnq9P zA;;JMMZCUjb>v>%kpP8-td46XqSz{B)O@%PYe&HH=_5C___w9A-IwiXABA>PkyVEH zK)B-(7M`EwEj|pk-iFDQ5pRhsC4P^{CXJP5{1RNw3~z7iN+Q$1BnvlzC8@Qwa$>Iinaj~ zA99a|E()&J*#S1?{U7hE^H)o!e znK-WO&c6lt>=Tnp%cvlApQ(x^`0^xT_O&FcEoEy^!V?1hWKPop(vUNnm$KaSipv65>-A2Pe5TX#4h+(!sn zBDd|LPag$hiZWtilCP{V)?hMteOb0Y_d{S-7MUwsj0LHcnE)}n%JaD+q)Dt{7+D96U-k%yD z&1d%(WF|E1$|ggf(8s=#_m?=4LqDsmV}z!$c^rb*YfY86k&{%FN^rjNPS{9%YlD+C zk}>mbZ7Y0|)38)@B8U5I-0;Doc@wx{aLq_E#Vmt;r>OH^&7;o5c21F=tMSyIv(T_ZgfO%`HQS>_`iR8Ek7d5ZHAbh0d$Khj(rKQNTVA@q4 z>I|D3ZQf~nEiBh>yl`?I{QRH;Fm4rtGGP7IN1egtBrr?8>L2nOZ|OE*Wp2jo-5+?P z**4|K-Lp;TnM@G|!R1bzf3y&IRFwhxIdl68M*a0(cHVuw^k)=x?KR`ff<>7iwnPZ9 zLC9%cg8U=l{Tt-Gmw4%lkuBe&DUTw9N_2kDgx)$yQfL)5r?7rBYcU*9&CD}DK!Yg; zVh}-b_NNpSZ%ZoC&5{C2l=^uZh55ExiZKh>R&AeMW%eEnDoudcDBW53F$Yqaz&4$$ zl*2>vx^AlHguq3RlGni{*Jo@$Iw3eY{LM-JqN+NySH);9 z4P{ub|7U`3WIS<321FP(971^NJ7XX9n>B0`9GI^5*CMSV`B;SrC$@_y9`RFoCH?d$1#{|hSNB9#q)%-(rzsCySwH((_{v_k&1v6#TOP_UqzPdXT|G*tP zGaE2WbNX!5|CVzkI{S5eaPEeVS3S^AN9`-Ti$?|R(?+oTYMW4$?9|RhCPX+|K43ls z!qr7V9XFXGL|*7P;zXEpgq)6{D@w5_O5&XLQ$I zRQ97FlcZ0!vA@%ThPH#AN$3q}q8?xW#%G|uY-vEfJRaeUicx;gbNzl>eQe&sY4%sp z9r|)*J%q;fToB+LK>af2Zay$?4W-%%vz6z(`O|vd9fWx{J8b2mfRVS9`RVc7S6~4? zpP8Ik@JQ70p44X>W8Z+tAA{gY`tPamDOdent-zj&=eU2iqwF@Z=ot-};dvuvuaafU zzWx2>9Bl@3*dv;3m7Yk0l)6{AKh>78ayEHifYi^O();>?q~TZ%1^xpcWV>Pah?pql zYL~0u##trAX9bL`_tyDH`75PLIEUgMx7Qwdab-?I?T zIsG|)tQV-boYC`~0#Y6XEsAZ>4%Q}NEL)-+-2*ac`STJvIBe8eOu#qm0`Y$zsd)$g z46k_$!zNxKI_v9AUnV(O^CXk!Vvg?&GjaXr8kmeY?Suo}nm*}H?CMpCwR!G?Tbw4=2(8IV!t*NmY8uS)7}%DSy`3&O4?=iX%y%X%wg zR&1&?+Xi(5w8JJmZ|D%QX#eF~6@fgFe@mG_^WNI<5t18Xxk*ll?2tKF`Kt8KCpibP zLx5WVqa@=@|31^#217T&JhKd2=WdW+u?#;iC`OcZ=JOe4 z08lE%S7A#_K4qU|BK3GRDfh9Rb;Pe({EWTw&UpGV$cNAzTAIY2urKm?;~?8N^rmu& z*`;C~{5WHBBQMg>4eHv>PKlW-=8MyzBeF&2=s)eijr4T{OHb4k-d}&HSi8)qZL-C| z)hC(Ni3RAmj^5V1G_3@!udB#9lgx}p?cElhQ94k;pidO{B9#kxbIgYA-$u{678?y+(PgV)ABats?ZQIPh=c4eD6$J zvkJcDn!gLB1=n=@BxQ1tgnSn7mzcKEa|5fWK|F~J zXEhB%k89ufVqu>~9u3IO*tB|Db)L3zeq&aK1&HJrGL)ku zGQkbUV3S{D^{iJRRX9TQ$6RTV5!GlzggaAy8MCQATIj?JWh$RbK2yohV@LI zIvPy1_Apg(R-jPu3M5eb@q%?_T)y{^Mm}rwFvaboT2k&aeQh{~@vVK6{@|i09s6GO zZrf+h;a>wDGc1@Mu^!V!Z}Pc7L28y&k82e+t~I8$r%aDjQK#w7G>{;2qy2vUNWB_) z;_n$KyD7;G$Q!>AfNy@YPjK`I?2G&(g`^DK=f+Jo(BwRzFz$pSDdNHn46}oMLgCF? z3s4W}RxK+Oj?2x5b@l90f-#2Q7qsN=&`UNJz%nDJW#~ES5}Vmzx%9n?C|ef72qkI3Z~UL zZ4-jAHLP@b81~pkCaFyXWai5SRUy0pu6D_&8jLg*m)jFTqItolom455)z9ao_e6r< z$^-%Zh`wB=)9|62#7)j>i~E#~3VHuc2I2wpNc)G&mOXz!>Ogzs%6#5_p(Q_yFnN77 zkz|XW6Qps^p3h$DY8-aw9Owa#jBX3)uuaaWX;a#t`ynca26H7mG)LS8!#KLn0&?>L zzo`G~49|(d)7xfHpuHDTq~AwLYpC?zbb-JBvpsE$SIfOoXJ1|3X3eJV`cV8NJ4;`W z)Vwbp&Sq`jjKgz3aX7aeC7vrH^aFsb- z_TZBgux{^Wl%JY5g*L|@f)WFf8IfYxk2hpNzg*m1@ti>3(E~??9l>h?BlNj%3&9;9 zHCfBilC}X5HZP5+$yt=Y(UAFi`@ytse^nQQSViB0wbs!Z=d&aKy-%3(lDV2{-m+Lw2L_p2bpj=~;G7M)lKrNH?}L!E6uV8AhG zeDL2_Hnh{|yg87Go&(B);YN~r1I(G~9`hQ*Y2)ObB=FC<99d*%B&2|I(r;S|C88}K zyrhAb-os7+&kDR;tqhuds=>cHDR6HH!SsD6BT+KIp>bmVx}mfsfbDxEaziL`Q)6*TX6AD;Z2+9gjBwOzsk{ijG$;QCDm7BYl147o}v**0T zhxDs2wp=bQsmQO-dYXHkpP&d@jonR*RH+t{dm%G-j~TO>XPRyHE_B5%W+(Jua zRMwDS*h1av*Li8%g22fs7*)abL=vB)_Z93H-D&xn(-k^njd@J5O11;OnzF4vHaZ z!m1{J;B&X8Hzjd?Y3tDg8Hk1)M^C+OYtQh=z*<(i1E=`JG0|$om&htc_t}F4iYpAG z)USm*IO|Sq0;$=GI0EqnOm?-=J54XMo7opm7fLqc3p_v_UO5mtNWo6o7( zF2WWK`vl?G?(TRS>){KXp|$53hDW-_(MuMhvTKW!TXjM?tM)^&pFYq+NzL=uPVOPf zUvK1i7q>35KjTxdg?=WT@{uUF+4UQ9b15$;K+ z`vk-oZ#}^XB7ZHZ2I$YcV2FRhIt?|hsBUe|kOhkR-M;kn9 zOrM(D@R~b*VbH9)A(>Oh%ISXKx~ciVu=fRXQ6wdL>O`3h=(U8wxO!%%=zqI|zLV$q z`wu_ZY=p4xA=^Re$%H`V$y)BO7;4(p!T_?o_)bsbCzj6x-@a<*mGG0hil;^k^5jY? zDT+S3WL|H+Q}X7E2@K|Z`IXjW~T4-1~GQ|JqVzvL`y`y(A`-M+BO_ggsNnOZ>P4ayQ~OTxq#ZSU!St# z4oy@Bw}QBqnji&AxxZH^6qlVjz%EncO-oI@G=2+2GroHzt#vzL@$5`gvwh*>T|$Y~ z8L|vbmUu^2b)k@$=OP!xGjxSb>jBY&jfsB zKaky9PrdeX$|0Yjy`wCqz>hJZl%|PuO^yG(X$cB5%<4gg28d4nAHV)_{&ZAlKJ`~p z7n9K!y?Zl3)9})pKB3ycgebn!oV#KFb6?RdRDscP690Q9kjQa@^nCvaN0;vdBI<&H zf^T2;Nv6lEn(hVT>aCB#k-lDZ5b2+cgQ{Ns!J>d}JpcRYI&glfeEyf#r&Oh**A*9&*S5W(GU02$PwJx={uU zN`Kz`Y2)ubh7W4vB{HW@9D;rJv)Nm-qH)eqkCC^RTtA^ugQeg+p--W(Ohf&x|IV6l z%W8wMNS=clZP zcgmG(%)%75m@hygdAISAwXm~U#cwWS6jjM7+tMd&q)j|LXIuveDKGx_<4Q*+&M2+D z!{?M>p{&tW0mkjsOC5Z^S8Z*mbPj~tM8rG3i+`G|vQTZ4VIw~cGwAqH-8;{7)My>3*OWsTBE|U9ogy{N0%fOC@OjrHCS?+zZ(;~r z?ncqD$Y_+E9l&mbV&qA<&Vq)2I?@sn-h-V=2k!R33XGyQ3RudW{+`bB;KX?T&8btB zqQe3*X%=!buCwW=$fnnnh%J5=2JtoYZ_1K}hqRU1eth6AkU#y}ZFl293P}D7&W+@Z zGceT?UyWv1H*WG=3br#aNPi&I0M8*r`%g?Ox406Ls0@7L6EdIW2${Q*r7b;X%FwQ; z31b)xDtSM;F3LHYqAhIRdO?#tR`uu)ia2qdd@6{a@9U`eR-a@!lJ_5`YJR-kx@UyY zxNYC5WSfAU7Wv73=gI$Ewf$y8?Ym<%aen_S=X#tP!|SC~WJ|9D{(Sd0#hgq)jNJ1_ zc&Gh1*;}#LQub&N%}cdtLOC#dSXp|e#Pl5X0482cBssfh@RhIz&Wxv?n@rXUwW~EH zj${4i=HL$DC3A9*`0+tDuH?G#~ zAL={A)tMF3h_%F~5B-hr5FcECKFxyjk+K1WxNX?^<;crjW-LOkQfWPXmO>x9ya?`Up{qJY#x)!XwIt)B1Bz ziP`iH;RWvuLtmS*MO2$e(B0J2diybm+B9sKCfFfgR-!#*I zu54Km+-Y_}z$}Bto_8DWvk9@}ZI@r0z=FEX+(1*QRDpNN|0?UP!`k?wu2BdH?(PIF z?ohnJp+JEm1&X(Lu_DDuaA`|$r@?7)io3fPcPs8*q}=rP-uv9={l5Qa_MDls=geAr zt+U4)D`zWYLzPw(TQ9omAXMrs%$D>1MH;J#7nVI5X6^D!yi5+YB6NT%rcTxci%%4= z&6azL-BpS8z&lQ*}pZ`@}fB6s**btD$f{2b(98vcD~u*7H8JdXDl32m$!e>(=5+Ct3H z?b%<0256ijYjKb+8-Bo*8bpsQEhLeJUOyaQS~Gm&dOsSc zcY-EAY05^Mdj0#UO5>gYuj_mSO-n%W7JpN~_n$wJeki0v5)bf$6Q(fr zzqTn97O!9=acisr03pc=R{$Bl!8V?OWzx5qCqm>c;to$H>fJ#4$>FRW~@*CU*sJ% zWIoZYY=VH#G((u?wdx%tGN=M`+*#;mt~f%fTc~IYVOO`bq>ne8j)mo$qZBBTS;%0N zFbJF0Nt`I_S0&wVpJH1NiFb2-nSY!#sk~jHK?($u?%}`3xmiBXe?Ihx2QU62T6q-z zXMgv_~@d(7mzj`|KIr22>iCyug2CS{NH}#cLfK8>F7Z27(F&#?c=77YMv zxls_)NjeXwYpL6R^Ig{-c8p8r}p0t zKcvx61p;CL{V!K~J{PV?f0N{3^Q9SZiOE~Tj4X!@2YwDU#i4YEg1thI-cE@~DD!-@ zQT*@fYXqpoh$umGH;M0gHGmn-Gz%U>i=zKok4X3zQKOet6-$eHUoI;A-%j+q^NwRc z)FE^_#_bj@;i&81)I%Iez;T`pFmUcqmZ0mb+<%b>OB=+hDS#yhYpqUYI@7~ULXx_Q zW&O|+Qv|z96jKmh=-cU9Z~x#cUQ9nC4gZAsmnJf#hOi8#XK8M9_!w%-lDb9#jyg8K zr+HwnH)YEkxA7k85ADf4d_U?-Flz+@sTC%3wz7%bmCE8n{v0ew^p5Cxjd0f=K@WpC zy%BK=9(x*z1N$LxUA#j#=x?@{PQUpW(p-;T=S&|TjT#0#3fS2E zzysv>25TgANJeiHq`G;EL@$VexPpl=fdD)vI|++LK;Cb$3DxFfdhOrV9afK)`cq+}POcX%~#Alv9%P)_JMkvyTZYonf-dosRB)!n#SX}i0*(KD+c*64P z3sw_BKqkB14VekJ+MU^xBg~k5TD^| z5w>PNQ@K@;L>ja!((!7?TrhaZqNiWAqWvH%Jy+6{g0)^ff$HZ0aBY=_l_*AaeL~M-u{ChYn&&_rzgYaEy6`g zSb-cE%u-tUTdt;X)_8Jff~M)6Q_tU`$ckv_uhPzS#vry>cjiIYjNHd9G^KHNLU2$r zPyN)HB)Xc~Xt2S&e4z9pOm!1xibfj9KegOz7nCg!hF0K$E11PCP89FHEMUX>TndI` zG|AF)X0u3Oe&bRht~d7`ksg+zM!@64iWpp52cB@WOK&vQB;6SVOogeGl60Um`_C2e zKL0u^OA?0(>_cSQyoh%<>9n@O!2K6%XfYs6y&5`_-??F*7IghpICR@lfjtMbe!S_0 z-ZPYtd2&6AMU$2a<)=fGzEhRQ3?rNY*t>9BM%5yBxH#`rZqk5YN<4e@0yjDHMT@7a z!H2>H&_@0VgR;xT{In~pTw2G4Asz2cW8Ny8LjCtnA>P0f3R^RbXJ^`&b7-p1j_rl-)IY;&|x!Z3@)X%?v$MA0K zogu9`{(&NU8J+P@+4EhJ$m`rD z!pTa8FL@r?XSNr+HsgJ@3hPPv5%hvr8L^iP11D>wt3=jK*u_njr2YrfBm8-vD35(u zLGt$@o1+e!E+-Bgx;goEsLS%F8zwvzE{-x`m-xy?UulF|#qiSQd#`dW`R^uGFsbor zKBWpc$da=d_Kdu3H| zmaHO(6i5aHDR5Y#<+JY+!_G#{qT^F^5T%AvmV28q9F7IF59!RBkGVN3|xa+#-`!ls&e#I@fglr3JEUgLhjMh z`^Gi46z(I&J8YVa0RmXIXQ%GFow*j`Zou!~nsF!KJFe=AaL+eY)+~$`{X#BA8gLMX zU~OQigQ;Qg=Wj2R&+l#qtIwV$OT-LyMb}++FzJpz(DX>{v7yk-gr;$<{e>lvG;)SK5%0V@)Oxgtg{a;ZXmB2r4^sV6JkYyNLSB;k3-#BErlM&q^x5&3jwey8ce{=w zw)LCyb#VgssWTOl?}yFY=vySra6d`8_zErgm{1n9dP zz!}TdXnv99D~6wIohfS?YtvXc2~R57^D=v?RSvv7^2zyCq9G>mj<7|*v}X6ymebqF zpiG)^r$OvfDpj$%!#~ur3on?^uY=UzKh~n&CDB0;%f5ea=3aQXgudC&N3cO#b8F~_ z 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 F{vQpy@Sp$y diff --git a/docs/source/images/scratch_inline_example.png b/docs/source/images/scratch_inline_example.png index 358f04208017a8340290e9845c6e9420bfeda63c..e459094721b7ef358dce898d98663a57b10e2ec8 100644 GIT binary patch literal 20560 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 Xaz%dd^uGvPf6w6Q>gTe~DWM4fL2{Tq literal 2492 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 +{{ scratch_block }} diff --git a/verto/html-templates/scratch.html b/verto/html-templates/scratch.html index 5e504c44..89e71176 100644 --- a/verto/html-templates/scratch.html +++ b/verto/html-templates/scratch.html @@ -1,6 +1 @@ -
-{% for hash in images -%} - - -{% endfor -%} -
+
{{ scratch_blocks }}
diff --git a/verto/processor-info.json b/verto/processor-info.json index 36fbaf62..46f81fdd 100644 --- a/verto/processor-info.json +++ b/verto/processor-info.json @@ -481,7 +481,7 @@ }, "scratch": { "class": "custom", - "pattern": "^scratch(?P(:[^:\\n$]+)*) *($|\\n)", + "pattern": "^scratch", "scratch-compatibility": { "pattern": "(?P^(?:~{3,}|`{3,}))[ ]*scratch(?P(:[^:\\n$]+)*)[ ]*(hl_lines=(?P\"|')(?P.*?)(?P=quot))?[ ]*}?[ ]*\n(?P.*?)(?<=\n)(?P=fence)[ ]*$" } diff --git a/verto/processors/ScratchInlineTreeprocessor.py b/verto/processors/ScratchInlineTreeprocessor.py index 7cfcfd64..d1af7102 100644 --- a/verto/processors/ScratchInlineTreeprocessor.py +++ b/verto/processors/ScratchInlineTreeprocessor.py @@ -19,7 +19,6 @@ def __init__(self, ext, *args, **kwargs): self.processor = 'scratch-inline' self.pattern = re.compile(ext.processor_info[self.processor]['pattern']) self.template = ext.jinja_templates[self.processor] - self.scratch_images = ext.required_files['scratch_images'] self.fenced_compatibility = 'fenced_code_block' in ext.compatibility def run(self, root): @@ -50,12 +49,10 @@ def process_html(self, node): match = self.pattern.match(content) if match is not None: - block = content[match.end():] - content_hash = self.hash_content(block) - self.update_required_images(content_hash, block) + scratch_block = content[match.end():] parser = HtmlParser() - html_string = self.template.render({'hash': content_hash}) + html_string = self.template.render({'scratch_block': scratch_block}) new_node = parser.feed(html_string).close().get_root() node.tag = 'remove' diff --git a/verto/processors/ScratchTreeprocessor.py b/verto/processors/ScratchTreeprocessor.py index a9c315e0..35541747 100644 --- a/verto/processors/ScratchTreeprocessor.py +++ b/verto/processors/ScratchTreeprocessor.py @@ -3,9 +3,6 @@ from verto.utils.HtmlParser import HtmlParser from verto.utils.HtmlSerializer import HtmlSerializer from collections import namedtuple -from functools import reduce -from hashlib import sha256 -from random import shuffle import re @@ -34,7 +31,6 @@ def __init__(self, ext, *args, **kwargs): self.processor = 'scratch' self.pattern = re.compile(ext.processor_info[self.processor]['pattern']) self.template = ext.jinja_templates[self.processor] - self.scratch_images = ext.required_files['scratch_images'] self.fenced_compatibility = 'fenced_code_block' in ext.compatibility def run(self, root): @@ -68,7 +64,8 @@ def run(self, root): self.markdown.htmlStash.rawHtmlBlocks[i] = html_string, safe def process_html(self, node): - ''' Checks if given node is a scratch code tag and replaces + ''' + Checks if given node is a scratch code tag and replaces with the given html template. Args: @@ -76,29 +73,19 @@ def process_html(self, node): ''' children = list(node) if (len(children) == 1 and children[0].tag == 'code'): - content = children[0].text.strip() - language = children[0].attrib.get('class', content) - language_in_content = 'class' not in children[0].attrib.keys() + scratch_blocks = children[0].text.strip() + language = children[0].attrib.get('class', scratch_blocks) + # Boolean if scratch language is not defined in class attribute + language_in_scratch_blocks = 'class' not in children[0].attrib.keys() match = self.pattern.search(language) if match is not None: - options = list(filter(None, match.group('options').split(':'))) - if language_in_content: - content = content[match.end():] - - content_blocks = list(filter(None, content.split('\n\n'))) - if 'random' in options: - shuffle(content_blocks) - if 'split' not in options: - content_blocks = [reduce(lambda x, y: '\n\n'.join([x, y]), content_blocks)] - - images = [] - for block in content_blocks: - content_hash = ScratchTreeprocessor.hash_content(block) - self.update_required_images(content_hash, block) - images.append(content_hash) - - html_string = self.template.render({'images': images}) + if language_in_scratch_blocks: + scratch_blocks = scratch_blocks[match.end():] + + html_string = self.template.render({ + 'scratch_blocks': scratch_blocks, + }) parser = HtmlParser() new_node = parser.feed(html_string).close().get_root() @@ -106,23 +93,3 @@ def process_html(self, node): node.text = '' node.append(new_node) node.remove(children[0]) - - @staticmethod - def hash_content(text): - '''Finds the hash of the given text for image retrieval. - - Args: - text: The text to hash. - Returns: - The hash of the text for image retrieval. - ''' - return sha256(text.encode('utf8')).hexdigest() - - def update_required_images(self, content_hash, text): - '''Adds the scratch code and hash to the verto result. - - Args: - content_hash: The image hash. - text: The source text of the image. - ''' - self.scratch_images.add(ScratchImageMetaData(hash=content_hash, text=text)) diff --git a/verto/tests/ConfigurationTest.py b/verto/tests/ConfigurationTest.py index 43092c48..75ab5c20 100644 --- a/verto/tests/ConfigurationTest.py +++ b/verto/tests/ConfigurationTest.py @@ -47,12 +47,6 @@ def test_multiple_calls(self): }, 'images': set(), 'page_scripts': set(), - 'scratch_images': { - ScratchImageMetaData( - hash='a0f8fcad796864abfacac8bda6e0719813833fd1fca348700abbd040557c1576', - text='when flag clicked\nclear\nforever\npen down\nif < and > then\nswitch costume to [button v]\nelse\nadd (x position) to [list v]\nend\nmove (foo) steps\nturn ccw (9) degrees' - ), - } }, heading_tree=( HeadingNode( @@ -81,7 +75,6 @@ def test_multiple_calls(self): 'interactives': set(), 'images': {'totally-legit-image.png'}, 'page_scripts': set(), - 'scratch_images': set() }, heading_tree=(HeadingNode( title='Another Example Title', @@ -113,7 +106,6 @@ def test_multiple_calls(self): 'finite-state-automata-trap-added-extreme-example.png', }, 'page_scripts': set(), - 'scratch_images': set() }, heading_tree=(HeadingNode( title='Another Example Title', @@ -157,12 +149,6 @@ def test_multiple_calls_without_clearing(self): }, 'images': set(), 'page_scripts': set(), - 'scratch_images': { - ScratchImageMetaData( - hash='a0f8fcad796864abfacac8bda6e0719813833fd1fca348700abbd040557c1576', - text='when flag clicked\nclear\nforever\npen down\nif < and > then\nswitch costume to [button v]\nelse\nadd (x position) to [list v]\nend\nmove (foo) steps\nturn ccw (9) degrees' - ), - } }, heading_tree=( HeadingNode( @@ -193,16 +179,6 @@ def test_multiple_calls_without_clearing(self): 'pixel-diamond.png' }, 'page_scripts': set(), - 'scratch_images': { - ScratchImageMetaData( - hash='a0f8fcad796864abfacac8bda6e0719813833fd1fca348700abbd040557c1576', - text='when flag clicked\nclear\nforever\npen down\nif < and > then\nswitch costume to [button v]\nelse\nadd (x position) to [list v]\nend\nmove (foo) steps\nturn ccw (9) degrees' - ), - ScratchImageMetaData( - hash='b78bff524e54a18116e1e898a93e360827f874a8b0b508e1edc47d21516495ad', - text='never\ngoing\nto\ngive\nyou\nup' - ), - } }, heading_tree=(HeadingNode( title='Example Title', diff --git a/verto/tests/InteractiveContainerTest.py b/verto/tests/InteractiveContainerTest.py index 78f69fd6..cf4b29c3 100644 --- a/verto/tests/InteractiveContainerTest.py +++ b/verto/tests/InteractiveContainerTest.py @@ -50,7 +50,6 @@ def test_whole_page_external_thumbnail(self): }, 'images': set(), 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -98,7 +97,6 @@ def test_multiple_interactives_text_true(self): 'interactives/flying-boxes/img/thumbnail.png' }, 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -123,7 +121,6 @@ def test_contains_multiple_interactives_some_text(self): 'binarycards.png' }, 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -143,7 +140,6 @@ def test_text_false(self): 'interactives': set(), 'images': set(), 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -163,7 +159,6 @@ def test_no_text(self): 'interactives': set(), 'images': set(), 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -197,7 +192,6 @@ def test_whole_page_parameters(self): 'interactives/binary-cards/img/thumbnail.png' }, 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -221,7 +215,6 @@ def test_whole_page_thumbnail(self): 'interactives/binary-cards/img/binarycards.png' }, 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -245,7 +238,6 @@ def test_whole_page_thumbnail_parameters(self): 'binarycards.png' }, 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -265,7 +257,6 @@ def test_iframe(self): 'interactives': set(), 'images': set(), 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -311,7 +302,6 @@ def test_multiple_interactives(self): 'interactives/flying-boxes/img/thumbnail.png' }, 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -486,7 +476,6 @@ def test_doc_example_whole_page(self): 'interactives/binary-cards/img/thumbnail.png' }, 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -514,6 +503,5 @@ def test_doc_example_override_html(self): 'binarycards.png' }, 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(verto_extension.required_files, required_files) diff --git a/verto/tests/InteractiveTagTest.py b/verto/tests/InteractiveTagTest.py index 2fd2cbd5..87e00060 100644 --- a/verto/tests/InteractiveTagTest.py +++ b/verto/tests/InteractiveTagTest.py @@ -45,7 +45,6 @@ def test_whole_page_text(self): 'interactives': set(), 'images': set(), 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -67,7 +66,6 @@ def test_iframe_parameters(self): }, 'images': set(), 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -125,7 +123,6 @@ def test_multiple_interactives(self): 'page_scripts': { 'interactive/flying-boxes/scripts.html' }, - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -277,7 +274,6 @@ def test_doc_example_in_page(self): 'page_scripts': { 'interactive/binary-cards/scripts.html' }, - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -299,7 +295,6 @@ def test_doc_example_iframe(self): }, 'images': set(), 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(self.verto_extension.required_files, required_files) @@ -326,6 +321,5 @@ def test_doc_example_override_html(self): 'binarycards.png' }, 'page_scripts': set(), - 'scratch_images': set() } self.assertEqual(verto_extension.required_files, required_files) diff --git a/verto/tests/ScratchInlineTest.py b/verto/tests/ScratchInlineTest.py index d5270fed..f75c0795 100644 --- a/verto/tests/ScratchInlineTest.py +++ b/verto/tests/ScratchInlineTest.py @@ -1,7 +1,6 @@ import markdown from verto.VertoExtension import VertoExtension -from verto.processors.ScratchTreeprocessor import ScratchImageMetaData from verto.tests.ProcessorTest import ProcessorTest @@ -27,15 +26,6 @@ def test_doc_example_basic(self): expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - actual_scratch_images = self.verto_extension.required_files['scratch_images'] - expected_scratch_images = { - ScratchImageMetaData( - hash='3dfa73663a21d295e1e5c1e5583d8d01edd68ec53ad3050597de126076c44ea5', - text='say [Hello] for (2) secs' - ), - } - self.assertSetEqual(actual_scratch_images, expected_scratch_images) - def test_doc_example_override_html(self): '''An example showing how to override the html-template.''' test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') @@ -47,15 +37,6 @@ def test_doc_example_override_html(self): expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - actual_scratch_images = verto_extension.required_files['scratch_images'] - expected_scratch_images = { - ScratchImageMetaData( - hash='2f3ea223b778227287b8935bc5d209e25d3e8a25ef46ff85f6c44818159601d7', - text='when flag clicked' - ), - } - self.assertSetEqual(actual_scratch_images, expected_scratch_images) - #~ # Other Tests #~ @@ -68,23 +49,6 @@ def test_multiple_codeblocks(self): expected_string = self.read_test_file(self.processor_name, 'multiple_codeblocks_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - actual_scratch_images = self.verto_extension.required_files['scratch_images'] - expected_scratch_images = { - ScratchImageMetaData( - hash='3dfa73663a21d295e1e5c1e5583d8d01edd68ec53ad3050597de126076c44ea5', - text='say [Hello] for (2) secs' - ), - ScratchImageMetaData( - hash='2f3ea223b778227287b8935bc5d209e25d3e8a25ef46ff85f6c44818159601d7', - text='when flag clicked' - ), - ScratchImageMetaData( - hash='1c95862744e873cc87e4cadf6174257ce6e8a237b29b5c41f241e98e0d78eb14', - text='turn ccw (9) degrees' - ), - } - self.assertSetEqual(actual_scratch_images, expected_scratch_images) - def test_mixed_codeblocks(self): '''Tests that normal codeblocks are not inadvertently effected.''' extensions = ['markdown.extensions.fenced_code'] @@ -95,16 +59,6 @@ def test_mixed_codeblocks(self): expected_string = self.read_test_file(self.processor_name, 'mixed_codeblocks_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - actual_scratch_images = verto_extension.required_files['scratch_images'] - expected_scratch_images = { - ScratchImageMetaData( - hash='9dabe0bac28bc3a143cfb19c2e5d7f46aae62b3d793166a56665a789d0df5bf7', - text='say [Hello]' - ) - } - self.assertSetEqual(actual_scratch_images, expected_scratch_images) - - def test_codeblocks_compatibility(self): '''Test the codehilite and fenced_code do not causes any issues.''' extensions = ['markdown.extensions.codehilite', 'markdown.extensions.fenced_code'] @@ -114,20 +68,3 @@ def test_codeblocks_compatibility(self): converted_test_string = markdown.markdown(test_string, extensions=extensions + [verto_extension]) expected_string = self.read_test_file(self.processor_name, 'multiple_codeblocks_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - - actual_scratch_images = verto_extension.required_files['scratch_images'] - expected_scratch_images = { - ScratchImageMetaData( - hash='3dfa73663a21d295e1e5c1e5583d8d01edd68ec53ad3050597de126076c44ea5', - text='say [Hello] for (2) secs' - ), - ScratchImageMetaData( - hash='2f3ea223b778227287b8935bc5d209e25d3e8a25ef46ff85f6c44818159601d7', - text='when flag clicked' - ), - ScratchImageMetaData( - hash='1c95862744e873cc87e4cadf6174257ce6e8a237b29b5c41f241e98e0d78eb14', - text='turn ccw (9) degrees' - ), - } - self.assertSetEqual(actual_scratch_images, expected_scratch_images) diff --git a/verto/tests/ScratchTest.py b/verto/tests/ScratchTest.py index 68e9feb5..8d634c46 100644 --- a/verto/tests/ScratchTest.py +++ b/verto/tests/ScratchTest.py @@ -35,15 +35,6 @@ def test_doc_example_basic(self): expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - actual_scratch_images = self.verto_extension.required_files['scratch_images'] - expected_scratch_images = { - ScratchImageMetaData( - hash='a0f8fcad796864abfacac8bda6e0719813833fd1fca348700abbd040557c1576', - text='when flag clicked\nclear\nforever\npen down\nif < and > then\nswitch costume to [button v]\nelse\nadd (x position) to [list v]\nend\nmove (foo) steps\nturn ccw (9) degrees' - ), - } - self.assertSetEqual(actual_scratch_images, expected_scratch_images) - def test_doc_example_override_html(self): '''An example showing how to override the html-template. ''' @@ -56,15 +47,6 @@ def test_doc_example_override_html(self): expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - actual_scratch_images = verto_extension.required_files['scratch_images'] - expected_scratch_images = { - ScratchImageMetaData( - hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', - text='when flag clicked\nsay [Hi]' - ), - } - self.assertSetEqual(actual_scratch_images, expected_scratch_images) - #~ # Other Tests #~ @@ -78,15 +60,6 @@ def test_example_standard_markdown_block(self): expected_string = self.read_test_file(self.processor_name, 'example_standard_markdown_block_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - actual_scratch_images = verto_extension.required_files['scratch_images'] - expected_scratch_images = { - ScratchImageMetaData( - hash='a0f8fcad796864abfacac8bda6e0719813833fd1fca348700abbd040557c1576', - text='when flag clicked\nclear\nforever\npen down\nif < and > then\nswitch costume to [button v]\nelse\nadd (x position) to [list v]\nend\nmove (foo) steps\nturn ccw (9) degrees' - ), - } - self.assertSetEqual(actual_scratch_images, expected_scratch_images) - def test_example_separate_blocks(self): '''Tests that code separated by whitespace is still processed. ''' @@ -96,15 +69,6 @@ def test_example_separate_blocks(self): expected_string = self.read_test_file(self.processor_name, 'example_separate_blocks_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - actual_scratch_images = self.verto_extension.required_files['scratch_images'] - expected_scratch_images = { - ScratchImageMetaData( - hash='8e8a2129c3cecf32101248439961735fc1d45793fadc56e2575673f63d42b9fb', - text='when flag clicked\nclear\nforever\npen down\n\nif < and > then\nswitch costume to [button v]\nelse\nadd (x position) to [list v]\nend\n\nmove (foo) steps\nturn ccw (9) degrees' - ), - } - self.assertSetEqual(actual_scratch_images, expected_scratch_images) - def test_example_multiple_codeblocks(self): '''Tests that multiple codeblocks are processed independently. ''' @@ -114,23 +78,6 @@ def test_example_multiple_codeblocks(self): expected_string = self.read_test_file(self.processor_name, 'example_multiple_codeblocks_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - actual_scratch_images = self.verto_extension.required_files['scratch_images'] - expected_scratch_images = { - ScratchImageMetaData( - hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', - text='when flag clicked\nsay [Hi]' - ), - ScratchImageMetaData( - hash='cd6d9a0d464bb8f5eec1e6fc9a4e33378a64ebfce7c6198794ead614962f38e5', - text='when flag clicked\nsay [Hi]\nmove (foo) steps\nturn ccw (9) degrees' - ), - ScratchImageMetaData( - hash='8e8a2129c3cecf32101248439961735fc1d45793fadc56e2575673f63d42b9fb', - text='when flag clicked\nclear\nforever\npen down\n\nif < and > then\nswitch costume to [button v]\nelse\nadd (x position) to [list v]\nend\n\nmove (foo) steps\nturn ccw (9) degrees' - ), - } - self.assertSetEqual(actual_scratch_images, expected_scratch_images) - def test_example_multiple_codeblocks_2(self): '''Tests that enabling the codehilite extension does not effect the functionality. (Loads the compatiability processor). @@ -143,134 +90,6 @@ def test_example_multiple_codeblocks_2(self): expected_string = self.read_test_file(self.processor_name, 'example_multiple_codeblocks_expected_2.html', strip=True) self.assertEqual(expected_string, converted_test_string) - actual_scratch_images = verto_extension.required_files['scratch_images'] - expected_scratch_images = { - ScratchImageMetaData( - hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', - text='when flag clicked\nsay [Hi]' - ), - ScratchImageMetaData( - hash='cd6d9a0d464bb8f5eec1e6fc9a4e33378a64ebfce7c6198794ead614962f38e5', - text='when flag clicked\nsay [Hi]\nmove (foo) steps\nturn ccw (9) degrees' - ), - ScratchImageMetaData( - hash='8e8a2129c3cecf32101248439961735fc1d45793fadc56e2575673f63d42b9fb', - text='when flag clicked\nclear\nforever\npen down\n\nif < and > then\nswitch costume to [button v]\nelse\nadd (x position) to [list v]\nend\n\nmove (foo) steps\nturn ccw (9) degrees' - ), - } - self.assertSetEqual(actual_scratch_images, expected_scratch_images) - - def test_example_split_codeblocks(self): - '''Tests that scratch images are split if the split option is - given on the language. - ''' - test_string = self.read_test_file(self.processor_name, 'example_split_codeblocks.md') - - converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.verto_extension]) - expected_string = self.read_test_file(self.processor_name, 'example_split_codeblocks_expected.html', strip=True) - self.assertEqual(expected_string, converted_test_string) - - actual_scratch_images = self.verto_extension.required_files['scratch_images'] - expected_scratch_images = { - ScratchImageMetaData( - hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', - text='when flag clicked\nsay [Hi]' - ), - ScratchImageMetaData( - hash='cd6d9a0d464bb8f5eec1e6fc9a4e33378a64ebfce7c6198794ead614962f38e5', - text='when flag clicked\nsay [Hi]\nmove (foo) steps\nturn ccw (9) degrees' - ), - ScratchImageMetaData( - hash='a0f8fcad796864abfacac8bda6e0719813833fd1fca348700abbd040557c1576', - text='when flag clicked\nclear\nforever\npen down\nif < and > then\nswitch costume to [button v]\nelse\nadd (x position) to [list v]\nend\nmove (foo) steps\nturn ccw (9) degrees' - ), - } - self.assertSetEqual(actual_scratch_images, expected_scratch_images) - - def test_example_split_codeblocks_default(self): - '''Tests that scratch images are split if the split option is - given on the language. - ''' - verto_extension = VertoExtension([self.processor_name], {}, []) - test_string = self.read_test_file(self.processor_name, 'example_split_codeblocks_default.md') - - converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) - expected_string = self.read_test_file(self.processor_name, 'example_split_codeblocks_expected.html', strip=True) - self.assertEqual(expected_string, converted_test_string) - - actual_scratch_images = verto_extension.required_files['scratch_images'] - expected_scratch_images = { - ScratchImageMetaData( - hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', - text='when flag clicked\nsay [Hi]' - ), - ScratchImageMetaData( - hash='cd6d9a0d464bb8f5eec1e6fc9a4e33378a64ebfce7c6198794ead614962f38e5', - text='when flag clicked\nsay [Hi]\nmove (foo) steps\nturn ccw (9) degrees' - ), - ScratchImageMetaData( - hash='a0f8fcad796864abfacac8bda6e0719813833fd1fca348700abbd040557c1576', - text='when flag clicked\nclear\nforever\npen down\nif < and > then\nswitch costume to [button v]\nelse\nadd (x position) to [list v]\nend\nmove (foo) steps\nturn ccw (9) degrees' - ), - } - self.assertSetEqual(actual_scratch_images, expected_scratch_images) - - def test_example_split_codeblocks_compatibility(self): - '''Tests that options are compatible with codehilite. - ''' - extensions = ['markdown.extensions.codehilite', 'markdown.extensions.fenced_code'] - verto_extension = VertoExtension([self.processor_name], {}, extensions) - test_string = self.read_test_file(self.processor_name, 'example_split_codeblocks.md') - - converted_test_string = markdown.markdown(test_string, extensions=extensions + [verto_extension]) - expected_string = self.read_test_file(self.processor_name, 'example_split_codeblocks_expected.html', strip=True) - self.assertEqual(expected_string, converted_test_string) - - actual_scratch_images = verto_extension.required_files['scratch_images'] - expected_scratch_images = { - ScratchImageMetaData( - hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', - text='when flag clicked\nsay [Hi]' - ), - ScratchImageMetaData( - hash='cd6d9a0d464bb8f5eec1e6fc9a4e33378a64ebfce7c6198794ead614962f38e5', - text='when flag clicked\nsay [Hi]\nmove (foo) steps\nturn ccw (9) degrees' - ), - ScratchImageMetaData( - hash='a0f8fcad796864abfacac8bda6e0719813833fd1fca348700abbd040557c1576', - text='when flag clicked\nclear\nforever\npen down\nif < and > then\nswitch costume to [button v]\nelse\nadd (x position) to [list v]\nend\nmove (foo) steps\nturn ccw (9) degrees' - ), - } - self.assertSetEqual(actual_scratch_images, expected_scratch_images) - - def test_example_random_codeblocks(self): - '''Tests that scratch images are arranged randomly given - the random option is given. - ''' - test_string = self.read_test_file(self.processor_name, 'example_random_codeblocks.md') - - outputs = set() - for i in range(6): #P(Outputs the Same) < 0.99 [3 Blocks] - converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.verto_extension]) - outputs.add(converted_test_string) - self.assertEqual(len(self.verto_extension.required_files['scratch_images']), 1) - self.verto_extension.clear_saved_data() - self.assertFalse(len(outputs) == 1) - - def test_example_random_split_codeblocks(self): - '''Tests that scratch images are arranged randomly given - the random and split option is given. - ''' - test_string = self.read_test_file(self.processor_name, 'example_random_split_codeblocks.md') - - outputs = set() - for i in range(6): #P(Outputs the Same) < 0.99 [3 Blocks] - converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.verto_extension]) - outputs.add(converted_test_string) - self.assertEqual(len(self.verto_extension.required_files['scratch_images']), 3) - self.verto_extension.clear_saved_data() - self.assertFalse(len(outputs) == 1) - def test_example_other_code(self): '''Tests that other codeblocks that are not scratch codeblocks are not erroneously matched. @@ -280,12 +99,3 @@ def test_example_other_code(self): converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'example_other_code_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - - actual_scratch_images = self.verto_extension.required_files['scratch_images'] - expected_scratch_images = { - ScratchImageMetaData( - hash='a0f8fcad796864abfacac8bda6e0719813833fd1fca348700abbd040557c1576', - text='when flag clicked\nclear\nforever\npen down\nif < and > then\nswitch costume to [button v]\nelse\nadd (x position) to [list v]\nend\nmove (foo) steps\nturn ccw (9) degrees' - ), - } - self.assertSetEqual(actual_scratch_images, expected_scratch_images) diff --git a/verto/tests/assets/configuration/all_processors_custom_html_expected.html b/verto/tests/assets/configuration/all_processors_custom_html_expected.html index 41904832..09a1b462 100644 --- a/verto/tests/assets/configuration/all_processors_custom_html_expected.html +++ b/verto/tests/assets/configuration/all_processors_custom_html_expected.html @@ -34,10 +34,19 @@

-
- - -
{{ table_of_contents }} +

+when flag clicked
+clear
+forever
+pen down
+if <<mouse down?> and <touching [mouse-pointer v]?>> then
+switch costume to [button v]
+else
+add (x position) to [list v]
+end
+move (foo) steps
+turn ccw (9) degrees
+
{{ table_of_contents }}
diff --git a/verto/tests/assets/configuration/all_processors_except_comment_expected.html b/verto/tests/assets/configuration/all_processors_except_comment_expected.html index fc481627..77f1b197 100644 --- a/verto/tests/assets/configuration/all_processors_except_comment_expected.html +++ b/verto/tests/assets/configuration/all_processors_except_comment_expected.html @@ -44,10 +44,19 @@

-
- - -
{{ table_of_contents }} +

+when flag clicked
+clear
+forever
+pen down
+if <<mouse down?> and <touching [mouse-pointer v]?>> then
+switch costume to [button v]
+else
+add (x position) to [list v]
+end
+move (foo) steps
+turn ccw (9) degrees
+
{{ table_of_contents }}
diff --git a/verto/tests/assets/configuration/all_processors_expected.html b/verto/tests/assets/configuration/all_processors_expected.html index df3a7494..3735db9d 100644 --- a/verto/tests/assets/configuration/all_processors_expected.html +++ b/verto/tests/assets/configuration/all_processors_expected.html @@ -43,10 +43,19 @@

-
- - -
{{ table_of_contents }} +

+when flag clicked
+clear
+forever
+pen down
+if <<mouse down?> and <touching [mouse-pointer v]?>> then
+switch costume to [button v]
+else
+add (x position) to [list v]
+end
+move (foo) steps
+turn ccw (9) degrees
+
{{ table_of_contents }}
diff --git a/verto/tests/assets/configuration/multiline_templates_expected.html b/verto/tests/assets/configuration/multiline_templates_expected.html index 5aa68efa..3fb2f3c8 100644 --- a/verto/tests/assets/configuration/multiline_templates_expected.html +++ b/verto/tests/assets/configuration/multiline_templates_expected.html @@ -42,10 +42,19 @@

-
- - -
{{ table_of_contents }} +

+when flag clicked
+clear
+forever
+pen down
+if <<mouse down?> and <touching [mouse-pointer v]?>> then
+switch costume to [button v]
+else
+add (x position) to [list v]
+end
+move (foo) steps
+turn ccw (9) degrees
+
{{ table_of_contents }}
diff --git a/verto/tests/assets/scratch-inline/doc_example_basic_usage_expected.html b/verto/tests/assets/scratch-inline/doc_example_basic_usage_expected.html index 09960caa..6825f231 100644 --- a/verto/tests/assets/scratch-inline/doc_example_basic_usage_expected.html +++ b/verto/tests/assets/scratch-inline/doc_example_basic_usage_expected.html @@ -1 +1 @@ -

Lipsum Lorem ipsem.

+

Lipsum Lorem say [Hello] for (2) secs ipsem.

diff --git a/verto/tests/assets/scratch-inline/doc_example_override_html_expected.html b/verto/tests/assets/scratch-inline/doc_example_override_html_expected.html index b1146b16..a0060869 100644 --- a/verto/tests/assets/scratch-inline/doc_example_override_html_expected.html +++ b/verto/tests/assets/scratch-inline/doc_example_override_html_expected.html @@ -1 +1 @@ -

How about some scratch:

+

How about some scratch: when flag clicked

diff --git a/verto/tests/assets/scratch-inline/doc_example_override_html_template.html b/verto/tests/assets/scratch-inline/doc_example_override_html_template.html index eede164d..677eef79 100644 --- a/verto/tests/assets/scratch-inline/doc_example_override_html_template.html +++ b/verto/tests/assets/scratch-inline/doc_example_override_html_template.html @@ -1 +1 @@ - +{{ scratch_block }} diff --git a/verto/tests/assets/scratch-inline/mixed_codeblocks_expected.html b/verto/tests/assets/scratch-inline/mixed_codeblocks_expected.html index 71e4cde0..e9ecd85d 100644 --- a/verto/tests/assets/scratch-inline/mixed_codeblocks_expected.html +++ b/verto/tests/assets/scratch-inline/mixed_codeblocks_expected.html @@ -1 +1 @@ -

How about some scratch: which is the same as the python expression: print('Hello')

+

How about some scratch: say [Hello] which is the same as the python expression: print('Hello')

diff --git a/verto/tests/assets/scratch-inline/multiple_codeblocks_expected.html b/verto/tests/assets/scratch-inline/multiple_codeblocks_expected.html index 30f7cc1f..c7bfc6cb 100644 --- a/verto/tests/assets/scratch-inline/multiple_codeblocks_expected.html +++ b/verto/tests/assets/scratch-inline/multiple_codeblocks_expected.html @@ -1 +1 @@ -

How about some scratch: which will lead into the expression which causes the avatar to .

+

How about some scratch: say [Hello] for (2) secs which will lead into the expression when flag clicked which causes the avatar to turn ccw (9) degrees.

diff --git a/verto/tests/assets/scratch/doc_example_basic_usage_expected.html b/verto/tests/assets/scratch/doc_example_basic_usage_expected.html index 69a8511d..ea01d51d 100644 --- a/verto/tests/assets/scratch/doc_example_basic_usage_expected.html +++ b/verto/tests/assets/scratch/doc_example_basic_usage_expected.html @@ -1,4 +1,11 @@ -
- - -
+
when flag clicked
+clear
+forever
+pen down
+if <<mouse down?> and <touching [mouse-pointer v]?>> then
+switch costume to [button v]
+else
+add (x position) to [list v]
+end
+move (foo) steps
+turn ccw (9) degrees
diff --git a/verto/tests/assets/scratch/doc_example_override_html_expected.html b/verto/tests/assets/scratch/doc_example_override_html_expected.html index ab66e320..0913f011 100644 --- a/verto/tests/assets/scratch/doc_example_override_html_expected.html +++ b/verto/tests/assets/scratch/doc_example_override_html_expected.html @@ -1,3 +1,4 @@ -
- -
+

+when flag clicked
+say [Hi]
+
diff --git a/verto/tests/assets/scratch/doc_example_override_html_template.html b/verto/tests/assets/scratch/doc_example_override_html_template.html index ab7ba3af..5b200514 100644 --- a/verto/tests/assets/scratch/doc_example_override_html_template.html +++ b/verto/tests/assets/scratch/doc_example_override_html_template.html @@ -1,5 +1,3 @@ -
-{% for hash in images -%} - -{% endfor -%} -
+

+{{ scratch_blocks }}
+
diff --git a/verto/tests/assets/scratch/example_multiple_codeblocks_expected.html b/verto/tests/assets/scratch/example_multiple_codeblocks_expected.html index 0af35204..6097b841 100644 --- a/verto/tests/assets/scratch/example_multiple_codeblocks_expected.html +++ b/verto/tests/assets/scratch/example_multiple_codeblocks_expected.html @@ -1,15 +1,22 @@

Scratch is great for kids you can create simple code like:

-
- - -
+
when flag clicked
+say [Hi]

Which then easily builds into:

-
- - -
+
when flag clicked
+say [Hi]
+move (foo) steps
+turn ccw (9) degrees

Finally they can create complex code like so:

-
- - -
+
when flag clicked
+clear
+forever
+pen down
+
+if <<mouse down?> and <touching [mouse-pointer v]?>> then
+switch costume to [button v]
+else
+add (x position) to [list v]
+end
+
+move (foo) steps
+turn ccw (9) degrees
diff --git a/verto/tests/assets/scratch/example_multiple_codeblocks_expected_2.html b/verto/tests/assets/scratch/example_multiple_codeblocks_expected_2.html index 7e55e834..e273cf0b 100644 --- a/verto/tests/assets/scratch/example_multiple_codeblocks_expected_2.html +++ b/verto/tests/assets/scratch/example_multiple_codeblocks_expected_2.html @@ -1,13 +1,20 @@

Scratch is great for kids you can create simple code like:

-
- - -
-
- - -
-
- - -
+
when flag clicked
+say [Hi]
+
when flag clicked
+say [Hi]
+move (foo) steps
+turn ccw (9) degrees
+
when flag clicked
+clear
+forever
+pen down
+
+if <<mouse down?> and <touching [mouse-pointer v]?>> then
+switch costume to [button v]
+else
+add (x position) to [list v]
+end
+
+move (foo) steps
+turn ccw (9) degrees
diff --git a/verto/tests/assets/scratch/example_other_code_expected.html b/verto/tests/assets/scratch/example_other_code_expected.html index 1b1ac718..7fffc6b2 100644 --- a/verto/tests/assets/scratch/example_other_code_expected.html +++ b/verto/tests/assets/scratch/example_other_code_expected.html @@ -1,6 +1,13 @@ -
- - -
+
when flag clicked
+clear
+forever
+pen down
+if <<mouse down?> and <touching [mouse-pointer v]?>> then
+switch costume to [button v]
+else
+add (x position) to [list v]
+end
+move (foo) steps
+turn ccw (9) degrees
type = True
 
diff --git a/verto/tests/assets/scratch/example_random_codeblocks.md b/verto/tests/assets/scratch/example_random_codeblocks.md deleted file mode 100644 index 5e8f5765..00000000 --- a/verto/tests/assets/scratch/example_random_codeblocks.md +++ /dev/null @@ -1,23 +0,0 @@ -Scratch is great for kids you can great simple code like: - -```scratch:random -when flag clicked -say [Hi] - -when flag clicked -say [Hi] -move (foo) steps -turn ccw (9) degrees - -when flag clicked -clear -forever -pen down -if < and > then -switch costume to [button v] -else -add (x position) to [list v] -end -move (foo) steps -turn ccw (9) degrees -``` diff --git a/verto/tests/assets/scratch/example_random_split_codeblocks.md b/verto/tests/assets/scratch/example_random_split_codeblocks.md deleted file mode 100644 index 20d540c2..00000000 --- a/verto/tests/assets/scratch/example_random_split_codeblocks.md +++ /dev/null @@ -1,23 +0,0 @@ -Scratch is great for kids you can great simple code like: - -```scratch:split:random -when flag clicked -say [Hi] - -when flag clicked -say [Hi] -move (foo) steps -turn ccw (9) degrees - -when flag clicked -clear -forever -pen down -if < and > then -switch costume to [button v] -else -add (x position) to [list v] -end -move (foo) steps -turn ccw (9) degrees -``` diff --git a/verto/tests/assets/scratch/example_separate_blocks_expected.html b/verto/tests/assets/scratch/example_separate_blocks_expected.html index 0a80a2ac..c02fddae 100644 --- a/verto/tests/assets/scratch/example_separate_blocks_expected.html +++ b/verto/tests/assets/scratch/example_separate_blocks_expected.html @@ -1,4 +1,13 @@ -
- - -
+
when flag clicked
+clear
+forever
+pen down
+
+if <<mouse down?> and <touching [mouse-pointer v]?>> then
+switch costume to [button v]
+else
+add (x position) to [list v]
+end
+
+move (foo) steps
+turn ccw (9) degrees
diff --git a/verto/tests/assets/scratch/example_split_codeblocks.md b/verto/tests/assets/scratch/example_split_codeblocks.md deleted file mode 100644 index 4a4d6d72..00000000 --- a/verto/tests/assets/scratch/example_split_codeblocks.md +++ /dev/null @@ -1,23 +0,0 @@ -Scratch is great for kids you can great simple code like: - -```scratch:split -when flag clicked -say [Hi] - -when flag clicked -say [Hi] -move (foo) steps -turn ccw (9) degrees - -when flag clicked -clear -forever -pen down -if < and > then -switch costume to [button v] -else -add (x position) to [list v] -end -move (foo) steps -turn ccw (9) degrees -``` diff --git a/verto/tests/assets/scratch/example_split_codeblocks_default.md b/verto/tests/assets/scratch/example_split_codeblocks_default.md deleted file mode 100644 index cdab90b1..00000000 --- a/verto/tests/assets/scratch/example_split_codeblocks_default.md +++ /dev/null @@ -1,22 +0,0 @@ -Scratch is great for kids you can great simple code like: - - scratch:split - when flag clicked - say [Hi] - - when flag clicked - say [Hi] - move (foo) steps - turn ccw (9) degrees - - when flag clicked - clear - forever - pen down - if < and > then - switch costume to [button v] - else - add (x position) to [list v] - end - move (foo) steps - turn ccw (9) degrees diff --git a/verto/tests/assets/scratch/example_split_codeblocks_expected.html b/verto/tests/assets/scratch/example_split_codeblocks_expected.html deleted file mode 100644 index b41c56d0..00000000 --- a/verto/tests/assets/scratch/example_split_codeblocks_expected.html +++ /dev/null @@ -1,9 +0,0 @@ -

Scratch is great for kids you can great simple code like:

-
- - - - - - -
diff --git a/verto/tests/assets/scratch/example_standard_markdown_block_expected.html b/verto/tests/assets/scratch/example_standard_markdown_block_expected.html index c589b3d2..704e9b65 100644 --- a/verto/tests/assets/scratch/example_standard_markdown_block_expected.html +++ b/verto/tests/assets/scratch/example_standard_markdown_block_expected.html @@ -1,5 +1,14 @@

Codeblock follows:

-
- - -
+

+when flag clicked
+clear
+forever
+pen down
+if <<mouse down?> and <touching [mouse-pointer v]?>> then
+switch costume to [button v]
+else
+add (x position) to [list v]
+end
+move (foo) steps
+turn ccw (9) degrees
+
From 9cf506d55155a0d5d8431b8115ce27504cd817b3 Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Fri, 21 May 2021 14:35:00 +1200 Subject: [PATCH 10/26] Fix error in README --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 15d0f2e0..58779178 100644 --- a/README.rst +++ b/README.rst @@ -36,7 +36,7 @@ output to stdout: from verto import Verto - text = open('example.md', 'r') + text = open('example.md', 'r').read() converter = Verto() result = converter.convert(text) From 8f1a453fa6bd75757962de456c252607a6f5e64d Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Fri, 21 May 2021 14:35:18 +1200 Subject: [PATCH 11/26] Update authors --- docs/source/conf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index c5779ff5..64fd1df8 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -23,7 +23,7 @@ from verto import __version__ -# -- General configuration ------------------------------------------------ +# -- General configuration ------------------------------------------------`` # If your documentation needs a minimal Sphinx version, state it here. # @@ -49,7 +49,7 @@ # General information about the project. project = 'Verto' copyright = '2017 University of Canterbury Computer Science Education Research Group' -author = 'Hayley vas Waas, Jack Morgan, Hayden Jackson, Jordan Griffiths' +author = 'UCCSER: Hayley vas Waas, Jack Morgan, Hayden Jackson, Jordan Griffiths' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -131,7 +131,7 @@ # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'Verto.tex', 'Verto Documentation', - 'Hayley vas Waas, Jack Morgan', 'manual'), + 'UCCSER', 'manual'), ] From 9b88eb2637d43481e0e826cd8879ac3a0b542177 Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Fri, 21 May 2021 14:49:11 +1200 Subject: [PATCH 12/26] Update dependencies --- requirements-dev.txt | 2 +- requirements.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 810e86d3..977b7820 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,4 +2,4 @@ setuptools==56.2.0 sphinx==4.0.1 sphinx_rtd_theme==0.5.2 coverage==5.5 -flake8==3.8.4 +flake8==3.9.2 diff --git a/requirements.txt b/requirements.txt index 3ff25dcf..f4fe48c2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ markdown==2.6.11 -Jinja2==2.11.3 -python-slugify==4.0.1 +Jinja2==3.0.1 +python-slugify==5.0.2 From 2148c14c0829d7f470250e7d1bd574f9c49a9821 Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Fri, 21 May 2021 14:55:13 +1200 Subject: [PATCH 13/26] Replace testing on Travis CI with GitHub actions --- .codeclimate.yml | 30 --------------------- .github/workflows/python-package.yaml | 38 +++++++++++++++++++++++++++ .travis.yml | 34 ------------------------ 3 files changed, 38 insertions(+), 64 deletions(-) delete mode 100644 .codeclimate.yml create mode 100644 .github/workflows/python-package.yaml delete mode 100644 .travis.yml diff --git a/.codeclimate.yml b/.codeclimate.yml deleted file mode 100644 index 0e14468e..00000000 --- a/.codeclimate.yml +++ /dev/null @@ -1,30 +0,0 @@ -engines: - radon: - enabled: true - config: - python_version: 3 - pep8: - enabled: true - duplication: - enabled: true - config: - languages: - python: - python_version: 3 - mass_threshold: 32 - fixme: - enabled: true - config: - strings: - - FIXME - - BUG - - CUSTOM - - TODO - - NTS - - NOTE - - HACK -ratings: - paths: - - "**.py" -exclude_paths: -- "verto/tests/*" diff --git a/.github/workflows/python-package.yaml b/.github/workflows/python-package.yaml new file mode 100644 index 00000000..387ea6b2 --- /dev/null +++ b/.github/workflows/python-package.yaml @@ -0,0 +1,38 @@ +name: Python package + +on: [push] + +jobs: + build: + runs-on: ubuntu-20.04 + strategy: + matrix: + python-version: [3.6, 3.7, 3.8, 3.9] + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2.2.2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install -r requirements-dev.txt + + - name: Lint with flake8 + run: | + flake8 . --show-source --statistics + + - name: Test suite + run: | + coverage run --rcfile=.coveragerc -m verto.tests.start_tests + coverage xml -i + coverage report -m --skip-covered + + - name: Code Coverage + uses: codecov/codecov-action@v1.5.0 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 06de4143..00000000 --- a/.travis.yml +++ /dev/null @@ -1,34 +0,0 @@ -language: python - -python: - - "3.4" - - "3.5" - - "3.5-dev" # 3.5 development branch - - "3.6" - - "3.6-dev" # 3.6 development branch - -# Install dependencies -install: - - pip install -r requirements.txt - - pip install -r requirements-dev.txt - -# Runs test suite -script: - - flake8 - - coverage run --rcfile=.coveragerc -m verto.tests.start_tests --travis -after_success: - - coverage xml -i - - coverage report -m --skip-covered - - bash <(curl -s https://codecov.io/bash) - -# Stop email notifications but post to organisation Slack channel -notifications: - email: false - slack: - rooms: deptfunstuff:abJKvzApk5SKtcEyAgtswXAv - on_success: change - on_failure: change - -addons: - code_climate: - repo_token: e8d3f32c2549e7919e154bc5506d4cc743a03408f3ca2bf957020c3e5f826eaf From 6156d9f26d094599c5266acb7e6a05dfdf4d1e81 Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Fri, 21 May 2021 14:58:11 +1200 Subject: [PATCH 14/26] Create codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..bf2a5784 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,46 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ develop, master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ develop ] + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-20.04 + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'python' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 From 48c5a66a7fa5b6d4b70d4c98d2d3aa39ffdcb9a9 Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Fri, 21 May 2021 15:35:46 +1200 Subject: [PATCH 15/26] Tidy logic for video id function --- verto/processors/VideoBlockProcessor.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/verto/processors/VideoBlockProcessor.py b/verto/processors/VideoBlockProcessor.py index 6c1b6c2a..0032aea9 100644 --- a/verto/processors/VideoBlockProcessor.py +++ b/verto/processors/VideoBlockProcessor.py @@ -86,22 +86,18 @@ def extract_video_identifier(self, video_url): Returns: A tuple of the service and video identifier. ''' - - if re.match(r'.*?youtu\.{0,1}be(.com){0,1}', video_url) is not None: # is a youtube url + if re.match(r'.*?youtu\.{0,1}be(.com){0,1}', video_url) is not None: # is a YouTube url video_url = re.sub(r'(.*?)(\?rel=0)', r'\g<1>', video_url) if 'youtu.be' in video_url or 'youtube.com/embed' in video_url: video_query = video_url.split('/')[-1] - elif 'youtube.com' in video_url: + else: start_pos = video_url.find('v=') + 2 end_pos = video_url.find('&') if end_pos == -1: end_pos = len(video_url) video_query = video_url[start_pos:end_pos] - return('youtube', video_query) - elif 'vimeo' in video_url: video_query = video_url.split('/')[-1] return ('vimeo', video_query) - return (None, '') From 6b6f1807cc4e800b8927c06c7e567858902bea1e Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Fri, 21 May 2021 15:41:24 +1200 Subject: [PATCH 16/26] Rename GitHub action workflow --- .github/workflows/{python-package.yaml => test-suite.yaml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{python-package.yaml => test-suite.yaml} (97%) diff --git a/.github/workflows/python-package.yaml b/.github/workflows/test-suite.yaml similarity index 97% rename from .github/workflows/python-package.yaml rename to .github/workflows/test-suite.yaml index 387ea6b2..2b188841 100644 --- a/.github/workflows/python-package.yaml +++ b/.github/workflows/test-suite.yaml @@ -1,4 +1,4 @@ -name: Python package +name: Test suite on: [push] From 0598dc73599600f57cd88d53e96b6b0aaa357989 Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Fri, 21 May 2021 15:45:34 +1200 Subject: [PATCH 17/26] State only version 3 of Python is supported --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e40b6ee2..9f3bc7ff 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ from verto import __version__ if not sys.version_info[0] == 3: - sys.exit('Sorry, currently only Python 3 is supported.') + sys.exit('Sorry, only Python 3 is supported.') with open('requirements.txt') as f: requirements = f.read().splitlines() From ec1cb5869a3fffd313b90e6d6beca7d8ac78d3c6 Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Fri, 21 May 2021 20:22:54 +1200 Subject: [PATCH 18/26] Update build and publish method --- .github/workflows/publish-to-pypi.yml | 33 +++++++++++++++++++ LICENSE.md => LICENSE.rst | 0 MANIFEST.in | 3 -- README.rst | 4 +-- docs/source/usage.rst | 3 -- pyproject.toml | 6 ++++ requirements.txt | 4 +-- setup.cfg | 47 +++++++++++++++++++++++++++ setup.py | 39 ---------------------- verto/__init__.py | 2 +- 10 files changed, 90 insertions(+), 51 deletions(-) create mode 100644 .github/workflows/publish-to-pypi.yml rename LICENSE.md => LICENSE.rst (100%) delete mode 100644 MANIFEST.in create mode 100644 pyproject.toml create mode 100644 setup.cfg delete mode 100644 setup.py diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml new file mode 100644 index 00000000..ed0b46fa --- /dev/null +++ b/.github/workflows/publish-to-pypi.yml @@ -0,0 +1,33 @@ +name: Publish to PyPI + +on: + release: + types: [published] + +jobs: + build-and-publish: + name: Build and publish to PyPI + runs-on: ubuntu-20.04 + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Set up Python 3 + uses: actions/setup-python@v2.2.2 + with: + python-version: '3.x' + + - name: Install build dependencies + run: | + pip install -U setuptools wheel build + + - name: Build distribution files + run: | + python -m build . + + - name: Publish + uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/LICENSE.md b/LICENSE.rst similarity index 100% rename from LICENSE.md rename to LICENSE.rst diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 2f4ad2a1..00000000 --- a/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -include *.txt -include *.md -recursive-include verto *.html *.py *.png *.conf *.md *.json diff --git a/README.rst b/README.rst index 58779178..4bfd0756 100644 --- a/README.rst +++ b/README.rst @@ -67,7 +67,7 @@ FAQ **Where is the changelog?** -The changelog is available within the `documentation`_. +The changelog is available within the `CHANGELOG`_ file. **How do I install the development version as local package?** @@ -76,7 +76,7 @@ The changelog is available within the `documentation`_. 3. ``$ pip3 install .`` .. _ReadTheDocs: http://verto.readthedocs.io/en/latest/ -.. _documentation: http://verto.readthedocs.io/en/latest/changelog.html +.. _CHANGELOG: CHANGELOG.md .. _license file: LICENSE.md .. _existing and closed issues: https://github.com/uccser/verto/issues .. _open a new issue: https://github.com/uccser/verto/issues/new diff --git a/docs/source/usage.rst b/docs/source/usage.rst index 1f3548c4..fbe12995 100644 --- a/docs/source/usage.rst +++ b/docs/source/usage.rst @@ -122,9 +122,6 @@ The following attributes are available: - ``html_string`` - A resulting string of HTML after conversion by Verto. - ``title`` - The text of the first heading saved by the ``save-title`` processor. - ``required_files`` - A dictionary of files encountered in a Verto conversion. The dictionary has a string for the file type as the key (for example: ``image``) and a set of all file paths encountered as the value (for example: ``{'image/face.png', 'image/logo.png`}``). - - - See :ref:`accessing-scratch-image-data` for data from Scratch processor. - - ``heading_tree`` - A tuple of namedtuples which describes the tree of headings, as generated by our heading processor. Each namedtuple contains a ``title`` (string), ``title_slug`` (string), ``level`` (integer) and ``children`` (tuple of nodes). - For example the heading root after a conversion of a file: diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..ef185807 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,6 @@ +[build-system] +requires = [ + "setuptools>=47", + "wheel" +] +build-backend = "setuptools.build_meta" diff --git a/requirements.txt b/requirements.txt index f4fe48c2..d6e1198b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1 @@ -markdown==2.6.11 -Jinja2==3.0.1 -python-slugify==5.0.2 +-e . diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..40734a8f --- /dev/null +++ b/setup.cfg @@ -0,0 +1,47 @@ +[metadata] +name = verto +version = attr: verto.__version__ +description = Verto is an extension of the Python Markdown package, which allows authors to include complex HTML elements with simple text tags in their Markdown. +long_description = file: README.rst, CHANGELOG.rst, LICENSE.rst +author = University of Canterbury Computer Science Education Research Group +author_email = csse-education-research@canterbury.ac.nz +keywords = + markdown + verto + development + textbook + converter + media + richtext + interactive + education + html + book + author + extension +license = MIT +license_files = LICENSE.md +classifiers = + Intended Audience :: Developers + Intended Audience :: Education + License :: OSI Approved :: MIT License + Operating System :: MacOS :: MacOS X + Operating System :: Microsoft :: Windows + Operating System :: POSIX + Programming Language :: Python :: 3 + Topic :: Text Processing :: Markup + Topic :: Text Processing :: Markup :: HTML +project_urls = + Issue Tracker = https://github.com/uccser/verto/issues + Documentation = https://verto.readthedocs.io/en/latest/ + Source Code = https://github.com/uccser/verto + + +[options] +packages = find: +python_requires = >=3.6 +include_package_data = True +install_requires = + markdown==2.6.11 + Jinja2==3.0.1 + python-slugify==5.0.2 diff --git a/setup.py b/setup.py deleted file mode 100644 index 9f3bc7ff..00000000 --- a/setup.py +++ /dev/null @@ -1,39 +0,0 @@ -from setuptools import setup, find_packages -import sys -from verto import __version__ - -if not sys.version_info[0] == 3: - sys.exit('Sorry, only Python 3 is supported.') - -with open('requirements.txt') as f: - requirements = f.read().splitlines() - -with open('README.rst') as f: - long_description = f.read() - -setup( - name='verto', - version=__version__, - description='Verto is an extension of the Python Markdown package, which allows authors to include complex HTML elements with simple text tags in their Markdown.', - long_description=long_description, - url='https://github.com/uccser/verto', - author='University of Canterbury Computer Science Education Research Group', - author_email='csse-education-research@canterbury.ac.nz', - license='MIT', - classifiers=[ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'Intended Audience :: Education', - 'License :: OSI Approved :: MIT License', - 'Operating System :: MacOS :: MacOS X', - 'Operating System :: Microsoft :: Windows', - 'Operating System :: POSIX', - 'Programming Language :: Python :: 3', - 'Topic :: Text Processing :: Markup', - 'Topic :: Text Processing :: Markup :: HTML' - ], - keywords='markdown verto development textbook converter media richtext interactive education html book author extension', - packages=find_packages(), - include_package_data=True, - install_requires=requirements -) diff --git a/verto/__init__.py b/verto/__init__.py index d6c3e202..16ee11b6 100644 --- a/verto/__init__.py +++ b/verto/__init__.py @@ -1,4 +1,4 @@ # flake8: noqa from .Verto import Verto -__version__ = '0.11.0' +__version__ = '1.0.0' From 7ef275df1e91b76f5fd7b85aca83830d001cb98e Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Fri, 21 May 2021 20:24:39 +1200 Subject: [PATCH 19/26] Update documentation on release process --- docs/source/contributing.rst | 49 ++---------------------------------- 1 file changed, 2 insertions(+), 47 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 0261e1b6..03b3bbc7 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -380,53 +380,8 @@ For example: Creating a release ======================================= -This is our current process for creating and publishing a Verto release. This -can only be performed by repository administrators. - -1. `Create a release branch`_. Checkout to this branch. - - .. code-block:: bash - - $ git checkout develop - $ git pull - $ git checkout -b release/0.7.0 - -2. Update the version number [1]_ within ``verto/__init__.py``. -3. Check test suite for errors, and fix any issues that arise, or `log an issue`_. -4. Detail the changes in ``docs/source/changelog.rst``. -5. `Complete the release branch`_. Be sure to tag the release with the version number for creating the release on GitHub. - - .. code-block:: bash - - $ git checkout master - $ git pull - $ git merge --no-ff release/0.7.0 - $ git tag -a 0.7.0 - $ git push - $ git push --tags - - -6. `Upload the release to PyPI`_ - - .. code-block:: bash - - $ rm -r dist/ - $ python3 -m pip install --user --upgrade setuptools wheel - $ python3 setup.py sdist bdist_wheel - $ python3 -m pip install --user --upgrade twine - $ twine upload dist/* - -7. Merge the release into develop - - .. code-block:: bash - - $ git checkout develop - $ git pull - $ git merge --no-ff release/0.7.0 - -8. Create the release on `GitHub`_ on the tagged commit. -9. Delete the release branch. - +Releases are built and published automatically to PyPI by a GitHub actions workflow. +See ``.github/workflows/publish-to-pypi.yml``. Other notes ======================================= From a67b55b773024424f12ab7cc9f2d7c465c7f2f3f Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Fri, 21 May 2021 20:25:45 +1200 Subject: [PATCH 20/26] Update sphinx dependency --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 977b7820..437afe46 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,5 +1,5 @@ setuptools==56.2.0 -sphinx==4.0.1 +sphinx==4.0.2 sphinx_rtd_theme==0.5.2 coverage==5.5 flake8==3.9.2 From bb7c992d9c0a8aaa73a2dc984db4cc8dc5c2eb3b Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Fri, 21 May 2021 20:45:28 +1200 Subject: [PATCH 21/26] Test publishing package at Test PyPI --- .github/workflows/publish-to-pypi.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml index ed0b46fa..67f85153 100644 --- a/.github/workflows/publish-to-pypi.yml +++ b/.github/workflows/publish-to-pypi.yml @@ -1,8 +1,6 @@ name: Publish to PyPI -on: - release: - types: [published] +on: push jobs: build-and-publish: @@ -26,7 +24,15 @@ jobs: run: | python -m build . - - name: Publish + - name: Publish to Test PyPI + uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.TEST_PYPI_API_TOKEN }} + repository_url: https://test.pypi.org/legacy/ + + - name: Publish to PyPI + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') uses: pypa/gh-action-pypi-publish@master with: user: __token__ From 03ce1a13e65b4485863ed79a4f00d343712d2b06 Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Sat, 22 May 2021 11:00:05 +1200 Subject: [PATCH 22/26] Add build documentation workflow --- .github/workflows/documentation.yaml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/documentation.yaml diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml new file mode 100644 index 00000000..0fc840d1 --- /dev/null +++ b/.github/workflows/documentation.yaml @@ -0,0 +1,27 @@ +name: Documentation + +on: [push] + +jobs: + build-documentation: + runs-on: ubuntu-20.04 + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Set up Python 3 + uses: actions/setup-python@v2.2.2 + with: + python-version: '3.x' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install -r requirements-dev.txt + + - name: Build documentation + uses: ammaraskar/sphinx-action@master + with: + docs-folder: "docs/" From bc83b957c686e98ff7054353081cb78e81de6659 Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Sat, 22 May 2021 11:39:04 +1200 Subject: [PATCH 23/26] Update changelog --- README.rst | 4 ++-- docs/source/changelog.rst | 35 +++++++++++++++++++++++++++++++++++ docs/source/contributing.rst | 2 -- setup.cfg | 4 ++-- 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 4bfd0756..58779178 100644 --- a/README.rst +++ b/README.rst @@ -67,7 +67,7 @@ FAQ **Where is the changelog?** -The changelog is available within the `CHANGELOG`_ file. +The changelog is available within the `documentation`_. **How do I install the development version as local package?** @@ -76,7 +76,7 @@ The changelog is available within the `CHANGELOG`_ file. 3. ``$ pip3 install .`` .. _ReadTheDocs: http://verto.readthedocs.io/en/latest/ -.. _CHANGELOG: CHANGELOG.md +.. _documentation: http://verto.readthedocs.io/en/latest/changelog.html .. _license file: LICENSE.md .. _existing and closed issues: https://github.com/uccser/verto/issues .. _open a new issue: https://github.com/uccser/verto/issues/new diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index c58c4c16..832df9a5 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -1,6 +1,41 @@ Changelog ####################################### +1.0.0 +======================================= + +This is the first official release of Verto, after over four years of use in production systems. +There are several changes in this release that may break existing pipelines and require changes. + +- Add new :doc:`processors/external-link` processor that modifies hyperlinks to open in a new tab. +- Modify :doc:`processors/scratch` and :doc:`processors/scratch-inline` processors to set Scratch code to be rendered by a JavaScript library. + + - This replaces the previous method of creating images. + - The ``split`` option has been removed as it is no longer relevant to the new method. + - The ``random`` option has been removed to improve consistency in rendered material. + + - Randomising the blocks can be achieved after rendering the code. + +- Use GitHub Actions for automated builds and publishing to PyPI. +- Use new declarative setup.cfg file for packaging configuration. +- Removed CodeClimate configuration file. +- Use GitHub Actions for automated testing (instead of Travis CI) and code analysis. +- Switch dependency tracking from PyUp to Dependabot. +- Move changelog outside of documentation to homepage for inclusion on PyPI homepage. +- Correct argument ``custom_settings`` to ``settings``. +- Update images for Scratch examples to use Scratch 3. +- Update regular expression strings in Python code to use raw strings. +- Updated authors to state UCCSER as primary owner. +- Dependency updates: + + - Update ``setuptools`` from 41.0.1 to 56.2.0. + - Update ``sphinx`` from 1.8.1 to 4.0.2. + - Update ``sphinx_rtd_theme`` from 0.4.3 to 0.5.2. + - Update ``coverage`` from 4.5.3 to 5.5. + - Update ``flake8`` from 3.5.0 to 3.9.2. + - Update ``Jinja2`` from 2.10.1 to 3.0.1. + - Update ``python-slugify`` from 3.0.2 to 5.0.2. + 0.11.0 ======================================= diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 03b3bbc7..48020755 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -397,8 +397,6 @@ Why are all dependency versions pinned? Yes, this is not considered the best practice by the Python Software Foundation in their `packaging guide `_. However pinning dependencies ensure we control over each Verto release, following the logic of `Vincent Driessen `_. -.. [1] We follow `Semantic Versioning `_ for our numbering system. The number is used by ``setup.py`` to tell PyPI which version is being uploaded or ``pip`` which version is installed, and also used during the documentation build to number the version of Verto it was built from. - .. _CS Unplugged: https://github.com/uccser/cs-unplugged/ .. _CS Field Guide: https://github.com/uccser/cs-field-guide/ .. _here: https://github.com/uccser/verto diff --git a/setup.cfg b/setup.cfg index 40734a8f..74cc48d1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,7 +2,7 @@ name = verto version = attr: verto.__version__ description = Verto is an extension of the Python Markdown package, which allows authors to include complex HTML elements with simple text tags in their Markdown. -long_description = file: README.rst, CHANGELOG.rst, LICENSE.rst +long_description = file: README.rst, LICENSE.rst author = University of Canterbury Computer Science Education Research Group author_email = csse-education-research@canterbury.ac.nz keywords = @@ -34,9 +34,9 @@ classifiers = project_urls = Issue Tracker = https://github.com/uccser/verto/issues Documentation = https://verto.readthedocs.io/en/latest/ + Changelog = http://verto.readthedocs.io/en/latest/changelog.html Source Code = https://github.com/uccser/verto - [options] packages = find: python_requires = >=3.6 From 7c12e495e79f789c6dd8422ce78823297b5d19f6 Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Sat, 22 May 2021 11:44:11 +1200 Subject: [PATCH 24/26] Ignore duplicate uploads to Test PyPI --- .github/workflows/publish-to-pypi.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml index 67f85153..f8ea8856 100644 --- a/.github/workflows/publish-to-pypi.yml +++ b/.github/workflows/publish-to-pypi.yml @@ -30,6 +30,7 @@ jobs: user: __token__ password: ${{ secrets.TEST_PYPI_API_TOKEN }} repository_url: https://test.pypi.org/legacy/ + skip_existing: true - name: Publish to PyPI if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') From 6404e02754f9d91f882d389e0b4dd5940337bfef Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Sat, 22 May 2021 12:03:34 +1200 Subject: [PATCH 25/26] Modify documentation workflow step --- .github/workflows/documentation.yaml | 4 +--- docs/source/processors/blockquote.rst | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 0fc840d1..74aa2523 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -22,6 +22,4 @@ jobs: pip install -r requirements-dev.txt - name: Build documentation - uses: ammaraskar/sphinx-action@master - with: - docs-folder: "docs/" + run: sphinx-build -a -W -b html docs/source/ docs/build/ diff --git a/docs/source/processors/blockquote.rst b/docs/source/processors/blockquote.rst index 1fa79934..4ec91533 100644 --- a/docs/source/processors/blockquote.rst +++ b/docs/source/processors/blockquote.rst @@ -13,7 +13,7 @@ Optional Tag Parameters - ``footer`` - Boolean flag to indicate whether the blockquote contains a footer. - - If given as ``true``, then the last line should start with ``- `` to show it's the footer. + - If given as ``true``, then the last line should start with a dash (``-``) followed by a space to show it's the footer. - ``source`` - Sets the ``cite`` parameter of the ``blockquote`` element. From 761bc594118f8f55fa31615e509f503800b73eb4 Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Sat, 22 May 2021 12:39:16 +1200 Subject: [PATCH 26/26] Fix errors in building documentation --- .github/workflows/documentation.yaml | 2 +- docs/source/usage.rst | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 74aa2523..58b3c121 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -22,4 +22,4 @@ jobs: pip install -r requirements-dev.txt - name: Build documentation - run: sphinx-build -a -W -b html docs/source/ docs/build/ + run: sphinx-build -a -W -E -b html docs/source/ docs/build/ diff --git a/docs/source/usage.rst b/docs/source/usage.rst index fbe12995..51f419a8 100644 --- a/docs/source/usage.rst +++ b/docs/source/usage.rst @@ -170,8 +170,10 @@ Changing processors ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automethod:: verto.Verto.update_processors(processors) + :noindex: .. automethod:: verto.Verto.processor_defaults(processors) + :noindex: This function is useful if you want to make minor changes to the default used processors. For example: You wish to still use all default processors but skip video tags: @@ -193,8 +195,10 @@ Changing HTML templates ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. automethod:: verto.Verto.update_templates(html_templates) + :noindex: .. automethod:: verto.Verto.clear_templates() + :noindex: Full list of package methods =======================================