From 1b28e246b773dee65ffd957f058299a50ae13b3c Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Wed, 22 Feb 2017 17:12:29 +1300 Subject: [PATCH 01/86] Started work on complex style preprocessor. --- kordac/processor-info.json | 13 +++ kordac/processors/StylePreprocessor.py | 142 +++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 kordac/processors/StylePreprocessor.py diff --git a/kordac/processor-info.json b/kordac/processor-info.json index d35a0780..0c03f163 100644 --- a/kordac/processor-info.json +++ b/kordac/processor-info.json @@ -1,4 +1,17 @@ { + "style": { + "strings": { + "inline": ["comment", "glossary-link"], + "block": ["panel", "video", "image", "interactive", "button-link", "boxed-text"] + }, + "rules": { + "block": "(regex (format \"\\{\\{block\\} ?([^\\}]*)(?[^\\}]*)(? close_parentheses else "More closing than opening." + raise Exception('Parentheses don\'t match. {0}'.format(extra)) + return commands From afca29f4da8988798657ea78c3cc378fa848ad41 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Thu, 23 Feb 2017 14:28:55 +1300 Subject: [PATCH 02/86] Added hardcoded style preprocessor. --- kordac/Kordac.py | 1 + kordac/KordacExtension.py | 2 + kordac/processor-info.json | 13 +- kordac/processors/StylePreprocessor.py | 164 +++++++----------------- kordac/processors/errors/StyleError.py | 16 +++ kordac/tests/assets/smoke/algorithms.md | 21 +++ 6 files changed, 92 insertions(+), 125 deletions(-) create mode 100644 kordac/processors/errors/StyleError.py diff --git a/kordac/Kordac.py b/kordac/Kordac.py index f8c3085b..886cbc8a 100644 --- a/kordac/Kordac.py +++ b/kordac/Kordac.py @@ -10,6 +10,7 @@ 'relative-link', 'boxed-text', 'button-link', + 'style', }) class Kordac(object): diff --git a/kordac/KordacExtension.py b/kordac/KordacExtension.py index 3a40163c..00807c5d 100644 --- a/kordac/KordacExtension.py +++ b/kordac/KordacExtension.py @@ -15,6 +15,7 @@ from kordac.processors.ButtonLinkBlockProcessor import ButtonLinkBlockProcessor from kordac.processors.BoxedTextBlockProcessor import BoxedTextBlockProcessor from kordac.processors.BeautifyPostprocessor import BeautifyPostprocessor +from kordac.processors.StylePreprocessor import StylePreprocessor from collections import defaultdict from os import listdir @@ -40,6 +41,7 @@ def extendMarkdown(self, md, md_globals): ['save-title', SaveTitlePreprocessor(self, md), '_end'], ['remove-title', RemoveTitlePreprocessor(self, md), '_end'], ['comment', CommentPreprocessor(self, md), '_begin'], + ['style', StylePreprocessor(self, md), '_begin'] ] inlinepatterns = [ ['relative-link', RelativeLinkPattern(self, md), '_begin'] diff --git a/kordac/processor-info.json b/kordac/processor-info.json index 0c03f163..1f864e16 100644 --- a/kordac/processor-info.json +++ b/kordac/processor-info.json @@ -1,15 +1,10 @@ { "style": { + "block_pattern": "\\{{{block} ?([^\\}}]*)\\}}", + "inline_pattern": "\\{{{inline} ?([^\\}}]*)\\}}", "strings": { - "inline": ["comment", "glossary-link"], - "block": ["panel", "video", "image", "interactive", "button-link", "boxed-text"] - }, - "rules": { - "block": "(regex (format \"\\{\\{block\\} ?([^\\}]*)(? close_parentheses else "More closing than opening." - raise Exception('Parentheses don\'t match. {0}'.format(extra)) - return commands + ''' + Validates lines and raising StyleErrors when rules are not upheld. + Args: + lines: A string of Markdown text. + Returns: + The original document. + ''' + for i, line in enumerate(lines): + for block_string in self.block_strings: + c = re.compile(self.block_pattern.format(**{'block': block_string})) + block_match = c.search(line) + if block_match is not None: + # Grab important lines and their numbers + line_nums, error_lines = zip(*map(lambda x: (x[0], x[1].strip()), (list(enumerate(lines))[max(0, i - 1): min(len(lines) - 1, i + 1)]))) + + # Remove all empty lines Should only be one line left + if len([line for line in error_lines if line != '']) != 1: + raise StyleError(line_nums, error_lines, "Blocks must be separated by whitespace.") + + start_index, end_index = block_match.span() + rest = line[:start_index] + line[end_index+1:] + for char in rest: + if not char.isspace(): + raise StyleError(line_nums, error_lines, "Blocks must be the only thing on the line.") + + # for inline_string in self.inline_strings: + # c = re.compile(self.inline_pattern.format(**{'inline': inline_string})) + # inline_match = c.search(line) + # if inline_match is not None: + # start_index, end_index = inline_match.span() + # + # if not ((start_index - 1) >= 0 and line[start_index - 1].isspace() or (start_index - 1) < 0): + # raise StyleError([i], [line], "Inline must be separated by whitespace.") + # if not ((end_index + 1) < len(line) and line[end_index + 1].isspace() or (end_index + 1) >= len(line)): + # raise StyleError([i], [line], "Inline must be separated by whitespace.") + + return lines diff --git a/kordac/processors/errors/StyleError.py b/kordac/processors/errors/StyleError.py new file mode 100644 index 00000000..d189a5f1 --- /dev/null +++ b/kordac/processors/errors/StyleError.py @@ -0,0 +1,16 @@ +from kordac.processors.errors.Error import Error + +class StyleError(Exception): + """Exception raised when a Style rule is broken. + + Attributes: + rule -- rule which was broken + lines -- lines where the style rule was broken + message -- explanation of why error was thrown + """ + + def __init__(self, line_nums, lines, message): + super().__init__(message) + self.line_nums = line_nums + self.lines = lines + self.message = message diff --git a/kordac/tests/assets/smoke/algorithms.md b/kordac/tests/assets/smoke/algorithms.md index 765c169a..ad32debe 100644 --- a/kordac/tests/assets/smoke/algorithms.md +++ b/kordac/tests/assets/smoke/algorithms.md @@ -146,6 +146,7 @@ To run this as a classroom activity get all the students to play each section of While they are playing the second part some may have trouble finding the correct algorithm to find the pet. If they are finding these levels confusing you can give them a hint like "Why don't you start by opening the present in the centre" and when they do ask them "What does the number you found tell you about all the numbers before it?" if the number is smaller than the one they are looking for, or "all the numbers after it?" if the number is bigger than the one they are looking for. When students have finished ask them questions like "Where you able to find the pet even though you had less lives? What strategy did you use to find the pet?", we have found that many students will have ended up doing a binary search (or similar) without even knowing what a binary search is! Explaining these algorithms to students is likely to be easier now that they have seen them in action. + {panel end} Searching through collections of data is something computers have to do all the time. It happens every time you type in a search on Google, or when you type in a file name to search for on your computer. Computers deal with such huge amounts of data that we need fast algorithms to help us find information quickly. @@ -172,7 +173,9 @@ Since the boxes in the first game were in a random order there really wasn't any If you used this algorithm you might get lucky and find what you are looking for on your first go, but if you were really unlucky you might have to look through everything in your list before you found the right object! For a list of 10 items this means on average you would only have to look at 5 items to find what you were looking for, but for a list of 10000 you would have to look through on average 5000. {panel type="curiosity" summary="How is Bozo search different from Linear search?"} + If you watched the video at the beginning of the chapter you might be thinking that what you did in the present searching game sounds more like Bozo Search than Linear Search, but actually Bozo Search is even sillier than this! If you were doing a Bozo Search then after unwrapping a present and finding a monster inside, you would wrap the present back up and try another one at random! This means you might end up checking the same present again and again and again and you might never find the pet, even with a small number of presents! + {panel end} ### Binary search @@ -182,12 +185,14 @@ If you watched the video at the beginning of the chapter you might be thinking t A much better algorithm to use is called Binary Search. In the second part of the present searching game the boxes were in order, which meant you were able to be more clever when you were searching for the pet, and you might have been using a Binary Search without realising! {panel type="teacher-note" summary="Teaching binary search with a phone book"} + The binary search algorithm can be demonstrated with a phone book or dictionary: choose a name, then open it at the *middle* page of the book (students might point out that you could guess how far through to open it, but insist on starting in the middle). If you can spare the book, rip it in half at the chosen page, and ask the class which of the two halves contains the name (the ones before the middle, or the ones after). If you don't have replacement books available, you can still proceed by just holding up the chosen half, but it will be more memorable for students when they see the problem literally divided in half. Throw away the half that can't contain the name, pointing out that hundreds of pages have been eliminated by one decision. Repeat this on the remaining half, ripping that in half, then half again, and so on. On the board you can work out the number of pages left; for example, if there were 512 pages in the phone book, after the first rip there are 256, then 128, then 64, 32, 16, 89, 4, 2 and finally just one page. That's 9 pages that were examined to get down to the desired page. (Note that it's easiest to pick numbers that are powers of 2 i.e. 512, 1024, 2048, otherwise you have to deal with halving odd numbers, which works fine, but is a bit distracting). The power of binary search becomes obvious when you ask how long it would take to search a book twice as large. The first rip on the larger book will reduce it to the original problem, so, for example, a book of 1024 pages requires 10 rips instead of the 9 used for 512 pages. A million page phone book (1,048,576 pages to be precise) is reduced to 1 page by only 20 rips (students will probably think that it will be a lot more, but they can work it out by halving 1,048,576 20 times). A billion pages requires only 30 rips - again, have students work this out for themselves, as it is surprising. You could point out that a billion-page phone book could hold every name in the world, and in fact a social network site could have a billion users on it, so searching for someone on a billion-user system could be done *by hand* looking at just 30 names. The catch? They need to be in sorted order, but sorting things into order is easy too if you use the right algorithm. (In practice large systems use a variation of this kind of searching, but this demonstrates how a very fast algorithm is possible on very large amounts of data, such as those used by search engines or social networks). + {panel end} If you used a Binary Search on each of the levels then you would have always had enough lives to find the pet! Informally, the Binary Search algorithm is as follows: @@ -200,18 +205,22 @@ If you used a Binary Search on each of the levels then you would have always had Binary Search is a very powerful algorithm. If you had 1000 presents to search through it would take you at most 10 checks for Binary search to find something and Linear search would take at most 1000 checks, but if you doubled the number of presents to search through how would this change the number of checks made by Binary Search and Linear search? {panel type="spoiler" summary="How does doubling the number of boxes affect the number of checks required?"} + The answer to the above question is that the maximum number of checks for Linear Search would double, but the maximum number for Binary Search would only increase by one. + {panel end} It is important to remember that you can only perform a Binary Search if the items you are searching through are sorted into order. This makes the sorting algorithms we will look at next even more important because without sorting algorithms we wouldn't be able to use Binary Search to quickly look through data! {panel type="project" summary="Code to run linear and binary search for yourself"} + The following files will run linear and binary search in various languages; you can use them to generate random lists of values and measure how long they take to find a given value. Your project is to measure the amount of time taken as the number of items (*n*) increases; try drawing a graph showing this. - [Scratch](files/linear-binary-search-scratch.zip) - [Download Scratch here](https://scratch.mit.edu/scratch2download/) - [Python (Version 2)](files/linear-binary-search-python2.py) - [Download Python 2 here](https://www.python.org/downloads/) - [Python (Version 3)](files/linear-binary-search-python3.py) - [Download Python 3 here](https://www.python.org/downloads/) + {panel end} {glossary-link term="Algorithm" reference-text="sorting algorithms"}{glossary-link end} @@ -219,9 +228,11 @@ Your project is to measure the amount of time taken as the number of items (*n*) ## Sorting {panel type="teacher-note" summary="Why are we also covering sorting?"} + Our main points have already been made --- what an algorithm is, how to estimate its cost, and that the cost isn't always proportional to the amount of data. However, it's good to reinforce this with some different algorithms. Sorting algorithms are useful to study because they illustrate many of the key issues that come up in algorithms, and there are some good contrasts, particularly between quicksort (which is fast and is widely used) and selection or insertion sort (which become very slow as the number of items sorted increases). + {panel end} Sorting is another very important area of algorithms. Computers often have to sort large amounts of data into order based on some attribute of that data, such as sorting a list of files by their name or size, or emails by the date they were received, or a customer list according to people's names. Most of the time this is done to make searching easier. For example you might have a large amount of data and each piece of data could be someone's name and their phone number. If you want to search for someone by name it would help to first have the data sorted alphabetically according to everyones names, but if you then wanted to search for a phone number it would be more useful to have the data sorted according to people's phone numbers. @@ -255,6 +266,7 @@ Tip: Start by moving all the boxes to the right of the screen and then once you If you record how many comparisons you had to make each time to find the next lightest box you might notice a pattern (hint: finding the lightest should take 7 comparisons, and then finding the second lightest should take 6 comparisons…). If you can see the pattern then how many comparisons do you think it would take to then sort 9 boxes into order? What about 20? If you knew how many comparisons it would take to sort 1000 boxes, then how many more comparisons would it take to sort 1001 instead? {panel type="teacher-note" summary="Answer for box analysis"} + For a list of 8 objects (like in the interactive) it should take 7 comparisons to find the lightest, 6 to find the next lightest, 5 to find the next, then 4, then 3, then 2, and then 1 to sort the final two boxes. In total this is 7+6+5+4+3+2+1 = 28 comparisons. If there had been 9 boxes it would have taken 8+7+6+5+4+3+2+1 = 36 comparisons. 20 boxes will take 190. Going from 1000 boxes up to 1001 will require 1000 extra comparisons, even though only 1 box has been added. Selection sort will always take $(n\times(n-1))/2$ comparisons to sort *n* items into order. @@ -269,10 +281,13 @@ For example: To calculate the number of comparisons required for 20 boxes, using = 190 comparisons Some students may recognise this formula as Gauss' trick (see [the anecdotes about Gauss on Wikipedia](https://en.wikipedia.org/wiki/Carl_Friedrich_Gauss#Anecdotes). One way of expressing this trick for the above example is that 20 boxes would require summing the numbers 1+2+3+...+17+18+19. If we write the numbers backwards (19+18+17+...3+2+1) then it would be the same sum. Now if we add these two lists together, pairing up the corresponding numbers, we get (1+19)+(2+18)+(3+17)+...+(17+3)+(18+2)+(19+1). Each pair in this sum adds up to 20, and there are 19 pairs, so adding the two lists together is just 20x19. Since both lists add up to the same amount, the original sum is a half of that, or 20x19/2, which is 190 comparisons, which is what we got from the formula above. If students can follow this reasoning then they can easily work out the comparisons needed for a large number of boxes, and the don't have to use the "magic" formula given above. There's a visual explanation in [this video](http://www.numberphile.com/videos/one_to_million.html) and more examples on [this page](http://nzmaths.co.nz/gauss-trick-staff-seminar). + {panel end} {comment} + TODO: Include a spoiler so that students can see the answer (or an interactive), and additionally a curiosity about Gauss' trick + {comment end} This algorithm is called Selection sort, because each time you look through the list you are 'selecting' the next lightest box and putting it into the correct position. If you go back to the algorithms racing interactive at the top of the page you might now be able to watch the selection sort list and understand what it is doing at each step. @@ -287,9 +302,12 @@ You can swap the word 'smallest' for 'largest' and the algorithm will still work ### Insertion Sort {panel type="teacher-note" summary="This section could be skipped"} + This algorithm is useful and commonly taught, although for the purpose of teaching the principles of algorithms, it's doesn't add a lot to what we've just covered with selection sort, so could be skipped. However, if you have time, it's worth looking at for extra examples. + {panel end} + This algorithm works by removing each box from the original group of boxes and inserting it into its correct position in a new sorted list. Like Selection Sort, it is very intuitive and people often perform it when they are sorting objects themselves, like cards in their hands. Try this with the scales interactive. Start by moving all the boxes to one side of the screen, this is your original, and unsorted, group. Now choose a box at random and place that on the other side of the screen, this is the start of your sorted group. @@ -330,12 +348,14 @@ Quicksort can be described in the following way: - Choose a subgroup and repeat this process. Eventually each subgroup will contain only one item and at this stage the items will be in sorted order. {panel type="project" summary="Code to run selection sort and quicksort for yourself"} + The following files will run selection sort and quicksort in various languages; you can use them to generate random lists of values and measure how long they take to be sorted. Note how long these take for various amounts of input (*n*), and show it in a table or graph. You should notice that the time taken by Quicksort is quite different to that taken by selection sort. - [Scratch](files/selection-quicksort-scratch.zip) - [Download Scratch here](https://scratch.mit.edu/scratch2download/) - [Python (Version 2)](files/selection-quicksort-python2.py) - [Download Python 2 here](https://www.python.org/downloads/) - [Python (Version 3)](files/selection-quicksort-python3.py) - [Download Python 3 here](https://www.python.org/downloads/) + {panel end} There are dozens of sorting algorithms that have been invented; most of the ones that are used in practice are based on quicksort and/or mergesort. These, and many others, can be seen in this intriguing animated video. @@ -353,6 +373,7 @@ In this chapter we have only talked about the number of comparisons an algorithm $n^2$ {panel type="extra-for-experts" summary="Examples of Big O notation"} + Here are some Big O examples: - $O(1)$ - An algorithm with $O(1)$ complexity will always execute in the same amount of time regardless of how much data you give it to process. For example, finding the smallest value in a sorted list is always easy. From 4012c4e23d13a27bffe7a7bc6ce3e3c8d035f655 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Thu, 23 Feb 2017 16:00:29 +1300 Subject: [PATCH 03/86] Added tests and fixed bug (not including following line). --- kordac/processors/StylePreprocessor.py | 2 +- kordac/tests/StyleTest.py | 53 +++++++++++++++++++ .../style/doc_example_block_solitary.md | 3 ++ .../style/doc_example_block_solitary_1.md | 3 ++ .../assets/style/doc_example_block_valid.md | 9 ++++ .../style/doc_example_block_whitespace.md | 5 ++ .../style/doc_example_block_whitespace_1.md | 3 ++ .../style/doc_example_block_whitespace_2.md | 4 ++ .../style/doc_example_block_whitespace_3.md | 4 ++ kordac/tests/start_tests.py | 2 + 10 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 kordac/tests/StyleTest.py create mode 100644 kordac/tests/assets/style/doc_example_block_solitary.md create mode 100644 kordac/tests/assets/style/doc_example_block_solitary_1.md create mode 100644 kordac/tests/assets/style/doc_example_block_valid.md create mode 100644 kordac/tests/assets/style/doc_example_block_whitespace.md create mode 100644 kordac/tests/assets/style/doc_example_block_whitespace_1.md create mode 100644 kordac/tests/assets/style/doc_example_block_whitespace_2.md create mode 100644 kordac/tests/assets/style/doc_example_block_whitespace_3.md diff --git a/kordac/processors/StylePreprocessor.py b/kordac/processors/StylePreprocessor.py index feb9194b..d17d7d5e 100644 --- a/kordac/processors/StylePreprocessor.py +++ b/kordac/processors/StylePreprocessor.py @@ -48,7 +48,7 @@ def run(self, lines): block_match = c.search(line) if block_match is not None: # Grab important lines and their numbers - line_nums, error_lines = zip(*map(lambda x: (x[0], x[1].strip()), (list(enumerate(lines))[max(0, i - 1): min(len(lines) - 1, i + 1)]))) + line_nums, error_lines = zip(*map(lambda x: (x[0] + 1, x[1].strip()), (list(enumerate(lines))[max(0, i - 1): i + 2]))) # Remove all empty lines Should only be one line left if len([line for line in error_lines if line != '']) != 1: diff --git a/kordac/tests/StyleTest.py b/kordac/tests/StyleTest.py new file mode 100644 index 00000000..1e1c43ec --- /dev/null +++ b/kordac/tests/StyleTest.py @@ -0,0 +1,53 @@ +import markdown +from unittest.mock import Mock + +from kordac.KordacExtension import KordacExtension +from kordac.processors.StylePreprocessor import StylePreprocessor +from kordac.processors.errors.StyleError import StyleError +from kordac.tests.ProcessorTest import ProcessorTest + +class StyleTest(ProcessorTest): + """ + Inline = single line comment .e.g. {comment hello you look lovely today} + """ + + def __init__(self, *args, **kwargs): + """Set processor name in class for file names""" + ProcessorTest.__init__(self, *args, **kwargs) + self.processor_name = 'style' + self.ext = Mock() + self.ext.processor_info = ProcessorTest.loadProcessorInfo(self) + + def test_doc_example_block_whitespace(self): + test_string = self.read_test_file(self.processor_name, 'doc_example_block_whitespace.md') + with self.assertRaises(StyleError): + converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + + def test_doc_example_block_whitespace_1(self): + test_string = self.read_test_file(self.processor_name, 'doc_example_block_whitespace_1.md') + with self.assertRaises(StyleError): + converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + + def test_doc_example_block_whitespace_2(self): + test_string = self.read_test_file(self.processor_name, 'doc_example_block_whitespace_2.md') + with self.assertRaises(StyleError): + converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + + def test_doc_example_block_whitespace_3(self): + test_string = self.read_test_file(self.processor_name, 'doc_example_block_whitespace_3.md') + with self.assertRaises(StyleError): + converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + + def test_doc_example_block_solitary(self): + test_string = self.read_test_file(self.processor_name, 'doc_example_block_solitary.md') + with self.assertRaises(StyleError): + converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + + def test_doc_example_block_solitary_1(self): + test_string = self.read_test_file(self.processor_name, 'doc_example_block_solitary_1.md') + with self.assertRaises(StyleError): + converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + + def test_doc_example_block_valid(self): + test_string = self.read_test_file(self.processor_name, 'doc_example_block_valid.md') + converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) diff --git a/kordac/tests/assets/style/doc_example_block_solitary.md b/kordac/tests/assets/style/doc_example_block_solitary.md new file mode 100644 index 00000000..9245e236 --- /dev/null +++ b/kordac/tests/assets/style/doc_example_block_solitary.md @@ -0,0 +1,3 @@ +{panel} This is not valid + +{comment this is not valid} {panel end} diff --git a/kordac/tests/assets/style/doc_example_block_solitary_1.md b/kordac/tests/assets/style/doc_example_block_solitary_1.md new file mode 100644 index 00000000..604cea55 --- /dev/null +++ b/kordac/tests/assets/style/doc_example_block_solitary_1.md @@ -0,0 +1,3 @@ +{panel} + +{glossary-link this is not valid} {panel end} diff --git a/kordac/tests/assets/style/doc_example_block_valid.md b/kordac/tests/assets/style/doc_example_block_valid.md new file mode 100644 index 00000000..922c6f03 --- /dev/null +++ b/kordac/tests/assets/style/doc_example_block_valid.md @@ -0,0 +1,9 @@ +This is valid. + +{panel} + +This is valid. + +{panel end} + +This is valid. diff --git a/kordac/tests/assets/style/doc_example_block_whitespace.md b/kordac/tests/assets/style/doc_example_block_whitespace.md new file mode 100644 index 00000000..a6881abf --- /dev/null +++ b/kordac/tests/assets/style/doc_example_block_whitespace.md @@ -0,0 +1,5 @@ +This is not valid +{panel} +This is not valid +panel end} +This is not valid diff --git a/kordac/tests/assets/style/doc_example_block_whitespace_1.md b/kordac/tests/assets/style/doc_example_block_whitespace_1.md new file mode 100644 index 00000000..1cb34abd --- /dev/null +++ b/kordac/tests/assets/style/doc_example_block_whitespace_1.md @@ -0,0 +1,3 @@ +{panel} +This is not valid +{panel end} diff --git a/kordac/tests/assets/style/doc_example_block_whitespace_2.md b/kordac/tests/assets/style/doc_example_block_whitespace_2.md new file mode 100644 index 00000000..07efbff8 --- /dev/null +++ b/kordac/tests/assets/style/doc_example_block_whitespace_2.md @@ -0,0 +1,4 @@ +This is not valid +{panel} + +panel end} diff --git a/kordac/tests/assets/style/doc_example_block_whitespace_3.md b/kordac/tests/assets/style/doc_example_block_whitespace_3.md new file mode 100644 index 00000000..9d428a38 --- /dev/null +++ b/kordac/tests/assets/style/doc_example_block_whitespace_3.md @@ -0,0 +1,4 @@ +{panel} + +{panel end} +This is not valid diff --git a/kordac/tests/start_tests.py b/kordac/tests/start_tests.py index 51d8f72c..b69ed840 100644 --- a/kordac/tests/start_tests.py +++ b/kordac/tests/start_tests.py @@ -15,6 +15,7 @@ from kordac.tests.SaveTitleTest import SaveTitleTest from kordac.tests.RemoveTitleTest import RemoveTitleTest from kordac.tests.RelativeLinkTest import RelativeLinkTest +from kordac.tests.StyleTest import StyleTest def parse_args(): opts = optparse.OptionParser( @@ -45,6 +46,7 @@ def system_suite(): def unit_suite(): # NTS what order should these go in? return unittest.TestSuite(( + unittest.makeSuite(StyleTest), unittest.makeSuite(SaveTitleTest), unittest.makeSuite(RemoveTitleTest), # unittest.makeSuite(GlossaryLinkTest), # order of tests by cmp() From 357f76aa0288c3c4bd2c4a7f1c35e1179d0d3e41 Mon Sep 17 00:00:00 2001 From: Hayley van Waas Date: Mon, 6 Mar 2017 13:00:56 +1300 Subject: [PATCH 04/86] Added structure for new contributing page in docs --- docs/source/contributing.rst | 27 +++++++++++++++++++++++++++ docs/source/index.rst | 1 + 2 files changed, 28 insertions(+) create mode 100644 docs/source/contributing.rst diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst new file mode 100644 index 00000000..b899e075 --- /dev/null +++ b/docs/source/contributing.rst @@ -0,0 +1,27 @@ +Contributing to Kordac +####################################### + +The git repository for Kordac can be found here_. + +.. _here: https://github.com/uccser/kordac + + +Issue Reporting +======================================= + + +The Code Base +======================================= + +Creating a New Processor +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +The Test Suite +======================================= + + + + +Style Guide +======================================= \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst index 70eae78a..20332421 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -22,6 +22,7 @@ For example: processors/index extensions changelog + contributing Other Features ============== From 505ce7b9d3fa63cc30af7759003abdfa76a861ec Mon Sep 17 00:00:00 2001 From: Hayley van Waas Date: Tue, 7 Mar 2017 22:40:16 +1300 Subject: [PATCH 05/86] Added a few more notes to the contributing page --- docs/source/contributing.rst | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index b899e075..a2a9dbaf 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -8,20 +8,49 @@ The git repository for Kordac can be found here_. Issue Reporting ======================================= +If you come across a bug in Kordac, please report it on the GitHub repository_. +.. _repository: https://github.com/uccser/kordac/issues The Code Base ======================================= +If you would like to contribute to Kordac, fork the repository. + +Kordac is an extension for `Python Markdown`_. + +.. _Python Markdown: https://pythonhosted.org/Markdown/ + + +< what does kordac return > +< how is kordac called > + Creating a New Processor ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +To create a new processor, a good place to start is the `Extension API`_ page of the Python docs, or even the `source code`_ itself. + +.. _Extension API: https://pythonhosted.org/Markdown/extensions/api.html +.. _source code: https://github.com/waylan/Python-Markdown + +There are several different kinds of processors available, each serving a slightly different purpose. + +Generally, every processor will have an ``__init__``, ``test`` and ``run`` method. + +The processors are called from the ``KordacExtension`` class. The Test Suite ======================================= +To start the test suite: + +.. code-block:: none + + $ python3 -m kordac.tests.start_tests +This will execute the Smoke, System and then Unit tests. +To execute the test suite without the smoke tests: +.. code-block:: none -Style Guide -======================================= \ No newline at end of file + $ python3 -m kordac.tests.start_tests --no_smoke From 9a3811f3a89781fba0a85c872bd299c777382949 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Wed, 8 Mar 2017 17:18:36 +1300 Subject: [PATCH 06/86] Adding release documentation. --- docs/source/contributing.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index a2a9dbaf..406c40bd 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -54,3 +54,20 @@ To execute the test suite without the smoke tests: .. code-block:: none $ python3 -m kordac.tests.start_tests --no_smoke + +Creating a release +======================================= + +This is our current process for creating and publishing a Kordac release. This +can only be performed by users that are part of the `uccser/Kordac team`, if you +are not on this team get in contact with someone who is. + +1. `Create a release branch `_. Checkout to this branch. +2. Update the version number [1]_ within ``kordac/__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. +6. Create the release on `GitHub `_ on the tagged commit. +7. Upload a new version of Kordac to PyPI. + +.. [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. From 67ba9dce41f948a98d624001cc05244de96cd7a8 Mon Sep 17 00:00:00 2001 From: Hayley van Waas Date: Thu, 9 Mar 2017 10:12:45 +1300 Subject: [PATCH 07/86] Added more notes to contributing docs --- docs/source/contributing.rst | 58 +++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index a2a9dbaf..2f037142 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -8,21 +8,52 @@ The git repository for Kordac can be found here_. Issue Reporting ======================================= -If you come across a bug in Kordac, please report it on the GitHub repository_. +If you come across a bug in Kordac, please `report it`_ on the repo. -.. _repository: https://github.com/uccser/kordac/issues +.. _report it: https://github.com/uccser/kordac/issues The Code Base ======================================= If you would like to contribute to Kordac, fork the repository. +Overview +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +For an overview on how to use kordac, refer to the usage page of these docs. + +Kordac is split into <> main parts: + +- ``Kordac()`` + The convertor object itself. This is what a user will use to create a Kordac converter, and what is used to define a custom processor list, custom html templates and custom Markdown Extensions to use. + +- ``KordacResult()`` + The object returned by ``Kordac()`` containing: + - Converted html string + - Title + - Required files (images, interactives, scratch images, page scripts) + - Heading tree + - Required glossary terms + +- ``KordacExtension()`` + Inherits the `Extension` class from Markdown. + This class is the main class of the project. It loads all the processor information, loads the template files and clears and populates the attributes to be returned by the ``KordacResult`` object. + +- ``Processors/`` + Each processor is independent from all other processors. There are several different kinds of processors, the types used in Kordac so far are ``preprocessor``, ``blockprocessor``, ``inlinepattern`` and ``treeprocessor``. + + - What does a processor actually do + - Order + - Types + +- ``Templates/`` + The jinja templates to be populated by processors. + +- ``processor-info.json`` + Kordac is an extension for `Python Markdown`_. .. _Python Markdown: https://pythonhosted.org/Markdown/ -< what does kordac return > -< how is kordac called > Creating a New Processor @@ -39,6 +70,15 @@ Generally, every processor will have an ``__init__``, ``test`` and ``run`` metho The processors are called from the ``KordacExtension`` class. +Where do I add my processor to kordac, so that kordac knows to use it? (default processors) +What order do processors happen in? +How do I chose what type of processor to use? +Add to processor information file. +What things should remain independent from each other - only a couple things that interact, (required files, headingnode) + +Put page in docs, examples of how to use it, how to configure. Required and optional arguments. Jinja template overrides. + + The Test Suite ======================================= To start the test suite: @@ -54,3 +94,13 @@ To execute the test suite without the smoke tests: .. code-block:: none $ python3 -m kordac.tests.start_tests --no_smoke + + +Talk about Base classes that we provide. +Want to know why type of tests we want. (Check input and output) + +Bug fix? Add tests. + + + +Adding something that interacts with something else? Best to catch those interactions downstream - don't change things at the start of the pipeline to try and get things ready for a processor later on, let that second processor deal with it. \ No newline at end of file From 33ea9bd6a5c329e2c91cb02436d9ad69ab1ae290 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Thu, 9 Mar 2017 12:40:33 +1300 Subject: [PATCH 08/86] Add code tag extract to avoid beautifying from the beautifulsoup. --- kordac/processors/BeautifyPostprocessor.py | 45 +++++++++++++++++++++- kordac/tests/start_tests.py | 2 +- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/kordac/processors/BeautifyPostprocessor.py b/kordac/processors/BeautifyPostprocessor.py index e206f701..ca76042e 100644 --- a/kordac/processors/BeautifyPostprocessor.py +++ b/kordac/processors/BeautifyPostprocessor.py @@ -1,10 +1,53 @@ from markdown.postprocessors import Postprocessor +from markdown.util import HtmlStash +from markdown.odict import OrderedDict from bs4 import BeautifulSoup +import re class BeautifyPostprocessor(Postprocessor): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.pre_pattern = re.compile(r'
.*?
', re.DOTALL) + self.code_pattern = re.compile(r'(?P.*?)', re.DOTALL) + self.html_stash = HtmlStash() def run(self, text): - return BeautifulSoup(text, 'html.parser').prettify() + text = self.store_non_pre_code_tags(text) + text = BeautifulSoup(text, 'html.parser').prettify() # Could use `formatter="html"` + text = self.restore_non_pre_code_tags(text) + return text + + def store_non_pre_code_tags(self, text): + prepass_text = text + pre_spans = [] + + match = self.pre_pattern.search(prepass_text) + while match is not None: + pre_spans.append(match.span()) + prepass_text = prepass_text[match.end():] + match = self.pre_pattern.search(prepass_text) + + out_text = '' + match = self.code_pattern.search(text) + while match is not None: + html_string = match.group() + placeholder = self.html_stash.store(html_string, True) + out_text = text[:match.start()] + placeholder + text = text[match.end():] + match = self.pre_pattern.search(text) + out_text += text + + return out_text + + def restore_non_pre_code_tags(self, text): + replacements = OrderedDict() + for i in range(self.html_stash.html_counter): + html, safe = self.html_stash.rawHtmlBlocks[i] + replacements[self.html_stash.get_placeholder(i)] = html + + if len(replacements) > 0: + pattern = re.compile("|".join(re.escape(k) for k in replacements)) + text = pattern.sub(lambda m: replacements[m.group(0)], text) + + return text diff --git a/kordac/tests/start_tests.py b/kordac/tests/start_tests.py index 725fa375..665c4b7b 100644 --- a/kordac/tests/start_tests.py +++ b/kordac/tests/start_tests.py @@ -94,5 +94,5 @@ def unit_suite(): unit_result = runner.run(unit_suite()) print() - if (smoke_result is not None and not system_result.wasSuccessful()) or (system_result is not None and not system_result.wasSuccessful()) or (unit_result is not None and not unit_result.wasSuccessful()): + if (smoke_result is not None and not smoke_result.wasSuccessful()) or (system_result is not None and not system_result.wasSuccessful()) or (unit_result is not None and not unit_result.wasSuccessful()): sys.exit(1) From 11803e95dd4f58f5b4b4bed3bf56d0793cd6a434 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Thu, 9 Mar 2017 13:12:30 +1300 Subject: [PATCH 09/86] Adding tests to validate functionality. --- kordac/tests/BeautifyTest.py | 41 +++++++++++++++++++ .../assets/beautify/example_inline_code.md | 1 + .../example_inline_code_expected.html | 3 ++ .../beautify/example_mixed_code_types.md | 5 +++ .../example_mixed_code_types_expected.html | 8 ++++ .../beautify/example_preformatted_code.md | 3 ++ .../example_preformatted_code_expected.html | 5 +++ ...xample_preformatted_code_with_extension.md | 4 ++ ...ormatted_code_with_extension_expected.html | 5 +++ kordac/tests/start_tests.py | 4 +- 10 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 kordac/tests/BeautifyTest.py create mode 100644 kordac/tests/assets/beautify/example_inline_code.md create mode 100644 kordac/tests/assets/beautify/example_inline_code_expected.html create mode 100644 kordac/tests/assets/beautify/example_mixed_code_types.md create mode 100644 kordac/tests/assets/beautify/example_mixed_code_types_expected.html create mode 100644 kordac/tests/assets/beautify/example_preformatted_code.md create mode 100644 kordac/tests/assets/beautify/example_preformatted_code_expected.html create mode 100644 kordac/tests/assets/beautify/example_preformatted_code_with_extension.md create mode 100644 kordac/tests/assets/beautify/example_preformatted_code_with_extension_expected.html diff --git a/kordac/tests/BeautifyTest.py b/kordac/tests/BeautifyTest.py new file mode 100644 index 00000000..c63874f3 --- /dev/null +++ b/kordac/tests/BeautifyTest.py @@ -0,0 +1,41 @@ +import markdown +from unittest.mock import Mock + +from kordac.KordacExtension import KordacExtension +from kordac.processors.CommentPreprocessor import CommentPreprocessor +from kordac.tests.ProcessorTest import ProcessorTest + +class BeautifyTest(ProcessorTest): + def __init__(self, *args, **kwargs): + """Set processor name in class for file names""" + ProcessorTest.__init__(self, *args, **kwargs) + self.processor_name = 'beautify' + + def test_example_inline_code(self): + test_string = self.read_test_file(self.processor_name, 'example_inline_code.md') + + converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + expected_string = self.read_test_file(self.processor_name, 'example_inline_code_expected.html', strip=True) + self.assertEqual(expected_string, converted_test_string) + + def test_example_preformatted_code(self): + test_string = self.read_test_file(self.processor_name, 'example_preformatted_code.md') + + converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + expected_string = self.read_test_file(self.processor_name, 'example_preformatted_code_expected.html', strip=True) + self.assertEqual(expected_string, converted_test_string) + + def test_example_preformatted_code_with_extension(self): + kordac_extension = KordacExtension([self.processor_name], {}, ['markdown.extensions.fenced_code']) + test_string = self.read_test_file(self.processor_name, 'example_preformatted_code_with_extension.md') + + converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension, 'markdown.extensions.fenced_code']) + expected_string = self.read_test_file(self.processor_name, 'example_preformatted_code_with_extension_expected.html', strip=True) + self.assertEqual(expected_string, converted_test_string) + + def text_example_mixed_code_types(self): + test_string = self.read_test_file(self.processor_name, 'example_mixed_code_types.md') + + converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + expected_string = self.read_test_file(self.processor_name, 'example_mixed_code_types_expected.html', strip=True) + self.assertEqual(expected_string, converted_test_string) diff --git a/kordac/tests/assets/beautify/example_inline_code.md b/kordac/tests/assets/beautify/example_inline_code.md new file mode 100644 index 00000000..79129fce --- /dev/null +++ b/kordac/tests/assets/beautify/example_inline_code.md @@ -0,0 +1 @@ +Here is a fragment of code that is important: `string = "Hello World"` and the formatting is unchanged. diff --git a/kordac/tests/assets/beautify/example_inline_code_expected.html b/kordac/tests/assets/beautify/example_inline_code_expected.html new file mode 100644 index 00000000..bf71afa3 --- /dev/null +++ b/kordac/tests/assets/beautify/example_inline_code_expected.html @@ -0,0 +1,3 @@ +

+ Here is a fragment of code that is important: string = "Hello World" and the formatting is unchanged. +

diff --git a/kordac/tests/assets/beautify/example_mixed_code_types.md b/kordac/tests/assets/beautify/example_mixed_code_types.md new file mode 100644 index 00000000..7b503643 --- /dev/null +++ b/kordac/tests/assets/beautify/example_mixed_code_types.md @@ -0,0 +1,5 @@ +Here is a fragment of code that is important: `string = "Hello World"` and the formatting is unchanged. + +Here is another fragment of code that is important: + + string = "Hello Jack!" diff --git a/kordac/tests/assets/beautify/example_mixed_code_types_expected.html b/kordac/tests/assets/beautify/example_mixed_code_types_expected.html new file mode 100644 index 00000000..d2307daf --- /dev/null +++ b/kordac/tests/assets/beautify/example_mixed_code_types_expected.html @@ -0,0 +1,8 @@ +

+ Here is a fragment of code that is important: string = "Hello World" and the formatting is unchanged. +

+

+ Here is another fragment of code that is important: +

+
string = "Hello Jack!"
+
diff --git a/kordac/tests/assets/beautify/example_preformatted_code.md b/kordac/tests/assets/beautify/example_preformatted_code.md new file mode 100644 index 00000000..649da348 --- /dev/null +++ b/kordac/tests/assets/beautify/example_preformatted_code.md @@ -0,0 +1,3 @@ +Here is a fragment of code that is important: + + string = "Hello World!" diff --git a/kordac/tests/assets/beautify/example_preformatted_code_expected.html b/kordac/tests/assets/beautify/example_preformatted_code_expected.html new file mode 100644 index 00000000..47171b9f --- /dev/null +++ b/kordac/tests/assets/beautify/example_preformatted_code_expected.html @@ -0,0 +1,5 @@ +

+ Here is a fragment of code that is important: +

+
string = "Hello World!"
+
diff --git a/kordac/tests/assets/beautify/example_preformatted_code_with_extension.md b/kordac/tests/assets/beautify/example_preformatted_code_with_extension.md new file mode 100644 index 00000000..80346228 --- /dev/null +++ b/kordac/tests/assets/beautify/example_preformatted_code_with_extension.md @@ -0,0 +1,4 @@ +Here is a fragment of code that is important: +``` +string = "Hello World!" +``` diff --git a/kordac/tests/assets/beautify/example_preformatted_code_with_extension_expected.html b/kordac/tests/assets/beautify/example_preformatted_code_with_extension_expected.html new file mode 100644 index 00000000..d2825d7b --- /dev/null +++ b/kordac/tests/assets/beautify/example_preformatted_code_with_extension_expected.html @@ -0,0 +1,5 @@ +

+ Here is a fragment of code that is important: +

+
string = "Hello World!"
+
diff --git a/kordac/tests/start_tests.py b/kordac/tests/start_tests.py index 665c4b7b..79895e86 100644 --- a/kordac/tests/start_tests.py +++ b/kordac/tests/start_tests.py @@ -19,6 +19,7 @@ from kordac.tests.FrameTest import FrameTest from kordac.tests.TableOfContentsTest import TableOfContentsTest from kordac.tests.ScratchTest import ScratchTest +from kordac.tests.BeautifyTest import BeautifyTest def parse_args(): opts = optparse.OptionParser( @@ -64,7 +65,8 @@ def unit_suite(): unittest.makeSuite(ConditionalTest), unittest.makeSuite(FrameTest), unittest.makeSuite(TableOfContentsTest), - unittest.makeSuite(ScratchTest) + unittest.makeSuite(ScratchTest), + unittest.makeSuite(BeautifyTest) )) if __name__ == '__main__': From 09055018c693d1e5f0f0403b1ad76284b5a0704c Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Thu, 9 Mar 2017 13:18:11 +1300 Subject: [PATCH 10/86] Updated based on pull request. --- docs/source/contributing.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 406c40bd..017cecb8 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -59,8 +59,7 @@ Creating a release ======================================= This is our current process for creating and publishing a Kordac release. This -can only be performed by users that are part of the `uccser/Kordac team`, if you -are not on this team get in contact with someone who is. +can only be performed by repository administrators 1. `Create a release branch `_. Checkout to this branch. 2. Update the version number [1]_ within ``kordac/__init__.py``. @@ -70,4 +69,4 @@ are not on this team get in contact with someone who is. 6. Create the release on `GitHub `_ on the tagged commit. 7. Upload a new version of Kordac to PyPI. -.. [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. +.. [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 Kordac it was built from. From 94cd1e2e98b196adaac2b2d7674a4639210db291 Mon Sep 17 00:00:00 2001 From: Hayley van Waas Date: Thu, 9 Mar 2017 13:23:11 +1300 Subject: [PATCH 11/86] WIP contributing docs --- docs/source/contributing.rst | 47 ++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 2f037142..df6c30cd 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -18,9 +18,25 @@ If you would like to contribute to Kordac, fork the repository. Overview ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -For an overview on how to use kordac, refer to the usage page of these docs. +Before reading this section, make sure you have read `how to use Kordac`_ (or even better, have already used Kordac!). -Kordac is split into <> main parts: +.. _how to use Kordac: http://kordac.readthedocs.io/en/develop/usage.html + + +There are several parts and terms of Kordac to become familiar with: + +- **Tag** + This refers to the custom markdown syntax that Kordac processes. + + For example: + + .. code-block:: none + + {comment this will be removed by the converter} + + {image file-path='img/totally-real-image.png' alt='process me'} + + are examples of the ``comment`` and ``image`` tags in Kordac. - ``Kordac()`` The convertor object itself. This is what a user will use to create a Kordac converter, and what is used to define a custom processor list, custom html templates and custom Markdown Extensions to use. @@ -34,42 +50,41 @@ Kordac is split into <> main parts: - Required glossary terms - ``KordacExtension()`` - Inherits the `Extension` class from Markdown. + Inherits the ``Extension`` class from Markdown. This class is the main class of the project. It loads all the processor information, loads the template files and clears and populates the attributes to be returned by the ``KordacResult`` object. - ``Processors/`` - Each processor is independent from all other processors. There are several different kinds of processors, the types used in Kordac so far are ``preprocessor``, ``blockprocessor``, ``inlinepattern`` and ``treeprocessor``. - - - What does a processor actually do - - Order - - Types + There is a different processor for each tag. A processor uses it's corresponding regex loaded from ``processor-info.json`` to find matches in the text, and uses the given arguments in the matched tag to populate and output it's html template. -- ``Templates/`` - The jinja templates to be populated by processors. +- ``html-templates/`` + The html templates (using Jinja2 template engine) to be populated by processors. - ``processor-info.json`` - -Kordac is an extension for `Python Markdown`_. - -.. _Python Markdown: https://pythonhosted.org/Markdown/ - + Every processor is listed in this file, and will at least contain a regex pattern to match it's corresponding tag. + Most will also define required and optional parameters, these correspond to arguments in the tag's template. Creating a New Processor ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -To create a new processor, a good place to start is the `Extension API`_ page of the Python docs, or even the `source code`_ itself. +To create a new processor, a good place to start is the `Extension API`_ page of the Python Markdown docs, or even the `source code`_ itself. .. _Extension API: https://pythonhosted.org/Markdown/extensions/api.html .. _source code: https://github.com/waylan/Python-Markdown + There are several different kinds of processors available, each serving a slightly different purpose. Generally, every processor will have an ``__init__``, ``test`` and ``run`` method. The processors are called from the ``KordacExtension`` class. + There are several different kinds of processors, the types used in Kordac so far are ``preprocessor``, ``blockprocessor``, ``inlinepattern`` and ``treeprocessor``. Each processor behaves slightly differently, and expects different input. + + Each processor is independent from all other processors, and the order of processors matters. + + Where do I add my processor to kordac, so that kordac knows to use it? (default processors) What order do processors happen in? How do I chose what type of processor to use? From 0b960599279f372e06a4a37052ef98da6dc79164 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Thu, 9 Mar 2017 13:57:01 +1300 Subject: [PATCH 12/86] Add forgotten check for being contained in pre. --- kordac/processors/BeautifyPostprocessor.py | 9 ++++++--- ...xample_preformatted_code_with_extension_expected.html | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/kordac/processors/BeautifyPostprocessor.py b/kordac/processors/BeautifyPostprocessor.py index ca76042e..8c7b654b 100644 --- a/kordac/processors/BeautifyPostprocessor.py +++ b/kordac/processors/BeautifyPostprocessor.py @@ -31,9 +31,12 @@ def store_non_pre_code_tags(self, text): out_text = '' match = self.code_pattern.search(text) while match is not None: - html_string = match.group() - placeholder = self.html_stash.store(html_string, True) - out_text = text[:match.start()] + placeholder + if not any(match.start() in range(*span) or match.end() in range(*span) for span in pre_spans): + html_string = match.group() + placeholder = self.html_stash.store(html_string, True) + out_text = text[:match.start()] + placeholder + else: + out_text = text[:match.end()] text = text[match.end():] match = self.pre_pattern.search(text) out_text += text diff --git a/kordac/tests/assets/beautify/example_preformatted_code_with_extension_expected.html b/kordac/tests/assets/beautify/example_preformatted_code_with_extension_expected.html index d2825d7b..47171b9f 100644 --- a/kordac/tests/assets/beautify/example_preformatted_code_with_extension_expected.html +++ b/kordac/tests/assets/beautify/example_preformatted_code_with_extension_expected.html @@ -1,5 +1,5 @@

Here is a fragment of code that is important:

-
string = "Hello World!"
+
string = "Hello World!"
 
From 6d17ab27f68e130b28e421ba01b69e1186b6f2ae Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Thu, 9 Mar 2017 13:59:18 +1300 Subject: [PATCH 13/86] update test to confirm text after codeblock is unchanged. --- kordac/tests/assets/beautify/example_mixed_code_types.md | 2 ++ .../assets/beautify/example_mixed_code_types_expected.html | 3 +++ 2 files changed, 5 insertions(+) diff --git a/kordac/tests/assets/beautify/example_mixed_code_types.md b/kordac/tests/assets/beautify/example_mixed_code_types.md index 7b503643..4f26345e 100644 --- a/kordac/tests/assets/beautify/example_mixed_code_types.md +++ b/kordac/tests/assets/beautify/example_mixed_code_types.md @@ -3,3 +3,5 @@ Here is a fragment of code that is important: `string = "Hello World"` and the f Here is another fragment of code that is important: string = "Hello Jack!" + +I really hope he sees this. diff --git a/kordac/tests/assets/beautify/example_mixed_code_types_expected.html b/kordac/tests/assets/beautify/example_mixed_code_types_expected.html index d2307daf..166d1a4f 100644 --- a/kordac/tests/assets/beautify/example_mixed_code_types_expected.html +++ b/kordac/tests/assets/beautify/example_mixed_code_types_expected.html @@ -6,3 +6,6 @@

string = "Hello Jack!"
 
+

+ I really hope he sees this. +

From 5c88b58655620f08814eb6d2adf414c37f8348ac Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Thu, 9 Mar 2017 16:27:01 +1300 Subject: [PATCH 14/86] Prototype changes for a cleaner Kordac with generic features. --- kordac/processor-info.json | 38 +++++- .../GenericContainerBlockProcessor.py | 113 ++++++++++++++++++ kordac/processors/GenericTagBlockProcessor.py | 66 ++++++++++ ...issingError.py => ArgumentMissingError.py} | 2 +- kordac/processors/utils.py | 36 ++++-- 5 files changed, 237 insertions(+), 18 deletions(-) create mode 100644 kordac/processors/GenericContainerBlockProcessor.py create mode 100644 kordac/processors/GenericTagBlockProcessor.py rename kordac/processors/errors/{ParameterMissingError.py => ArgumentMissingError.py} (93%) diff --git a/kordac/processor-info.json b/kordac/processor-info.json index 9c5005e4..b43f8ca9 100644 --- a/kordac/processor-info.json +++ b/kordac/processor-info.json @@ -66,17 +66,43 @@ } }, "boxed-text": { + "class": "generic_container", "pattern_start": "\\{boxed-text ?(?P[^\\}]*)(?[^\\}]*)\\}", - "required_parameters": ["link"], - "optional_parameter_dependencies": {} + "class": "generic_tag", + "arguments": { + "link": { + "required": true, + "dependencies": [] + } + }, + "template_name": "iframe", + "template_parameters": { + "link": { + "argument": "link", + "transform": null + } + } }, "table-of-contents": { "pattern": "(^|\\n)\\{table-of-contents\\}(\\n|$)" diff --git a/kordac/processors/GenericContainerBlockProcessor.py b/kordac/processors/GenericContainerBlockProcessor.py new file mode 100644 index 00000000..a4f8b981 --- /dev/null +++ b/kordac/processors/GenericContainerBlockProcessor.py @@ -0,0 +1,113 @@ +from markdown.blockprocessors import BlockProcessor +from kordac.processors.utils import * +import re + +class GenericContainerBlockProcessor(BlockProcessor): + def __init__(self, processor, ext, *args, **kwargs): + ''' + Args: + ext: An instance of the Kordac Extension. + ''' + super().__init__(*args, **kwargs) + self.processor = processor + self.p_start = re.compile(r'\{{{0} ?(?P[^\}}]*)(? end_tag.start())): + raise TagNotMatchedError(self.processor, block, 'end tag found before start tag') + + before = block[:start_tag.start()] + after = block[start_tag.end():] + + if before.strip() != '': + self.parser.parseChunk(parent, before) + if after.strip() != '': + blocks.insert(0, after) + + if len(self.arguments) > 0: + check_arguments(self.processor, match.group('args'), self.arguments) + + content_blocks = [] + the_rest = None + inner_start_tags = 0 + inner_end_tags = 0 + + while len(blocks) > 0: + block = blocks.pop(0) + inner_tag = self.p_start.search(block) + end_tag = self.p_end.search(block) + + if ((inner_tag and end_tag is None) + or (inner_tag.start() < end_tag.end())): + inner_start_tags += 1 + + if end_tag and inner_start_tags == inner_end_tags: + content_blocks.append(block[:end_tag.start()]) + the_rest = block[end_tag.end():] + break + elif end_tag: + inner_end_tags += 1 + end_tag = None + content_blocks.append(block) + + if the_rest.strip() != '': + blocks.insert(0, the_rest) + + if end_tag is None or inner_start_tags != inner_end_tags: + raise TagNotMatchedError(self.processor, block, 'no end tag found to close start tag') + + content_tree = etree.Element('content') + self.parser.parseChunk(content_tree, blocks_to_string(content_blocks)) + + content = '' + for child in content_tree: + content += etree.tostring(child, encoding="unicode", method="html") + '\n' + + context = dict() + for parameter, parameter_info in self.template_parameters.items(): + argument_name = parameter_info['argument'] + parameter_default = parameter_info['default'] if 'default' in parameter_info else None + parameter_value = None + if argument_info['argument'] == 'content': + parameter_value = content + else: + argument_value = parse_argument(argument_name, match.group('args'), parameter_default) + transformation = find_transformation(parameter_info['transform']) + parameter_value = transformation(argument_value) if transformation is not None else argument_value + context[parameter] = parameter_value + + html_string = self.template.render(context) + node = etree.fromstring(html_string) + parent.append(node) diff --git a/kordac/processors/GenericTagBlockProcessor.py b/kordac/processors/GenericTagBlockProcessor.py new file mode 100644 index 00000000..7820d303 --- /dev/null +++ b/kordac/processors/GenericTagBlockProcessor.py @@ -0,0 +1,66 @@ +from markdown.blockprocessors import BlockProcessor +from kordac.processors.utils import * +import re + +class GenericTagBlockProcessor(BlockProcessor): + def __init__(self, processor, ext, *args, **kwargs): + ''' + Args: + ext: An instance of the Kordac Extension. + ''' + super().__init__(*args, **kwargs) + self.processor = processor + self.pattern = re.compile(r'\{{{0} ?(?P[^\}}]*)\}}').format(self.processor) + self.arguments = ext.processor_info[self.processor]['arguments'] + template_name = self.processor['template_name'] + self.template = ext.jinja_templates[ext.processor_info[template_name] + self.template_parameters = ext.processor_info[self.processor]['template_parameters'] + + def test(self, parent, block): + ''' Tests a block to see if the run method should be applied. + + Args: + parent: The parent node of the element tree that children + will reside in. + block: The block to be tested. + + Returns: + True if there is a match within the block. + ''' + return self.pattern.search(block) is not None + + def run(self, parent, blocks): + ''' Generic run method for single match tags. + + Args: + parent: The parent node of the element tree that children + will reside in. + blocks: A list of strings of the document, where the + first block tests true. + ''' + block = blocks.pop(0) + + match = self.pattern.search(block) + before = block[:match.start()] + after = block[match.end():] + + if before.strip() != '': + self.parser.parseChunk(parent, before) + if after.strip() != '': + blocks.insert(0, after) + + if len(self.arguments) > 0: + check_arguments(self.processor, match.group('args'), self.arguments) + + context = dict() + for parameter, parameter_info in self.template_parameters.items(): + argument_name = parameter_info['argument'] + parameter_default = parameter_info['default'] if 'default' in parameter_info else None + argument_value = parse_argument(argument_name, match.group('args'), parameter_default) + transformation = find_transformation(parameter_info['transform']) + parameter_value = transformation(argument_value) if transformation is not None else argument_value + context[parameter] = parameter_value + + html_string = self.template.render(context) + node = etree.fromstring(html_string) + parent.append(node) diff --git a/kordac/processors/errors/ParameterMissingError.py b/kordac/processors/errors/ArgumentMissingError.py similarity index 93% rename from kordac/processors/errors/ParameterMissingError.py rename to kordac/processors/errors/ArgumentMissingError.py index a79fcb6a..03ce80df 100644 --- a/kordac/processors/errors/ParameterMissingError.py +++ b/kordac/processors/errors/ArgumentMissingError.py @@ -1,6 +1,6 @@ from kordac.processors.errors.Error import Error -class ParameterMissingError(Error): +class ArgumentMissingError(Error): """Exception raised when a custom markdown tag in not matched. Attributes: diff --git a/kordac/processors/utils.py b/kordac/processors/utils.py index b49a0a12..be713f99 100644 --- a/kordac/processors/utils.py +++ b/kordac/processors/utils.py @@ -1,6 +1,6 @@ import re from markdown.util import etree -from kordac.processors.errors.ParameterMissingError import ParameterMissingError +from kordac.processors.errors.ArgumentMissingError import ArgumentMissingError def parse_argument(argument_key, arguments, default=None): """Search for the given argument in a string of all arguments @@ -22,20 +22,34 @@ def parse_flag(argument_key, arguments, default=False): argument_value = default return argument_value -def check_argument_requirements(processor, arguments, required_parameters, optional_parameters): +def check_arguments(processor, inputs, arguments): ''' Raises an error if the arguments are missing any required parameters or a parameter an optional parameter is dependent on. ''' - if not all(parse_argument(parameter, arguments, None) is not None for parameter in required_parameters): - parameter = next(parameter for parameter in required_parameters if parse_argument(parameter, arguments, None) is None) - raise ParameterMissingError(processor, parameter, "{} is a required parameter.".format(parameter)) + for argument, argument_info in arguments.items(): + is_required = argument_info['required'] + is_arg = parse_argument(argument, arguments, None) is not None + is_flag = parse_flag(argument, arguments) - for option, dependencies in optional_parameters.items(): - is_arg = parse_argument(option, arguments, None) is not None - is_flag = parse_flag(option, arguments) - if (is_arg or is_flag) and not all(parse_argument(parameter, arguments, None) is not None for parameter in dependencies): - parameter = next(parameter for parameter in dependencies if parse_argument(parameter, arguments, None) is None) - raise ParameterMissingError(processor, parameter, "{} is a required parameter because {} exists.".format(parameter, option)) + if is_required and (is_arg or is_flag): + raise ArgumentMissingError(processor, parameter, "{} is a required argument.".format(argument)) + elif not is_required and (is_arg or is_flag): + dependencies = argument_info['dependencies'] + for other_argument in dependencies: + if not (parse_argument(other_argument, arguments, None) is None + or parse_flag(other_argument, arguments) is None): + raise ArgumentMissingError(processor, argument, "{} is a required parameter because {} exists.".format(other_argument, argument)) + +def find_transformation(option): + ''' + Returns a transformation for a given string. + In future should be able to combine piped transformations into a single + function. + ''' + return { + 'str.lower': lambda x: x.lower(), + 'str.upper': lambda x: x.upper(), + }.get(option, None) def blocks_to_string(blocks): """Returns a string after the blocks have been joined back together.""" From 12d359d530eeaec033b48af7957a8e8bf2601724 Mon Sep 17 00:00:00 2001 From: Hayley van Waas Date: Thu, 9 Mar 2017 17:30:27 +1300 Subject: [PATCH 15/86] WIP contributing docs --- docs/source/contributing.rst | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index df6c30cd..47124213 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -74,20 +74,26 @@ To create a new processor, a good place to start is the `Extension API`_ page of .. _source code: https://github.com/waylan/Python-Markdown -There are several different kinds of processors available, each serving a slightly different purpose. +There are several different kinds of processors in Python Markdown, each serving a slightly different purpose. We recommend reading the API docs to determine which processor best suits your purpose (Kordac currently makes use of ``preprocessor``, ``blockprocessor``, ``inlinepattern`` and ``treeprocessor``). + +The order of the processors matters and is defined when each processor is added to the ``OrderedDict`` in ``KordacExtension.py``. Each processor is independent of every other processor. If you have two processors in the pipeline that may overlap (e.g. codehilite and fencedcode), the second processor must handle whatever the first outputs, i.e. refrain from manipulating the outout of the first processor to help the second. + +Every processor belongs in the ``processors/`` directory, but there are several other places they need to be listed, these are: + +- The frozenset of ``DEFAULT_PROCESSORS`` in ``Kordac.py`` +- The relevant list in ``extendMarkdown()`` in ``KordacExtension.py`` (see `OrderedDict in the Markdown API docs`_ for determining order) +.. _OrderedDict in the Markdown API docs: https://pythonhosted.org/Markdown/extensions/api.html#ordereddict +- The processor's template should be added to ``html-templates`` using the Jinja2 Template Engine syntax for variable parameters +- The processor's relevant information (regex pattern, required parameters etc) should be included in ``processor-info.json`` Generally, every processor will have an ``__init__``, ``test`` and ``run`` method. -The processors are called from the ``KordacExtension`` class. - There are several different kinds of processors, the types used in Kordac so far are ``preprocessor``, ``blockprocessor``, ``inlinepattern`` and ``treeprocessor``. Each processor behaves slightly differently, and expects different input. - Each processor is independent from all other processors, and the order of processors matters. Where do I add my processor to kordac, so that kordac knows to use it? (default processors) -What order do processors happen in? -How do I chose what type of processor to use? + Add to processor information file. What things should remain independent from each other - only a couple things that interact, (required files, headingnode) From d64b095bb4d407499415488b5330d9637dfe1281 Mon Sep 17 00:00:00 2001 From: Hayley van Waas Date: Fri, 10 Mar 2017 11:47:26 +1300 Subject: [PATCH 16/86] WIP contributing docs...again.... --- docs/source/contributing.rst | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 3ff05d8b..de88a3bb 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -76,28 +76,35 @@ To create a new processor, a good place to start is the `Extension API`_ page of There are several different kinds of processors in Python Markdown, each serving a slightly different purpose. We recommend reading the API docs to determine which processor best suits your purpose (Kordac currently makes use of ``preprocessor``, ``blockprocessor``, ``inlinepattern`` and ``treeprocessor``). -The order of the processors matters and is defined when each processor is added to the ``OrderedDict`` in ``KordacExtension.py``. Each processor is independent of every other processor. If you have two processors in the pipeline that may overlap (e.g. codehilite and fencedcode), the second processor must handle whatever the first outputs, i.e. refrain from manipulating the outout of the first processor to help the second. +The order of the processors matters and is defined when each processor is added to the ``OrderedDict`` in ``KordacExtension.py``. + +Each processor is independent of every other processor. If you have two processors in the pipeline that may overlap (e.g. codehilite and fencedcode), the second processor must handle whatever the first outputs, i.e. refrain from manipulating the output of the first processor to help the second. Every processor belongs in the ``processors/`` directory, but there are several other places they need to be listed, these are: - The frozenset of ``DEFAULT_PROCESSORS`` in ``Kordac.py`` - The relevant list in ``extendMarkdown()`` in ``KordacExtension.py`` (see `OrderedDict in the Markdown API docs`_ for determining order) -.. _OrderedDict in the Markdown API docs: https://pythonhosted.org/Markdown/extensions/api.html#ordereddict - The processor's template should be added to ``html-templates`` using the Jinja2 Template Engine syntax for variable parameters - The processor's relevant information (regex pattern, required parameters etc) should be included in ``processor-info.json`` -Generally, every processor will have an ``__init__``, ``test`` and ``run`` method. +.. _OrderedDict in the Markdown API docs: https://pythonhosted.org/Markdown/extensions/api.html#ordereddict +The new processors should also: - +- Be thoroughly tested (see the section below) +- Have clear and accurate documentation. See the docs on other processors for the preferred format. Your docs should include: + - An example of the tag in markdown + - Required parameters + - Optional parameters + - Examples + - Examples of overriding the html +We suggest writing the docs before you even write the processor itself as this will give you a clear idea of how a processor in Kordac should behave. -Where do I add my processor to kordac, so that kordac knows to use it? (default processors) -Add to processor information file. -What things should remain independent from each other - only a couple things that interact, (required files, headingnode) +Generally, every processor will have at least three methods (``__init__``, ``test`` and ``run``). -Put page in docs, examples of how to use it, how to configure. Required and optional arguments. Jinja template overrides. +The ``test`` method should only return boolean values. This method is used to test if the regex has found a match or not, (and is often used by the Test Suite to check the regex is correct). For Block Processors, this method is also used to determine whether to execute the ``run()`` method or not. The Test Suite From 4af31f359d6a1d2077ff4c9b8d5f285643902657 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Fri, 10 Mar 2017 12:04:30 +1300 Subject: [PATCH 17/86] Enabled html escaping for non-standard characters. --- kordac/processors/BeautifyPostprocessor.py | 2 +- kordac/tests/assets/button-link/no_button_expected.html | 6 +++--- .../comment/text_contains_the_word_comment_expected.html | 4 ++-- .../assets/glossary-link/leading_inline_text_expected.html | 4 ++-- kordac/tests/assets/image/default_image_expected.html | 2 +- .../assets/image/text_contains_the_word_image_expected.html | 2 +- kordac/tests/assets/video/youtube_watch_link_expected.html | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/kordac/processors/BeautifyPostprocessor.py b/kordac/processors/BeautifyPostprocessor.py index 8c7b654b..76a88f47 100644 --- a/kordac/processors/BeautifyPostprocessor.py +++ b/kordac/processors/BeautifyPostprocessor.py @@ -14,7 +14,7 @@ def __init__(self, *args, **kwargs): def run(self, text): text = self.store_non_pre_code_tags(text) - text = BeautifulSoup(text, 'html.parser').prettify() # Could use `formatter="html"` + text = BeautifulSoup(text, 'html.parser').prettify(formatter="html") text = self.restore_non_pre_code_tags(text) return text diff --git a/kordac/tests/assets/button-link/no_button_expected.html b/kordac/tests/assets/button-link/no_button_expected.html index 346c630c..7c7b7b6f 100644 --- a/kordac/tests/assets/button-link/no_button_expected.html +++ b/kordac/tests/assets/button-link/no_button_expected.html @@ -1,5 +1,5 @@

- Finally, you’re the top layer of the system. You use the program but you will (hopefully) never have to interact with the more complicated parts of the operating system such as driver software, let alone the hardware. In this way, you can use the computer without ever having to worry about these things. + Finally, you’re the top layer of the system. You use the program but you will (hopefully) never have to interact with the more complicated parts of the operating system such as driver software, let alone the hardware. In this way, you can use the computer without ever having to worry about these things.

{image filename="computer-layers.png" alt="The computer can be broken down into multiple layers, starting with the user, then the programs, then the operating system, then finally the hardware." caption="The computer can be broken down into multiple layers, starting with the user, then the programs, then the operating system, then finally the hardware."} @@ -15,14 +15,14 @@ Each layer in the system needs to provide an interface so that the layer above it can communicate with it. For example, a processor provides a set of instructions to the operating system; the operating system provides commands to programs to create or delete files on the hard drive; a program provides buttons and commands so that you can interact with it.

- One layer knows nothing about the internal workings of the layer below; it only needs to know how to use the layer’s interface. In this way, the complexity of lower layers is completely hidden, or + One layer knows nothing about the internal workings of the layer below; it only needs to know how to use the layer’s interface. In this way, the complexity of lower layers is completely hidden, or abstracted . Each layer represents a higher level of abstraction.

- So each layer hides some complexity, so that as we go up the layers things remain manageable. Another advantage of having layers is that we can change one layer without affecting the others, as long as we keep the layer’s interface the same of course. For example, your browser’s code might change but you might never notice as long as the browser still looks and works the same as before. Of course, if the browser stops working or new buttons appear suddenly you know that something has changed. + So each layer hides some complexity, so that as we go up the layers things remain manageable. Another advantage of having layers is that we can change one layer without affecting the others, as long as we keep the layer’s interface the same of course. For example, your browser’s code might change but you might never notice as long as the browser still looks and works the same as before. Of course, if the browser stops working or new buttons appear suddenly you know that something has changed.

Something about a button or more explicitly a button-link that you should not match. diff --git a/kordac/tests/assets/comment/text_contains_the_word_comment_expected.html b/kordac/tests/assets/comment/text_contains_the_word_comment_expected.html index d5470153..10936821 100644 --- a/kordac/tests/assets/comment/text_contains_the_word_comment_expected.html +++ b/kordac/tests/assets/comment/text_contains_the_word_comment_expected.html @@ -6,10 +6,10 @@ Try being a "parrot" that just copies everything Eliza says.

  • - What happens when you don’t give meaningful answers to her questions? + What happens when you don’t give meaningful answers to her questions?
  • - If you say the same thing you said earlier in the conversation, does Eliza always respond in the same way? (When you say it immediately after, she probably won’t, as she’ll comment on the fact that you repeated yourself the second time!) + If you say the same thing you said earlier in the conversation, does Eliza always respond in the same way? (When you say it immediately after, she probably won’t, as she’ll comment on the fact that you repeated yourself the second time!)
  • What happens when you talk about things that are unrelated to what would be said in a therapy session, i.e. you try to have a general conversation with Eliza (remember that Eliza works in a restricted domain, i.e. she assumes she is a therapist). diff --git a/kordac/tests/assets/glossary-link/leading_inline_text_expected.html b/kordac/tests/assets/glossary-link/leading_inline_text_expected.html index dcbaabb8..0b7f7e15 100644 --- a/kordac/tests/assets/glossary-link/leading_inline_text_expected.html +++ b/kordac/tests/assets/glossary-link/leading_inline_text_expected.html @@ -3,9 +3,9 @@ Klingon Linguistics activity at CS4FN - . This page introduces the fundamentals of languages — words (the alphabet) and + . This page introduces the fundamentals of languages — words (the alphabet) and grammar (the rules of syntax). It discusses why languages are translated and how meaning can be changed by translation. It also explains why computer languages need to be translated. -

    \ No newline at end of file +

    diff --git a/kordac/tests/assets/image/default_image_expected.html b/kordac/tests/assets/image/default_image_expected.html index effc7d92..93371ae0 100644 --- a/kordac/tests/assets/image/default_image_expected.html +++ b/kordac/tests/assets/image/default_image_expected.html @@ -12,7 +12,7 @@

    - Many humans take for granted the fact that they can easily have a conversation with another person, and choose appropriate things to say based on the conversation. The ability to do this is a form of intelligence, and for computers it isn’t so easy! Many attempts have been made to design computer programs that can have a conversation with a human and sound intelligent. These computer programs are called + Many humans take for granted the fact that they can easily have a conversation with another person, and choose appropriate things to say based on the conversation. The ability to do this is a form of intelligence, and for computers it isn’t so easy! Many attempts have been made to design computer programs that can have a conversation with a human and sound intelligent. These computer programs are called chatterbots diff --git a/kordac/tests/assets/image/text_contains_the_word_image_expected.html b/kordac/tests/assets/image/text_contains_the_word_image_expected.html index 8c6d084f..94b4b521 100644 --- a/kordac/tests/assets/image/text_contains_the_word_image_expected.html +++ b/kordac/tests/assets/image/text_contains_the_word_image_expected.html @@ -1,6 +1,6 @@

    There is an image format that uses the simple one-symbol-per-pixel representation we have just described. The format is called "portable bitmap format" (PBM). -PBM files are saved with the file extension “.pbm”, and contain a simple header, followed by the image data. +PBM files are saved with the file extension “.pbm”, and contain a simple header, followed by the image data. The data in the file can be viewed by opening it in a text editor, much like opening a .txt file, and the image itself can be viewed by opening it in a drawing or image viewing program that supports PBM files (the format isn't very well supported, but a number of image viewing and editing programs can display them). diff --git a/kordac/tests/assets/video/youtube_watch_link_expected.html b/kordac/tests/assets/video/youtube_watch_link_expected.html index 16cff688..38782968 100644 --- a/kordac/tests/assets/video/youtube_watch_link_expected.html +++ b/kordac/tests/assets/video/youtube_watch_link_expected.html @@ -10,7 +10,7 @@ Siri - chatterbot in the device’s help system. Siri is an example of a chatterbot that has the job of + chatterbot in the device’s help system. Siri is an example of a chatterbot that has the job of helping @@ -31,4 +31,4 @@

    {panel end} -

    \ No newline at end of file +

    From ccc9a4114c6226f60ba31aeb523c79ed4d2fef08 Mon Sep 17 00:00:00 2001 From: Hayley van Waas Date: Fri, 10 Mar 2017 12:49:01 +1300 Subject: [PATCH 18/86] WIP testing section of contributing docs --- docs/source/contributing.rst | 49 ++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index de88a3bb..d8018acb 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -6,10 +6,12 @@ The git repository for Kordac can be found here_. .. _here: https://github.com/uccser/kordac -Issue Reporting +Issue Reporting and Bug Fixes ======================================= If you come across a bug in Kordac, please `report it`_ on the repo. + + .. _report it: https://github.com/uccser/kordac/issues The Code Base @@ -117,11 +119,47 @@ To start the test suite: This will execute the Smoke, System and then Unit tests. -To execute the test suite without the smoke tests: +There are several arguments that can be used with this command to skip particular tests (``--no_smoke``, ``--no_system`` and ``--no_unit``). + + + + +Adding Tests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +If you are adding an new test file (e.g. for a new processor), then this needs to be added to the Test Suite in ``start_tests.py``. + +Provided Base Classes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Processor Tests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +All processor tests inherit from the ``ProcessorTest`` class. Processors should create a ``Mock()`` object, which will contain the bare minimum for the processor to be run (it's jinja template's and properties loaded from ``processor-info.json``), i.e. there is no reason for it to know about properties of the other processors. + +A test method will typically follow the same sequence of steps: + + 1. Retrieve the test string (there is a ``read_test_file()`` method provided by the ``ProcessorTest`` class) + 2. Split into blocks (there is a ``to_blocks()`` method provided by the ``ProcessorTest`` class) + 3. Use an ``Assert`` to confirm there are(not) matches to the regex + 4. Convert the test string using the ``kordac_extension`` (provided by the ``SetUp()`` method in ``ProcessorTest``) + 5. Load the expected converted result + 6. Check the converted result is the same as the expected result + + +Testing Assets +*************************************** + + + +The test markdown file and expected html file should be placed in ``kordac/tests/assets//``. The expected file should have the same name as the corresponding test file, with ``expected`` appended to the file name. + +For example: .. code-block:: none + + kordac/tests/assets/boxed-text/no_boxed_text.md + kordac/tests/assets/boxed-text/no_boxed_text_expected.html + - $ python3 -m kordac.tests.start_tests --no_smoke Creating a release ======================================= @@ -139,14 +177,11 @@ can only be performed by repository administrators .. [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 Kordac it was built from. + Notes ======================================= -Talk about Base classes that we provide. Want to know why type of tests we want. (Check input and output) -Bug fix? Add tests. - - Adding something that interacts with something else? Best to catch those interactions downstream - don't change things at the start of the pipeline to try and get things ready for a processor later on, let that second processor deal with it. From 05d5c828a7a68e8e8298f1e952edda81b68f90ef Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Fri, 10 Mar 2017 15:04:51 +1300 Subject: [PATCH 19/86] Inject blockelement matching into markdown, and update templates. --- kordac/KordacExtension.py | 3 +++ kordac/html-templates/scratch.html | 6 +++-- .../doc_example_basic_usage_expected.html | 4 ++-- .../doc_example_override_html_expected.html | 7 +++--- .../doc_example_override_html_template.html | 4 +++- .../example_multiple_codeblocks_expected.html | 12 +++++----- .../scratch/example_other_code_expected.html | 4 ++-- .../example_separate_blocks_expected.html | 4 ++-- ...mple_standard_markdown_block_expected.html | 6 +++-- kordac/utils/overrides.py | 23 +++++++++++++++++++ 10 files changed, 53 insertions(+), 20 deletions(-) create mode 100644 kordac/utils/overrides.py diff --git a/kordac/KordacExtension.py b/kordac/KordacExtension.py index 3e254634..86da06f9 100644 --- a/kordac/KordacExtension.py +++ b/kordac/KordacExtension.py @@ -24,6 +24,7 @@ from kordac.utils.UniqueSlugify import UniqueSlugify from kordac.utils.HeadingNode import HeadingNode +from kordac.utils.overrides import is_block_level, BLOCK_LEVEL_ELEMENTS from collections import defaultdict from os import listdir @@ -104,6 +105,8 @@ def extendMarkdown(self, md, md_globals): md.postprocessors.add('jinja', JinjaPostprocessor(md), '_end') # Compatibility modules + md.postprocessors['raw_html'].isblocklevel = lambda html: is_block_level(html, BLOCK_LEVEL_ELEMENTS) + if 'hilite' in self.compatibility and 'fenced_code_block' in self.compatibility and 'scratch' in self.processors: md.preprocessors.add('scratch-compatibility', ScratchCompatibilityPreprocessor(self, md), ' - +
    + + +
    diff --git a/kordac/tests/assets/scratch/doc_example_basic_usage_expected.html b/kordac/tests/assets/scratch/doc_example_basic_usage_expected.html index 923f5d7c..bcc48fe0 100644 --- a/kordac/tests/assets/scratch/doc_example_basic_usage_expected.html +++ b/kordac/tests/assets/scratch/doc_example_basic_usage_expected.html @@ -1,4 +1,4 @@ -

    +

    -

    +
    diff --git a/kordac/tests/assets/scratch/doc_example_override_html_expected.html b/kordac/tests/assets/scratch/doc_example_override_html_expected.html index 3955b493..bfea6660 100644 --- a/kordac/tests/assets/scratch/doc_example_override_html_expected.html +++ b/kordac/tests/assets/scratch/doc_example_override_html_expected.html @@ -1,3 +1,4 @@ -

    - -

    +
    + + +
    diff --git a/kordac/tests/assets/scratch/doc_example_override_html_template.html b/kordac/tests/assets/scratch/doc_example_override_html_template.html index eede164d..012e811c 100644 --- a/kordac/tests/assets/scratch/doc_example_override_html_template.html +++ b/kordac/tests/assets/scratch/doc_example_override_html_template.html @@ -1 +1,3 @@ - +
    + +
    diff --git a/kordac/tests/assets/scratch/example_multiple_codeblocks_expected.html b/kordac/tests/assets/scratch/example_multiple_codeblocks_expected.html index ddd2cb77..792a4c07 100644 --- a/kordac/tests/assets/scratch/example_multiple_codeblocks_expected.html +++ b/kordac/tests/assets/scratch/example_multiple_codeblocks_expected.html @@ -1,21 +1,21 @@

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

    -

    +

    -

    +

    Which then easily builds into:

    -

    +

    -

    +

    Finally they can create complex code like so:

    -

    +

    -

    +
    diff --git a/kordac/tests/assets/scratch/example_other_code_expected.html b/kordac/tests/assets/scratch/example_other_code_expected.html index 6e1962fc..f1105efa 100644 --- a/kordac/tests/assets/scratch/example_other_code_expected.html +++ b/kordac/tests/assets/scratch/example_other_code_expected.html @@ -1,6 +1,6 @@ -

    +

    -

    +
    type = True
     
    diff --git a/kordac/tests/assets/scratch/example_separate_blocks_expected.html b/kordac/tests/assets/scratch/example_separate_blocks_expected.html index 6462bade..4509c3f9 100644 --- a/kordac/tests/assets/scratch/example_separate_blocks_expected.html +++ b/kordac/tests/assets/scratch/example_separate_blocks_expected.html @@ -1,4 +1,4 @@ -

    +

    -

    +
    diff --git a/kordac/tests/assets/scratch/example_standard_markdown_block_expected.html b/kordac/tests/assets/scratch/example_standard_markdown_block_expected.html index e591681c..90c4abcc 100644 --- a/kordac/tests/assets/scratch/example_standard_markdown_block_expected.html +++ b/kordac/tests/assets/scratch/example_standard_markdown_block_expected.html @@ -1,5 +1,7 @@

    Codeblock follows:

    - - +
    + + +
    diff --git a/kordac/utils/overrides.py b/kordac/utils/overrides.py new file mode 100644 index 00000000..def830e5 --- /dev/null +++ b/kordac/utils/overrides.py @@ -0,0 +1,23 @@ +import re +from markdown.util import string_type + +BLOCK_LEVEL_ELEMENTS = [ + 'address', 'article', 'aside', 'blockqoute', 'br', 'canvas', 'dd', 'div', + 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h[1-6]', + 'header', 'hr', 'li', 'main', 'nav', 'noscript', 'ol', 'output', 'p', + 'pre', 'section', 'table', 'tfoot', 'ul', 'video', 'remove' +] # TO MAKE CONFIGURABLE + +def is_block_level(html, block_level_elements): + m = re.match(r'^\<\/?([^ >]+)', html) + if m: + tag = m.group(1) + if tag[0] in ('!', '?', '@', '%'): + return True + if isinstance(tag, string_type): + elements = '|'.join(block_level_elements) + block_elements_re = re.compile("^({})$".format(elements), + re.IGNORECASE) + return block_elements_re.match(tag) + return False + return False From 821d0130824345dd49e893d318955d75ef2592f3 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Fri, 10 Mar 2017 15:12:12 +1300 Subject: [PATCH 20/86] Additional scratch test for whitespacing. --- kordac/tests/ScratchTest.py | 25 +++++++++++++++++ .../scratch/example_multiple_codeblocks_2.md | 28 +++++++++++++++++++ ...xample_multiple_codeblocks_expected_2.html | 15 ++++++++++ 3 files changed, 68 insertions(+) create mode 100644 kordac/tests/assets/scratch/example_multiple_codeblocks_2.md create mode 100644 kordac/tests/assets/scratch/example_multiple_codeblocks_expected_2.html diff --git a/kordac/tests/ScratchTest.py b/kordac/tests/ScratchTest.py index df3bed7c..f98a9ac2 100644 --- a/kordac/tests/ScratchTest.py +++ b/kordac/tests/ScratchTest.py @@ -116,6 +116,31 @@ def test_example_multiple_codeblocks(self): } self.assertSetEqual(actual, expected) + def test_example_multiple_codeblocks_2(self): + test_string = self.read_test_file(self.processor_name, 'example_multiple_codeblocks_2.md') + + converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.kordac_extension]) + expected_string = self.read_test_file(self.processor_name, 'example_multiple_codeblocks_expected_2.html', strip=True) + self.assertEqual(expected_string, converted_test_string) + + # Should really test result a better way + actual = self.kordac_extension.required_files['scratch_images'] + expected = { + 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, expected) + def test_example_other_code(self): test_string = self.read_test_file(self.processor_name, 'example_other_code.md') diff --git a/kordac/tests/assets/scratch/example_multiple_codeblocks_2.md b/kordac/tests/assets/scratch/example_multiple_codeblocks_2.md new file mode 100644 index 00000000..8379007c --- /dev/null +++ b/kordac/tests/assets/scratch/example_multiple_codeblocks_2.md @@ -0,0 +1,28 @@ +Scratch is great for kids you can great simple code like: + +```scratch +when flag clicked +say [Hi] +``` +```scratch +when flag clicked +say [Hi] +move (foo) steps +turn ccw (9) degrees +``` + +```scratch +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/kordac/tests/assets/scratch/example_multiple_codeblocks_expected_2.html b/kordac/tests/assets/scratch/example_multiple_codeblocks_expected_2.html new file mode 100644 index 00000000..a36cbc13 --- /dev/null +++ b/kordac/tests/assets/scratch/example_multiple_codeblocks_expected_2.html @@ -0,0 +1,15 @@ +

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

    +
    + + +
    +
    + + +
    +
    + + +
    From 5dbe76b2b48a512174199ce2a1b177d0af94c4c7 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Fri, 10 Mar 2017 15:19:18 +1300 Subject: [PATCH 21/86] Test the compatability processor. --- kordac/tests/ScratchTest.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kordac/tests/ScratchTest.py b/kordac/tests/ScratchTest.py index f98a9ac2..e1a196fd 100644 --- a/kordac/tests/ScratchTest.py +++ b/kordac/tests/ScratchTest.py @@ -117,14 +117,16 @@ def test_example_multiple_codeblocks(self): self.assertSetEqual(actual, expected) def test_example_multiple_codeblocks_2(self): + extensions = ['markdown.extensions.codehilite', 'markdown.extensions.fenced_code'] + kordac_extension = KordacExtension([self.processor_name], {}, extensions) test_string = self.read_test_file(self.processor_name, 'example_multiple_codeblocks_2.md') - converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=extensions + [kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'example_multiple_codeblocks_expected_2.html', strip=True) self.assertEqual(expected_string, converted_test_string) # Should really test result a better way - actual = self.kordac_extension.required_files['scratch_images'] + actual = kordac_extension.required_files['scratch_images'] expected = { ScratchImageMetaData( hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', From 34de398c0d8150de7ed54bc991e69f0ea526636d Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Fri, 10 Mar 2017 15:41:34 +1300 Subject: [PATCH 22/86] Added comments/docstrings based on PR. --- kordac/utils/overrides.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/kordac/utils/overrides.py b/kordac/utils/overrides.py index def830e5..5e1f6944 100644 --- a/kordac/utils/overrides.py +++ b/kordac/utils/overrides.py @@ -6,9 +6,19 @@ 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h[1-6]', 'header', 'hr', 'li', 'main', 'nav', 'noscript', 'ol', 'output', 'p', 'pre', 'section', 'table', 'tfoot', 'ul', 'video', 'remove' -] # TO MAKE CONFIGURABLE +] # TODO: TO MAKE CONFIGURABLE def is_block_level(html, block_level_elements): + ''' + Checks if the root element (or first element) of the given + html is a block level element. + Args: + html: A string of the html to check. + block_level_elements: A list of strings which are the + block level elements. + Returns: + True if the first element is a block level element. + ''' m = re.match(r'^\<\/?([^ >]+)', html) if m: tag = m.group(1) From a6d8d8ae7726a4608d2c1764ba73e197f4db92de Mon Sep 17 00:00:00 2001 From: Hayley van Waas Date: Fri, 10 Mar 2017 16:08:52 +1300 Subject: [PATCH 23/86] Changes to contributings docs from PR suggestions. Deleted unused file. --- docs/source/contributing.rst | 79 +++++++++++++++++++++++++----------- kordac/template.html | 17 -------- 2 files changed, 56 insertions(+), 40 deletions(-) delete mode 100644 kordac/template.html diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index d8018acb..2ddfc5ed 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -1,22 +1,31 @@ Contributing to Kordac ####################################### -The git repository for Kordac can be found here_. +Welcome to the Kordac developer community! We have spent many months developing this project, and we would love for you to get involved! The following documentation has been written to help you get a grasp on how Kordac is pieced together to make contributing as simple and straight forward as possible. Please feel free to fix bugs and/or suggest new features and improvements to the system (or the docs) by making a pull request. + +Kordac was created to be used by two much larger projects (the `CS Unplugged`_ and `CS Field Guide`_ websites) as the markdown-to-html converter. The tags we chose are designed to allow authors of these two projects to easily write material without technical elements getting in the way. It is therefore important to us that Kordac remains as simple and robust as possible, please keep this in mind if you decide to work on Kordac with us. + +.. _CS Unplugged: https://github.com/uccser/cs-unplugged/ +.. _CS Field Guide: https://github.com/uccser/cs-field-guide/ + +The git repository for Kordac can be found `here`_, jump in and take a look around! .. _here: https://github.com/uccser/kordac + Issue Reporting and Bug Fixes ======================================= -If you come across a bug in Kordac, please `report it`_ on the repo. +If you come across a bug in Kordac, please `report it on the repo issue tracker`_. - +.. _report it on the repo issue tracker: https://github.com/uccser/kordac/issues + +If you choose to fix the bug for us, consider adding the relevant tests to the Test Suite (detailed further down this page) to help us catch any future bugs. -.. _report it: https://github.com/uccser/kordac/issues The Code Base ======================================= -If you would like to contribute to Kordac, fork the repository. +If you would like to contribute to Kordac, create a fork of the repository. Overview ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +34,9 @@ Before reading this section, make sure you have read `how to use Kordac`_ (or ev .. _how to use Kordac: http://kordac.readthedocs.io/en/develop/usage.html -There are several parts and terms of Kordac to become familiar with: +Terminology +*************************************** +There are a couple of terms we use when describing Kordac to become familiar with: - **Tag** This refers to the custom markdown syntax that Kordac processes. @@ -36,9 +47,35 @@ There are several parts and terms of Kordac to become familiar with: {comment this will be removed by the converter} - {image file-path='img/totally-real-image.png' alt='process me'} + {image file-path="img/totally-real-image.png" alt="process me"} - are examples of the ``comment`` and ``image`` tags in Kordac. + are examples of the ``comment`` and ``image`` tags in Kordac. + +- **Processor** + This refers to the class that is responsible for converting a specific tag. For example, `RelativeLinkPattern` is the processor for internal links. + + +Project Structure +*************************************** +Below is a basic overview of the project structure: + +.. code-block:: none + + ├── docs/ + ├── kordac/ + │   ├── html-templates/ + │   ├── KordacExtension.py + │   ├── Kordac.py + │   ├── processor-info.json + │   ├── processors/ + │   │   └── errors/ + │   ├── tests/ + │   │   └── assets/ + │   └── utils/ + ├── requirements.txt + └── setup.py + +The files and folders of interest are: - ``Kordac()`` The convertor object itself. This is what a user will use to create a Kordac converter, and what is used to define a custom processor list, custom html templates and custom Markdown Extensions to use. @@ -52,8 +89,8 @@ There are several parts and terms of Kordac to become familiar with: - Required glossary terms - ``KordacExtension()`` - Inherits the ``Extension`` class from Markdown. - This class is the main class of the project. It loads all the processor information, loads the template files and clears and populates the attributes to be returned by the ``KordacResult`` object. + This is the main class of the project, and inherits the ``Extension`` class from Markdown. + It loads all of the processor information, loads the template files and clears and populates the attributes to be returned by the ``KordacResult`` object. - ``Processors/`` There is a different processor for each tag. A processor uses it's corresponding regex loaded from ``processor-info.json`` to find matches in the text, and uses the given arguments in the matched tag to populate and output it's html template. @@ -69,25 +106,26 @@ There are several parts and terms of Kordac to become familiar with: Creating a New Processor ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -To create a new processor, a good place to start is the `Extension API`_ page of the Python Markdown docs, or even the `source code`_ itself. +To create a new processor, a good place to start is the `Extension API`_ page of the Python Markdown docs, and you can also read the `source code`_ itself. .. _Extension API: https://pythonhosted.org/Markdown/extensions/api.html .. _source code: https://github.com/waylan/Python-Markdown -There are several different kinds of processors in Python Markdown, each serving a slightly different purpose. We recommend reading the API docs to determine which processor best suits your purpose (Kordac currently makes use of ``preprocessor``, ``blockprocessor``, ``inlinepattern`` and ``treeprocessor``). +There are several different kinds of processors in Python Markdown, each serving a slightly different purpose. We recommend reading the API docs to determine which processor best suits your purpose (Kordac currently makes use of ``preprocessor``, ``blockprocessor``, ``inlinepattern``, ``treeprocessor`` and ``postprocessor``). The order of the processors matters and is defined when each processor is added to the ``OrderedDict`` in ``KordacExtension.py``. -Each processor is independent of every other processor. If you have two processors in the pipeline that may overlap (e.g. codehilite and fencedcode), the second processor must handle whatever the first outputs, i.e. refrain from manipulating the output of the first processor to help the second. +Each processor is independent of every other processor. If you have two processors in the pipeline that may overlap (e.g. codehilite and fencedcode), the second processor must handle whatever the first outputs. Therefore refrain from manipulating the output of a processor for a later processor. -Every processor belongs in the ``processors/`` directory, but there are several other places they need to be listed, these are: +The logic for each processor belongs in the ``processors/`` directory, and there are several other places where processors details need to be listed. These are: -- The frozenset of ``DEFAULT_PROCESSORS`` in ``Kordac.py`` +- The processor's relevant information (regex pattern, required parameters etc) should be included in ``processor-info.json`` +- If it should be a default processor, it should be added to the frozenset of ``DEFAULT_PROCESSORS`` in ``Kordac.py`` - The relevant list in ``extendMarkdown()`` in ``KordacExtension.py`` (see `OrderedDict in the Markdown API docs`_ for determining order) - The processor's template should be added to ``html-templates`` using the Jinja2 Template Engine syntax for variable parameters -- The processor's relevant information (regex pattern, required parameters etc) should be included in ``processor-info.json`` + .. _OrderedDict in the Markdown API docs: https://pythonhosted.org/Markdown/extensions/api.html#ordereddict @@ -101,19 +139,14 @@ The new processors should also: - Examples - Examples of overriding the html -We suggest writing the docs before you even write the processor itself as this will give you a clear idea of how a processor in Kordac should behave. - - -Generally, every processor will have at least three methods (``__init__``, ``test`` and ``run``). - -The ``test`` method should only return boolean values. This method is used to test if the regex has found a match or not, (and is often used by the Test Suite to check the regex is correct). For Block Processors, this method is also used to determine whether to execute the ``run()`` method or not. +We recommend writing documentation and test cases before you even write the processor itself as this will give you a clear idea of how a processor in Kordac should behave. The Test Suite ======================================= To start the test suite: -.. code-block:: none +.. code-block:: bash $ python3 -m kordac.tests.start_tests diff --git a/kordac/template.html b/kordac/template.html deleted file mode 100644 index aabbd013..00000000 --- a/kordac/template.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - Template - - - - - - - -
    {{content}}
    - - - From ada57a61e3a531c9799c98722905d50c6c13f32f Mon Sep 17 00:00:00 2001 From: Hayley van Waas Date: Fri, 10 Mar 2017 16:57:44 +1300 Subject: [PATCH 24/86] WIp contributing. Added newlines around headings for readability. --- docs/source/contributing.rst | 66 ++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 2ddfc5ed..21d8c2d5 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -14,8 +14,10 @@ The git repository for Kordac can be found `here`_, jump in and take a look arou + Issue Reporting and Bug Fixes ======================================= + If you come across a bug in Kordac, please `report it on the repo issue tracker`_. .. _report it on the repo issue tracker: https://github.com/uccser/kordac/issues @@ -25,10 +27,13 @@ If you choose to fix the bug for us, consider adding the relevant tests to the T The Code Base ======================================= + If you would like to contribute to Kordac, create a fork of the repository. + Overview ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Before reading this section, make sure you have read `how to use Kordac`_ (or even better, have already used Kordac!). .. _how to use Kordac: http://kordac.readthedocs.io/en/develop/usage.html @@ -36,6 +41,7 @@ Before reading this section, make sure you have read `how to use Kordac`_ (or ev Terminology *************************************** + There are a couple of terms we use when describing Kordac to become familiar with: - **Tag** @@ -57,12 +63,13 @@ There are a couple of terms we use when describing Kordac to become familiar wit Project Structure *************************************** + Below is a basic overview of the project structure: .. code-block:: none - ├── docs/ - ├── kordac/ + ├── docs/ + ├── kordac/ │   ├── html-templates/ │   ├── KordacExtension.py │   ├── Kordac.py @@ -70,7 +77,6 @@ Below is a basic overview of the project structure: │   ├── processors/ │   │   └── errors/ │   ├── tests/ - │   │   └── assets/ │   └── utils/ ├── requirements.txt └── setup.py @@ -102,10 +108,16 @@ The files and folders of interest are: Every processor is listed in this file, and will at least contain a regex pattern to match it's corresponding tag. Most will also define required and optional parameters, these correspond to arguments in the tag's template. +- ``tests/`` are explained in the Test Suite section further down the page + + +It is important to note that Kordac is not just a Markdown Extension, it is in fact a wrapper for Python Markdown. +``KordacExtension`` **is** an extension for Python Markdown. We have created an Creating a New Processor ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + To create a new processor, a good place to start is the `Extension API`_ page of the Python Markdown docs, and you can also read the `source code`_ itself. .. _Extension API: https://pythonhosted.org/Markdown/extensions/api.html @@ -144,6 +156,7 @@ We recommend writing documentation and test cases before you even write the proc The Test Suite ======================================= + To start the test suite: .. code-block:: bash @@ -154,18 +167,53 @@ This will execute the Smoke, System and then Unit tests. There are several arguments that can be used with this command to skip particular tests (``--no_smoke``, ``--no_system`` and ``--no_unit``). - +Test Suite Structure +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Recall our folder structure diagrom from earlier. This time, we're focusing just on the ``tests/`` folder: + +.. code-block:: none + + └── kordac/ + └── tests/ + ├── assets/ + ├── BaseTest.py + ├── ConfigurationTest.py + ├── ProcessorTest.py + ├── SmokeTests.py + └── start_tests.py + +The folder and files of interest are: + +- ``BaseTest.py`` + +- ``ConfigurationTest.py`` + Contains the unit tests. + +- ``ProcessorTest.py`` + +- ``SmokeTests.py`` + Contains smoke tests for both the docs and kordac + +- ``start_tests.py`` + +- - ``assets/`` + Adding Tests ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + If you are adding an new test file (e.g. for a new processor), then this needs to be added to the Test Suite in ``start_tests.py``. + Provided Base Classes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Processor Tests ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + All processor tests inherit from the ``ProcessorTest`` class. Processors should create a ``Mock()`` object, which will contain the bare minimum for the processor to be run (it's jinja template's and properties loaded from ``processor-info.json``), i.e. there is no reason for it to know about properties of the other processors. A test method will typically follow the same sequence of steps: @@ -178,8 +226,10 @@ A test method will typically follow the same sequence of steps: 6. Check the converted result is the same as the expected result + Testing Assets *************************************** + @@ -214,7 +264,9 @@ can only be performed by repository administrators Notes ======================================= -Want to know why type of tests we want. (Check input and output) - +Kordac should make use GitHub's features: -Adding something that interacts with something else? Best to catch those interactions downstream - don't change things at the start of the pipeline to try and get things ready for a processor later on, let that second processor deal with it. +Issue template +Pull request template +Contributing page +So GitHub can display these when appropriate. \ No newline at end of file From 3871e2a6d721182e09339c2cf801aa46ef57bfc4 Mon Sep 17 00:00:00 2001 From: Hayley van Waas Date: Sun, 12 Mar 2017 22:03:20 +1300 Subject: [PATCH 25/86] Contributing docs nearly finished... --- docs/source/contributing.rst | 113 +++++++++++++++++------------------ 1 file changed, 54 insertions(+), 59 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 21d8c2d5..acbef50e 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -5,30 +5,21 @@ Welcome to the Kordac developer community! We have spent many months developing Kordac was created to be used by two much larger projects (the `CS Unplugged`_ and `CS Field Guide`_ websites) as the markdown-to-html converter. The tags we chose are designed to allow authors of these two projects to easily write material without technical elements getting in the way. It is therefore important to us that Kordac remains as simple and robust as possible, please keep this in mind if you decide to work on Kordac with us. -.. _CS Unplugged: https://github.com/uccser/cs-unplugged/ -.. _CS Field Guide: https://github.com/uccser/cs-field-guide/ - The git repository for Kordac can be found `here`_, jump in and take a look around! -.. _here: https://github.com/uccser/kordac - - - Issue Reporting and Bug Fixes ======================================= If you come across a bug in Kordac, please `report it on the repo issue tracker`_. -.. _report it on the repo issue tracker: https://github.com/uccser/kordac/issues - If you choose to fix the bug for us, consider adding the relevant tests to the Test Suite (detailed further down this page) to help us catch any future bugs. The Code Base ======================================= -If you would like to contribute to Kordac, create a fork of the repository. +If you would like to contribute to Kordac, `create a fork of the repository`_. Overview @@ -36,8 +27,6 @@ Overview Before reading this section, make sure you have read `how to use Kordac`_ (or even better, have already used Kordac!). -.. _how to use Kordac: http://kordac.readthedocs.io/en/develop/usage.html - Terminology *************************************** @@ -58,7 +47,7 @@ There are a couple of terms we use when describing Kordac to become familiar wit are examples of the ``comment`` and ``image`` tags in Kordac. - **Processor** - This refers to the class that is responsible for converting a specific tag. For example, `RelativeLinkPattern` is the processor for internal links. + This refers to the class that is responsible for converting a specific tag. For example, ``RelativeLinkPattern`` is the processor for internal links. Project Structure @@ -81,12 +70,12 @@ Below is a basic overview of the project structure: ├── requirements.txt └── setup.py -The files and folders of interest are: +The items of interest are: - ``Kordac()`` The convertor object itself. This is what a user will use to create a Kordac converter, and what is used to define a custom processor list, custom html templates and custom Markdown Extensions to use. -- ``KordacResult()`` +- ``KordacResult()`` (found in ``Kordac.py``) The object returned by ``Kordac()`` containing: - Converted html string - Title @@ -102,17 +91,16 @@ The files and folders of interest are: There is a different processor for each tag. A processor uses it's corresponding regex loaded from ``processor-info.json`` to find matches in the text, and uses the given arguments in the matched tag to populate and output it's html template. - ``html-templates/`` - The html templates (using Jinja2 template engine) to be populated by processors. + The html templates (using the Jinja2 template engine) with variable arguments to be populated by processors. - ``processor-info.json`` Every processor is listed in this file, and will at least contain a regex pattern to match it's corresponding tag. - Most will also define required and optional parameters, these correspond to arguments in the tag's template. + Most will also define required and optional parameters, these correspond to arguments in the tag's html template. -- ``tests/`` are explained in the Test Suite section further down the page +- ``tests/`` are explained in the Test Suite section further down the page. -It is important to note that Kordac is not just a Markdown Extension, it is in fact a wrapper for Python Markdown. -``KordacExtension`` **is** an extension for Python Markdown. We have created an +It is important to note that Kordac is not just a Markdown Extension, it is a wrapper for Python Markdown. ``KordacExtension`` **is** an extension for Python Markdown. We have created a wrapper because we wanted to not only convert text, but also extract information from the text as it was being converted (recall ``KordacResult()`` listed above). Creating a New Processor @@ -120,26 +108,18 @@ Creating a New Processor To create a new processor, a good place to start is the `Extension API`_ page of the Python Markdown docs, and you can also read the `source code`_ itself. -.. _Extension API: https://pythonhosted.org/Markdown/extensions/api.html - -.. _source code: https://github.com/waylan/Python-Markdown - - -There are several different kinds of processors in Python Markdown, each serving a slightly different purpose. We recommend reading the API docs to determine which processor best suits your purpose (Kordac currently makes use of ``preprocessor``, ``blockprocessor``, ``inlinepattern``, ``treeprocessor`` and ``postprocessor``). +There are several different kinds of processors in Python Markdown, each serving a slightly different purpose. We recommend reading the API docs to determine which processor best suits your purpose. Kordac currently makes use of ``preprocessor``, ``blockprocessor``, ``inlinepattern``, ``treeprocessor`` and ``postprocessor``, but you are welcome to use another type of processor if it better suits the task. The order of the processors matters and is defined when each processor is added to the ``OrderedDict`` in ``KordacExtension.py``. -Each processor is independent of every other processor. If you have two processors in the pipeline that may overlap (e.g. codehilite and fencedcode), the second processor must handle whatever the first outputs. Therefore refrain from manipulating the output of a processor for a later processor. +Each processor should try to be as independent of every other processor as possible. Sometimes this is not possible, and in this case compatibility should occur in the processor that happens last (i.e. the downstream processor). That is output should be consistent based on input, not the other way round (e.g. ``codehilite`` and ``fenced_code``). The logic for each processor belongs in the ``processors/`` directory, and there are several other places where processors details need to be listed. These are: - The processor's relevant information (regex pattern, required parameters etc) should be included in ``processor-info.json`` - If it should be a default processor, it should be added to the frozenset of ``DEFAULT_PROCESSORS`` in ``Kordac.py`` -- The relevant list in ``extendMarkdown()`` in ``KordacExtension.py`` (see `OrderedDict in the Markdown API docs`_ for determining order) -- The processor's template should be added to ``html-templates`` using the Jinja2 Template Engine syntax for variable parameters - - -.. _OrderedDict in the Markdown API docs: https://pythonhosted.org/Markdown/extensions/api.html#ordereddict +- The relevant list in ``extendMarkdown()`` in ``KordacExtension.py`` (see `OrderedDict in the Markdown API docs`_ for manipulating processor order) +- The processor's template should be added to ``html-templates`` using the Jinja2 template engine syntax for variable parameters The new processors should also: @@ -170,7 +150,7 @@ There are several arguments that can be used with this command to skip particula Test Suite Structure ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Recall our folder structure diagrom from earlier. This time, we're focusing just on the ``tests/`` folder: +Recall our project structure diagram from earlier. This time, we're focusing just on the ``tests/`` directory: .. code-block:: none @@ -183,57 +163,55 @@ Recall our folder structure diagrom from earlier. This time, we're focusing just ├── SmokeTests.py └── start_tests.py -The folder and files of interest are: +The items of interest are: - ``BaseTest.py`` + This class is inherited by nearly every other test file, and contains a method to read a given test asset file. - ``ConfigurationTest.py`` - Contains the unit tests. + This is the test class for testing different configurations of ``Kordac()`` (e.g. using a custom list of processors and/or custom html templates). This class inherits the ``BaseTest`` class. - ``ProcessorTest.py`` + This is the class inherited by all processor test classes. It contains several useful methods for testing processors, including those for loading templates and processor info. - ``SmokeTests.py`` - Contains smoke tests for both the docs and kordac + This contains two classes for smoke testing (one class for ``Kordac``, the other for the docs). - ``start_tests.py`` + This is the file that is executed in order to run each of the three types of tests (Smoke, System and Unit). Every new test class must be added to the relevant section of this file. -- - ``assets/`` +- ``assets/`` + This directory contains a sub directory for every test class that loads external assets (i.e. test input files). - Adding Tests ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If you are adding an new test file (e.g. for a new processor), then this needs to be added to the Test Suite in ``start_tests.py``. - - -Provided Base Classes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +When writing a new test function, it is important that the method name is as descriptive as possible, and is prefixed with ``test_``. +If you have added a new processor to ``Kordac``, then a corresponding test suite also needs to be added. This test suite should be added to the ``unit_suite()`` function in ``start_tests.py``. The section below has details on how to write a processor test. + Processor Tests ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -All processor tests inherit from the ``ProcessorTest`` class. Processors should create a ``Mock()`` object, which will contain the bare minimum for the processor to be run (it's jinja template's and properties loaded from ``processor-info.json``), i.e. there is no reason for it to know about properties of the other processors. +All processor tests inherit from the ``ProcessorTest`` class. Processors should create a ``Mock()`` object, which will contain the bare minimum for the processor to be run (it's html template and properties loaded from ``processor-info.json``), i.e. there is no reason for it to know about properties of the other processors. A test method will typically follow the same sequence of steps: 1. Retrieve the test string (there is a ``read_test_file()`` method provided by the ``ProcessorTest`` class) - 2. Split into blocks (there is a ``to_blocks()`` method provided by the ``ProcessorTest`` class) - 3. Use an ``Assert`` to confirm there are(not) matches to the regex - 4. Convert the test string using the ``kordac_extension`` (provided by the ``SetUp()`` method in ``ProcessorTest``) - 5. Load the expected converted result - 6. Check the converted result is the same as the expected result - + 2. Confirm there are(not) matches to the regex in the test string + 3. Convert the test string using the ``kordac_extension`` (provided by the ``SetUp()`` method in ``ProcessorTest``) + 4. Load the expected converted result + 5. Check the converted result is the same as the expected result Testing Assets *************************************** - +Most tests will load an asset file. This file contains example markdown text (and therefore has a ``.md`` extension). For comparing the converted result of this markdown file with it's expected output, a corresponding "expected" file should be created. The expected file should have the same name as the corresponding test file, with ``expected`` appended to the file name. - -The test markdown file and expected html file should be placed in ``kordac/tests/assets//``. The expected file should have the same name as the corresponding test file, with ``expected`` appended to the file name. +These asset files should be placed in ``kordac/tests/assets//``. For example: @@ -242,7 +220,8 @@ For example: kordac/tests/assets/boxed-text/no_boxed_text.md kordac/tests/assets/boxed-text/no_boxed_text_expected.html - +.. note:: + - Asset files should have discriptive names, and in many cases will have the same name as the method they are used in. Creating a release ======================================= @@ -250,12 +229,12 @@ Creating a release This is our current process for creating and publishing a Kordac release. This can only be performed by repository administrators -1. `Create a release branch `_. Checkout to this branch. +1. `Create a release branch`_. Checkout to this branch. 2. Update the version number [1]_ within ``kordac/__init__.py``. -3. Check test suite for errors, and fix any issues that arise, or `log an issue `_. +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. -6. Create the release on `GitHub `_ on the tagged commit. +5. `Complete the release branch`_. Be sure to tag the release with the version number for creating the release on GitHub. +6. Create the release on `GitHub`_ on the tagged commit. 7. Upload a new version of Kordac to PyPI. .. [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 Kordac it was built from. @@ -269,4 +248,20 @@ Kordac should make use GitHub's features: Issue template Pull request template Contributing page -So GitHub can display these when appropriate. \ No newline at end of file +So GitHub can display these when appropriate. + + + +.. _CS Unplugged: https://github.com/uccser/cs-unplugged/ +.. _CS Field Guide: https://github.com/uccser/cs-field-guide/ +.. _here: https://github.com/uccser/kordac +.. _report it on the repo issue tracker: https://github.com/uccser/kordac/issues +.. _create a fork of the repository: https://help.github.com/articles/fork-a-repo/ +.. _how to use Kordac: http://kordac.readthedocs.io/en/develop/usage.html +.. _Extension API: https://pythonhosted.org/Markdown/extensions/api.html +.. _source code: https://github.com/waylan/Python-Markdown +.. _OrderedDict in the Markdown API docs: https://pythonhosted.org/Markdown/extensions/api.html#ordereddict +.. _Create a release branch: http://nvie.com/posts/a-successful-git-branching-model/#creating-a-release-branch +.. _log an issue: https://github.com/uccser/cs-field-guide/issues/new +.. _Complete the release branch: http://nvie.com/posts/a-successful-git-branching-model/#finishing-a-release-branch +.. _GitHub: https://github.com/uccser/kordac/releases/ \ No newline at end of file From e917e110cc4263827fc867cdd35ac66b9507956d Mon Sep 17 00:00:00 2001 From: Hayley van Waas Date: Mon, 13 Mar 2017 09:29:14 +1300 Subject: [PATCH 26/86] Minor changes to contributing page --- docs/source/contributing.rst | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index acbef50e..47cfbd1b 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -7,6 +7,20 @@ Kordac was created to be used by two much larger projects (the `CS Unplugged`_ a The git repository for Kordac can be found `here`_, jump in and take a look around! +.. note:: + + The two projects that Kordac was developed for are Django projects, so you may come across HTML (in templates, test cases etc) that contains Django syntax. + + For example, below is the expected output for a for a image tag test: + + .. code-block:: HTMl + +
    + Lipsum +
    + + This does not mean that Kordac is only suitable for Django projects, as it's just a matter of customising the relevant HTMl templates. + Issue Reporting and Bug Fixes ======================================= @@ -150,7 +164,7 @@ There are several arguments that can be used with this command to skip particula Test Suite Structure ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Recall our project structure diagram from earlier. This time, we're focusing just on the ``tests/`` directory: +We are now focusing on our project structure diagram from earlier: .. code-block:: none @@ -165,29 +179,29 @@ Recall our project structure diagram from earlier. This time, we're focusing jus The items of interest are: -- ``BaseTest.py`` +- ``BaseTest())`` This class is inherited by nearly every other test file, and contains a method to read a given test asset file. -- ``ConfigurationTest.py`` +- ``ConfigurationTest()`` This is the test class for testing different configurations of ``Kordac()`` (e.g. using a custom list of processors and/or custom html templates). This class inherits the ``BaseTest`` class. - ``ProcessorTest.py`` This is the class inherited by all processor test classes. It contains several useful methods for testing processors, including those for loading templates and processor info. -- ``SmokeTests.py`` - This contains two classes for smoke testing (one class for ``Kordac``, the other for the docs). +- ``SmokeDocsTest()`` and ``SmokeFileTest()`` + These are the two classes for smoke testing. - ``start_tests.py`` This is the file that is executed in order to run each of the three types of tests (Smoke, System and Unit). Every new test class must be added to the relevant section of this file. - ``assets/`` - This directory contains a sub directory for every test class that loads external assets (i.e. test input files). + This directory contains a sub directory for every test class that loads external assets (e.g. test input files). Adding Tests ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -When writing a new test function, it is important that the method name is as descriptive as possible, and is prefixed with ``test_``. +When writing a new test function, it is important that the method name is as descriptive as possible. The method name should also be prefixed with ``test_`` as the test suite will only execute methods with this prefix. If you have added a new processor to ``Kordac``, then a corresponding test suite also needs to be added. This test suite should be added to the ``unit_suite()`` function in ``start_tests.py``. The section below has details on how to write a processor test. @@ -195,12 +209,12 @@ If you have added a new processor to ``Kordac``, then a corresponding test suite Processor Tests ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -All processor tests inherit from the ``ProcessorTest`` class. Processors should create a ``Mock()`` object, which will contain the bare minimum for the processor to be run (it's html template and properties loaded from ``processor-info.json``), i.e. there is no reason for it to know about properties of the other processors. +All processor tests inherit from the ``ProcessorTest`` class. Processors should create a ``Mock()`` object, which will contain the bare minimum for the processor to be run (it's HTML template and properties loaded from ``processor-info.json``), i.e. there is no reason for it to know about properties of the other processors. A test method will typically follow the same sequence of steps: 1. Retrieve the test string (there is a ``read_test_file()`` method provided by the ``ProcessorTest`` class) - 2. Confirm there are(not) matches to the regex in the test string + 2. Confirm there are (not) matches to the regex in the test string 3. Convert the test string using the ``kordac_extension`` (provided by the ``SetUp()`` method in ``ProcessorTest``) 4. Load the expected converted result 5. Check the converted result is the same as the expected result @@ -209,7 +223,7 @@ A test method will typically follow the same sequence of steps: Testing Assets *************************************** -Most tests will load an asset file. This file contains example markdown text (and therefore has a ``.md`` extension). For comparing the converted result of this markdown file with it's expected output, a corresponding "expected" file should be created. The expected file should have the same name as the corresponding test file, with ``expected`` appended to the file name. +Most tests will load an asset file. This file contains example Markdown text (and therefore has a ``.md`` extension). For comparing the converted result of this Markdown file with it's expected output, a corresponding "expected" file should be created. The expected file should have the same name as the corresponding test file, with ``expected`` appended to the file name (and has a ``.html`` extension). These asset files should be placed in ``kordac/tests/assets//``. @@ -250,8 +264,6 @@ Pull request template Contributing page So GitHub can display these when appropriate. - - .. _CS Unplugged: https://github.com/uccser/cs-unplugged/ .. _CS Field Guide: https://github.com/uccser/cs-field-guide/ .. _here: https://github.com/uccser/kordac From ae4499c8f9de2182260f46ba1e65f058d2a6007c Mon Sep 17 00:00:00 2001 From: Hayley van Waas Date: Mon, 13 Mar 2017 11:46:09 +1300 Subject: [PATCH 27/86] Tidied up whitespace disaster in contributing docs Also added templates for PR and issue creating, as well as code of conduct and basic contributing for github page --- .github/ISSUE_TEMPLATE.md | 21 ++++ .github/PULL_REQUEST_TEMPLATE.md | 22 ++++ CODE_OF_CONDUCT.md | 74 +++++++++++++ CONTRIBUTING.md | 59 +++++++++++ docs/source/contributing.rst | 175 ++++++++++++++----------------- 5 files changed, 254 insertions(+), 97 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..4e61a4b4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,21 @@ +## Description + +Clearly and concisely describe the issue or suggestion here: + + + + + + + +### Checklist + +*Put an `x` in the boxes that apply. You can also fill these out after creating the issue.* + +- [ ] I have linked any relevant [existing issues/suggestions](https://github.com/uccser/kordac/issues) in the description above (include `#???` in your description to reference an issue, where `???` is the issue number) + +If this is a code related issue, please include the following in your description: + +- [ ] Steps to reproduce the behavior +- [ ] The platform(s) you are encountering the issue on +- [ ] The behavior you expect to see, and the actual behavior diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..f3057d65 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,22 @@ +## Proposed changes + +Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request: + + + + + + + +### Checklist + +*Put an `x` in the boxes that apply. You can also fill these out after creating the pull request. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your change.* + +- [ ] I have read the [contribution guidelines](.github/CONTRIBUTING.md) +- [ ] I have linked any relevant [existing issues/suggestions](https://github.com/uccser/kordac/issues) in the description above (include `#???` in your description to reference an issue, where `???` is the issue number) +- [ ] I have run the test suite and all tests passed +- [ ] I have added necessary documentation (if appropriate) + +### Further comments + +If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc. Feel free to add any images that might be helpful to understand the initial problem/solution. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..a52609a0 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [csse-education-research@canterbury.ac.nz](mailto:csse-education-research@canterbury.ac.nz). All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..40b05c3a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,59 @@ +# Contributing Guide + +Welcome to the Kordac developer community! We have spent many months developing this project, and we would love for you to get involved! + +We've written a technical guide about how Kordac works and how to contribute [here](kordac.readthedocs.io/en/develop/contributing.html). These docs should give you a good overview of how Kordac is pieced together. + +Below are a few more general notes to remember while you are working on Kordac. + +### Code of Conduct + +This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md). +By participating, you are expected to uphold this code. +Please report unacceptable behavior to [csse-education-research@canterbury.ac.nz](csse-education-research@canterbury.ac.nz) + +### Reporting issues + +This section guides you through submitting an issue for Kordac. +Following these guidelines helps maintainers and the community understand your findings. + +Before submitting an issue, please take a look at the [issues](https://github.com/uccser/kordac/issues) on the repository to check it hasn't already been reported. + +### Your first code contribution + +Unsure where to begin contributing to Kordac? Take a look at the [issues](https://github.com/uccser/kordac/issues) on the repository. + +### Pull requests + +- Include a detailed explaination of the proposed change +- Read and applied the [style guides listed below](#style-guides). +- Your pull request should be on a new branch from our `develop` branch (unless it's something tiny like a typo). The naming conventions of branches should be descriptive of the new addition/modification. Ideally they would specify their namespace as well, for example: + - `processor/image` + - `issue/234` +- Linked any relevant [existing issues](https://github.com/uccser/kordac/issues). +- Run the test suite and all tests passed +- Added necessary documentation (if appropriate). + +## Style guides + +### Git + +- Commits should be as descriptive as possible. Other developers (and even future you) will thank you for your forethought and verbosity for well documented commits. [Ideally follow this commit structure](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), otherwise in short: + - Limit the first line to 72 characters or less + - Reference issues and pull requests liberally +- Use [Vincent Driessen's Git Branching Model](http://nvie.com/posts/a-successful-git-branching-model/) for managing development. Please read this document to understand our branching methods. + +### Programming + +> Every line of code should appear to be written by a single person, no matter the number of contributors. + +These are our abridged guidelines for working on code within this repository: +- Code should be easily readable (avoid abbreviations etc) +- Files should be set to `utf-8`, use `lf` line endings, and have a final newline at the end of a file. +- Functions should have comments/docstrings explaining their purpose. +- Indents should be spaces (not tab characters) +- Indent sizes: + - HTML: 2 spaces + - Python: 4 spaces + +We aim to follow the [PEP8 style guide](https://www.python.org/dev/pep-0008/) and use [Flake8](flake8.pycqa.org/en/latest/) to enforce this. diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 47cfbd1b..2502ba81 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -9,17 +9,17 @@ The git repository for Kordac can be found `here`_, jump in and take a look arou .. note:: - The two projects that Kordac was developed for are Django projects, so you may come across HTML (in templates, test cases etc) that contains Django syntax. + The two projects that Kordac was developed for are Django projects, so you may come across HTML (in templates, test cases etc) that contains Django syntax. - For example, below is the expected output for a for a image tag test: + For example, below is the expected output for a for a image tag test: - .. code-block:: HTMl + .. code-block:: HTMl -
    - Lipsum -
    +
    + Lipsum +
    - This does not mean that Kordac is only suitable for Django projects, as it's just a matter of customising the relevant HTMl templates. + This does not mean that Kordac is only suitable for Django projects, as it's just a matter of customising the relevant HTMl templates. Issue Reporting and Bug Fixes @@ -48,20 +48,22 @@ Terminology There are a couple of terms we use when describing Kordac to become familiar with: - **Tag** - This refers to the custom markdown syntax that Kordac processes. - - For example: - - .. code-block:: none - {comment this will be removed by the converter} + This refers to the custom markdown syntax that Kordac processes. - {image file-path="img/totally-real-image.png" alt="process me"} - - are examples of the ``comment`` and ``image`` tags in Kordac. + For example: + + .. code-block:: none + + {comment this will be removed by the converter} + + {image file-path="img/totally-real-image.png" alt="process me"} + + are examples of the ``comment`` and ``image`` tags in Kordac. - **Processor** - This refers to the class that is responsible for converting a specific tag. For example, ``RelativeLinkPattern`` is the processor for internal links. + + This refers to the class that is responsible for converting a specific tag. For example, ``RelativeLinkPattern`` is the processor for internal links. Project Structure @@ -71,47 +73,42 @@ Below is a basic overview of the project structure: .. code-block:: none - ├── docs/ - ├── kordac/ - │   ├── html-templates/ - │   ├── KordacExtension.py - │   ├── Kordac.py - │   ├── processor-info.json - │   ├── processors/ - │   │   └── errors/ - │   ├── tests/ - │   └── utils/ - ├── requirements.txt - └── setup.py + ├── docs/ + ├── kordac/ + │   ├── html-templates/ + │   ├── KordacExtension.py + │   ├── Kordac.py + │   ├── processor-info.json + │   ├── processors/ + │   │   └── errors/ + │   ├── tests/ + │   └── utils/ + ├── requirements.txt + └── setup.py The items of interest are: -- ``Kordac()`` - The convertor object itself. This is what a user will use to create a Kordac converter, and what is used to define a custom processor list, custom html templates and custom Markdown Extensions to use. +- ``Kordac()`` - The convertor object itself. This is what a user will use to create a Kordac converter, and what is used to define a custom processor list, custom html templates and custom Markdown Extensions to use. + + +- ``KordacResult()`` (found in ``Kordac.py``) - The object returned by ``Kordac()`` containing: -- ``KordacResult()`` (found in ``Kordac.py``) - The object returned by ``Kordac()`` containing: - - Converted html string - - Title - - Required files (images, interactives, scratch images, page scripts) - - Heading tree - - Required glossary terms + - Converted html string + - Title + - Required files (images, interactives, scratch images, page scripts) + - Heading tree + - Required glossary terms -- ``KordacExtension()`` - This is the main class of the project, and inherits the ``Extension`` class from Markdown. - It loads all of the processor information, loads the template files and clears and populates the attributes to be returned by the ``KordacResult`` object. -- ``Processors/`` - There is a different processor for each tag. A processor uses it's corresponding regex loaded from ``processor-info.json`` to find matches in the text, and uses the given arguments in the matched tag to populate and output it's html template. +- ``KordacExtension()`` - This is the main class of the project, and inherits the ``Extension`` class from Markdown. It loads all of the processor information, loads the template files and clears and populates the attributes to be returned by the ``KordacResult`` object. -- ``html-templates/`` - The html templates (using the Jinja2 template engine) with variable arguments to be populated by processors. +- ``Processors/`` - There is a different processor for each tag. A processor uses it's corresponding regex loaded from ``processor-info.json`` to find matches in the text, and uses the given arguments in the matched tag to populate and output it's html template. -- ``processor-info.json`` - Every processor is listed in this file, and will at least contain a regex pattern to match it's corresponding tag. - Most will also define required and optional parameters, these correspond to arguments in the tag's html template. +- ``html-templates/`` - The html templates (using the Jinja2 template engine) with variable arguments to be populated by processors. -- ``tests/`` are explained in the Test Suite section further down the page. +- ``processor-info.json`` - Every processor is listed in this file, and will at least contain a regex pattern to match it's corresponding tag. Most will also define required and optional parameters, these correspond to arguments in the tag's html template. + +- ``tests/`` - explained in the Test Suite section further down the page. It is important to note that Kordac is not just a Markdown Extension, it is a wrapper for Python Markdown. ``KordacExtension`` **is** an extension for Python Markdown. We have created a wrapper because we wanted to not only convert text, but also extract information from the text as it was being converted (recall ``KordacResult()`` listed above). @@ -139,11 +136,11 @@ The new processors should also: - Be thoroughly tested (see the section below) - Have clear and accurate documentation. See the docs on other processors for the preferred format. Your docs should include: - - An example of the tag in markdown - - Required parameters - - Optional parameters - - Examples - - Examples of overriding the html + - An example of the tag in markdown + - Required parameters + - Optional parameters + - Examples + - Examples of overriding the html We recommend writing documentation and test cases before you even write the processor itself as this will give you a clear idea of how a processor in Kordac should behave. @@ -155,7 +152,7 @@ To start the test suite: .. code-block:: bash - $ python3 -m kordac.tests.start_tests + $ python3 -m kordac.tests.start_tests This will execute the Smoke, System and then Unit tests. @@ -168,34 +165,28 @@ We are now focusing on our project structure diagram from earlier: .. code-block:: none - └── kordac/ - └── tests/ - ├── assets/ - ├── BaseTest.py - ├── ConfigurationTest.py - ├── ProcessorTest.py - ├── SmokeTests.py - └── start_tests.py + └── kordac/ + └── tests/ + ├── assets/ + ├── BaseTest.py + ├── ConfigurationTest.py + ├── ProcessorTest.py + ├── SmokeTests.py + └── start_tests.py The items of interest are: -- ``BaseTest())`` - This class is inherited by nearly every other test file, and contains a method to read a given test asset file. +- ``BaseTest())`` - This class is inherited by nearly every other test file, and contains a method to read a given test asset file. -- ``ConfigurationTest()`` - This is the test class for testing different configurations of ``Kordac()`` (e.g. using a custom list of processors and/or custom html templates). This class inherits the ``BaseTest`` class. +- ``ConfigurationTest()`` - This is the test class for testing different configurations of ``Kordac()`` (e.g. using a custom list of processors and/or custom html templates). This class inherits the ``BaseTest`` class. -- ``ProcessorTest.py`` - This is the class inherited by all processor test classes. It contains several useful methods for testing processors, including those for loading templates and processor info. +- ``ProcessorTest.py`` - This is the class inherited by all processor test classes. It contains several useful methods for testing processors, including those for loading templates and processor info. -- ``SmokeDocsTest()`` and ``SmokeFileTest()`` - These are the two classes for smoke testing. +- ``SmokeDocsTest()`` and ``SmokeFileTest()`` - These are the two classes for smoke testing. -- ``start_tests.py`` - This is the file that is executed in order to run each of the three types of tests (Smoke, System and Unit). Every new test class must be added to the relevant section of this file. +- ``start_tests.py`` - This is the file that is executed in order to run each of the three types of tests (Smoke, System and Unit). Every new test class must be added to the relevant section of this file. -- ``assets/`` - This directory contains a sub directory for every test class that loads external assets (e.g. test input files). +- ``assets/`` - This directory contains a sub directory for every test class that loads external assets (e.g. test input files). Adding Tests @@ -204,7 +195,7 @@ Adding Tests When writing a new test function, it is important that the method name is as descriptive as possible. The method name should also be prefixed with ``test_`` as the test suite will only execute methods with this prefix. If you have added a new processor to ``Kordac``, then a corresponding test suite also needs to be added. This test suite should be added to the ``unit_suite()`` function in ``start_tests.py``. The section below has details on how to write a processor test. - + Processor Tests ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -213,11 +204,11 @@ All processor tests inherit from the ``ProcessorTest`` class. Processors should A test method will typically follow the same sequence of steps: - 1. Retrieve the test string (there is a ``read_test_file()`` method provided by the ``ProcessorTest`` class) - 2. Confirm there are (not) matches to the regex in the test string - 3. Convert the test string using the ``kordac_extension`` (provided by the ``SetUp()`` method in ``ProcessorTest``) - 4. Load the expected converted result - 5. Check the converted result is the same as the expected result +1. Retrieve the test string (there is a ``read_test_file()`` method provided by the ``ProcessorTest`` class) +2. Confirm there are (not) matches to the regex in the test string +3. Convert the test string using the ``kordac_extension`` (provided by the ``SetUp()`` method in ``ProcessorTest``) +4. Load the expected converted result +5. Check the converted result is the same as the expected result Testing Assets @@ -225,17 +216,17 @@ Testing Assets Most tests will load an asset file. This file contains example Markdown text (and therefore has a ``.md`` extension). For comparing the converted result of this Markdown file with it's expected output, a corresponding "expected" file should be created. The expected file should have the same name as the corresponding test file, with ``expected`` appended to the file name (and has a ``.html`` extension). -These asset files should be placed in ``kordac/tests/assets//``. +These asset files should be placed in ``kordac/tests/assets//``. For example: .. code-block:: none - - kordac/tests/assets/boxed-text/no_boxed_text.md - kordac/tests/assets/boxed-text/no_boxed_text_expected.html + + kordac/tests/assets/boxed-text/no_boxed_text.md + kordac/tests/assets/boxed-text/no_boxed_text_expected.html .. note:: - - Asset files should have discriptive names, and in many cases will have the same name as the method they are used in. + - Asset files should have discriptive names, and in many cases will have the same name as the method they are used in. Creating a release ======================================= @@ -254,16 +245,6 @@ can only be performed by repository administrators .. [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 Kordac it was built from. -Notes -======================================= - -Kordac should make use GitHub's features: - -Issue template -Pull request template -Contributing page -So GitHub can display these when appropriate. - .. _CS Unplugged: https://github.com/uccser/cs-unplugged/ .. _CS Field Guide: https://github.com/uccser/cs-field-guide/ .. _here: https://github.com/uccser/kordac @@ -276,4 +257,4 @@ So GitHub can display these when appropriate. .. _Create a release branch: http://nvie.com/posts/a-successful-git-branching-model/#creating-a-release-branch .. _log an issue: https://github.com/uccser/cs-field-guide/issues/new .. _Complete the release branch: http://nvie.com/posts/a-successful-git-branching-model/#finishing-a-release-branch -.. _GitHub: https://github.com/uccser/kordac/releases/ \ No newline at end of file +.. _GitHub: https://github.com/uccser/kordac/releases/ From baead8061b683a0ffd63eb3370c694b2072da0f9 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Mon, 13 Mar 2017 11:53:58 +1300 Subject: [PATCH 28/86] Update all processors in processor-info. --- kordac/processor-info.json | 278 +++++++++++++----- .../GenericContainerBlockProcessor.py | 4 +- kordac/processors/GenericTagBlockProcessor.py | 2 +- 3 files changed, 206 insertions(+), 78 deletions(-) diff --git a/kordac/processor-info.json b/kordac/processor-info.json index b43f8ca9..d2e5f0cf 100644 --- a/kordac/processor-info.json +++ b/kordac/processor-info.json @@ -1,74 +1,6 @@ { - "panel": { - "pattern_start": "^\\{panel ?(?P[^\\}]*)(?[^\\}]*)}?(?P.*?){glossary-link end\\}", - "required_parameters": ["term"], - "optional_parameter_dependencies": { - "reference-text" :[] - } - }, - "comment": { - "pattern" : "\\{comment [^\\}]+\\}" - }, - "conditional": { - "pattern": "^\\{conditional (?P[^\\}]*(?[^\\}]*)\\}", - "required_parameters": ["url"], - "optional_parameter_dependencies": {} - }, - "image": { - "pattern": "(\\{image (?P[^\\}]*)\\})", - "required_parameters": ["file-path"], - "optional_parameter_dependencies": { - "alt": [], - "caption": [], - "caption-link": ["caption"], - "source": [], - "alignment": [], - "hover-text": [] - } - }, - "interactive": { - "pattern": "^\\{interactive (?P[^\\}]*)\\}$", - "required_parameters": ["name", "type"], - "optional_parameter_dependencies": { - "text": [], - "parameters": [], - "thumbnail": [] - } - }, - "title": { - "pattern": "^#+ ?(.*)" - }, - "button-link": { - "pattern": "\\{button-link (?P[^\\}]*)\\}", - "required_parameters": ["link", "text"], - "optional_parameter_dependencies": { - "file": [] - } - }, "boxed-text": { "class": "generic_container", - "pattern_start": "\\{boxed-text ?(?P[^\\}]*)(?[^\\}]*)}?(?P.*?){glossary-link end\\}", + "arguments": { + "term": { + "required": true, + "dependencies": [] + }, + "reference-text": { + "required": false, + "dependencies": [] + } + } + }, + "heading": { + "class": "custom", + "pattern": "(^|\\n)(?P#{1,6})(?!#+)\\s?(?P
    .*?)\\s?#*(\\n|$)" + }, "iframe": { "class": "generic_tag", "arguments": { @@ -104,18 +114,136 @@ } } }, - "table-of-contents": { - "pattern": "(^|\\n)\\{table-of-contents\\}(\\n|$)" + "image": { + "class": "custom", + "pattern": "(^|\\n) *\\{image (?P[^\\}]*)\\} *(\\n|$)", + "arguments": { + "file-path": { + "required": true, + "dependencies": [] + }, + "alt": { + "required": false, + "dependencies": [] + }, + "caption": { + "required": false, + "dependencies": [] + }, + "caption-link": { + "required": false, + "dependencies": [] + }, + "source": { + "required": false, + "dependencies": [] + }, + "alignment": { + "required": false, + "dependencies": [] + }, + "hover-text": { + "required": false, + "dependencies": [] + } + } }, - "heading": { - "pattern": "(^|\\n)(?P#{1,6})(?!#+)\\s?(?P
    .*?)\\s?#*(\\n|$)" + "interactive": { + "class": "custom", + "pattern": "(^|\\n) *\\{interactive (?P[^\\}]*)\\} *(\\n|$)", + "arguments": { + "name": { + "required": true, + "dependencies": [] + }, + "type": { + "required": true, + "dependencies": [] + }, + "text": { + "required": false, + "dependencies": [] + }, + "parameters": { + "required": false, + "dependencies": [] + }, + "thumbnail": { + "required": false, + "dependencies": [] + } + } + }, + "panel": { + "class": "generic_container", + "arguments": { + "type": { + "required": true, + "dependencies": [] + }, + "title": { + "required": true, + "dependencies": [] + }, + "subtitle": { + "required": false, + "dependencies": [] + }, + "expanded": { + "required": false, + "dependencies": [] + } + }, + "template_parameters": { + "type": { + "argument": "type", + "transform": null + }, + "title": { + "argument": "title", + "transform": null, + }, + "subtitle": { + "argument": "subtitle", + "transform": null + }, + "expanded": { + "argument": "expanded", + "transform": null + }, + "content": { + "argument": "content", + "transform": null + } + } + }, + "table-of-contents": { + "class": "generic_tag", + "arguments": {}, + "template_parameters": {} }, "relative-link": { + "class": "custom", "pattern": "\\[(?P[^\\]]+)\\]\\((?!(https?|ftps?|mailto|news):)(?P[^\\)]+)\\)" }, "scratch": { - "scratch-compatibility": { - "pattern": "(?P^(?:~{3,}|`{3,}))[ ]*scratch?[ ]*(hl_lines=(?P\"|')(?P.*?)(?P=quot))?[ ]*}?[ ]*\n(?P.*?)(?<=\n)(?P=fence)[ ]*$" - } + "class": "custom", + "scratch-compatibility": { + "pattern": "(?P^(?:~{3,}|`{3,}))[ ]*scratch?[ ]*(hl_lines=(?P\"|')(?P.*?)(?P=quot))?[ ]*}?[ ]*\n(?P.*?)(?<=\n)(?P=fence)[ ]*$" + } + }, + "title": { + "class": "custom", + "pattern": "^#+ ?(.*)" + }, + "video": { + "class": "custom", + "pattern": "(^|\\n) *\\{video (?P[^\\}]*)\\} *(\\n|$)", + "arguments": { + "url": { + "required": true, + "dependencies": [] + } + }, } } diff --git a/kordac/processors/GenericContainerBlockProcessor.py b/kordac/processors/GenericContainerBlockProcessor.py index a4f8b981..5557f9ef 100644 --- a/kordac/processors/GenericContainerBlockProcessor.py +++ b/kordac/processors/GenericContainerBlockProcessor.py @@ -10,8 +10,8 @@ def __init__(self, processor, ext, *args, **kwargs): ''' super().__init__(*args, **kwargs) self.processor = processor - self.p_start = re.compile(r'\{{{0} ?(?P[^\}}]*)(?[^\}}]*)(?[^\}}]*)\}}').format(self.processor) + self.pattern = re.compile(r'(^|\n) *\{{{0} ?(?P[^\}}]*)\}} *(\n|$)').format(self.processor) self.arguments = ext.processor_info[self.processor]['arguments'] template_name = self.processor['template_name'] self.template = ext.jinja_templates[ext.processor_info[template_name] From ea5b2c51d769883da75cb9c2dfe0caa0c2ec82e1 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Mon, 13 Mar 2017 13:04:44 +1300 Subject: [PATCH 29/86] Extract processing of parameters into a separate function. --- kordac/KordacExtension.py | 4 +- kordac/processor-info.json | 44 +++++++------------ .../GenericContainerBlockProcessor.py | 17 ++----- kordac/processors/GenericTagBlockProcessor.py | 13 +----- kordac/processors/utils.py | 42 +++++++++++++++++- 5 files changed, 64 insertions(+), 56 deletions(-) diff --git a/kordac/KordacExtension.py b/kordac/KordacExtension.py index 3e254634..86ce11da 100644 --- a/kordac/KordacExtension.py +++ b/kordac/KordacExtension.py @@ -25,7 +25,7 @@ from kordac.utils.UniqueSlugify import UniqueSlugify from kordac.utils.HeadingNode import HeadingNode -from collections import defaultdict +from collections import defaultdict, OrderedDict from os import listdir import os.path import re @@ -132,7 +132,7 @@ def loadJinjaTemplates(self, custom_templates): def loadProcessorInfo(self): json_data = open(os.path.join(os.path.dirname(__file__), 'processor-info.json')).read() - return json.loads(json_data) + return json.loads(json_data, object_pairs_hook=OrderedDict) def get_heading_tree(self): return self.heading_tree diff --git a/kordac/processor-info.json b/kordac/processor-info.json index d2e5f0cf..f5215286 100644 --- a/kordac/processor-info.json +++ b/kordac/processor-info.json @@ -16,7 +16,7 @@ }, "text": { "argument": "content", - "transform": null, + "transform": null } } }, @@ -37,6 +37,11 @@ } }, "template_parameters": { + "file": { + "argument": "file", + "transform": "str.lower", + "default": "no" + }, "link": { "argument": "link", "transform": "relative_file", @@ -44,12 +49,7 @@ }, "text": { "argument": "text", - "transform": null, - }, - "file": { - "argument": "file", - "transform": "str.lower", - "default": "no" + "transform": null } } }, @@ -178,42 +178,33 @@ "class": "generic_container", "arguments": { "type": { - "required": true, - "dependencies": [] + "required": true }, "title": { - "required": true, - "dependencies": [] + "required": true }, "subtitle": { - "required": false, - "dependencies": [] + "required": false }, "expanded": { - "required": false, - "dependencies": [] + "required": false } }, "template_parameters": { "type": { - "argument": "type", - "transform": null + "argument": "type" }, "title": { - "argument": "title", - "transform": null, + "argument": "title" }, "subtitle": { - "argument": "subtitle", - "transform": null + "argument": "subtitle" }, "expanded": { - "argument": "expanded", - "transform": null + "argument": "expanded" }, "content": { - "argument": "content", - "transform": null + "argument": "content" } } }, @@ -241,8 +232,7 @@ "pattern": "(^|\\n) *\\{video (?P[^\\}]*)\\} *(\\n|$)", "arguments": { "url": { - "required": true, - "dependencies": [] + "required": true } }, } diff --git a/kordac/processors/GenericContainerBlockProcessor.py b/kordac/processors/GenericContainerBlockProcessor.py index 5557f9ef..44308e39 100644 --- a/kordac/processors/GenericContainerBlockProcessor.py +++ b/kordac/processors/GenericContainerBlockProcessor.py @@ -56,8 +56,7 @@ def run(self, parent, blocks): if after.strip() != '': blocks.insert(0, after) - if len(self.arguments) > 0: - check_arguments(self.processor, match.group('args'), self.arguments) + argument_values = parse_arguments(self.processor, match.group('args'), self.arguments) content_blocks = [] the_rest = None @@ -95,18 +94,8 @@ def run(self, parent, blocks): for child in content_tree: content += etree.tostring(child, encoding="unicode", method="html") + '\n' - context = dict() - for parameter, parameter_info in self.template_parameters.items(): - argument_name = parameter_info['argument'] - parameter_default = parameter_info['default'] if 'default' in parameter_info else None - parameter_value = None - if argument_info['argument'] == 'content': - parameter_value = content - else: - argument_value = parse_argument(argument_name, match.group('args'), parameter_default) - transformation = find_transformation(parameter_info['transform']) - parameter_value = transformation(argument_value) if transformation is not None else argument_value - context[parameter] = parameter_value + argument_values['content'] = content + context = process_parameters(self.processor, self.template_parameters, argument_values) html_string = self.template.render(context) node = etree.fromstring(html_string) diff --git a/kordac/processors/GenericTagBlockProcessor.py b/kordac/processors/GenericTagBlockProcessor.py index 6c9b8144..53d0fe3c 100644 --- a/kordac/processors/GenericTagBlockProcessor.py +++ b/kordac/processors/GenericTagBlockProcessor.py @@ -49,17 +49,8 @@ def run(self, parent, blocks): if after.strip() != '': blocks.insert(0, after) - if len(self.arguments) > 0: - check_arguments(self.processor, match.group('args'), self.arguments) - - context = dict() - for parameter, parameter_info in self.template_parameters.items(): - argument_name = parameter_info['argument'] - parameter_default = parameter_info['default'] if 'default' in parameter_info else None - argument_value = parse_argument(argument_name, match.group('args'), parameter_default) - transformation = find_transformation(parameter_info['transform']) - parameter_value = transformation(argument_value) if transformation is not None else argument_value - context[parameter] = parameter_value + argument_values = parse_arguments(self.processor, match.group('args'), self.arguments) + context = process_parameters(self.processor, self.template_parameters, argument_values) html_string = self.template.render(context) node = etree.fromstring(html_string) diff --git a/kordac/processors/utils.py b/kordac/processors/utils.py index be713f99..a932e0c3 100644 --- a/kordac/processors/utils.py +++ b/kordac/processors/utils.py @@ -1,5 +1,6 @@ import re from markdown.util import etree +from collections import OrderedDict from kordac.processors.errors.ArgumentMissingError import ArgumentMissingError def parse_argument(argument_key, arguments, default=None): @@ -22,10 +23,12 @@ def parse_flag(argument_key, arguments, default=False): argument_value = default return argument_value -def check_arguments(processor, inputs, arguments): +def parse_arguments(processor, inputs, arguments): ''' + Returns a dictionary of argument to value. Raises an error if the arguments are missing any required parameters or a parameter an optional parameter is dependent on. ''' + argument_values = dict() for argument, argument_info in arguments.items(): is_required = argument_info['required'] is_arg = parse_argument(argument, arguments, None) is not None @@ -34,12 +37,47 @@ def check_arguments(processor, inputs, arguments): if is_required and (is_arg or is_flag): raise ArgumentMissingError(processor, parameter, "{} is a required argument.".format(argument)) elif not is_required and (is_arg or is_flag): - dependencies = argument_info['dependencies'] + dependencies = argument_info.get('dependencies', []) for other_argument in dependencies: if not (parse_argument(other_argument, arguments, None) is None or parse_flag(other_argument, arguments) is None): raise ArgumentMissingError(processor, argument, "{} is a required parameter because {} exists.".format(other_argument, argument)) + if is_flag: + argument_values[argument] = True + elif is_arg: + argument_values[argument] = parse_argument(argument, arguments, None) + + return argument_values + +def process_parameters(processor, parameters, argument_values): + ''' + Returns a dictionary of parameter to value. + ''' + context = dict() + transformations = OrderedDict() + for parameter, parameter_info in parameters.items(): + argument_name = parameter_info['argument'] + parameter_default = parameter_info['default'] if 'default' in parameter_info else None + argument_value = argument_values[argument_name] if argument_values[argument_name] is not None else parameter_default + + parameter_value = argument_value + if parameter_info.get('transform', None): + transformation = find_transformation(parameter_info['transform']) + if parameter_info.get('transform_condition', None): + transformations[parameter] = (eval(parameter_info['transform_condition']), transformation) + else: + transformations[parameter] = (True, transformation) + + context[parameter] = parameter_value + + for parameter, (condition, transformation) in transformations.items(): + if isinstance(condition, bool) and condition == True: + context[parameter] = transform(context[parameter]) + if callable(condition) and condition(context): + context[parameter] = transform(context[parameter]) + return context + def find_transformation(option): ''' Returns a transformation for a given string. From bffc08917d160222ffdd7430829ad54e28c259ca Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Mon, 13 Mar 2017 13:28:43 +1300 Subject: [PATCH 30/86] Use custom template name. --- kordac/processors/GenericContainerBlockProcessor.py | 2 +- kordac/processors/GenericTagBlockProcessor.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kordac/processors/GenericContainerBlockProcessor.py b/kordac/processors/GenericContainerBlockProcessor.py index 44308e39..58f154d7 100644 --- a/kordac/processors/GenericContainerBlockProcessor.py +++ b/kordac/processors/GenericContainerBlockProcessor.py @@ -13,7 +13,7 @@ def __init__(self, processor, ext, *args, **kwargs): self.p_start = re.compile(r'(^|\n) *\{{{0} ?(?P[^\}}]*)(?[^\}}]*)\}} *(\n|$)').format(self.processor) self.arguments = ext.processor_info[self.processor]['arguments'] - template_name = self.processor['template_name'] + template_name = self.processor.get('template_name', self.processor) self.template = ext.jinja_templates[ext.processor_info[template_name] self.template_parameters = ext.processor_info[self.processor]['template_parameters'] From 070f02a50fa239c5bdb6614d0feb20ce96751f52 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Mon, 13 Mar 2017 16:09:23 +1300 Subject: [PATCH 31/86] Update all processors. --- kordac/KordacExtension.py | 85 +++++----- kordac/processor-info.json | 4 +- kordac/processors/BoxedTextBlockProcessor.py | 88 ---------- kordac/processors/ButtonLinkBlockProcessor.py | 52 ------ kordac/processors/CommentPreprocessor.py | 6 +- kordac/processors/ConditionalProcessor.py | 157 +++++++++--------- kordac/processors/FrameBlockProcessor.py | 52 ------ .../GenericContainerBlockProcessor.py | 2 +- kordac/processors/GenericTagBlockProcessor.py | 2 +- kordac/processors/GlossaryLinkPattern.py | 42 +++-- kordac/processors/HeadingBlockProcessor.py | 3 +- kordac/processors/ImageBlockProcessor.py | 70 +++++--- .../processors/InteractiveBlockProcessor.py | 32 ++-- kordac/processors/JinjaPostprocessor.py | 10 ++ kordac/processors/PanelBlockProcessor.py | 97 ----------- kordac/processors/RelativeLinkPattern.py | 12 +- kordac/processors/RemovePostprocessor.py | 11 ++ kordac/processors/RemoveTitlePreprocessor.py | 20 ++- kordac/processors/SaveTitlePreprocessor.py | 23 +++ kordac/processors/ScratchTreeprocessor.py | 2 +- .../TableOfContentsBlockProcessor.py | 47 ------ kordac/processors/VideoBlockProcessor.py | 53 +++--- kordac/processors/utils.py | 73 ++++++-- 23 files changed, 381 insertions(+), 562 deletions(-) delete mode 100644 kordac/processors/BoxedTextBlockProcessor.py delete mode 100644 kordac/processors/ButtonLinkBlockProcessor.py delete mode 100644 kordac/processors/FrameBlockProcessor.py delete mode 100644 kordac/processors/PanelBlockProcessor.py delete mode 100644 kordac/processors/TableOfContentsBlockProcessor.py diff --git a/kordac/KordacExtension.py b/kordac/KordacExtension.py index 86ce11da..6b6b6c57 100644 --- a/kordac/KordacExtension.py +++ b/kordac/KordacExtension.py @@ -1,7 +1,6 @@ from markdown.extensions import Extension import markdown.util as utils -from kordac.processors.PanelBlockProcessor import PanelBlockProcessor from kordac.processors.CommentPreprocessor import CommentPreprocessor from kordac.processors.VideoBlockProcessor import VideoBlockProcessor from kordac.processors.ImageBlockProcessor import ImageBlockProcessor @@ -10,17 +9,15 @@ from kordac.processors.RemoveTitlePreprocessor import RemoveTitlePreprocessor from kordac.processors.SaveTitlePreprocessor import SaveTitlePreprocessor from kordac.processors.GlossaryLinkPattern import GlossaryLinkPattern -from kordac.processors.ButtonLinkBlockProcessor import ButtonLinkBlockProcessor -from kordac.processors.BoxedTextBlockProcessor import BoxedTextBlockProcessor from kordac.processors.BeautifyPostprocessor import BeautifyPostprocessor from kordac.processors.ConditionalProcessor import ConditionalProcessor from kordac.processors.RemovePostprocessor import RemovePostprocessor from kordac.processors.JinjaPostprocessor import JinjaPostprocessor from kordac.processors.HeadingBlockProcessor import HeadingBlockProcessor -from kordac.processors.FrameBlockProcessor import FrameBlockProcessor -from kordac.processors.TableOfContentsBlockProcessor import TableOfContentsBlockProcessor from kordac.processors.ScratchTreeprocessor import ScratchTreeprocessor from kordac.processors.ScratchCompatibilityPreprocessor import ScratchCompatibilityPreprocessor +from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor +from kordac.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor from kordac.utils.UniqueSlugify import UniqueSlugify from kordac.utils.HeadingNode import HeadingNode @@ -34,6 +31,30 @@ from jinja2 import Environment, PackageLoader, select_autoescape class KordacExtension(Extension): + PREPROCESSORS = [ + ['comment', CommentPreprocessor(self, md), '_begin'], + ['save-title', SaveTitlePreprocessor(self, md), '_end'], + ['remove-title', RemoveTitlePreprocessor(self, md), '_end'], + ] + BLOCKPROCESSORS = [ + # Markdown overrides + ['heading', HeadingBlockProcessor(self, md.parser), 'inline' if 'hilite' not in self.compatibility else 'inline' if 'hilite' not in self.compatibility else '[^\\}]*)}?(?P.*?){glossary-link end\\}", + "pattern": "\\{glossary-link ?(?P[^\\}]*)\\}?(?P.*?)\\{glossary-link end\\}", "arguments": { "term": { "required": true, diff --git a/kordac/processors/BoxedTextBlockProcessor.py b/kordac/processors/BoxedTextBlockProcessor.py deleted file mode 100644 index 6fa31582..00000000 --- a/kordac/processors/BoxedTextBlockProcessor.py +++ /dev/null @@ -1,88 +0,0 @@ -from markdown.blockprocessors import BlockProcessor -from kordac.processors.utils import blocks_to_string, parse_argument, etree, check_argument_requirements -import kordac.processors.errors.TagNotMatchedError as TagNotMatchedError -import re - -class BoxedTextBlockProcessor(BlockProcessor): - def __init__(self, ext, *args, **kwargs): - super().__init__(*args, **kwargs) - self.processor = 'boxed-text' - self.p_start = re.compile(ext.processor_info[self.processor]['pattern_start']) - self.p_end = re.compile(ext.processor_info[self.processor]['pattern_end']) - self.template = ext.jinja_templates[self.processor] - self.required_parameters = ext.processor_info[self.processor]['required_parameters'] - self.optional_parameters = ext.processor_info[self.processor]['optional_parameter_dependencies'] - - def test(self, parent, block): - return self.p_start.search(block) is not None or self.p_end.search(block) is not None - - def run(self, parent, blocks): - block = blocks.pop(0) - - start_tag = self.p_start.search(block) - end_tag = self.p_end.search(block) - - # Found an end tag without processing a start tag first - if start_tag is None and end_tag is not None: - raise TagNotMatchedError(self.processor, block, 'end tag found before start tag') - - check_argument_requirements(self.processor, start_tag.group('args'), self.required_parameters, self.optional_parameters) - - # Put left overs back on blocks, should be empty though - blocks.insert(0, block[start_tag.end():]) - - content_blocks = [] - the_rest = None - inner_start_tags = 0 - inner_end_tags = 0 - - # While there is still some work todo - while len(blocks) > 0: - block = blocks.pop(0) - - # Do we have either a start or end tag - inner_tag = self.p_start.search(block) - end_tag = self.p_end.search(block) - - # Keep track of how many inner boxed-text start tags we have seen - if inner_tag: - inner_start_tags += 1 - - # If we have an end tag and all inner boxed-text tags have been closed - ~FIN - if end_tag and inner_start_tags == inner_end_tags: - content_blocks.append(block[:end_tag.start()]) - the_rest = block[end_tag.end():] - break - elif end_tag: - inner_end_tags += 1 - end_tag = None - content_blocks.append(block) - - if the_rest: - blocks.insert(0, the_rest) # Keep anything off the end, should be empty though - - # Error if we reached the end without closing the start tag - # or not all inner boxed-text tags were closed - if end_tag is None or inner_start_tags != inner_end_tags: - raise TagNotMatchedError(self.processor, block, 'no end tag found to close start tag') - - # Parse all the inner content of the boxed-text tags - content_tree = etree.Element('content') - self.parser.parseChunk(content_tree, blocks_to_string(content_blocks)) - - # Convert parsed element tree back into html text for rendering - content = '' - for child in content_tree: - content += etree.tostring(child, encoding="unicode", method="html") + '\n' - - # Collect all information for rendering the html template - context = dict() - context['indented'] = parse_argument('indented', start_tag.group('args'), 'no').lower() == 'yes' - context['text'] = content - - # Render template and compile into an element - html_string = self.template.render(context) - node = etree.fromstring(html_string) - - # Update parent with the boxed-text element - parent.append(node) diff --git a/kordac/processors/ButtonLinkBlockProcessor.py b/kordac/processors/ButtonLinkBlockProcessor.py deleted file mode 100644 index d1944e92..00000000 --- a/kordac/processors/ButtonLinkBlockProcessor.py +++ /dev/null @@ -1,52 +0,0 @@ -from markdown.blockprocessors import BlockProcessor -from kordac.processors.utils import parse_argument, check_argument_requirements -import re -from markdown.util import etree - -class ButtonLinkBlockProcessor(BlockProcessor): - '''Searches blocks provided by markdown and turns button-link tags e.g. {button-link link="www.example.com" text="Lipsum" file="no"} and replaces them with the html template from the html-template directory. - ''' - def __init__(self, ext, *args, **kwargs): - super().__init__(*args, **kwargs) - self.processor = 'button-link' - self.template = ext.jinja_templates[self.processor] - self.relative_file_template = ext.jinja_templates['relative-file-link'] - self.pattern = re.compile(ext.processor_info[self.processor]['pattern']) - self.required_parameters = ext.processor_info[self.processor]['required_parameters'] - self.optional_parameters = ext.processor_info[self.processor]['optional_parameter_dependencies'] - - def test(self, parent, block): - '''Return whether the provided document contains comments needing removal. - - Args: - block: A string to test against. - - Returns: - True if the document needs to be processed. - ''' - return self.pattern.search(block) is not None - - def run(self, parent, blocks): - ''' Inherited from BlockProcessor class from Markdown. - - Args: - parent: Element (from ElementTree library) which this block resides within. The created html-template elements are placed within here. - blocks: Blocks of text where the first block matched via the test method. - ''' - block = blocks.pop(0) - match = self.pattern.search(block) - - arguments = match.group('args') - check_argument_requirements(self.processor, arguments, self.required_parameters, self.optional_parameters) - - context = dict() - context['link'] = parse_argument('link', arguments) - context['text'] = parse_argument('text', arguments) - context['file'] = parse_argument('file', arguments, 'no').lower() == 'yes' - - if context['file']: - context['link'] = self.relative_file_template.render({'file_path': context['link']}) - - html_string = self.template.render(context) - node = etree.fromstring(html_string) - parent.append(node) diff --git a/kordac/processors/CommentPreprocessor.py b/kordac/processors/CommentPreprocessor.py index 5e1c4844..e5981b6e 100644 --- a/kordac/processors/CommentPreprocessor.py +++ b/kordac/processors/CommentPreprocessor.py @@ -2,7 +2,8 @@ import re class CommentPreprocessor(Preprocessor): - '''Searches a Document for comments e.g. {comment example text here} and removes them from the document. + ''' Searches a Document for comments (e.g. {comment example text here}) + and removes them from the document. ''' def __init__(self, ext, *args, **kwargs): @@ -11,7 +12,8 @@ def __init__(self, ext, *args, **kwargs): ext: An instance of the Markdown parser class. ''' super().__init__(*args, **kwargs) - self.pattern = re.compile(ext.processor_info['comment']['pattern']) + self.processor = 'comment' + self.pattern = re.compile(ext.processor_info[self.processor]['pattern']) def test(self, lines): '''Return whether the provided document contains comments needing removal. diff --git a/kordac/processors/ConditionalProcessor.py b/kordac/processors/ConditionalProcessor.py index ebc3a625..9b769521 100644 --- a/kordac/processors/ConditionalProcessor.py +++ b/kordac/processors/ConditionalProcessor.py @@ -1,11 +1,11 @@ -from markdown.blockprocessors import BlockProcessor -from kordac.processors.utils import blocks_to_string, parse_argument, parse_flag, etree, check_argument_requirements +from kordac.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor from kordac.processors.errors.TagNotMatchedError import TagNotMatchedError +from kordac.processors.utils import * from collections import OrderedDict import re -class ConditionalProcessor(BlockProcessor): - ''' Searches a Document for conditional tags e.g. {conditonal flag conditoon=""} +class ConditionalProcessor(GenericContainerBlockProcessor): + ''' Searches a Document for conditional tags e.g. {conditonal flag condition=""} The processor matches the following `elif` and `else` statements in the document and parses them via the provided html template. ''' @@ -14,15 +14,10 @@ def __init__(self, ext, *args, **kwargs): Args: ext: An instance of the KordacExtension. ''' - super().__init__(*args, **kwargs) - self.processor = 'conditional' + super().__init__('conditional', ext, *args, **kwargs) self.pattern = re.compile(ext.processor_info[self.processor]['pattern']) self.p_end = re.compile(ext.processor_info[self.processor]['pattern_end']) - self.template = ext.jinja_templates[self.processor] - self.required_parameters = ext.processor_info[self.processor]['required_parameters'] - self.optional_parameters = ext.processor_info[self.processor]['optional_parameter_dependencies'] - def test(self, parent, block): ''' Tests if the block if it contains any type of conditional types. @@ -35,6 +30,74 @@ def test(self, parent, block): ''' return self.pattern.search(block) is not None or self.p_end.search(block) is not None + def run(self, parent, blocks): + ''' Removes all instances of text that match the following example {comment example text here}. Inherited from Preprocessor class. + + Args: + lines: A list of lines of the Markdown document to be converted. + + Returns: + Markdown document with comments removed. + ''' + block = blocks.pop(0) + context = dict() + + start_tag = self.pattern.search(block) + end_tag = self.p_end.search(block) + + if ((start_tag is None and end_tag is not None) + or (start_tag.end() > end_tag.start())): + raise TagNotMatchedError(self.processor, block, 'end tag found before start tag') + + is_if = parse_flag('if', start_tag.group('args')) + + # elif or else before an if conditional + if not is_if: + is_elif = parse_flag('elif', start_tag.group('args')) + is_else = parse_flag('else', start_tag.group('args')) + msg = '{} conditional found before if'.format('elif' if is_elif else 'else' if is_else else 'unrecognised') + raise TagNotMatchedError(self.processor, block, msg) + + # Put left overs back on blocks, should be empty though + if block[:start_tag.start()].strip() != '': + self.parser.parseChunk(parent, block[:start_tag.start()]) + if block[start_tag.end():].strip() != '': + blocks.insert(0, block[start_tag.end():]) + + # Process if statement + argument_values = parse_arguments(self.processor, start_tag.group('args'), self.arguments) + if_expression = argument_values['condition'] + next_tag, block, content_blocks = self.get_content(blocks) + if_content = self.parse_blocks(content_blocks) + + context['if_expression'] = if_expression + context['if_content'] = if_content + + # Process elif statements + elifs = OrderedDict() + while next_tag is not None and parse_flag('elif', next_tag.group('args')): + argument_values = parse_arguments(self.processor, next_tag.group('args'), self.arguments) + elif_expression = argument_values['condition'] + next_tag, block, content_blocks = self.get_content(blocks) + content = self.parse_blocks(content_blocks) + elifs[elif_expression] = content + context['elifs'] = elifs + + # Process else statement + has_else = next_tag is not None and parse_flag('else', next_tag.group('args')) + else_content = '' + if has_else: + argument_values = parse_arguments(self.processor, next_tag.group('args'), self.arguments) + next_tag, block, content_blocks = self.get_content(blocks) + else_content = self.parse_blocks(content_blocks) + context['has_else'] = has_else + context['else_content'] = else_content + + # Render template and compile into an element + html_string = self.template.render(context) + node = etree.fromstring(html_string) + parent.append(node) + def get_content(self, blocks): ''' Recursively parses blocks into an element tree, returning a string of the output. @@ -76,7 +139,8 @@ def get_content(self, blocks): inner_end_tags += 1 end_tag = None elif is_elif or is_else: - content_blocks.append(block[:next_tag.start()]) + if block[:next_tag.start()].strip() != '': + content_blocks.append(block[:next_tag.start()]) the_rest = block[next_tag.end():] break elif end_tag is not None: @@ -85,13 +149,13 @@ def get_content(self, blocks): break content_blocks.append(block) - if the_rest: + if the_rest.strip() != '': blocks.insert(0, the_rest) # Keep anything off the end, should be empty though if inner_if_tags != inner_end_tags: raise TagNotMatchedError(self.processor, block, 'no end tag found to close start tag') - return next_tag, block, content_blocks[:-1] if content_blocks[-1].strip() == '' else content_blocks + return next_tag, block, content_blocks def parse_blocks(self, blocks): '''Recursively parses blocks into an element tree, returning a string of the output. @@ -111,70 +175,3 @@ def parse_blocks(self, blocks): for child in content_tree: content += etree.tostring(child, encoding="unicode", method="html") return content - - def run(self, parent, blocks): - ''' Removes all instances of text that match the following example {comment example text here}. Inherited from Preprocessor class. - - Args: - lines: A list of lines of the Markdown document to be converted. - - Returns: - Markdown document with comments removed. - ''' - block = blocks.pop(0) - context = dict() - - start_tag = self.pattern.search(block) - end_tag = self.p_end.search(block) - - # Found an end tag without processing a start tag first - if start_tag is None and end_tag is not None: - raise TagNotMatchedError(self.processor, block, 'end tag found before start tag') - - is_if = parse_flag('if', start_tag.group('args')) - - # elif or else before an if conditional - if not is_if: - is_elif = parse_flag('elif', start_tag.group('args')) - is_else = parse_flag('else', start_tag.group('args')) - msg = '{} conditional found before if'.format('elif' if is_elif else 'else' if is_else else 'unrecognised') - raise TagNotMatchedError(self.processor, block, msg) - - # Put left overs back on blocks, should be empty though - blocks.insert(0, block[start_tag.end():]) - - # Process if statement - check_argument_requirements(self.processor, start_tag.group('args'), self.required_parameters, self.optional_parameters) - if_expression = parse_argument('condition', start_tag.group('args')) - next_tag, block, content_blocks = self.get_content(blocks) - if_content = self.parse_blocks(content_blocks) - - context['if_expression'] = if_expression - context['if_content'] = if_content - - # Process elif statements - elifs = OrderedDict() - while next_tag is not None and parse_flag('elif', next_tag.group('args')): - check_argument_requirements(self.processor, next_tag.group('args'), self.required_parameters, self.optional_parameters) - elif_expression = parse_argument('condition', next_tag.group('args')) - blocks.insert(0, block[next_tag.end():]) - next_tag, block, content_blocks = self.get_content(blocks) - content = self.parse_blocks(content_blocks) - elifs[elif_expression] = content - context['elifs'] = elifs - - # Process else statement - has_else = next_tag is not None and parse_flag('else', next_tag.group('args')) - else_content = '' - if has_else: - check_argument_requirements(self.processor, next_tag.group('args'), self.required_parameters, self.optional_parameters) - blocks.insert(0, block[next_tag.end():]) - next_tag, block, content_blocks = self.get_content(blocks) - else_content = self.parse_blocks(content_blocks) - context['has_else'] = has_else - context['else_content'] = else_content - - # Render template and compile into an element - html_string = self.template.render(context) - node = etree.fromstring(html_string) - parent.append(node) diff --git a/kordac/processors/FrameBlockProcessor.py b/kordac/processors/FrameBlockProcessor.py deleted file mode 100644 index a4f3acfa..00000000 --- a/kordac/processors/FrameBlockProcessor.py +++ /dev/null @@ -1,52 +0,0 @@ -from markdown.blockprocessors import BlockProcessor -from kordac.processors.utils import blocks_to_string, parse_argument, etree, check_argument_requirements -import re - -class FrameBlockProcessor(BlockProcessor): - def __init__(self, ext, *args, **kwargs): - ''' - Args: - ext: An instance of the Kordac Extension. - ''' - super().__init__(*args, **kwargs) - self.processor = 'iframe' - self.pattern = re.compile(ext.processor_info[self.processor]['pattern']) - self.template = ext.jinja_templates[self.processor] - self.required_parameters = ext.processor_info[self.processor]['required_parameters'] - self.optional_parameters = ext.processor_info[self.processor]['optional_parameter_dependencies'] - - def test(self, parent, block): - ''' Tests a block to see if the run method should be applied. - - Args: - parent: The parent node of the element tree that children - will reside in. - block: The block to be tested. - - Returns: - True if the block matches the pattern regex of a HeadingBlock. - ''' - return self.pattern.search(block) is not None - - def run(self, parent, blocks): - ''' Processes the block matching the heading and adding to the - html tree and the kordac heading tree. - - Args: - parent: The parent node of the element tree that children - will reside in. - blocks: A list of strings of the document, where the - first block tests true. - ''' - block = blocks.pop(0) - - match = self.pattern.search(block) - - check_argument_requirements(self.processor, match.group('args'), self.required_parameters, self.optional_parameters) - - context = dict() - context['link'] = parse_argument('link', match.group('args')) - - html_string = self.template.render(context) - node = etree.fromstring(html_string) - parent.append(node) diff --git a/kordac/processors/GenericContainerBlockProcessor.py b/kordac/processors/GenericContainerBlockProcessor.py index 58f154d7..06eb953c 100644 --- a/kordac/processors/GenericContainerBlockProcessor.py +++ b/kordac/processors/GenericContainerBlockProcessor.py @@ -15,7 +15,7 @@ def __init__(self, processor, ext, *args, **kwargs): self.arguments = ext.processor_info[self.processor]['arguments'] template_name = self.processor.get('template_name', self.processor) self.template = ext.jinja_templates[ext.processor_info[template_name] - self.template_parameters = ext.processor_info[self.processor]['template_parameters'] + self.template_parameters = ext.processor_info[self.processor].get('template_parameters', None) def test(self, parent, block): ''' Tests a block to see if the run method should be applied. diff --git a/kordac/processors/GenericTagBlockProcessor.py b/kordac/processors/GenericTagBlockProcessor.py index 1c85c656..66de5448 100644 --- a/kordac/processors/GenericTagBlockProcessor.py +++ b/kordac/processors/GenericTagBlockProcessor.py @@ -14,7 +14,7 @@ def __init__(self, processor, ext, *args, **kwargs): self.arguments = ext.processor_info[self.processor]['arguments'] template_name = self.processor.get('template_name', self.processor) self.template = ext.jinja_templates[ext.processor_info[template_name] - self.template_parameters = ext.processor_info[self.processor]['template_parameters'] + self.template_parameters = ext.processor_info[self.processor].get('template_parameters', None) def test(self, parent, block): ''' Tests a block to see if the run method should be applied. diff --git a/kordac/processors/GlossaryLinkPattern.py b/kordac/processors/GlossaryLinkPattern.py index ead1cc35..c5dc8746 100644 --- a/kordac/processors/GlossaryLinkPattern.py +++ b/kordac/processors/GlossaryLinkPattern.py @@ -1,11 +1,11 @@ -from kordac.processors.utils import check_argument_requirements, parse_argument +from markdown.inlinepatterns import Pattern +from kordac.processors.utils import * from markdown.util import etree -import markdown.inlinepatterns import re -class GlossaryLinkPattern(markdown.inlinepatterns.Pattern): - """Return a glossary link element from the given match +class GlossaryLinkPattern(Pattern): + '''Return a glossary link element from the given match Matches: {glossary-link term="super-serious-term"}Super Serious Term{glossary-link end} @@ -15,32 +15,38 @@ class GlossaryLinkPattern(markdown.inlinepatterns.Pattern): Super Serious Term

    - """ + ''' def __init__(self, ext, *args, **kwargs): super().__init__(*args, **kwargs) self.ext = ext self.processor = 'glossary-link' self.pattern = self.ext.processor_info['glossary-link']['pattern'] - self.compiled_re = re.compile('^(.*?){}(.*)$'.format(self.pattern), re.DOTALL | re.UNICODE) # TODO raw string prefix - self.template = self.ext.jinja_templates[self.processor] - self.required_parameters = self.ext.processor_info[self.processor]['required_parameters'] - self.optional_parameters = self.ext.processor_info[self.processor]['optional_parameter_dependencies'] - self.ext_glossary_terms = ext.glossary_terms - self.unique_slugify = ext.custom_slugify + self.compiled_re = re.compile(r'^(.*?){}(.*)$'.format(self.pattern), re.DOTALL | re.UNICODE) + self.arguments = ext.processor_info[self.processor]['arguments'] + template_name = self.processor.get('template_name', self.processor) + self.template = ext.jinja_templates[ext.processor_info[template_name] def handleMatch(self, match): - + ''' + Turns a match into a glossary-link and adds the slug and + identifier to the extension as part of the final result. + Args: + match: The string of text where the match was found. + Returns: + An element tree node to be appended to the html tree. + ''' text = match.group('text') arguments = match.group('args') - check_argument_requirements(self.processor, arguments, self.required_parameters, self.optional_parameters) + argument_values = parse_arguments(self.processor, arguments, self.arguments) - term = parse_argument('term', arguments) - reference = parse_argument('reference-text', arguments) + term = arugment_values['term'] + reference = arugment_values['reference-text'] - context = dict() - context['term'] = term - context['text'] = text + context = { + 'term': term, + 'text': text + } if reference is not None: identifier = self.unique_slugify('glossary-' + term) diff --git a/kordac/processors/HeadingBlockProcessor.py b/kordac/processors/HeadingBlockProcessor.py index ecea8145..fbeab543 100644 --- a/kordac/processors/HeadingBlockProcessor.py +++ b/kordac/processors/HeadingBlockProcessor.py @@ -12,8 +12,7 @@ class HeadingBlockProcessor(BlockProcessor): def __init__(self, ext, *args, **kwargs): ''' Args: - ext: The parent node of the element tree that children will - reside in. + ext: The KordacExtension object. args: Arguments handed to the super class. kwargs: Arguments handed to the super class. ''' diff --git a/kordac/processors/ImageBlockProcessor.py b/kordac/processors/ImageBlockProcessor.py index 6461e518..b0101685 100644 --- a/kordac/processors/ImageBlockProcessor.py +++ b/kordac/processors/ImageBlockProcessor.py @@ -1,35 +1,65 @@ -from markdown.blockprocessors import BlockProcessor -import re -from kordac.processors.utils import parse_argument, centre_html +from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor +from kordac.processors.utils import * from markdown.util import etree -from kordac.processors.utils import check_argument_requirements import jinja2 +import re -# NTS needs to include alt tags -class ImageBlockProcessor(BlockProcessor): +class ImageBlockProcessor(GenericTagBlockProcessor): + ''' Searches a Document for image tags e.g. {image file-path=""} + adding any internal images to the kordac extension final result. + ''' def __init__(self, ext, *args, **kwargs): - super().__init__(*args, **kwargs) - self.processor = 'image' + ''' + Args: + ext: The parent node of the element tree that children will + reside in. + args: Arguments handed to the super class. + kwargs: Arguments handed to the super class. + ''' + super().__init__('image', ext, *args, **kwargs) self.pattern = re.compile(ext.processor_info[self.processor]['pattern']) - self.template = ext.jinja_templates[self.processor] self.relative_image_template = ext.jinja_templates['relative-file-link'] self.required = ext.required_files['images'] - self.required_parameters = ext.processor_info[self.processor]['required_parameters'] - self.optional_parameters = ext.processor_info[self.processor]['optional_parameter_dependencies'] def test(self, parent, block): + ''' Tests a block to see if the run method should be applied. + + Args: + parent: The parent node of the element tree that children + will reside in. + block: The block to be tested. + Returns: + True if the block matches the pattern regex of a HeadingBlock. + ''' return self.pattern.search(block) is not None def run(self, parent, blocks): + ''' Processes the block matching the image pattern, adding + any internal images to the KordacExtension result. + + Args: + parent: The parent node of the element tree that children + will reside in. + blocks: A list of strings of the document, where the + first block tests true. + ''' block = blocks.pop(0) + match = self.pattern.match(block) + before = block[:match.start()] + after = block[match.end():] + + if before.strip() != '': + self.parser.parseChunk(parent, before) + if after.strip() != '': + blocks.insert(0, after) arguments = match.group('args') - check_argument_requirements(self.processor, arguments, self.required_parameters, self.optional_parameters) + argument_values = parse_arguments(self.processor, arguments, self.arguments) # check if internal or external image - file_path = parse_argument('file-path', arguments) + file_path = argument_values['file-path'] external_path_match = re.search(r'^http', file_path) if external_path_match is None: # internal image self.required.add(file_path) @@ -37,13 +67,13 @@ def run(self, parent, blocks): context = dict() context['file_path'] = file_path - context['alt'] = parse_argument('alt', arguments) - context['title'] = parse_argument('title', arguments) - context['caption'] = parse_argument('caption', arguments) - context['caption_link'] = parse_argument('caption-link', arguments) - context['source_link'] = parse_argument('source', arguments) - context['alignment'] = parse_argument('alignment', arguments) - context['hover_text'] = parse_argument('hover-text', arguments) + context['alt'] = argument_values['alt'] + context['title'] = argument_values['title'] + context['caption'] = argument_values['caption'] + context['caption_link'] = argument_values['caption-link'] + context['source_link'] = argument_values['source'] + context['alignment'] = argument_values['alignment'] + context['hover_text'] = argument_values['hover-text'] html_string = self.template.render(context) node = etree.fromstring(html_string) diff --git a/kordac/processors/InteractiveBlockProcessor.py b/kordac/processors/InteractiveBlockProcessor.py index 0e71019c..213e1972 100644 --- a/kordac/processors/InteractiveBlockProcessor.py +++ b/kordac/processors/InteractiveBlockProcessor.py @@ -1,14 +1,12 @@ -from markdown.blockprocessors import BlockProcessor -from markdown.postprocessors import Postprocessor -from markdown.treeprocessors import Treeprocessor -from kordac.processors.utils import parse_argument, check_argument_requirements +from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor from kordac.processors.errors.InvalidParameterError import InvalidParameterError +from kordac.processors.utils import * from markdown.util import etree import re import os -class InteractiveBlockProcessor(BlockProcessor): +class InteractiveBlockProcessor(GenericTagBlockProcessor): '''Searches a Document for interactive tags: e.g. {interactive name='example' type='in-page'} These are then replaced with the html template. @@ -19,15 +17,11 @@ def __init__(self, ext, *args, **kwargs): Args: ext: An instance of the Kordac Extension. ''' - super().__init__(*args, **kwargs) - self.processor = 'interactive' + super().__init__('interactive', ext, *args, **kwargs) self.pattern = re.compile(ext.processor_info[self.processor]['pattern']) - self.template = ext.jinja_templates[self.processor] self.relative_file_template = ext.jinja_templates['relative-file-link'] self.scripts = ext.required_files["page_scripts"] self.required = ext.required_files["interactives"] - self.required_parameters = ext.processor_info[self.processor]['required_parameters'] - self.optional_parameters = ext.processor_info[self.processor]['optional_parameter_dependencies'] def test(self, parent, block): ''' Tests a block to see if the run method should be applied. @@ -53,15 +47,23 @@ def run(self, parent, blocks): first block tests true. ''' block = blocks.pop(0) + match = self.pattern.match(block) + before = block[:match.start()] + after = block[match.end():] + + if before.strip() != '': + self.parser.parseChunk(parent, before) + if after.strip() != '': + blocks.insert(0, after) arguments = match.group('args') - check_argument_requirements(self.processor, arguments, self.required_parameters, self.optional_parameters) + argument_values = parse_arguments(self.processor, arguments, self.arguments) - name = parse_argument('name', arguments) - interactive_type = parse_argument('type', arguments) - text = parse_argument('text', arguments) - parameters = parse_argument('parameters', arguments) + name = argument_values['name'] + interactive_type = argument_values['type'] + text = argument_values['text'] + parameters = argument_values['parameters'] if name is not None and name is '': raise InvalidParameterError(self.processor, "name", "Name parameter must not be an empty string.") diff --git a/kordac/processors/JinjaPostprocessor.py b/kordac/processors/JinjaPostprocessor.py index 2c4853bb..2901ddcd 100644 --- a/kordac/processors/JinjaPostprocessor.py +++ b/kordac/processors/JinjaPostprocessor.py @@ -3,10 +3,20 @@ import re class JinjaPostprocessor(Postprocessor): + ''' Checks all jinja blocks in the output and ensures that they + are not escaped like other html blocks. + ''' + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def run(self, text): + ''' + Args: + text: A string of the document. + Returns: + The document text with all Jinja blocks unescaped. + ''' r = re.compile(r'{% ([^}])*}(?<= %})') out = '' diff --git a/kordac/processors/PanelBlockProcessor.py b/kordac/processors/PanelBlockProcessor.py deleted file mode 100644 index f439c4e7..00000000 --- a/kordac/processors/PanelBlockProcessor.py +++ /dev/null @@ -1,97 +0,0 @@ -from markdown.blockprocessors import BlockProcessor -from markdown.util import etree -from kordac.processors.errors.TagNotMatchedError import TagNotMatchedError -from kordac.processors.utils import blocks_to_string, parse_argument, check_argument_requirements -import re - - -class PanelBlockProcessor(BlockProcessor): - def __init__(self, ext, *args, **kwargs): - super().__init__(*args, **kwargs) - self.processor = 'panel' - self.p_start = re.compile(ext.processor_info[self.processor]['pattern_start']) - self.p_end = re.compile(ext.processor_info[self.processor]['pattern_end']) - self.template = ext.jinja_templates[self.processor] - self.required_parameters = ext.processor_info[self.processor]['required_parameters'] - self.optional_parameters = ext.processor_info[self.processor]['optional_parameter_dependencies'] - - def test(self, parent, block): - return self.p_start.search(block) is not None or self.p_end.search(block) is not None - - def run(self, parent, blocks): - block = blocks.pop(0) - - # find start of match and place back in blocks list up to end of match - start_tag = self.p_start.search(block) - end_tag = self.p_end.search(block) - - if start_tag is None and end_tag is not None: - raise TagNotMatchedError(self.processor, block, 'end tag found before start tag') - - check_argument_requirements(self.processor, start_tag.group('args'), self.required_parameters, self.optional_parameters) - - blocks.insert(0, block[start_tag.end():]) - - # iterate over blocks until find {panel end} block - content_blocks = [] - the_rest = None - inner_start_tags = 0 - inner_end_tags = 0 - - while len(blocks) > 0: - block = blocks.pop(0) - - # Do we have either a start or end tag print("Here") - inner_tag = self.p_start.search(block) - end_tag = self.p_end.search(block) - - # Keep track of how many inner boxed-text start tags we have seen - if inner_tag: - inner_start_tags += 1 - - # If we have an end tag and all inner boxed-text tags have been closed - ~FIN - if end_tag and inner_start_tags == inner_end_tags: - content_blocks.append(block[:end_tag.start()]) - the_rest = block[end_tag.end():] - break - elif end_tag: - inner_end_tags += 1 - end_tag = None - content_blocks.append(block) - - if the_rest: - blocks.insert(0, the_rest) # Keep anything off the end, should be empty though - - # Error if we reached the end without closing the start tag - # or not all inner boxed-text tags were closed - if end_tag is None or inner_start_tags != inner_end_tags: - raise TagNotMatchedError(self.processor, block, 'no end tag found to close start tag') - - # Parse all the inner content of the boxed-text tags - content_tree = etree.Element('content') - self.parser.parseChunk(content_tree, blocks_to_string(content_blocks)) - - # Convert parsed element tree back into html text for rendering - content = '' - for child in content_tree: - content += etree.tostring(child, encoding="unicode", method="html") + '\n' - - context = self.get_attributes(start_tag.group('args')) - context['content'] = content - - # create panel node and add it to parent element - html_string = self.template.render(context) - node = etree.fromstring(html_string) - parent.append(node) - - def get_attributes(self, args): - panel_type = parse_argument('type', args) - title = parse_argument('title', args) - subtitle = parse_argument('subtitle', args) - expanded = parse_argument('expanded', args, default='no') - return { - 'type': panel_type, - 'title': title, - 'subtitle': subtitle, - 'expanded': expanded - } diff --git a/kordac/processors/RelativeLinkPattern.py b/kordac/processors/RelativeLinkPattern.py index 5cc4f7f9..f3386fe7 100644 --- a/kordac/processors/RelativeLinkPattern.py +++ b/kordac/processors/RelativeLinkPattern.py @@ -1,9 +1,8 @@ +from markdown.inlinepatterns import Pattern from markdown.util import etree -import markdown.util as util -import markdown.inlinepatterns import re -class RelativeLinkPattern(markdown.inlinepatterns.Pattern): +class RelativeLinkPattern(Pattern): """Return a link element from the given match. Only matches: @@ -24,7 +23,12 @@ def __init__(self, ext, *args, **kwargs): self.template = ext.jinja_templates[self.processor] def handleMatch(self, match): - + ''' + 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'] = match.group('link_url') context['text'] = match.group('link_text') diff --git a/kordac/processors/RemovePostprocessor.py b/kordac/processors/RemovePostprocessor.py index 960c8827..a2554ee0 100644 --- a/kordac/processors/RemovePostprocessor.py +++ b/kordac/processors/RemovePostprocessor.py @@ -1,8 +1,19 @@ from markdown.postprocessors import Postprocessor class RemovePostprocessor(Postprocessor): + ''' Parses the output document and removes all remove html tags + (i.e. or ) keeping the body of said tags. This + allows for the returning of illegal html for further processing. + ''' + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def run(self, text): + ''' + Args: + text: A string of the document. + Returns: + The document text with all remove tag removed. + ''' return text.replace('', '').replace('', '') diff --git a/kordac/processors/RemoveTitlePreprocessor.py b/kordac/processors/RemoveTitlePreprocessor.py index d71f69ee..1a385c4c 100644 --- a/kordac/processors/RemoveTitlePreprocessor.py +++ b/kordac/processors/RemoveTitlePreprocessor.py @@ -4,15 +4,33 @@ class RemoveTitlePreprocessor(Preprocessor): def __init__(self, ext, *args, **kwargs): + ''' + Args: + ext: An instance of the KordacExtension. + ''' super().__init__(*args, **kwargs) self.ext = ext self.pattern = re.compile(ext.processor_info['title']['pattern']) def test(self, lines): + ''' Tests the given document to check if the processor should be + run. + + Args: + lines: A string of the document text. + Result: + True if a match is found. + ''' return self.pattern.search(lines) is not None def run(self, lines): - '''If the title is found on a line, remove the line.''' + ''' If the title is found on a line, remove the line. + + Args: + lines: A list of strings that form the document. + Returns: + The document with the first title removed. + ''' title_found = False for i, line in enumerate(lines): if not title_found and self.pattern.search(line) is not None: diff --git a/kordac/processors/SaveTitlePreprocessor.py b/kordac/processors/SaveTitlePreprocessor.py index 2462ed24..9e6bda8c 100644 --- a/kordac/processors/SaveTitlePreprocessor.py +++ b/kordac/processors/SaveTitlePreprocessor.py @@ -2,16 +2,39 @@ import re class SaveTitlePreprocessor(Preprocessor): + ''' Saves the first title found in the document to + the KordacExtension as part of the final result. + ''' def __init__(self, ext, *args, **kwargs): + ''' + Args: + ext: An instance of the KordacExtension. + ''' super().__init__(*args, **kwargs) self.ext = ext self.pattern = re.compile(ext.processor_info['title']['pattern']) def test(self, lines): + ''' Tests the given document to check if the processor should be + run. + + Args: + lines: A string of the document text. + Result: + True if a match is found. + ''' return self.pattern.search(lines) is not None def run(self, lines): + ''' Finds the first title and saves it to the + KordacExtension for the final result. + + Args: + lines: A list of strings that form the document. + Returns: + The original document. + ''' for line in lines: match = self.pattern.search(line) if match is not None: diff --git a/kordac/processors/ScratchTreeprocessor.py b/kordac/processors/ScratchTreeprocessor.py index 0057ea90..245a8aed 100644 --- a/kordac/processors/ScratchTreeprocessor.py +++ b/kordac/processors/ScratchTreeprocessor.py @@ -1,5 +1,5 @@ from markdown.treeprocessors import Treeprocessor -from kordac.processors.utils import blocks_to_string, parse_argument, etree +from kordac.processors.utils import etree from kordac.processors.errors.TagNotMatchedError import TagNotMatchedError from collections import namedtuple from hashlib import sha256 diff --git a/kordac/processors/TableOfContentsBlockProcessor.py b/kordac/processors/TableOfContentsBlockProcessor.py deleted file mode 100644 index deb859d7..00000000 --- a/kordac/processors/TableOfContentsBlockProcessor.py +++ /dev/null @@ -1,47 +0,0 @@ -from markdown.blockprocessors import BlockProcessor -from markdown.util import etree -import re - -class TableOfContentsBlockProcessor(BlockProcessor): - def __init__(self, ext, *args, **kwargs): - ''' - Args: - ext: The parent node of the element tree that children will - reside in. - args: Arguments handed to the super class. - kwargs: Arguments handed to the super class. - ''' - super().__init__(*args, **kwargs) - self.processor = 'table-of-contents' - self.pattern = re.compile(ext.processor_info[self.processor]['pattern']) - self.template = ext.jinja_templates[self.processor] - - def test(self, parent, block): - ''' Tests a block to see if the run method should be applied. - - Args: - parent: The parent node of the element tree that children - will reside in. - block: The block to be tested. - - Returns: - True if the block matches the pattern regex of a HeadingBlock. - ''' - return self.pattern.search(block) is not None - - def run(self, parent, blocks): - ''' Processes the block matching the heading and adding to the - html tree and the kordac heading tree. - - Args: - parent: The parent node of the element tree that children - will reside in. - blocks: A list of strings of the document, where the - first block tests true. - ''' - block = blocks.pop(0) - match = self.pattern.search(block) - - html_string = self.template.render(dict()) - node = etree.fromstring(html_string) - parent.append(node) diff --git a/kordac/processors/VideoBlockProcessor.py b/kordac/processors/VideoBlockProcessor.py index 04727204..03ae2411 100644 --- a/kordac/processors/VideoBlockProcessor.py +++ b/kordac/processors/VideoBlockProcessor.py @@ -1,32 +1,32 @@ -from markdown.blockprocessors import BlockProcessor -from markdown.util import etree +from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor from kordac.processors.errors.NoSourceLinkError import NoSourceLinkError from kordac.processors.errors.NoVideoIdentifierError import NoVideoIdentifierError from kordac.processors.errors.UnsupportedVideoPlayerError import UnsupportedVideoPlayerError -from kordac.processors.utils import parse_argument, check_argument_requirements +from kordac.processors.utils import * import re -class VideoBlockProcessor(BlockProcessor): - '''Searches blocks of markdown text and turns video tags into embeded players +class VideoBlockProcessor(GenericTagBlockProcessor): + ''' Searches blocks of markdown text and turns video tags into + embeded players. ''' def __init__(self, ext, *args, **kwargs): - super().__init__(*args, **kwargs) - self.processor = 'video' + ''' + Args: + ext: An instance of the Kordac Extension. + ''' + super().__init__('video', ext, *args, **kwargs) self.pattern = re.compile(ext.processor_info[self.processor]['pattern']) self.youtube_template = ext.jinja_templates['video-youtube'] self.vimeo_template = ext.jinja_templates['video-vimeo'] - self.template = ext.jinja_templates[self.processor] - self.required_parameters = ext.processor_info[self.processor]['required_parameters'] - self.optional_parameters = ext.processor_info[self.processor]['optional_parameter_dependencies'] + def test(self, parent, block): - '''Return whether block contains a video tag + ''' Return whether block contains a video tag. Args: parent: Element which this block is in. block: A string of markdown text - Returns: True if a video tag is found ''' @@ -37,20 +37,25 @@ def run(self, parent, blocks): Args: parent: Element which this block is in. - block: A string of markdown text to be converted - - Returns: - html string with embedded videos + block: A string of markdown text to be converted. ''' block = blocks.pop(0) + match = self.pattern.search(block) + before = block[:match.start()] + after = block[match.end():] + + if before.strip() != '': + self.parser.parseChunk(parent, before) + if after.strip() != '': + blocks.insert(0, after) arguments = match.group('args') - check_argument_requirements(self.processor, arguments, self.required_parameters, self.optional_parameters) - url = parse_argument('url', arguments) + argument_values = parse_arguments(self.processor, arguments, self.arguments) + url = argument_values['url'] - (video_type, identifier) = self.extract_video_identifier(url, match) + (video_type, identifier) = self.extract_video_identifier(url) if not video_type: raise UnsupportedVideoPlayerError(block, url, 'unsupported video player') @@ -72,9 +77,13 @@ def run(self, parent, blocks): node = etree.fromstring(html_string) parent.append(node) - - def extract_video_identifier(self, video_url, match): - '''Returns the indentifier from a given URL''' + def extract_video_identifier(self, video_url): + '''Extracts an identifier and service from a video url. + Args: + video_url: The input url. + Returns: + 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 video_url = re.sub(r'(.*?)(\?rel=0)', r'\g<1>', video_url) diff --git a/kordac/processors/utils.py b/kordac/processors/utils.py index a932e0c3..e1b0f631 100644 --- a/kordac/processors/utils.py +++ b/kordac/processors/utils.py @@ -4,8 +4,15 @@ from kordac.processors.errors.ArgumentMissingError import ArgumentMissingError def parse_argument(argument_key, arguments, default=None): - """Search for the given argument in a string of all arguments - Returns: Value of an argument as a string if found, otherwise None""" + ''' Search for the given argument in a string of all arguments + + Args: + argument_key: The name of the argument. + arguments: A string of the argument inputs. + default: The default value if not found. + Returns: + Value of an argument as a string if found, otherwise None. + ''' result = re.search(r'(^|\s+){}="([^"]*("(?<=\\")[^"]*)*)"'.format(argument_key), arguments) if result: argument_value = result.group(2) @@ -14,8 +21,16 @@ def parse_argument(argument_key, arguments, default=None): return argument_value def parse_flag(argument_key, arguments, default=False): - """Search for the given argument in a string of all arguments - Returns: Value of an argument as a string if found, otherwise None""" + ''' Search for the given argument in a string of all arguments, + treating the argument as a flag only. + + Args: + argument_key: The name of the argument. + arguments: A string of the argument inputs. + default: The default value if not found. + Returns: + Value of an argument as a string if found, otherwise None. + ''' result = re.search(r'(^|\s+){}($|\s)'.format(argument_key), arguments) if result: argument_value = True @@ -24,9 +39,18 @@ def parse_flag(argument_key, arguments, default=False): return argument_value def parse_arguments(processor, inputs, arguments): - ''' - Returns a dictionary of argument to value. - Raises an error if the arguments are missing any required parameters or a parameter an optional parameter is dependent on. + ''' Parses the arguments of a given input and ensures + they meet the defined requirements. + + Args: + processor: The processor of the given arguments. + inputs: A string of the arguments from user input. + arguments: A dictionary of argument descriptions. + Returns: + A dictionary of arguments to values. + Raises: + ArgumentMissingError: If any required arguments are missing or + an argument an optional argument is dependent on is missing. ''' argument_values = dict() for argument, argument_info in arguments.items(): @@ -52,7 +76,14 @@ def parse_arguments(processor, inputs, arguments): def process_parameters(processor, parameters, argument_values): ''' - Returns a dictionary of parameter to value. + Processes a given set of arguments by the parameter definitions. + + Args: + processor: The processor of the given arguments. + parameters: A dictionary of parameter definitions. + argument_values: A dictionary of argument to values. + Returns: + A dictionary of parameter to converted values. ''' context = dict() transformations = OrderedDict() @@ -81,21 +112,27 @@ def process_parameters(processor, parameters, argument_values): def find_transformation(option): ''' Returns a transformation for a given string. - In future should be able to combine piped transformations into a single - function. + TODO: + In future should be able to combine piped transformations + into a single function. + + Args: + option: The desired transformations. + Returns: + A function of the transformation. ''' return { 'str.lower': lambda x: x.lower(), 'str.upper': lambda x: x.upper(), + 'relative_file_link': lambda x: self.relative_file_template.render({'file_path': x}) }.get(option, None) def blocks_to_string(blocks): - """Returns a string after the blocks have been joined back together.""" - return '\n\n'.join(blocks).rstrip('\n') + ''' Returns a string after the blocks have been joined back together. -def centre_html(node, width): - """Wraps the given node with HTML to centre using the given number of columns""" - offset_width = (12 - width) // 2 - root = etree.fromstring(CENTERED_HTML.format(width=width, offset_width=offset_width)) - root.find(".//div[@content]").append(node) - return root + Args: + blocks: A list of strings of the document blocks. + Returns: + A string of the document. + ''' + return '\n\n'.join(blocks).rstrip('\n') From 905196d0f9d88c7baad13f7ae94e5dc8377adc46 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Mon, 13 Mar 2017 16:12:48 +1300 Subject: [PATCH 32/86] Fix accidental paste. --- kordac/processors/GenericContainerBlockProcessor.py | 2 +- kordac/processors/GenericTagBlockProcessor.py | 2 +- kordac/processors/GlossaryLinkPattern.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kordac/processors/GenericContainerBlockProcessor.py b/kordac/processors/GenericContainerBlockProcessor.py index 06eb953c..6ea14396 100644 --- a/kordac/processors/GenericContainerBlockProcessor.py +++ b/kordac/processors/GenericContainerBlockProcessor.py @@ -14,7 +14,7 @@ def __init__(self, processor, ext, *args, **kwargs): self.p_end = re.compile(r'(^|\n) *\{{{0} end\}} *(\n|$)').format(self.processor) self.arguments = ext.processor_info[self.processor]['arguments'] template_name = self.processor.get('template_name', self.processor) - self.template = ext.jinja_templates[ext.processor_info[template_name] + self.template = ext.jinja_templates[template_name] self.template_parameters = ext.processor_info[self.processor].get('template_parameters', None) def test(self, parent, block): diff --git a/kordac/processors/GenericTagBlockProcessor.py b/kordac/processors/GenericTagBlockProcessor.py index 66de5448..37b43daa 100644 --- a/kordac/processors/GenericTagBlockProcessor.py +++ b/kordac/processors/GenericTagBlockProcessor.py @@ -13,7 +13,7 @@ def __init__(self, processor, ext, *args, **kwargs): self.pattern = re.compile(r'(^|\n) *\{{{0} ?(?P[^\}}]*)\}} *(\n|$)').format(self.processor) self.arguments = ext.processor_info[self.processor]['arguments'] template_name = self.processor.get('template_name', self.processor) - self.template = ext.jinja_templates[ext.processor_info[template_name] + self.template = ext.jinja_templates[template_name] self.template_parameters = ext.processor_info[self.processor].get('template_parameters', None) def test(self, parent, block): diff --git a/kordac/processors/GlossaryLinkPattern.py b/kordac/processors/GlossaryLinkPattern.py index c5dc8746..ec14065e 100644 --- a/kordac/processors/GlossaryLinkPattern.py +++ b/kordac/processors/GlossaryLinkPattern.py @@ -25,7 +25,7 @@ def __init__(self, ext, *args, **kwargs): self.compiled_re = re.compile(r'^(.*?){}(.*)$'.format(self.pattern), re.DOTALL | re.UNICODE) self.arguments = ext.processor_info[self.processor]['arguments'] template_name = self.processor.get('template_name', self.processor) - self.template = ext.jinja_templates[ext.processor_info[template_name] + self.template = ext.jinja_templates[template_name] def handleMatch(self, match): ''' From 9324ca16ba4869dc6937c67a7705a1c136362256 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Mon, 13 Mar 2017 17:22:47 +1300 Subject: [PATCH 33/86] End of day, working on fixing test suite. --- kordac/KordacExtension.py | 60 +++++++++---------- kordac/processor-info.json | 3 +- kordac/processors/ConditionalProcessor.py | 10 ++-- .../GenericContainerBlockProcessor.py | 12 ++-- kordac/processors/GenericTagBlockProcessor.py | 4 +- kordac/processors/GlossaryLinkPattern.py | 9 ++- kordac/processors/ImageBlockProcessor.py | 14 ++--- .../processors/InteractiveBlockProcessor.py | 7 +-- kordac/processors/utils.py | 14 ++--- kordac/tests/BoxedTextTest.py | 17 +++--- kordac/tests/ButtonLinkTest.py | 21 +++---- kordac/tests/FrameTest.py | 16 ++--- kordac/tests/PanelTest.py | 27 +++++---- kordac/tests/TableOfContentsTest.py | 7 ++- 14 files changed, 109 insertions(+), 112 deletions(-) diff --git a/kordac/KordacExtension.py b/kordac/KordacExtension.py index 6b6b6c57..fb0c23ba 100644 --- a/kordac/KordacExtension.py +++ b/kordac/KordacExtension.py @@ -31,30 +31,6 @@ from jinja2 import Environment, PackageLoader, select_autoescape class KordacExtension(Extension): - PREPROCESSORS = [ - ['comment', CommentPreprocessor(self, md), '_begin'], - ['save-title', SaveTitlePreprocessor(self, md), '_end'], - ['remove-title', RemoveTitlePreprocessor(self, md), '_end'], - ] - BLOCKPROCESSORS = [ - # Markdown overrides - ['heading', HeadingBlockProcessor(self, md.parser), 'inline' if 'hilite' not in self.compatibility else 'inline' if 'hilite' not in self.compatibility else '[^\\}]*)\\} *(\\n|$)", "arguments": { "name": { "required": true, @@ -234,6 +233,6 @@ "url": { "required": true } - }, + } } } diff --git a/kordac/processors/ConditionalProcessor.py b/kordac/processors/ConditionalProcessor.py index 9b769521..711c209c 100644 --- a/kordac/processors/ConditionalProcessor.py +++ b/kordac/processors/ConditionalProcessor.py @@ -15,8 +15,6 @@ def __init__(self, ext, *args, **kwargs): ext: An instance of the KordacExtension. ''' super().__init__('conditional', ext, *args, **kwargs) - self.pattern = re.compile(ext.processor_info[self.processor]['pattern']) - self.p_end = re.compile(ext.processor_info[self.processor]['pattern_end']) def test(self, parent, block): ''' Tests if the block if it contains any type of conditional types. @@ -28,7 +26,7 @@ def test(self, parent, block): Returns: Return true if any conditional tag is found. ''' - return self.pattern.search(block) is not None or self.p_end.search(block) is not None + return self.p_start.search(block) is not None or self.p_end.search(block) is not None def run(self, parent, blocks): ''' Removes all instances of text that match the following example {comment example text here}. Inherited from Preprocessor class. @@ -42,11 +40,11 @@ def run(self, parent, blocks): block = blocks.pop(0) context = dict() - start_tag = self.pattern.search(block) + start_tag = self.p_start.search(block) end_tag = self.p_end.search(block) if ((start_tag is None and end_tag is not None) - or (start_tag.end() > end_tag.start())): + or (start_tag and end_tag and start_tag.end() > end_tag.start())): raise TagNotMatchedError(self.processor, block, 'end tag found before start tag') is_if = parse_flag('if', start_tag.group('args')) @@ -123,7 +121,7 @@ def get_content(self, blocks): block = blocks.pop(0) # Do we have either a start or end tag - next_tag = self.pattern.search(block) + next_tag = self.p_start.search(block) end_tag = self.p_end.search(block) is_if = next_tag is not None and parse_flag('if', next_tag.group('args')) diff --git a/kordac/processors/GenericContainerBlockProcessor.py b/kordac/processors/GenericContainerBlockProcessor.py index 6ea14396..0258cd45 100644 --- a/kordac/processors/GenericContainerBlockProcessor.py +++ b/kordac/processors/GenericContainerBlockProcessor.py @@ -10,10 +10,10 @@ def __init__(self, processor, ext, *args, **kwargs): ''' super().__init__(*args, **kwargs) self.processor = processor - self.p_start = re.compile(r'(^|\n) *\{{{0} ?(?P[^\}}]*)(?[^\}}]*)(? end_tag.start())): + or (start_tag and end_tag and start_tag.end() > end_tag.start())): raise TagNotMatchedError(self.processor, block, 'end tag found before start tag') before = block[:start_tag.start()] @@ -56,7 +56,7 @@ def run(self, parent, blocks): if after.strip() != '': blocks.insert(0, after) - argument_values = parse_arguments(self.processor, match.group('args'), self.arguments) + argument_values = parse_arguments(self.processor, start_tag.group('args'), self.arguments) content_blocks = [] the_rest = None @@ -69,7 +69,7 @@ def run(self, parent, blocks): end_tag = self.p_end.search(block) if ((inner_tag and end_tag is None) - or (inner_tag.start() < end_tag.end())): + or (inner_tag and end_tag and inner_tag.start() < end_tag.end())): inner_start_tags += 1 if end_tag and inner_start_tags == inner_end_tags: diff --git a/kordac/processors/GenericTagBlockProcessor.py b/kordac/processors/GenericTagBlockProcessor.py index 37b43daa..09c21c3a 100644 --- a/kordac/processors/GenericTagBlockProcessor.py +++ b/kordac/processors/GenericTagBlockProcessor.py @@ -10,9 +10,9 @@ def __init__(self, processor, ext, *args, **kwargs): ''' super().__init__(*args, **kwargs) self.processor = processor - self.pattern = re.compile(r'(^|\n) *\{{{0} ?(?P[^\}}]*)\}} *(\n|$)').format(self.processor) + self.pattern = re.compile(r'(^|\n) *\{{{0} ?(?P[^\}}]*)\}} *(\n|$)'.format(self.processor)) self.arguments = ext.processor_info[self.processor]['arguments'] - template_name = self.processor.get('template_name', self.processor) + template_name = ext.processor_info.get('template_name', self.processor) self.template = ext.jinja_templates[template_name] self.template_parameters = ext.processor_info[self.processor].get('template_parameters', None) diff --git a/kordac/processors/GlossaryLinkPattern.py b/kordac/processors/GlossaryLinkPattern.py index ec14065e..ba16fb9d 100644 --- a/kordac/processors/GlossaryLinkPattern.py +++ b/kordac/processors/GlossaryLinkPattern.py @@ -24,8 +24,11 @@ def __init__(self, ext, *args, **kwargs): self.pattern = self.ext.processor_info['glossary-link']['pattern'] self.compiled_re = re.compile(r'^(.*?){}(.*)$'.format(self.pattern), re.DOTALL | re.UNICODE) self.arguments = ext.processor_info[self.processor]['arguments'] - template_name = self.processor.get('template_name', self.processor) + template_name = ext.processor_info.get('template_name', self.processor) self.template = ext.jinja_templates[template_name] + + self.ext_glossary_terms = ext.glossary_terms + self.unique_slugify = ext.custom_slugify def handleMatch(self, match): ''' @@ -40,8 +43,8 @@ def handleMatch(self, match): arguments = match.group('args') argument_values = parse_arguments(self.processor, arguments, self.arguments) - term = arugment_values['term'] - reference = arugment_values['reference-text'] + term = argument_values['term'] + reference = argument_values.get('reference-text', None) context = { 'term': term, diff --git a/kordac/processors/ImageBlockProcessor.py b/kordac/processors/ImageBlockProcessor.py index b0101685..458402b9 100644 --- a/kordac/processors/ImageBlockProcessor.py +++ b/kordac/processors/ImageBlockProcessor.py @@ -67,13 +67,13 @@ def run(self, parent, blocks): context = dict() context['file_path'] = file_path - context['alt'] = argument_values['alt'] - context['title'] = argument_values['title'] - context['caption'] = argument_values['caption'] - context['caption_link'] = argument_values['caption-link'] - context['source_link'] = argument_values['source'] - context['alignment'] = argument_values['alignment'] - context['hover_text'] = argument_values['hover-text'] + context['alt'] = argument_values.get('alt', None) + context['title'] = argument_values.get('title', None) + context['caption'] = argument_values.get('caption', None) + context['caption_link'] = argument_values.get('caption-link', None) + context['source_link'] = argument_values.get('source', None) + context['alignment'] = argument_values.get('alignment', None) + context['hover_text'] = argument_values.get('hover-text', None) html_string = self.template.render(context) node = etree.fromstring(html_string) diff --git a/kordac/processors/InteractiveBlockProcessor.py b/kordac/processors/InteractiveBlockProcessor.py index 213e1972..44d43309 100644 --- a/kordac/processors/InteractiveBlockProcessor.py +++ b/kordac/processors/InteractiveBlockProcessor.py @@ -18,7 +18,6 @@ def __init__(self, ext, *args, **kwargs): ext: An instance of the Kordac Extension. ''' super().__init__('interactive', ext, *args, **kwargs) - self.pattern = re.compile(ext.processor_info[self.processor]['pattern']) self.relative_file_template = ext.jinja_templates['relative-file-link'] self.scripts = ext.required_files["page_scripts"] self.required = ext.required_files["interactives"] @@ -62,8 +61,8 @@ def run(self, parent, blocks): name = argument_values['name'] interactive_type = argument_values['type'] - text = argument_values['text'] - parameters = argument_values['parameters'] + text = argument_values.get('text', None) + parameters = argument_values.get('parameters', None) if name is not None and name is '': raise InvalidParameterError(self.processor, "name", "Name parameter must not be an empty string.") @@ -72,7 +71,7 @@ def run(self, parent, blocks): self.scripts.add('interactive/{}/scripts.html'.format(name)) self.required.add(name) - file_path = parse_argument('thumbnail', arguments) + file_path = argument_values.get('thumbnail', None) if file_path is None: file_path = "{}/thumbnail.png".format(name) diff --git a/kordac/processors/utils.py b/kordac/processors/utils.py index e1b0f631..a10650d6 100644 --- a/kordac/processors/utils.py +++ b/kordac/processors/utils.py @@ -55,22 +55,22 @@ def parse_arguments(processor, inputs, arguments): argument_values = dict() for argument, argument_info in arguments.items(): is_required = argument_info['required'] - is_arg = parse_argument(argument, arguments, None) is not None - is_flag = parse_flag(argument, arguments) + is_arg = parse_argument(argument, inputs, None) is not None + is_flag = parse_flag(argument, inputs) - if is_required and (is_arg or is_flag): + if is_required and not (is_arg or is_flag): raise ArgumentMissingError(processor, parameter, "{} is a required argument.".format(argument)) elif not is_required and (is_arg or is_flag): dependencies = argument_info.get('dependencies', []) for other_argument in dependencies: - if not (parse_argument(other_argument, arguments, None) is None - or parse_flag(other_argument, arguments) is None): + if not (parse_argument(other_argument, inputs, None) is None + or parse_flag(other_argument, inputs) is None): raise ArgumentMissingError(processor, argument, "{} is a required parameter because {} exists.".format(other_argument, argument)) if is_flag: argument_values[argument] = True elif is_arg: - argument_values[argument] = parse_argument(argument, arguments, None) + argument_values[argument] = parse_argument(argument, inputs, None) return argument_values @@ -90,7 +90,7 @@ def process_parameters(processor, parameters, argument_values): for parameter, parameter_info in parameters.items(): argument_name = parameter_info['argument'] parameter_default = parameter_info['default'] if 'default' in parameter_info else None - argument_value = argument_values[argument_name] if argument_values[argument_name] is not None else parameter_default + argument_value = argument_values[argument_name] if argument_values.get(argument_name, None) is not None else parameter_default parameter_value = argument_value if parameter_info.get('transform', None): diff --git a/kordac/tests/BoxedTextTest.py b/kordac/tests/BoxedTextTest.py index 493d457c..923888d2 100644 --- a/kordac/tests/BoxedTextTest.py +++ b/kordac/tests/BoxedTextTest.py @@ -2,7 +2,7 @@ from unittest.mock import Mock from kordac.KordacExtension import KordacExtension -from kordac.processors.BoxedTextBlockProcessor import BoxedTextBlockProcessor +from kordac.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor from kordac.tests.ProcessorTest import ProcessorTest @@ -16,12 +16,13 @@ def __init__(self, *args, **kwargs): self.ext = Mock() self.ext.processor_info = ProcessorTest.loadProcessorInfo(self) self.ext.jinja_templates = {self.processor_name: ProcessorTest.loadJinjaTemplate(self, self.processor_name)} + self.block_processor = GenericContainerBlockProcessor(self.processor_name, self.ext, Mock()) def test_no_boxed_text(self): test_string = self.read_test_file(self.processor_name, 'no_boxed_text.md') blocks = self.to_blocks(test_string) - self.assertListEqual([False, False, False, False], [BoxedTextBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([False, False, False, False], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'no_boxed_text_expected.html', strip=True) @@ -31,7 +32,7 @@ def test_single_boxed_text(self): test_string = self.read_test_file(self.processor_name, 'single_boxed_text.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, False, True], [BoxedTextBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'single_boxed_text_expected.html', strip=True) @@ -41,7 +42,7 @@ def test_indented_boxed_text(self): test_string = self.read_test_file(self.processor_name, 'indented_boxed_text.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, True], [BoxedTextBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'indented_boxed_text_expected.html', strip=True) @@ -51,7 +52,7 @@ def test_multiple_boxed_text(self): test_string = self.read_test_file(self.processor_name, 'multiple_boxed_text.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, True, False, True, False, True, False], [BoxedTextBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, True, False, True, False, True, False], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'multiple_boxed_text_expected.html', strip=True) @@ -61,7 +62,7 @@ def test_recursive_boxed_text(self): test_string = self.read_test_file(self.processor_name, 'recursive_boxed_text.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, True, False, True, False, True], [BoxedTextBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, True, False, True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'recursive_boxed_text_expected.html', strip=True) @@ -75,7 +76,7 @@ def test_doc_example_basic(self): test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, False, True], [BoxedTextBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) @@ -85,7 +86,7 @@ def test_doc_example_override_html(self): test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, True], [BoxedTextBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) diff --git a/kordac/tests/ButtonLinkTest.py b/kordac/tests/ButtonLinkTest.py index 7d63eebe..70a943ca 100644 --- a/kordac/tests/ButtonLinkTest.py +++ b/kordac/tests/ButtonLinkTest.py @@ -2,7 +2,7 @@ from unittest.mock import Mock from kordac.KordacExtension import KordacExtension -from kordac.processors.ButtonLinkBlockProcessor import ButtonLinkBlockProcessor +from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor from kordac.tests.ProcessorTest import ProcessorTest @@ -16,12 +16,13 @@ def __init__(self, *args, **kwargs): self.ext = Mock() self.ext.processor_info = ProcessorTest.loadProcessorInfo(self) self.ext.jinja_templates = {self.processor_name: ProcessorTest.loadJinjaTemplate(self, self.processor_name), 'relative-file-link': ProcessorTest.loadJinjaTemplate(self, 'relative-file-link')} + self.block_processor = GenericTagBlockProcessor(self.processor_name, self.ext, Mock()) def test_no_button(self): test_string = self.read_test_file(self.processor_name, 'no_button.md') blocks = self.to_blocks(test_string) - self.assertListEqual([False] * 7, [ButtonLinkBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([False] * 7, [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'no_button_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -30,7 +31,7 @@ def test_contains_button(self): test_string = self.read_test_file(self.processor_name, 'contains_button.md') blocks = self.to_blocks(test_string) - self.assertListEqual([False, True, False], [ButtonLinkBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([False, True, False], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_button_expected.html', strip=True) @@ -40,7 +41,7 @@ def test_contains_missing_button(self): test_string = self.read_test_file(self.processor_name, 'missing_end_brace.md') blocks = self.to_blocks(test_string) - self.assertListEqual([False, False, False], [ButtonLinkBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([False, False, False], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'missing_end_brace_expected.html', strip=True) @@ -50,7 +51,7 @@ def test_contains_multiple_buttons(self): test_string = self.read_test_file(self.processor_name, 'contains_multiple_buttons.md') blocks = self.to_blocks(test_string) - self.assertListEqual([False, True, False, False, True, False, False, True, False, False , True], [ButtonLinkBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([False, True, False, False, True, False, False, True, False, False , True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) @@ -61,7 +62,7 @@ def test_contains_file_link_button(self): test_string = self.read_test_file(self.processor_name, 'contains_file_link_button.md') blocks = self.to_blocks(test_string) - self.assertListEqual([False, True, False, True], [ButtonLinkBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([False, True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) @@ -76,7 +77,7 @@ def test_doc_example_basic(self): test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True], [ButtonLinkBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) @@ -86,7 +87,7 @@ def test_doc_example_file(self): test_string = self.read_test_file(self.processor_name, 'doc_example_file_usage.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True], [ButtonLinkBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_file_usage_expected.html', strip=True) @@ -96,7 +97,7 @@ def test_doc_example_file(self): test_string = self.read_test_file(self.processor_name, 'doc_example_file_usage.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True], [ButtonLinkBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_file_usage_expected.html', strip=True) @@ -106,7 +107,7 @@ def test_doc_example_override_html(self): test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True], [ButtonLinkBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) diff --git a/kordac/tests/FrameTest.py b/kordac/tests/FrameTest.py index 557eb56f..e891f4dd 100644 --- a/kordac/tests/FrameTest.py +++ b/kordac/tests/FrameTest.py @@ -2,27 +2,27 @@ from unittest.mock import Mock from kordac.KordacExtension import KordacExtension -from kordac.processors.FrameBlockProcessor import FrameBlockProcessor -from kordac.processors.errors.ParameterMissingError import ParameterMissingError +from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor +from kordac.processors.errors.ArgumentMissingError import ArgumentMissingError from kordac.tests.ProcessorTest import ProcessorTest class FrameTest(ProcessorTest): - """ - """ + def __init__(self, *args, **kwargs): ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'iframe' self.ext = Mock() self.ext.processor_info = ProcessorTest.loadProcessorInfo(self) self.ext.jinja_templates = {self.processor_name: ProcessorTest.loadJinjaTemplate(self, self.processor_name)} + self.block_processor = GenericTagBlockProcessor(self.processor_name, self.ext, Mock()) def test_example_no_link(self): test_string = self.read_test_file(self.processor_name, 'example_no_link.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True], [FrameBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - with self.assertRaises(ParameterMissingError): + with self.assertRaises(ArgumentMissingError): markdown.markdown(test_string, extensions=[self.kordac_extension]) #~ @@ -33,7 +33,7 @@ def test_doc_example_basic(self): test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True], [FrameBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) @@ -43,7 +43,7 @@ def test_doc_example_override_html(self): test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True], [FrameBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) diff --git a/kordac/tests/PanelTest.py b/kordac/tests/PanelTest.py index 7ebb3eaa..4cadc0ac 100644 --- a/kordac/tests/PanelTest.py +++ b/kordac/tests/PanelTest.py @@ -2,7 +2,7 @@ from unittest.mock import Mock from kordac.KordacExtension import KordacExtension -from kordac.processors.PanelBlockProcessor import PanelBlockProcessor +from kordac.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor from kordac.processors.errors.TagNotMatchedError import TagNotMatchedError from kordac.tests.ProcessorTest import ProcessorTest @@ -15,12 +15,13 @@ def __init__(self, *args, **kwargs): self.ext = Mock() self.ext.jinja_templates = {self.processor_name: ProcessorTest.loadJinjaTemplate(self, self.processor_name)} self.ext.processor_info = ProcessorTest.loadProcessorInfo(self) + self.block_processor = GenericContainerBlockProcessor(self.processor_name, self.ext, Mock()) def test_parses_blank(self): test_string = self.read_test_file(self.processor_name, 'parses_blank.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, True], [PanelBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'parses_blank_expected.html', strip=True) @@ -30,7 +31,7 @@ def test_parses_no_blank_lines_single_paragraph(self): test_string = self.read_test_file(self.processor_name, 'parses_no_blank_lines_single_paragraph.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, True], [PanelBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'parses_no_blank_lines_single_paragraph_expected.html', strip=True) @@ -40,7 +41,7 @@ def test_parses_expanded_panel(self): test_string = self.read_test_file(self.processor_name, 'parses_expanded_panel.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, True], [PanelBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'parses_expanded_panel_expected.html', strip=True) @@ -50,7 +51,7 @@ def test_parses_always_expanded_panel(self): test_string = self.read_test_file(self.processor_name, 'parses_always_expanded_panel.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, True], [PanelBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'parses_always_expanded_panel_expected.html', strip=True) @@ -60,7 +61,7 @@ def test_parses_blank_lines_multiple_paragraphs(self): test_string = self.read_test_file(self.processor_name, 'parses_blank_lines_multiple_paragraphs.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, False, False, False, False, False, False, True], [PanelBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, False, False, False, False, False, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'parses_blank_lines_multiple_paragraphs_expected.html', strip=True) @@ -70,7 +71,7 @@ def test_contains_multiple_panels(self): test_string = self.read_test_file(self.processor_name, 'contains_multiple_panels.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, False, True, True, False, True, True, False, True], [PanelBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, False, True, True, False, True, True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_multiple_panels_expected.html', strip=True) @@ -80,7 +81,7 @@ def test_contains_inner_panel(self): test_string = self.read_test_file(self.processor_name, 'contains_inner_panel.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, True, False, True, False, True], [PanelBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, True, False, True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_inner_panel_expected.html', strip=True) @@ -90,7 +91,7 @@ def test_missing_start_tag(self): test_string = self.read_test_file(self.processor_name, 'missing_start_tag.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, True, True], [PanelBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, True, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) self.assertRaises(TagNotMatchedError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) @@ -98,7 +99,7 @@ def test_missing_end_tag(self): test_string = self.read_test_file(self.processor_name, 'missing_end_tag.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, True, True], [PanelBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, True, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) self.assertRaises(TagNotMatchedError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) @@ -106,7 +107,7 @@ def test_missing_tag_inner(self): test_string = self.read_test_file(self.processor_name, 'missing_tag_inner.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, True, False, True], [PanelBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) self.assertRaises(TagNotMatchedError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) @@ -118,7 +119,7 @@ def test_doc_example_basic(self): test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, True], [PanelBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) @@ -128,7 +129,7 @@ def test_doc_example_override_html(self): test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True, False, True], [PanelBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) diff --git a/kordac/tests/TableOfContentsTest.py b/kordac/tests/TableOfContentsTest.py index fc345aa0..5d3dd5f4 100644 --- a/kordac/tests/TableOfContentsTest.py +++ b/kordac/tests/TableOfContentsTest.py @@ -2,7 +2,7 @@ from unittest.mock import Mock from kordac.KordacExtension import KordacExtension -from kordac.processors.TableOfContentsBlockProcessor import TableOfContentsBlockProcessor +from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor from kordac.tests.ProcessorTest import ProcessorTest @@ -13,6 +13,7 @@ def __init__(self, *args, **kwargs): self.ext = Mock() self.ext.processor_info = ProcessorTest.loadProcessorInfo(self) self.ext.jinja_templates = {self.processor_name: ProcessorTest.loadJinjaTemplate(self, self.processor_name)} + self.block_processor = GenericTagBlockProcessor(self.processor_name, self.ext, Mock()) #~ # Doc Tests @@ -21,7 +22,7 @@ def test_doc_example_basic(self): test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True], [TableOfContentsBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) @@ -31,7 +32,7 @@ def test_doc_example_override_html(self): test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') blocks = self.to_blocks(test_string) - self.assertListEqual([True], [TableOfContentsBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) From 3e58b2d51fabd1ed3714d235ae2e827514c55ef5 Mon Sep 17 00:00:00 2001 From: Hayley van Waas Date: Mon, 13 Mar 2017 21:22:42 +1300 Subject: [PATCH 34/86] Minor tweak to wording, and fixed email link --- .github/ISSUE_TEMPLATE.md | 2 +- .github/PULL_REQUEST_TEMPLATE.md | 2 +- CONTRIBUTING.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 4e61a4b4..05c3ea76 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -10,7 +10,7 @@ Clearly and concisely describe the issue or suggestion here: ### Checklist -*Put an `x` in the boxes that apply. You can also fill these out after creating the issue.* +*Change the space in the box to an `x` for those that apply. You can also fill these out after creating the issue.* - [ ] I have linked any relevant [existing issues/suggestions](https://github.com/uccser/kordac/issues) in the description above (include `#???` in your description to reference an issue, where `???` is the issue number) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f3057d65..aa44dc8b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -10,7 +10,7 @@ Describe the big picture of your changes here to communicate to the maintainers ### Checklist -*Put an `x` in the boxes that apply. You can also fill these out after creating the pull request. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your change.* +*Change the space in the box to an `x` for those that apply. You can also fill these out after creating the pull request. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your change.* - [ ] I have read the [contribution guidelines](.github/CONTRIBUTING.md) - [ ] I have linked any relevant [existing issues/suggestions](https://github.com/uccser/kordac/issues) in the description above (include `#???` in your description to reference an issue, where `???` is the issue number) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 40b05c3a..9edb8f8d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ Below are a few more general notes to remember while you are working on Kordac. This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. -Please report unacceptable behavior to [csse-education-research@canterbury.ac.nz](csse-education-research@canterbury.ac.nz) +Please report unacceptable behavior to [csse-education-research@canterbury.ac.nz](mailto:csse-education-research@canterbury.ac.nz) ### Reporting issues From e615373dbff9d86f362996f35a14dcfa8ba462f2 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Tue, 14 Mar 2017 11:26:40 +1300 Subject: [PATCH 35/86] Fixes unit tests. --- kordac/processor-info.json | 5 +-- .../GenericContainerBlockProcessor.py | 6 ++- kordac/processors/GenericTagBlockProcessor.py | 3 +- .../processors/errors/ArgumentMissingError.py | 6 +-- kordac/processors/utils.py | 40 +++++++++---------- kordac/tests/CommentTest.py | 2 +- .../comment_contains_comment_expected.html | 2 +- 7 files changed, 33 insertions(+), 31 deletions(-) diff --git a/kordac/processor-info.json b/kordac/processor-info.json index ba845254..5191f29b 100644 --- a/kordac/processor-info.json +++ b/kordac/processor-info.json @@ -11,8 +11,7 @@ "template_parameters": { "indented": { "argument": "indented", - "transform": "str.lower", - "default": "no" + "transform": "str.lower" }, "text": { "argument": "content", @@ -55,7 +54,7 @@ }, "comment": { "class": "custom", - "pattern" : "(^|\\n) *\\{comment [^\\}]+\\} *(\\n|$)", + "pattern": "(^|\\n) *\\{comment [^\\}]+\\} *(\\n|$)", "arguments": {}, "template_parameters": {} }, diff --git a/kordac/processors/GenericContainerBlockProcessor.py b/kordac/processors/GenericContainerBlockProcessor.py index 0258cd45..b18ff163 100644 --- a/kordac/processors/GenericContainerBlockProcessor.py +++ b/kordac/processors/GenericContainerBlockProcessor.py @@ -1,4 +1,5 @@ from markdown.blockprocessors import BlockProcessor +from kordac.processors.errors.TagNotMatchedError import TagNotMatchedError from kordac.processors.utils import * import re @@ -16,6 +17,7 @@ def __init__(self, processor, ext, *args, **kwargs): template_name = ext.processor_info.get('template_name', self.processor) self.template = ext.jinja_templates[template_name] self.template_parameters = ext.processor_info[self.processor].get('template_parameters', None) + self.process_parameters = lambda processor, parameters, argument_values: process_parameters(ext, processor, parameters, argument_values) def test(self, parent, block): ''' Tests a block to see if the run method should be applied. @@ -59,7 +61,7 @@ def run(self, parent, blocks): argument_values = parse_arguments(self.processor, start_tag.group('args'), self.arguments) content_blocks = [] - the_rest = None + the_rest = '' inner_start_tags = 0 inner_end_tags = 0 @@ -95,7 +97,7 @@ def run(self, parent, blocks): content += etree.tostring(child, encoding="unicode", method="html") + '\n' argument_values['content'] = content - context = process_parameters(self.processor, self.template_parameters, argument_values) + context = self.process_parameters(self.processor, self.template_parameters, argument_values) html_string = self.template.render(context) node = etree.fromstring(html_string) diff --git a/kordac/processors/GenericTagBlockProcessor.py b/kordac/processors/GenericTagBlockProcessor.py index 09c21c3a..9e3bf4c2 100644 --- a/kordac/processors/GenericTagBlockProcessor.py +++ b/kordac/processors/GenericTagBlockProcessor.py @@ -15,6 +15,7 @@ def __init__(self, processor, ext, *args, **kwargs): template_name = ext.processor_info.get('template_name', self.processor) self.template = ext.jinja_templates[template_name] self.template_parameters = ext.processor_info[self.processor].get('template_parameters', None) + self.process_parameters = lambda processor, parameters, argument_values: process_parameters(ext, processor, parameters, argument_values) def test(self, parent, block): ''' Tests a block to see if the run method should be applied. @@ -50,7 +51,7 @@ def run(self, parent, blocks): blocks.insert(0, after) argument_values = parse_arguments(self.processor, match.group('args'), self.arguments) - context = process_parameters(self.processor, self.template_parameters, argument_values) + context = self.process_parameters(self.processor, self.template_parameters, argument_values) html_string = self.template.render(context) node = etree.fromstring(html_string) diff --git a/kordac/processors/errors/ArgumentMissingError.py b/kordac/processors/errors/ArgumentMissingError.py index 03ce80df..cb018bee 100644 --- a/kordac/processors/errors/ArgumentMissingError.py +++ b/kordac/processors/errors/ArgumentMissingError.py @@ -6,12 +6,12 @@ class ArgumentMissingError(Error): Attributes: tag -- tag which was not matched block -- block where tag was not matched - parameter -- the parameter that was not found + argument -- the argument that was not found message -- explanation of why error was thrown """ - def __init__(self, tag, parameter, message): + def __init__(self, tag, argument, message): super().__init__(message) self.tag = tag - self.parameter = parameter + self.argument = argument self.message = message diff --git a/kordac/processors/utils.py b/kordac/processors/utils.py index a10650d6..e5b11d53 100644 --- a/kordac/processors/utils.py +++ b/kordac/processors/utils.py @@ -1,6 +1,6 @@ import re from markdown.util import etree -from collections import OrderedDict +from collections import OrderedDict, defaultdict from kordac.processors.errors.ArgumentMissingError import ArgumentMissingError def parse_argument(argument_key, arguments, default=None): @@ -52,29 +52,28 @@ def parse_arguments(processor, inputs, arguments): ArgumentMissingError: If any required arguments are missing or an argument an optional argument is dependent on is missing. ''' - argument_values = dict() + argument_values = defaultdict(None) for argument, argument_info in arguments.items(): is_required = argument_info['required'] is_arg = parse_argument(argument, inputs, None) is not None is_flag = parse_flag(argument, inputs) if is_required and not (is_arg or is_flag): - raise ArgumentMissingError(processor, parameter, "{} is a required argument.".format(argument)) + raise ArgumentMissingError(processor, argument, "{} is a required argument.".format(argument)) elif not is_required and (is_arg or is_flag): dependencies = argument_info.get('dependencies', []) for other_argument in dependencies: - if not (parse_argument(other_argument, inputs, None) is None - or parse_flag(other_argument, inputs) is None): - raise ArgumentMissingError(processor, argument, "{} is a required parameter because {} exists.".format(other_argument, argument)) + if not (parse_argument(other_argument, inputs, None) is not None + or parse_flag(other_argument, inputs) is not None): + raise ArgumentMissingError(processor, argument, "{} is a required argument because {} exists.".format(other_argument, argument)) if is_flag: argument_values[argument] = True elif is_arg: argument_values[argument] = parse_argument(argument, inputs, None) - return argument_values -def process_parameters(processor, parameters, argument_values): +def process_parameters(ext, processor, parameters, argument_values): ''' Processes a given set of arguments by the parameter definitions. @@ -89,27 +88,28 @@ def process_parameters(processor, parameters, argument_values): transformations = OrderedDict() for parameter, parameter_info in parameters.items(): argument_name = parameter_info['argument'] - parameter_default = parameter_info['default'] if 'default' in parameter_info else None - argument_value = argument_values[argument_name] if argument_values.get(argument_name, None) is not None else parameter_default + parameter_default = parameter_info.get('default', None) + argument_value = argument_values.get(argument_name, parameter_default) parameter_value = argument_value if parameter_info.get('transform', None): - transformation = find_transformation(parameter_info['transform']) + transform = find_transformation(ext, parameter_info['transform']) if parameter_info.get('transform_condition', None): - transformations[parameter] = (eval(parameter_info['transform_condition']), transformation) + transformations[parameter] = (eval(parameter_info['transform_condition']), transform) else: - transformations[parameter] = (True, transformation) + transformations[parameter] = (True, transform) context[parameter] = parameter_value - for parameter, (condition, transformation) in transformations.items(): - if isinstance(condition, bool) and condition == True: - context[parameter] = transform(context[parameter]) - if callable(condition) and condition(context): - context[parameter] = transform(context[parameter]) + for parameter, (condition, transform) in transformations.items(): + if context[parameter] is not None: + if isinstance(condition, bool) and condition == True: + context[parameter] = transform(context[parameter]) + if callable(condition) and condition(context): + context[parameter] = transform(context[parameter]) return context -def find_transformation(option): +def find_transformation(ext, option): ''' Returns a transformation for a given string. TODO: @@ -124,7 +124,7 @@ def find_transformation(option): return { 'str.lower': lambda x: x.lower(), 'str.upper': lambda x: x.upper(), - 'relative_file_link': lambda x: self.relative_file_template.render({'file_path': x}) + 'relative_file_link': lambda x: ext.jinja_templates['relative-file-link'].render({'file_path': x}) }.get(option, None) def blocks_to_string(blocks): diff --git a/kordac/tests/CommentTest.py b/kordac/tests/CommentTest.py index 6cb140e3..06492a78 100644 --- a/kordac/tests/CommentTest.py +++ b/kordac/tests/CommentTest.py @@ -58,7 +58,7 @@ def test_comment_contains_comment(self): # We expect to match the first closing '}' to enforce simple comments test_string = self.read_test_file(self.processor_name, 'comment_contains_comment.md') - self.assertTrue(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) + self.assertFalse(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'comment_contains_comment_expected.html', strip=True) diff --git a/kordac/tests/assets/comment/comment_contains_comment_expected.html b/kordac/tests/assets/comment/comment_contains_comment_expected.html index 284fb04a..40995fc7 100644 --- a/kordac/tests/assets/comment/comment_contains_comment_expected.html +++ b/kordac/tests/assets/comment/comment_contains_comment_expected.html @@ -1,3 +1,3 @@

    - } + {comment explain different views of algorithm (programming context) and Algorithm (that have interesting complexity) {comment explain different views of algorithm (programming context) and Algorithm (that have interesting complexity)}}

    From 2e7c9a02257c34791e502eff11b167e38a548e2f Mon Sep 17 00:00:00 2001 From: Hayley van Waas Date: Tue, 14 Mar 2017 11:28:47 +1300 Subject: [PATCH 36/86] Fixed internal link --- docs/source/contributing.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 2502ba81..4599d8ac 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -39,7 +39,7 @@ If you would like to contribute to Kordac, `create a fork of the repository`_. Overview ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Before reading this section, make sure you have read `how to use Kordac`_ (or even better, have already used Kordac!). +Before reading this section, make sure you have read :doc:`how to use ` (or even better, have already used Kordac!). Terminology @@ -250,7 +250,6 @@ can only be performed by repository administrators .. _here: https://github.com/uccser/kordac .. _report it on the repo issue tracker: https://github.com/uccser/kordac/issues .. _create a fork of the repository: https://help.github.com/articles/fork-a-repo/ -.. _how to use Kordac: http://kordac.readthedocs.io/en/develop/usage.html .. _Extension API: https://pythonhosted.org/Markdown/extensions/api.html .. _source code: https://github.com/waylan/Python-Markdown .. _OrderedDict in the Markdown API docs: https://pythonhosted.org/Markdown/extensions/api.html#ordereddict From 4431d36585d2e208925d57640a6de4903e7b980e Mon Sep 17 00:00:00 2001 From: Hayley van Waas Date: Tue, 14 Mar 2017 11:41:00 +1300 Subject: [PATCH 37/86] Changed order of contents, removed Jack's notes-to-self --- docs/source/index.rst | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index 20332421..f3d5904b 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -21,11 +21,5 @@ For example: usage processors/index extensions - changelog contributing - -Other Features -============== - -- HTML for any given processor can replaced -- Specific processors can be enabled while ignoring all other processors + changelog From 55398cd2061337d7cd53acb78d4c7ce2f5154c93 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Tue, 14 Mar 2017 14:11:04 +1300 Subject: [PATCH 38/86] Docstrings added to kordac extension. --- kordac/Kordac.py | 56 +++++++++++++++++----------------- kordac/KordacExtension.py | 63 ++++++++++++++++++++++++++++++++++++++- kordac/template.html | 17 ----------- 3 files changed, 91 insertions(+), 45 deletions(-) delete mode 100644 kordac/template.html diff --git a/kordac/Kordac.py b/kordac/Kordac.py index 18380335..9b74b12e 100644 --- a/kordac/Kordac.py +++ b/kordac/Kordac.py @@ -19,12 +19,12 @@ }) class Kordac(object): - """A converter object for converting markdown - with complex elements to HTML. - """ + '''A converter object for converting markdown with complex elements + to HTML. + ''' def __init__(self, processors=DEFAULT_PROCESSORS, html_templates={}, extensions=[]): - """Creates a Kordac object. + '''Creates a Kordac object. Args: processors: A set of processor names given as strings for which @@ -37,14 +37,14 @@ def __init__(self, processors=DEFAULT_PROCESSORS, html_templates={}, extensions= eg: {'image': ''} extensions: A list of extra extensions to run on the markdown package. - """ + ''' self.processors = set(processors) self.html_templates = dict(html_templates) self.extensions = list(extensions) self.create_converter() def create_converter(self): - """Create the Kordac extension and converter for future use.""" + '''Create the Kordac extension and converter for future use.''' self.kordac_extension = KordacExtension( processors=self.processors, html_templates=self.html_templates, @@ -54,7 +54,7 @@ def create_converter(self): self.converter = markdown.Markdown(extensions=all_extensions) def convert(self, text): - """Return a KordacResult object after converting + '''Return a KordacResult object after converting the given markdown string. Args: @@ -62,7 +62,7 @@ def convert(self, text): Returns: A KordacResult object. - """ + ''' self.kordac_extension.clear_saved_data() html_string = self.converter.convert(text) result = KordacResult( @@ -75,61 +75,63 @@ def convert(self, text): return result def update_templates(self, html_templates): - """Update the template dictionary with the given dictionary + '''Update the template dictionary with the given dictionary of templates, while leaving all other HTML templates (including any custom set templates) untouched. The updated dictionary will be used for converting from this point onwards. Args: html_templates: A dictionary of HTML templates to override - existing HTML templates for processors. Dictionary contains - processor names given as a string as keys mapping HTML strings - as values. + existing HTML templates for processors. Dictionary + contains processor names given as a string as keys + mapping HTML strings as values. eg: {'image': ''} - """ + ''' self.html_templates.update(html_templates) self.create_converter() def clear_templates(self): - """Set the template dictionary to it's original values.""" + '''Set the template dictionary to it's original values.''' self.html_templates = {} self.create_converter() @staticmethod def processor_defaults(): - """Returns a copy of the default processor set. + '''Returns a copy of the default processor set. Returns: A set of default processor names as strings. - """ + ''' return set(DEFAULT_PROCESSORS) def update_processors(self, processors=DEFAULT_PROCESSORS): - """Update the processors used for conversion with the given set. - The updated set will be used for converting from this point - onwards. If parameter is empty, default processors will be used. + '''Update the processors used for conversion with the given + set. The updated set will be used for converting from this + point onwards. If parameter is empty, default processors will + be used. Args: - processors: A set of processor names given as strings for which - their processors are enabled. If given, all other + processors: A set of processor names given as strings for + which their processors are enabled. If given, all other processors are skipped. - """ + ''' self.processors = set(processors) self.create_converter() class KordacResult(object): - """Object created by Kordac containing the result data + '''Object created by Kordac containing the result data after a conversion by run. - """ + ''' def __init__(self, html_string, title, required_files, heading_tree, required_glossary_terms): - """Create a KordacResult object. + '''Create a KordacResult object. Args: html_string: A string of HTML text. title: The first heading encountered when converting. - required_files: Dictionary of required file types to sets of paths. - """ + required_files: Dictionary of required file types to sets + of paths. + ''' self.html_string = html_string self.title = title self.required_files = required_files diff --git a/kordac/KordacExtension.py b/kordac/KordacExtension.py index fb0c23ba..d61c5f8a 100644 --- a/kordac/KordacExtension.py +++ b/kordac/KordacExtension.py @@ -31,7 +31,24 @@ from jinja2 import Environment, PackageLoader, select_autoescape class KordacExtension(Extension): + '''The Kordac markdown extension which enables all the processors, + and extracts all the important information to expose externally to + the Kordac converter. + ''' + def __init__(self, processors=[], html_templates={}, extensions=[], *args, **kwargs): + ''' + Args: + processors: A set of processor names given as strings for which + their processors are enabled. If given, all other + processors are skipped. + html_templates: A dictionary of HTML templates to override + existing HTML templates for processors. Dictionary contains + processor names given as a string as keys mapping HTML strings + as values. + eg: {'image': ''} + extensions: A list of extra extensions for compatibility. + ''' super().__init__(*args, **kwargs) self.required_files = defaultdict(set) self.title = None @@ -51,6 +68,13 @@ def __init__(self, processors=[], html_templates={}, extensions=[], *args, **kwa self.compatibility.append('fenced_code_block') def extendMarkdown(self, md, md_globals): + '''Inherited from the markdown.Extension class. Extends + markdown with custom processors. + + Args: + md: An instance of the markdown object to extend. + md_globals: Global variables in the markdown module namespace. + ''' self.preprocessors = [ ['comment', CommentPreprocessor(self, md), '_begin'], ['save-title', SaveTitlePreprocessor(self, md), '_end'], @@ -97,10 +121,15 @@ def extendMarkdown(self, md, md_globals): md.postprocessors.add('jinja', JinjaPostprocessor(md), '_end') # Compatibility modules - if 'hilite' in self.compatibility and 'fenced_code_block' in self.compatibility and 'scratch' in self.processors: + if ('hilite' in self.compatibility + and 'fenced_code_block' in self.compatibility + and 'scratch' in self.processors): md.preprocessors.add('scratch-compatibility', ScratchCompatibilityPreprocessor(self, md), ' - - - - - Template - - - - - - - -
    {{content}}
    - - - From 9f8665cfa1bdd7a80e6134236e07eda6b312973b Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Tue, 14 Mar 2017 15:27:17 +1300 Subject: [PATCH 39/86] Tidy code. --- .flake8 | 22 ++++++++ .travis.yml | 2 + kordac/Kordac.py | 2 + kordac/KordacExtension.py | 25 +++++---- kordac/__init__.py | 2 +- kordac/processors/BeautifyPostprocessor.py | 11 ++++ kordac/processors/CommentPreprocessor.py | 6 ++- kordac/processors/ConditionalProcessor.py | 23 ++++---- .../GenericContainerBlockProcessor.py | 10 ++-- kordac/processors/GenericTagBlockProcessor.py | 9 +++- kordac/processors/GlossaryLinkPattern.py | 5 +- kordac/processors/HeadingBlockProcessor.py | 8 +-- kordac/processors/ImageBlockProcessor.py | 11 ++-- .../processors/InteractiveBlockProcessor.py | 8 ++- kordac/processors/JinjaPostprocessor.py | 1 + kordac/processors/RelativeLinkPattern.py | 1 + kordac/processors/RemovePostprocessor.py | 3 +- kordac/processors/RemoveTitlePreprocessor.py | 6 ++- kordac/processors/SaveTitlePreprocessor.py | 1 + .../ScratchCompatibilityPreprocessor.py | 1 + kordac/processors/ScratchTreeprocessor.py | 32 +++++------ kordac/processors/VideoBlockProcessor.py | 10 ++-- .../processors/errors/ArgumentMissingError.py | 1 + .../errors/InvalidParameterError.py | 1 + kordac/processors/errors/NoSourceLinkError.py | 2 +- .../errors/NoVideoIdentifierError.py | 2 +- .../processors/errors/TagNotMatchedError.py | 1 + .../errors/UnsupportedVideoPlayerError.py | 2 +- kordac/processors/utils.py | 15 ++++-- kordac/utils/HeadingNode.py | 2 + kordac/utils/UniqueSlugify.py | 53 ++++++++++--------- 31 files changed, 177 insertions(+), 101 deletions(-) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..1cdb0993 --- /dev/null +++ b/.flake8 @@ -0,0 +1,22 @@ +[flake8] +exclude = + # No need to traverse our git or venv directories + .git, + venv, + + # Don't process our PyPi script + ./setup.py, + + # There's no value in checking cache directories + __pycache__, + + # This contains our documentation + docs, + + # This contains tests that we don't want to check + kordac/tests, + +show-source = True +statistics = True +count = True +max-line-length=119 diff --git a/.travis.yml b/.travis.yml index bda1e2f6..a75a0d37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,9 +8,11 @@ python: - "3.6-dev" # 3.6 development branch # Install dependencies +install: pip install flake8 install: pip install -r requirements.txt # Runs test suite +script: flake8 script: python -m kordac.tests.start_tests --travis # Stop email notifications but post to organisation Slack channel diff --git a/kordac/Kordac.py b/kordac/Kordac.py index 9b74b12e..f8048d07 100644 --- a/kordac/Kordac.py +++ b/kordac/Kordac.py @@ -18,6 +18,7 @@ 'scratch' }) + class Kordac(object): '''A converter object for converting markdown with complex elements to HTML. @@ -118,6 +119,7 @@ def update_processors(self, processors=DEFAULT_PROCESSORS): self.processors = set(processors) self.create_converter() + class KordacResult(object): '''Object created by Kordac containing the result data after a conversion by run. diff --git a/kordac/KordacExtension.py b/kordac/KordacExtension.py index d61c5f8a..43b0da1c 100644 --- a/kordac/KordacExtension.py +++ b/kordac/KordacExtension.py @@ -30,6 +30,7 @@ from jinja2 import Environment, PackageLoader, select_autoescape + class KordacExtension(Extension): '''The Kordac markdown extension which enables all the processors, and extracts all the important information to expose externally to @@ -81,21 +82,22 @@ def extendMarkdown(self, md, md_globals): ['remove-title', RemoveTitlePreprocessor(self, md), '_end'], ] self.blockprocessors = [ - # Markdown overrides + # Markdown overrides ['heading', HeadingBlockProcessor(self, md.parser), 'inline' if 'hilite' not in self.compatibility else ' end_tag.start())): + or (start_tag and end_tag and start_tag.end() > end_tag.start())): raise TagNotMatchedError(self.processor, block, 'end tag found before start tag') is_if = parse_flag('if', start_tag.group('args')) @@ -148,7 +153,7 @@ def get_content(self, blocks): content_blocks.append(block) if the_rest.strip() != '': - blocks.insert(0, the_rest) # Keep anything off the end, should be empty though + blocks.insert(0, the_rest) # Keep anything off the end, should be empty though if inner_if_tags != inner_end_tags: raise TagNotMatchedError(self.processor, block, 'no end tag found to close start tag') diff --git a/kordac/processors/GenericContainerBlockProcessor.py b/kordac/processors/GenericContainerBlockProcessor.py index b18ff163..d200a4bb 100644 --- a/kordac/processors/GenericContainerBlockProcessor.py +++ b/kordac/processors/GenericContainerBlockProcessor.py @@ -1,8 +1,9 @@ from markdown.blockprocessors import BlockProcessor from kordac.processors.errors.TagNotMatchedError import TagNotMatchedError -from kordac.processors.utils import * +from kordac.processors.utils import etree, parse_arguments, process_parameters, blocks_to_string import re + class GenericContainerBlockProcessor(BlockProcessor): def __init__(self, processor, ext, *args, **kwargs): ''' @@ -17,7 +18,8 @@ def __init__(self, processor, ext, *args, **kwargs): template_name = ext.processor_info.get('template_name', self.processor) self.template = ext.jinja_templates[template_name] self.template_parameters = ext.processor_info[self.processor].get('template_parameters', None) - self.process_parameters = lambda processor, parameters, argument_values: process_parameters(ext, processor, parameters, argument_values) + self.process_parameters = lambda processor, parameters, argument_values: \ + process_parameters(ext, processor, parameters, argument_values) def test(self, parent, block): ''' Tests a block to see if the run method should be applied. @@ -47,7 +49,7 @@ def run(self, parent, blocks): end_tag = self.p_end.search(block) if ((start_tag is None and end_tag is not None) - or (start_tag and end_tag and start_tag.end() > end_tag.start())): + or (start_tag and end_tag and start_tag.end() > end_tag.start())): raise TagNotMatchedError(self.processor, block, 'end tag found before start tag') before = block[:start_tag.start()] @@ -71,7 +73,7 @@ def run(self, parent, blocks): end_tag = self.p_end.search(block) if ((inner_tag and end_tag is None) - or (inner_tag and end_tag and inner_tag.start() < end_tag.end())): + or (inner_tag and end_tag and inner_tag.start() < end_tag.end())): inner_start_tags += 1 if end_tag and inner_start_tags == inner_end_tags: diff --git a/kordac/processors/GenericTagBlockProcessor.py b/kordac/processors/GenericTagBlockProcessor.py index 9e3bf4c2..1a0cb8a2 100644 --- a/kordac/processors/GenericTagBlockProcessor.py +++ b/kordac/processors/GenericTagBlockProcessor.py @@ -1,8 +1,12 @@ from markdown.blockprocessors import BlockProcessor -from kordac.processors.utils import * +from kordac.processors.utils import etree, parse_arguments, process_parameters import re + class GenericTagBlockProcessor(BlockProcessor): + ''' A generic processor that matches '{ args}' and replaces + with the according html template. + ''' def __init__(self, processor, ext, *args, **kwargs): ''' Args: @@ -15,7 +19,8 @@ def __init__(self, processor, ext, *args, **kwargs): template_name = ext.processor_info.get('template_name', self.processor) self.template = ext.jinja_templates[template_name] self.template_parameters = ext.processor_info[self.processor].get('template_parameters', None) - self.process_parameters = lambda processor, parameters, argument_values: process_parameters(ext, processor, parameters, argument_values) + self.process_parameters = lambda processor, parameters, argument_values: \ + process_parameters(ext, processor, parameters, argument_values) def test(self, parent, block): ''' Tests a block to see if the run method should be applied. diff --git a/kordac/processors/GlossaryLinkPattern.py b/kordac/processors/GlossaryLinkPattern.py index ba16fb9d..d3677ee6 100644 --- a/kordac/processors/GlossaryLinkPattern.py +++ b/kordac/processors/GlossaryLinkPattern.py @@ -1,6 +1,5 @@ from markdown.inlinepatterns import Pattern -from kordac.processors.utils import * -from markdown.util import etree +from kordac.processors.utils import etree, parse_arguments import re @@ -26,7 +25,7 @@ def __init__(self, ext, *args, **kwargs): self.arguments = ext.processor_info[self.processor]['arguments'] template_name = ext.processor_info.get('template_name', self.processor) self.template = ext.jinja_templates[template_name] - + self.ext_glossary_terms = ext.glossary_terms self.unique_slugify = ext.custom_slugify diff --git a/kordac/processors/HeadingBlockProcessor.py b/kordac/processors/HeadingBlockProcessor.py index fbeab543..4117ccc7 100644 --- a/kordac/processors/HeadingBlockProcessor.py +++ b/kordac/processors/HeadingBlockProcessor.py @@ -1,8 +1,9 @@ from markdown.blockprocessors import BlockProcessor from markdown.util import etree -from kordac.utils.HeadingNode import HeadingNode, DynamicHeadingNode +from kordac.utils.HeadingNode import DynamicHeadingNode import re + class HeadingBlockProcessor(BlockProcessor): ''' Searches a Document for markdown headings (e.g. # HeadingTitle) these are then processed into html headings and generates level @@ -53,7 +54,7 @@ def run(self, parent, blocks): ''' block = blocks.pop(0) match = self.pattern.search(block) - assert match is not None # If this is true how did we test successfully + assert match is not None # If this is true how did we test successfully before = block[:match.start()] after = block[match.end():] @@ -117,7 +118,8 @@ def add_to_heading_tree(self, heading, heading_slug, level): root_node = root_node.parent # Update the extension tree - self.update_ext_tree(tuple(self.roots + [root_node.to_immutable(),])) + self.update_ext_tree(tuple(self.roots + [root_node.to_immutable(), ])) + class LevelGenerator: ''' Generates a level trail for example (1, 2, 3) which might be diff --git a/kordac/processors/ImageBlockProcessor.py b/kordac/processors/ImageBlockProcessor.py index 458402b9..90a0ea06 100644 --- a/kordac/processors/ImageBlockProcessor.py +++ b/kordac/processors/ImageBlockProcessor.py @@ -1,9 +1,8 @@ from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor -from kordac.processors.utils import * -from markdown.util import etree -import jinja2 +from kordac.processors.utils import etree, parse_arguments import re + class ImageBlockProcessor(GenericTagBlockProcessor): ''' Searches a Document for image tags e.g. {image file-path=""} adding any internal images to the kordac extension final result. @@ -61,19 +60,19 @@ def run(self, parent, blocks): # check if internal or external image file_path = argument_values['file-path'] external_path_match = re.search(r'^http', file_path) - if external_path_match is None: # internal image + if external_path_match is None: # internal image self.required.add(file_path) file_path = self.relative_image_template.render({'file_path': file_path}) context = dict() context['file_path'] = file_path context['alt'] = argument_values.get('alt', None) - context['title'] = argument_values.get('title', None) + context['title'] = argument_values.get('title', None) context['caption'] = argument_values.get('caption', None) context['caption_link'] = argument_values.get('caption-link', None) context['source_link'] = argument_values.get('source', None) context['alignment'] = argument_values.get('alignment', None) - context['hover_text'] = argument_values.get('hover-text', None) + context['hover_text'] = argument_values.get('hover-text', None) html_string = self.template.render(context) node = etree.fromstring(html_string) diff --git a/kordac/processors/InteractiveBlockProcessor.py b/kordac/processors/InteractiveBlockProcessor.py index 44d43309..9ef199a5 100644 --- a/kordac/processors/InteractiveBlockProcessor.py +++ b/kordac/processors/InteractiveBlockProcessor.py @@ -1,10 +1,8 @@ from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor from kordac.processors.errors.InvalidParameterError import InvalidParameterError -from kordac.processors.utils import * -from markdown.util import etree - +from kordac.processors.utils import etree, parse_arguments import re -import os + class InteractiveBlockProcessor(GenericTagBlockProcessor): '''Searches a Document for interactive tags: @@ -76,7 +74,7 @@ def run(self, parent, blocks): file_path = "{}/thumbnail.png".format(name) external_path_match = re.search(r'^http', file_path) - if external_path_match is None: # internal image + if external_path_match is None: # internal image self.required.add(file_path) file_path = self.relative_file_template.render({'file_path': file_path}) diff --git a/kordac/processors/JinjaPostprocessor.py b/kordac/processors/JinjaPostprocessor.py index 2901ddcd..c77fb395 100644 --- a/kordac/processors/JinjaPostprocessor.py +++ b/kordac/processors/JinjaPostprocessor.py @@ -2,6 +2,7 @@ from html import unescape import re + class JinjaPostprocessor(Postprocessor): ''' Checks all jinja blocks in the output and ensures that they are not escaped like other html blocks. diff --git a/kordac/processors/RelativeLinkPattern.py b/kordac/processors/RelativeLinkPattern.py index f3386fe7..b7ea4d6b 100644 --- a/kordac/processors/RelativeLinkPattern.py +++ b/kordac/processors/RelativeLinkPattern.py @@ -2,6 +2,7 @@ from markdown.util import etree import re + class RelativeLinkPattern(Pattern): """Return a link element from the given match. diff --git a/kordac/processors/RemovePostprocessor.py b/kordac/processors/RemovePostprocessor.py index a2554ee0..746bb0cb 100644 --- a/kordac/processors/RemovePostprocessor.py +++ b/kordac/processors/RemovePostprocessor.py @@ -1,11 +1,12 @@ from markdown.postprocessors import Postprocessor + class RemovePostprocessor(Postprocessor): ''' Parses the output document and removes all remove html tags (i.e. or ) keeping the body of said tags. This allows for the returning of illegal html for further processing. ''' - + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/kordac/processors/RemoveTitlePreprocessor.py b/kordac/processors/RemoveTitlePreprocessor.py index 1a385c4c..772203d4 100644 --- a/kordac/processors/RemoveTitlePreprocessor.py +++ b/kordac/processors/RemoveTitlePreprocessor.py @@ -1,7 +1,9 @@ from markdown.preprocessors import Preprocessor import re + class RemoveTitlePreprocessor(Preprocessor): + '''Removes the first found title from the given document.''' def __init__(self, ext, *args, **kwargs): ''' @@ -13,7 +15,7 @@ def __init__(self, ext, *args, **kwargs): self.pattern = re.compile(ext.processor_info['title']['pattern']) def test(self, lines): - ''' Tests the given document to check if the processor should be + '''Tests the given document to check if the processor should be run. Args: @@ -24,7 +26,7 @@ def test(self, lines): return self.pattern.search(lines) is not None def run(self, lines): - ''' If the title is found on a line, remove the line. + '''If the title is found on a line, remove the line. Args: lines: A list of strings that form the document. diff --git a/kordac/processors/SaveTitlePreprocessor.py b/kordac/processors/SaveTitlePreprocessor.py index 9e6bda8c..789e8db2 100644 --- a/kordac/processors/SaveTitlePreprocessor.py +++ b/kordac/processors/SaveTitlePreprocessor.py @@ -1,6 +1,7 @@ from markdown.preprocessors import Preprocessor import re + class SaveTitlePreprocessor(Preprocessor): ''' Saves the first title found in the document to the KordacExtension as part of the final result. diff --git a/kordac/processors/ScratchCompatibilityPreprocessor.py b/kordac/processors/ScratchCompatibilityPreprocessor.py index a35b805c..e9f9dbe6 100644 --- a/kordac/processors/ScratchCompatibilityPreprocessor.py +++ b/kordac/processors/ScratchCompatibilityPreprocessor.py @@ -1,6 +1,7 @@ from markdown.preprocessors import Preprocessor import re + class ScratchCompatibilityPreprocessor(Preprocessor): '''Should only be active if using the scratch processor and the extensions for fenced_code and codehilite. This preprocessor works diff --git a/kordac/processors/ScratchTreeprocessor.py b/kordac/processors/ScratchTreeprocessor.py index 245a8aed..d78d7ca7 100644 --- a/kordac/processors/ScratchTreeprocessor.py +++ b/kordac/processors/ScratchTreeprocessor.py @@ -1,9 +1,8 @@ from markdown.treeprocessors import Treeprocessor from kordac.processors.utils import etree -from kordac.processors.errors.TagNotMatchedError import TagNotMatchedError from collections import namedtuple from hashlib import sha256 -import re + class ScratchImageMetaData(namedtuple('ScratchImageMetaData', 'hash, text')): ''' Represents data required to make a scratch image. @@ -13,6 +12,7 @@ class ScratchImageMetaData(namedtuple('ScratchImageMetaData', 'hash, text')): text: text of the scratch code ''' + class ScratchTreeprocessor(Treeprocessor): ''' Searches a Document for codeblocks with the scratch language. These are then processed into the kordac result and hashed for @@ -67,20 +67,20 @@ def process_html(self, node): ''' children = list(node) if (len(children) == 1 and children[0].tag == 'code' - and ((children[0].text.strip().startswith('scratch\n')) - or ('class' in children[0].attrib.keys() and children[0].attrib['class'] == 'scratch'))): - content = children[0].text.strip() - if content.startswith('scratch\n'): - content = content[len('scratch\n'):] - content_hash = ScratchTreeprocessor.hash_content(content) - self.update_required_images(content_hash, content) - html_string = self.template.render({ 'hash': content_hash }) - new_node = etree.fromstring(html_string) - - node.tag = "remove" - node.text = "" - node.append(new_node) - node.remove(children[0]) + and ((children[0].text.strip().startswith('scratch\n')) + or ('class' in children[0].attrib.keys() and children[0].attrib['class'] == 'scratch'))): + content = children[0].text.strip() + if content.startswith('scratch\n'): + content = content[len('scratch\n'):] + content_hash = ScratchTreeprocessor.hash_content(content) + self.update_required_images(content_hash, content) + html_string = self.template.render({'hash': content_hash}) + new_node = etree.fromstring(html_string) + + node.tag = "remove" + node.text = "" + node.append(new_node) + node.remove(children[0]) @staticmethod def hash_content(text): diff --git a/kordac/processors/VideoBlockProcessor.py b/kordac/processors/VideoBlockProcessor.py index 03ae2411..151e39a9 100644 --- a/kordac/processors/VideoBlockProcessor.py +++ b/kordac/processors/VideoBlockProcessor.py @@ -1,8 +1,7 @@ from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor -from kordac.processors.errors.NoSourceLinkError import NoSourceLinkError from kordac.processors.errors.NoVideoIdentifierError import NoVideoIdentifierError from kordac.processors.errors.UnsupportedVideoPlayerError import UnsupportedVideoPlayerError -from kordac.processors.utils import * +from kordac.processors.utils import etree, parse_arguments import re @@ -33,7 +32,8 @@ def test(self, parent, block): return self.pattern.search(block) is not None def run(self, parent, blocks): - '''Replaces all video tags {video url="example"} with embeded video link. Inherited from BlockProcessor class. + '''Replaces all video tags {video url="example"} with embeded + video link. Inherited from BlockProcessor class. Args: parent: Element which this block is in. @@ -85,13 +85,13 @@ 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('.*?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: start_pos = video_url.find('v=') + 2 - end_pos = video_url.find('&'); + end_pos = video_url.find('&') if end_pos == -1: end_pos = len(video_url) video_query = video_url[start_pos:end_pos] diff --git a/kordac/processors/errors/ArgumentMissingError.py b/kordac/processors/errors/ArgumentMissingError.py index cb018bee..909c11ea 100644 --- a/kordac/processors/errors/ArgumentMissingError.py +++ b/kordac/processors/errors/ArgumentMissingError.py @@ -1,5 +1,6 @@ from kordac.processors.errors.Error import Error + class ArgumentMissingError(Error): """Exception raised when a custom markdown tag in not matched. diff --git a/kordac/processors/errors/InvalidParameterError.py b/kordac/processors/errors/InvalidParameterError.py index cb5066fb..7ceff206 100644 --- a/kordac/processors/errors/InvalidParameterError.py +++ b/kordac/processors/errors/InvalidParameterError.py @@ -1,5 +1,6 @@ from kordac.processors.errors.Error import Error + class InvalidParameterError(Error): """Exception raised when an invalid parameter value is found. diff --git a/kordac/processors/errors/NoSourceLinkError.py b/kordac/processors/errors/NoSourceLinkError.py index 787dad1c..c44ababf 100644 --- a/kordac/processors/errors/NoSourceLinkError.py +++ b/kordac/processors/errors/NoSourceLinkError.py @@ -1,5 +1,6 @@ from kordac.processors.errors.Error import Error + class NoSourceLinkError(Error): """Exception raised when no source link is found for a video @@ -14,4 +15,3 @@ def __init__(self, block, url, message): self.block = block self.url = url self.message = message - diff --git a/kordac/processors/errors/NoVideoIdentifierError.py b/kordac/processors/errors/NoVideoIdentifierError.py index b115b958..01e0d6bc 100644 --- a/kordac/processors/errors/NoVideoIdentifierError.py +++ b/kordac/processors/errors/NoVideoIdentifierError.py @@ -1,5 +1,6 @@ from kordac.processors.errors.Error import Error + class NoVideoIdentifierError(Error): """Exception raised when no identifier is found for a video @@ -14,4 +15,3 @@ def __init__(self, block, url, message): self.block = block self.url = url self.message = message - diff --git a/kordac/processors/errors/TagNotMatchedError.py b/kordac/processors/errors/TagNotMatchedError.py index 8d9b0029..a3befad5 100644 --- a/kordac/processors/errors/TagNotMatchedError.py +++ b/kordac/processors/errors/TagNotMatchedError.py @@ -1,5 +1,6 @@ from kordac.processors.errors.Error import Error + class TagNotMatchedError(Error): """Exception raised when a custom markdown tag in not matched. diff --git a/kordac/processors/errors/UnsupportedVideoPlayerError.py b/kordac/processors/errors/UnsupportedVideoPlayerError.py index 750cb4dd..90f19a65 100644 --- a/kordac/processors/errors/UnsupportedVideoPlayerError.py +++ b/kordac/processors/errors/UnsupportedVideoPlayerError.py @@ -1,5 +1,6 @@ from kordac.processors.errors.Error import Error + class UnsupportedVideoPlayerError(Error): """Exception raised when video player is not recognised @@ -14,4 +15,3 @@ def __init__(self, block, url, message): self.block = block self.url = url self.message = message - diff --git a/kordac/processors/utils.py b/kordac/processors/utils.py index e5b11d53..1a725fab 100644 --- a/kordac/processors/utils.py +++ b/kordac/processors/utils.py @@ -1,8 +1,9 @@ import re -from markdown.util import etree +from markdown.util import etree # noqa: F401 from collections import OrderedDict, defaultdict from kordac.processors.errors.ArgumentMissingError import ArgumentMissingError + def parse_argument(argument_key, arguments, default=None): ''' Search for the given argument in a string of all arguments @@ -20,6 +21,7 @@ def parse_argument(argument_key, arguments, default=None): argument_value = default return argument_value + def parse_flag(argument_key, arguments, default=False): ''' Search for the given argument in a string of all arguments, treating the argument as a flag only. @@ -38,6 +40,7 @@ def parse_flag(argument_key, arguments, default=False): argument_value = default return argument_value + def parse_arguments(processor, inputs, arguments): ''' Parses the arguments of a given input and ensures they meet the defined requirements. @@ -64,8 +67,9 @@ def parse_arguments(processor, inputs, arguments): dependencies = argument_info.get('dependencies', []) for other_argument in dependencies: if not (parse_argument(other_argument, inputs, None) is not None - or parse_flag(other_argument, inputs) is not None): - raise ArgumentMissingError(processor, argument, "{} is a required argument because {} exists.".format(other_argument, argument)) + or parse_flag(other_argument, inputs) is not None): + message = "{} is a required argument because {} exists.".format(other_argument, argument) + raise ArgumentMissingError(processor, argument, message) if is_flag: argument_values[argument] = True @@ -73,6 +77,7 @@ def parse_arguments(processor, inputs, arguments): argument_values[argument] = parse_argument(argument, inputs, None) return argument_values + def process_parameters(ext, processor, parameters, argument_values): ''' Processes a given set of arguments by the parameter definitions. @@ -103,12 +108,13 @@ def process_parameters(ext, processor, parameters, argument_values): for parameter, (condition, transform) in transformations.items(): if context[parameter] is not None: - if isinstance(condition, bool) and condition == True: + if isinstance(condition, bool) and condition: context[parameter] = transform(context[parameter]) if callable(condition) and condition(context): context[parameter] = transform(context[parameter]) return context + def find_transformation(ext, option): ''' Returns a transformation for a given string. @@ -127,6 +133,7 @@ def find_transformation(ext, option): 'relative_file_link': lambda x: ext.jinja_templates['relative-file-link'].render({'file_path': x}) }.get(option, None) + def blocks_to_string(blocks): ''' Returns a string after the blocks have been joined back together. diff --git a/kordac/utils/HeadingNode.py b/kordac/utils/HeadingNode.py index 8528ec51..53a655e7 100644 --- a/kordac/utils/HeadingNode.py +++ b/kordac/utils/HeadingNode.py @@ -1,5 +1,6 @@ from collections import namedtuple + class HeadingNode(namedtuple('HeadingNode', 'title, title_slug, level, children')): ''' Represents a heading in the heading tree. @@ -10,6 +11,7 @@ class HeadingNode(namedtuple('HeadingNode', 'title, title_slug, level, children' children: a tuple of HeadingNodes the level directly below the current node. ''' + class DynamicHeadingNode(object): ''' Represents a heading in the heading tree. diff --git a/kordac/utils/UniqueSlugify.py b/kordac/utils/UniqueSlugify.py index ec999100..dfb219a8 100644 --- a/kordac/utils/UniqueSlugify.py +++ b/kordac/utils/UniqueSlugify.py @@ -1,27 +1,30 @@ from slugify import slugify from math import log10, floor + class UniqueSlugify(object): ''' Wrapper for the python-slugify library enforcing unique slugs on each successive call. ''' - 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) + 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) def __call__(self, text): ''' @@ -31,14 +34,14 @@ def __call__(self, text): A string which is a slug (as specified by slugify) that is unique. ''' slug = slugify(text=text, - entities=self.entities, - decimal=self.decimal, - hexadecimal=self.hexadecimal, - max_length=self.max_length, - word_boundary=self.word_boundary, - separator=self.separator, - save_order=self.save_order, - stopwords=self.stopwords) + entities=self.entities, + decimal=self.decimal, + hexadecimal=self.hexadecimal, + max_length=self.max_length, + word_boundary=self.word_boundary, + separator=self.separator, + save_order=self.save_order, + stopwords=self.stopwords) count = 1 new_slug = slug while new_slug in self.uids: @@ -74,4 +77,4 @@ def clear(self): ''' Clears the known slugs used for uniqueness comparisons. ''' - uids = set() + self.uids = set() From cfa46539a701fdb9f4e9d0c78d3450caadf98f64 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Tue, 14 Mar 2017 15:41:51 +1300 Subject: [PATCH 40/86] Duplicate code fix. --- kordac/KordacExtension.py | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/kordac/KordacExtension.py b/kordac/KordacExtension.py index 43b0da1c..25662a39 100644 --- a/kordac/KordacExtension.py +++ b/kordac/KordacExtension.py @@ -102,21 +102,16 @@ def extendMarkdown(self, md, md_globals): self.postprocessors = [] self.buildGenericProcessors(md, md_globals) - for processor_data in self.preprocessors: - if processor_data[0] in self.processors: - md.preprocessors.add(processor_data[0], processor_data[1], processor_data[2]) - for processor_data in self.blockprocessors: - if processor_data[0] in self.processors: - md.parser.blockprocessors.add(processor_data[0], processor_data[1], processor_data[2]) - for processor_data in self.inlinepatterns: - if processor_data[0] in self.processors: - md.inlinePatterns.add(processor_data[0], processor_data[1], processor_data[2]) - for processor_data in self.treeprocessors: - if processor_data[0] in self.processors: - md.treeprocessors.add(processor_data[0], processor_data[1], processor_data[2]) - for processor_data in self.postprocessors: - if processor_data[0] in self.processors: - md.postprocessors.add(processor_data[0], processor_data[1], processor_data[2]) + def update_processors(processors, markdown_processors): + for processor_data in processors: + if processor_data[0] in self.processors: + markdown_processors.add(processor_data[0], processor_data[1], processor_data[2]) + + update_processors(self.preprocessors, md.preprocessors) + update_processors(self.blockprocessors, md.parser.blockprocessors) + update_processors(self.inlinepatterns, md.inlinePatterns) + update_processors(self.treeprocessors, md.treeprocessors) + update_processors(self.postprocessors, md.postprocessors) md.postprocessors.add('remove', RemovePostprocessor(md), '_end') md.postprocessors.add('beautify', BeautifyPostprocessor(md), '_end') @@ -173,11 +168,11 @@ def buildGenericProcessors(self, md, md_globals): for processor, processor_info in self.processor_info.items(): processor_class = processor_info.get('class', None) if processor_class == 'generic_tag': - processor = GenericTagBlockProcessor(processor, self, md.parser) - self.blockprocessors.insert(0, [processor, processor, '_begin']) + processor_object = GenericTagBlockProcessor(processor, self, md.parser) + self.blockprocessors.insert(0, [processor, processor_object, '_begin']) if processor_class == 'generic_container': - processor = GenericContainerBlockProcessor(processor, self, md.parser) - self.blockprocessors.append([processor, processor, '_begin']) + processor_object = GenericContainerBlockProcessor(processor, self, md.parser) + self.blockprocessors.append([processor, processor_object, '_begin']) def loadProcessorInfo(self): '''Loads processor descriptions from a json file. From ef15540de43ceeaf225b1d06159510e08002dc94 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Tue, 14 Mar 2017 15:47:51 +1300 Subject: [PATCH 41/86] Minor fixes for conditional processors. --- kordac/processors/ConditionalProcessor.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/kordac/processors/ConditionalProcessor.py b/kordac/processors/ConditionalProcessor.py index 27717080..900b9d9d 100644 --- a/kordac/processors/ConditionalProcessor.py +++ b/kordac/processors/ConditionalProcessor.py @@ -27,7 +27,8 @@ def test(self, parent, block): Returns: Return true if any conditional tag is found. ''' - return self.p_start.search(block) is not None or self.p_end.search(block) is not None + return (self.p_start.search(block) is not None + or self.p_end.search(block) is not None) def run(self, parent, blocks): ''' Replaces all conditionals with the given html template. @@ -102,16 +103,19 @@ def run(self, parent, blocks): parent.append(node) def get_content(self, blocks): - ''' Recursively parses blocks into an element tree, returning a string of the output. + ''' Recursively parses blocks into an element tree, returning + a string of the output. Args: blocks: The markdown blocks to until a new tag is found. Returns: - The next tag (regex match) the current block (string) and the content of the blocks (list of strings). + The next tag (regex match) the current block (string) and + the content of the blocks (list of strings). Raises: - TagNotMatchedError: When a sibling conditional is not closed. + TagNotMatchedError: When a sibling conditional is not + closed. ''' next_tag = None @@ -147,7 +151,8 @@ def get_content(self, blocks): the_rest = block[next_tag.end():] break elif end_tag is not None: - content_blocks.append(block[:end_tag.start()]) + if block[:end_tag.start()].strip() != '': + content_blocks.append(block[:end_tag.start()]) the_rest = block[end_tag.end():] break content_blocks.append(block) @@ -161,7 +166,8 @@ def get_content(self, blocks): return next_tag, block, content_blocks def parse_blocks(self, blocks): - '''Recursively parses blocks into an element tree, returning a string of the output. + '''Recursively parses blocks into an element tree, + returning a string of the output. Args: blocks: The markdown blocks to process. From e317ef376445b58313069d4007db54d7a3848b39 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Tue, 14 Mar 2017 15:58:23 +1300 Subject: [PATCH 42/86] fix travis yml to work. --- .travis.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index a75a0d37..d49463fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,12 +8,14 @@ python: - "3.6-dev" # 3.6 development branch # Install dependencies -install: pip install flake8 -install: pip install -r requirements.txt +install: + - pip install flake8 + - pip install -r requirements.txt # Runs test suite -script: flake8 -script: python -m kordac.tests.start_tests --travis +script: + - flake8 + - python -m kordac.tests.start_tests --travis # Stop email notifications but post to organisation Slack channel notifications: From 795ebab8e686fa4d438000bb055d995d4dcb811a Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Tue, 14 Mar 2017 16:05:00 +1300 Subject: [PATCH 43/86] flake8 updates. --- kordac/__init__.py | 3 ++- kordac/processors/__init__.py | 2 +- kordac/processors/errors/__init__.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/kordac/__init__.py b/kordac/__init__.py index 2a7b0aae..341e6af7 100644 --- a/kordac/__init__.py +++ b/kordac/__init__.py @@ -1,3 +1,4 @@ -from .Kordac import Kordac # noqa: F401 +# flake8: noqa +from .Kordac import Kordac __version__ = '0.3.1' diff --git a/kordac/processors/__init__.py b/kordac/processors/__init__.py index 8b137891..9c0fa90a 100644 --- a/kordac/processors/__init__.py +++ b/kordac/processors/__init__.py @@ -1 +1 @@ - +# flake8: noqa diff --git a/kordac/processors/errors/__init__.py b/kordac/processors/errors/__init__.py index 8b137891..9c0fa90a 100644 --- a/kordac/processors/errors/__init__.py +++ b/kordac/processors/errors/__init__.py @@ -1 +1 @@ - +# flake8: noqa From 0d5e642ff0d1eb6ba981f17d005da602a4de4fec Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Tue, 14 Mar 2017 21:16:27 +1300 Subject: [PATCH 44/86] Add link to Scratch block project text generator --- docs/source/processors/scratch.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/source/processors/scratch.rst b/docs/source/processors/scratch.rst index b9881c4b..15e84b63 100644 --- a/docs/source/processors/scratch.rst +++ b/docs/source/processors/scratch.rst @@ -29,6 +29,8 @@ set at the start. You can test the output of your Scratch block text at `scratchblocks.github.io`_. +You can also generate Scratch block text from a published Scratch project at +`scratchblocks.github.io/generator/`_. .. warning:: @@ -114,4 +116,5 @@ would result in: .. _Scratch Block Plugin notation: https://wiki.scratch.mit.edu/wiki/Block_Plugin .. _scratchblocks.github.io: https://scratchblocks.github.io/#when%20flag%20clicked%0Aclear%0Aforever%0Apen%20down%0Aif%20%3C%3Cmouse%20down%3F%3E%20and%20%3Ctouching%20%5Bmouse-pointer%20v%5D%3F%3E%3E%20then%0Aswitch%20costume%20to%20%5Bbutton%20v%5D%0Aelse%0Aadd%20(x%20position)%20to%20%5Blist%20v%5D%0Aend%0Amove%20(foo)%20steps%0Aturn%20ccw%20(9)%20degrees +.. _scratchblocks.github.io/generator/: https://scratchblocks.github.io/generator/ .. _scratchblocks: https://github.com/scratchblocks/scratchblocks From b3263caa164124e4095d10a9ef7290b89f85d79c Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Wed, 15 Mar 2017 11:53:53 +1300 Subject: [PATCH 45/86] Extracted processor building out of extendMarkdown. --- kordac/KordacExtension.py | 53 +++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/kordac/KordacExtension.py b/kordac/KordacExtension.py index ecfe8161..6987eda2 100644 --- a/kordac/KordacExtension.py +++ b/kordac/KordacExtension.py @@ -77,31 +77,7 @@ def extendMarkdown(self, md, md_globals): md: An instance of the markdown object to extend. md_globals: Global variables in the markdown module namespace. ''' - self.preprocessors = [ - ['comment', CommentPreprocessor(self, md), '_begin'], - ['save-title', SaveTitlePreprocessor(self, md), '_end'], - ['remove-title', RemoveTitlePreprocessor(self, md), '_end'], - ] - self.blockprocessors = [ - # Markdown overrides - ['heading', HeadingBlockProcessor(self, md.parser), ' Date: Wed, 15 Mar 2017 15:13:25 +1300 Subject: [PATCH 46/86] Added documentation for generic processors. --- docs/source/contributing.rst | 173 ++++++++++++++++++++++--- docs/source/processors/boxed-text.rst | 2 + docs/source/processors/button-link.rst | 2 + 3 files changed, 162 insertions(+), 15 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 4599d8ac..95d32f85 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -102,11 +102,11 @@ The items of interest are: - ``KordacExtension()`` - This is the main class of the project, and inherits the ``Extension`` class from Markdown. It loads all of the processor information, loads the template files and clears and populates the attributes to be returned by the ``KordacResult`` object. -- ``Processors/`` - There is a different processor for each tag. A processor uses it's corresponding regex loaded from ``processor-info.json`` to find matches in the text, and uses the given arguments in the matched tag to populate and output it's html template. +- ``Processors/`` - There is a different processor for each tag. A processor uses it's corresponding description loaded from ``processor-info.json`` to find matches in the text, and uses the given arguments in the matched tag to populate and output it's html template. - ``html-templates/`` - The html templates (using the Jinja2 template engine) with variable arguments to be populated by processors. -- ``processor-info.json`` - Every processor is listed in this file, and will at least contain a regex pattern to match it's corresponding tag. Most will also define required and optional parameters, these correspond to arguments in the tag's html template. +- ``processor-info.json`` - Every processor is listed in this file, and will at least contain a class determining where it is custom or generic, where custom processors will have a pattern to match it's corresponding tag. Most will also define required and optional parameters, these correspond to arguments in the tag's html template. - ``tests/`` - explained in the Test Suite section further down the page. @@ -117,7 +117,161 @@ It is important to note that Kordac is not just a Markdown Extension, it is a wr Creating a New Processor ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -To create a new processor, a good place to start is the `Extension API`_ page of the Python Markdown docs, and you can also read the `source code`_ itself. +There are two ways distinctly different ways to create a new processor. The simplist way is to make use of the provided generic processors and define the new processor in the ``processor-info.json`` file, while more complex processors reqiure additional source code. Complex processors should be considered when custom functionality is required that cannot be achieved with generic processors. + +In all cases new processors should: + +- Be thoroughly tested (see the section on :ref:`testing `) +- Have clear and accurate documentation. See the docs on other processors for the preferred format. Your docs should include: + + - An example of the tag in markdown + - Required parameters + - Optional parameters + - Examples + - Examples of overriding the html + +We recommend writing documentation and test cases before you even write the processor itself as this will give you a clear idea of how a processor in Kordac should behave. + +Generic Processors +************************************** + +There are two types of generic processors: + + - tags (``generic_tag``): which match ``{ }`` in the markdown text replacing with the given html-template. + - containers (``generic_container``): which are a pair of tags which capture the content between the tags for the html-template. A generic container's opening tag specifies the arguments, while the closing tag only has the ``end`` argument allowing for the content to contain generic containers. + +To create a new processor that uses the generic processors the processor must be added to the ``processor-info.json`` file and an associated html-template must be created. + +How to make a JSON Definition +++++++++++++++++++++++++++++++++++++++ + +The json description of a generic processor must contain the attributes: + + - ``class``: Either ``generic_tag`` or ``generic_container`` for a generic processor. + - ``arguments``: An object describing arguments passed to the tag. + - ``template_parameters``: An object describing template parameters. + - (Optional) ``template_name``: A custom name for the html-template to use. Defaults to the processor name otherwise. + +The ``argument`` parameter is a dictionary (or object) containing argument name, argument-info pairs. Where the argument-info contains the attributes: + + - ``required``: ``true`` if the argument must be set or ``false`` otherwise. + - (Optional) ``dependencies``: A list of argument-names that must also be set if this argument is used. + +These arguments are transformed for use in the html-template by the ``template_parameters`` attribute. This attribute is similar to the ``argument`` attribute by containing parameter name, parameter-info pairs. Where the parameter-info contains the attributes: + + - ``argument``: The name of the argument to retrieve the value of to use/transform into the parameter value. + - (Optional) ``default``: The value the parameter defaults to if the argument is not given otherwise defaults to ``None``. + - (Optional) ``transform``: The name of the transform to modify the argument value by or defaults to null for no transformation. The avaliable transforms are detailed below. + - (Optional) ``transform_condition``: A function that takes the context after parameters are set but before transformation (The transformations are done in order they appear in the json document). If the function returns ``True`` then the transformation is applied. + +For a generic container type processor the ``argument`` of the parameter may be ``content`` which is the captured content between the start and end tags. + +The set of currently avaliable transformations for the ``transform`` attribute are: + + - ``str.lower``: Converts the string into a lowercase version. + - ``str.upper``: Converts the string into an UPPERCASE version. + - ``relative_file_link``: Applies the relative-file-link html-template to the argument. + +Examples +++++++++++++++++++++++++++++++++++++++ + +A generic tag processor, is a simple single line tag that uses the given arguments as parameters to an html template. An example of a processor that uses the generic tag processor is the :ref:`button-link ` processor which is described in the json as: + +.. code-block:: none + + "button-link": { + "class": "generic_tag", + "arguments": { + "link": { + "required": true, + "dependencies": [] + }, + "text": { + "required": true, + "dependencies": [] + }, + "file": { + "required": false, + "dependencies": [] + } + }, + "template_parameters": { + "file": { + "argument": "file", + "transform": "str.lower", + "default": "no" + }, + "link": { + "argument": "link", + "transform": "relative_file_link", + "transform_condition": "lambda context: context['file'] == 'yes'" + }, + "text": { + "argument": "text", + "transform": null + } + } + } + +And has the following html-template: + +.. literalinclude:: ../../kordac/html-templates/button-link.html + :language: css+jinja + +This enables the following markdown: + +.. literalinclude:: ../../kordac/tests/assets/button-link/doc_example_basic_usage.md + :language: none + +To generate the output: + +.. literalinclude:: ../../kordac/tests/assets/button-link/doc_example_basic_usage_expected.html + :language: html + +A generic container processor, a pair of matching tags where one opens the container and one closes the container. The start tag gives the arguments as parameters to an html template. An the end tag is used to capture the content between the tags to be used as an additional parameter to the html template. An example of a processor that uses the generic container processor is the :ref:`boxed-text ` processor which is described in the json as: + +.. code-block:: none + + "boxed-text": { + "class": "generic_container", + "arguments": { + "indented": { + "required": false, + "dependencies": [] + } + }, + "template_name": "boxed-text", + "template_parameters": { + "indented": { + "argument": "indented", + "transform": "str.lower" + }, + "text": { + "argument": "content", + "transform": null + } + } + } + +And has the following html-template: + +.. literalinclude:: ../../kordac/html-templates/boxed-text.html + :language: css+jinja + +This enables the following markdown: + +.. literalinclude:: ../../kordac/tests/assets/boxed-text/doc_example_basic_usage.md + :language: none + +To generate the output: + +.. literalinclude:: ../../kordac/tests/assets/boxed-text/doc_example_basic_usage_expected.html + :language: html + +Custom Processors +************************************** + +To create a custom processor, the ``class`` attribute of the processor in the ``processor-info.json`` file must be ``"custom"``. A good place to start when programming a new processor is the `Extension API`_ page of the Python Markdown docs, and you can also read the `source code`_ itself. There are several different kinds of processors in Python Markdown, each serving a slightly different purpose. We recommend reading the API docs to determine which processor best suits your purpose. Kordac currently makes use of ``preprocessor``, ``blockprocessor``, ``inlinepattern``, ``treeprocessor`` and ``postprocessor``, but you are welcome to use another type of processor if it better suits the task. @@ -132,18 +286,7 @@ The logic for each processor belongs in the ``processors/`` directory, and there - The relevant list in ``extendMarkdown()`` in ``KordacExtension.py`` (see `OrderedDict in the Markdown API docs`_ for manipulating processor order) - The processor's template should be added to ``html-templates`` using the Jinja2 template engine syntax for variable parameters -The new processors should also: - -- Be thoroughly tested (see the section below) -- Have clear and accurate documentation. See the docs on other processors for the preferred format. Your docs should include: - - An example of the tag in markdown - - Required parameters - - Optional parameters - - Examples - - Examples of overriding the html - -We recommend writing documentation and test cases before you even write the processor itself as this will give you a clear idea of how a processor in Kordac should behave. - +.. _the-test-suite: The Test Suite ======================================= diff --git a/docs/source/processors/boxed-text.rst b/docs/source/processors/boxed-text.rst index 69441f02..1730b207 100644 --- a/docs/source/processors/boxed-text.rst +++ b/docs/source/processors/boxed-text.rst @@ -1,3 +1,5 @@ +.. _boxed-text: + Boxed Text ####################################### diff --git a/docs/source/processors/button-link.rst b/docs/source/processors/button-link.rst index 797853c5..6365858b 100644 --- a/docs/source/processors/button-link.rst +++ b/docs/source/processors/button-link.rst @@ -1,3 +1,5 @@ +.. _button-link: + Button Link ####################################### From e88c5622d8c74985571a178922bdd5016c417042 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Mon, 20 Mar 2017 11:39:35 +1300 Subject: [PATCH 47/86] PR updates --- docs/source/contributing.rst | 4 ++-- kordac/Kordac.py | 9 +++++++-- kordac/KordacExtension.py | 10 ++++++++++ kordac/processors/ConditionalProcessor.py | 8 +++++--- kordac/processors/GenericContainerBlockProcessor.py | 6 +++--- kordac/processors/GenericTagBlockProcessor.py | 6 +++--- kordac/processors/ImageBlockProcessor.py | 8 ++++---- kordac/processors/InteractiveBlockProcessor.py | 7 +++---- kordac/processors/RelativeLinkPattern.py | 9 +++++++-- kordac/processors/RemovePostprocessor.py | 6 +++++- kordac/processors/errors/ArgumentMissingError.py | 12 ++++++------ kordac/processors/errors/Error.py | 4 ++-- kordac/processors/errors/InvalidParameterError.py | 12 ++++++------ kordac/processors/errors/NoSourceLinkError.py | 10 +++++----- kordac/processors/errors/NoVideoIdentifierError.py | 10 +++++----- kordac/processors/errors/TagNotMatchedError.py | 10 +++++----- .../processors/errors/UnsupportedVideoPlayerError.py | 10 +++++----- 17 files changed, 83 insertions(+), 58 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 95d32f85..0a9f3702 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -106,7 +106,7 @@ The items of interest are: - ``html-templates/`` - The html templates (using the Jinja2 template engine) with variable arguments to be populated by processors. -- ``processor-info.json`` - Every processor is listed in this file, and will at least contain a class determining where it is custom or generic, where custom processors will have a pattern to match it's corresponding tag. Most will also define required and optional parameters, these correspond to arguments in the tag's html template. +- ``processor-info.json`` - Every processor is listed in this file, and will at least contain a class determining whether it is custom or generic, where custom processors will have a pattern to match it's corresponding tag. Most will also define required and optional parameters, these correspond to arguments in the tag's html template. - ``tests/`` - explained in the Test Suite section further down the page. @@ -228,7 +228,7 @@ To generate the output: .. literalinclude:: ../../kordac/tests/assets/button-link/doc_example_basic_usage_expected.html :language: html -A generic container processor, a pair of matching tags where one opens the container and one closes the container. The start tag gives the arguments as parameters to an html template. An the end tag is used to capture the content between the tags to be used as an additional parameter to the html template. An example of a processor that uses the generic container processor is the :ref:`boxed-text ` processor which is described in the json as: +A generic container processor, a pair of matching tags where one opens the container and one closes the container. The start tag gives the arguments as parameters to an html template. The end tag is used to capture the content between the tags to be used as an additional parameter to the html template. An example of a processor that uses the generic container processor is the :ref:`boxed-text ` processor which is described in the json as: .. code-block:: none diff --git a/kordac/Kordac.py b/kordac/Kordac.py index f8048d07..efff8279 100644 --- a/kordac/Kordac.py +++ b/kordac/Kordac.py @@ -92,7 +92,8 @@ def update_templates(self, html_templates): self.create_converter() def clear_templates(self): - '''Set the template dictionary to it's original values.''' + '''Set the template dictionary to it's original values. + ''' self.html_templates = {} self.create_converter() @@ -132,7 +133,11 @@ def __init__(self, html_string, title, required_files, heading_tree, required_gl html_string: A string of HTML text. title: The first heading encountered when converting. required_files: Dictionary of required file types to sets - of paths. + of paths. + heading_tree: A tuple of HeadingNodes which represent the + heading structure of the document. + required_glossary_terms: A dictionary of glossary terms to + a list of tuples containing reference text and slugs. ''' self.html_string = html_string self.title = title diff --git a/kordac/KordacExtension.py b/kordac/KordacExtension.py index 6987eda2..f6f4b335 100644 --- a/kordac/KordacExtension.py +++ b/kordac/KordacExtension.py @@ -121,6 +121,9 @@ def loadJinjaTemplates(self, custom_templates): Args: custom_templates: a dictionary of names to custom templates which are used to override default templates. + Returns: + A dictionary of tuples containing template-names to + compiled jinja templated. ''' templates = {} env = Environment( @@ -138,6 +141,13 @@ def loadJinjaTemplates(self, custom_templates): return templates def buildProcessors(self, md, md_globals): + ''' + Populates internal variables for processors. This should not be + called externally, this is used by the extendMarkdown method. + Args: + md: An instance of the markdown object being extended. + md_globals: Global variables in the markdown module namespace. + ''' self.preprocessors = [ ['comment', CommentPreprocessor(self, md), '_begin'], ['save-title', SaveTitlePreprocessor(self, md), '_end'], diff --git a/kordac/processors/ConditionalProcessor.py b/kordac/processors/ConditionalProcessor.py index 900b9d9d..669edf9e 100644 --- a/kordac/processors/ConditionalProcessor.py +++ b/kordac/processors/ConditionalProcessor.py @@ -19,7 +19,8 @@ def __init__(self, ext, *args, **kwargs): super().__init__('conditional', ext, *args, **kwargs) def test(self, parent, block): - ''' Tests if the block if it contains any type of conditional types. + ''' Tests if the block if it contains any type of conditional + types. Args: parent: The parent element of the html tree. @@ -35,7 +36,8 @@ def run(self, parent, blocks): Allows for recursively defined if statements. Args: - lines: A list of lines of the Markdown document to be converted. + lines: A list of lines of the Markdown document to be + converted. Returns: Markdown document with comments removed. Raises: @@ -115,7 +117,7 @@ def get_content(self, blocks): Raises: TagNotMatchedError: When a sibling conditional is not - closed. + closed. ''' next_tag = None diff --git a/kordac/processors/GenericContainerBlockProcessor.py b/kordac/processors/GenericContainerBlockProcessor.py index d200a4bb..f3f0f1b5 100644 --- a/kordac/processors/GenericContainerBlockProcessor.py +++ b/kordac/processors/GenericContainerBlockProcessor.py @@ -26,7 +26,7 @@ def test(self, parent, block): Args: parent: The parent node of the element tree that children - will reside in. + will reside in. block: The block to be tested. Returns: @@ -39,9 +39,9 @@ def run(self, parent, blocks): Args: parent: The parent node of the element tree that children - will reside in. + will reside in. blocks: A list of strings of the document, where the - first block tests true. + first block tests true. ''' block = blocks.pop(0) diff --git a/kordac/processors/GenericTagBlockProcessor.py b/kordac/processors/GenericTagBlockProcessor.py index 1a0cb8a2..1414be08 100644 --- a/kordac/processors/GenericTagBlockProcessor.py +++ b/kordac/processors/GenericTagBlockProcessor.py @@ -27,7 +27,7 @@ def test(self, parent, block): Args: parent: The parent node of the element tree that children - will reside in. + will reside in. block: The block to be tested. Returns: @@ -40,9 +40,9 @@ def run(self, parent, blocks): Args: parent: The parent node of the element tree that children - will reside in. + will reside in. blocks: A list of strings of the document, where the - first block tests true. + first block tests true. ''' block = blocks.pop(0) diff --git a/kordac/processors/ImageBlockProcessor.py b/kordac/processors/ImageBlockProcessor.py index 90a0ea06..4f5ab730 100644 --- a/kordac/processors/ImageBlockProcessor.py +++ b/kordac/processors/ImageBlockProcessor.py @@ -12,7 +12,7 @@ def __init__(self, ext, *args, **kwargs): ''' Args: ext: The parent node of the element tree that children will - reside in. + reside in. args: Arguments handed to the super class. kwargs: Arguments handed to the super class. ''' @@ -26,7 +26,7 @@ def test(self, parent, block): Args: parent: The parent node of the element tree that children - will reside in. + will reside in. block: The block to be tested. Returns: True if the block matches the pattern regex of a HeadingBlock. @@ -39,9 +39,9 @@ def run(self, parent, blocks): Args: parent: The parent node of the element tree that children - will reside in. + will reside in. blocks: A list of strings of the document, where the - first block tests true. + first block tests true. ''' block = blocks.pop(0) diff --git a/kordac/processors/InteractiveBlockProcessor.py b/kordac/processors/InteractiveBlockProcessor.py index 9ef199a5..59c936bd 100644 --- a/kordac/processors/InteractiveBlockProcessor.py +++ b/kordac/processors/InteractiveBlockProcessor.py @@ -25,9 +25,8 @@ def test(self, parent, block): Args: parent: The parent node of the element tree that children - will reside in. + will reside in. block: The block to be tested. - Returns: True if the block matches the pattern regex of a HeadingBlock. ''' @@ -39,9 +38,9 @@ def run(self, parent, blocks): Args: parent: The parent node of the element tree that children - will reside in. + will reside in. blocks: A list of strings of the document, where the - first block tests true. + first block tests true. ''' block = blocks.pop(0) diff --git a/kordac/processors/RelativeLinkPattern.py b/kordac/processors/RelativeLinkPattern.py index b7ea4d6b..af537ec4 100644 --- a/kordac/processors/RelativeLinkPattern.py +++ b/kordac/processors/RelativeLinkPattern.py @@ -4,7 +4,7 @@ class RelativeLinkPattern(Pattern): - """Return a link element from the given match. + '''Return a link element from the given match. Only matches: - Markdown links using []() syntax. @@ -15,9 +15,13 @@ class RelativeLinkPattern(Pattern): - 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) @@ -25,6 +29,7 @@ def __init__(self, ext, *args, **kwargs): 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: diff --git a/kordac/processors/RemovePostprocessor.py b/kordac/processors/RemovePostprocessor.py index 746bb0cb..3884ca16 100644 --- a/kordac/processors/RemovePostprocessor.py +++ b/kordac/processors/RemovePostprocessor.py @@ -8,13 +8,17 @@ class RemovePostprocessor(Postprocessor): ''' def __init__(self, *args, **kwargs): + ''' Creates a new RemovePostprocessor. + ''' super().__init__(*args, **kwargs) def run(self, text): ''' + Deletes removes tags from the text, without changing sibling + elements. Args: text: A string of the document. Returns: The document text with all remove tag removed. ''' - return text.replace('', '').replace('', '') + return text.replace('\n', '').replace('\n', '').replace('', '').replace('', '') diff --git a/kordac/processors/errors/ArgumentMissingError.py b/kordac/processors/errors/ArgumentMissingError.py index 909c11ea..811f0086 100644 --- a/kordac/processors/errors/ArgumentMissingError.py +++ b/kordac/processors/errors/ArgumentMissingError.py @@ -2,14 +2,14 @@ class ArgumentMissingError(Error): - """Exception raised when a custom markdown tag in not matched. + '''Exception raised when a custom markdown tag in not matched. Attributes: - tag -- tag which was not matched - block -- block where tag was not matched - argument -- the argument that was not found - message -- explanation of why error was thrown - """ + tag: tag which was not matched + block: block where tag was not matched + argument: the argument that was not found + message: explanation of why error was thrown + ''' def __init__(self, tag, argument, message): super().__init__(message) diff --git a/kordac/processors/errors/Error.py b/kordac/processors/errors/Error.py index 5d502365..18c27f93 100644 --- a/kordac/processors/errors/Error.py +++ b/kordac/processors/errors/Error.py @@ -1,5 +1,5 @@ class Error(Exception): - """Base class for Errors. + '''Base class for Errors. (Exceptions from external sources such as inputs). - """ + ''' pass diff --git a/kordac/processors/errors/InvalidParameterError.py b/kordac/processors/errors/InvalidParameterError.py index 7ceff206..692d0b23 100644 --- a/kordac/processors/errors/InvalidParameterError.py +++ b/kordac/processors/errors/InvalidParameterError.py @@ -2,14 +2,14 @@ class InvalidParameterError(Error): - """Exception raised when an invalid parameter value is found. + '''Exception raised when an invalid parameter value is found. Attributes: - tag -- tag which was not matched - block -- block where tag was not matched - parameter -- the parameter that was not found - message -- explanation of why error was thrown - """ + tag: tag which was not matched + block: block where tag was not matched + parameter: the parameter that was not found + message: explanation of why error was thrown + ''' def __init__(self, tag, parameter, message): super().__init__(message) diff --git a/kordac/processors/errors/NoSourceLinkError.py b/kordac/processors/errors/NoSourceLinkError.py index c44ababf..a74021d9 100644 --- a/kordac/processors/errors/NoSourceLinkError.py +++ b/kordac/processors/errors/NoSourceLinkError.py @@ -2,13 +2,13 @@ class NoSourceLinkError(Error): - """Exception raised when no source link is found for a video + '''Exception raised when no source link is found for a video Attributes: - block -- block where tag was not matched - url -- original url - message -- explanation of why error was thrown - """ + block: block where tag was not matched + url: original url + message: explanation of why error was thrown + ''' def __init__(self, block, url, message): super().__init__(message) diff --git a/kordac/processors/errors/NoVideoIdentifierError.py b/kordac/processors/errors/NoVideoIdentifierError.py index 01e0d6bc..2b1d0fc0 100644 --- a/kordac/processors/errors/NoVideoIdentifierError.py +++ b/kordac/processors/errors/NoVideoIdentifierError.py @@ -2,13 +2,13 @@ class NoVideoIdentifierError(Error): - """Exception raised when no identifier is found for a video + '''Exception raised when no identifier is found for a video Attributes: - block -- block where tag was not matched - url -- original url - message -- explanation of why error was thrown - """ + block: block where tag was not matched + url: original url + message: explanation of why error was thrown + ''' def __init__(self, block, url, message): super().__init__(message) diff --git a/kordac/processors/errors/TagNotMatchedError.py b/kordac/processors/errors/TagNotMatchedError.py index a3befad5..86d5f8fd 100644 --- a/kordac/processors/errors/TagNotMatchedError.py +++ b/kordac/processors/errors/TagNotMatchedError.py @@ -2,13 +2,13 @@ class TagNotMatchedError(Error): - """Exception raised when a custom markdown tag in not matched. + '''Exception raised when a custom markdown tag in not matched. Attributes: - tag -- tag which was not matched - block -- block where tag was not matched - message -- explanation of why error was thrown - """ + tag: tag which was not matched + block: block where tag was not matched + message: explanation of why error was thrown + ''' def __init__(self, tag, block, message): super().__init__(message) diff --git a/kordac/processors/errors/UnsupportedVideoPlayerError.py b/kordac/processors/errors/UnsupportedVideoPlayerError.py index 90f19a65..dd3bc4b3 100644 --- a/kordac/processors/errors/UnsupportedVideoPlayerError.py +++ b/kordac/processors/errors/UnsupportedVideoPlayerError.py @@ -2,13 +2,13 @@ class UnsupportedVideoPlayerError(Error): - """Exception raised when video player is not recognised + '''Exception raised when video player is not recognised Attributes: - block -- block where tag was not matched - url -- original url - message -- explanation of why error was thrown - """ + block: block where tag was not matched + url: original url + message: explanation of why error was thrown + ''' def __init__(self, block, url, message): super().__init__(message) From f1708e6800131872b3ea503e5fb641c4a5290f13 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Mon, 20 Mar 2017 11:45:31 +1300 Subject: [PATCH 48/86] PR updates --- kordac/processors/BeautifyPostprocessor.py | 2 ++ kordac/processors/HeadingBlockProcessor.py | 2 -- kordac/processors/ImageBlockProcessor.py | 2 -- kordac/processors/JinjaPostprocessor.py | 2 ++ kordac/processors/RelativeLinkPattern.py | 4 ++-- kordac/processors/RemoveTitlePreprocessor.py | 3 ++- kordac/processors/ScratchTreeprocessor.py | 2 -- 7 files changed, 8 insertions(+), 9 deletions(-) diff --git a/kordac/processors/BeautifyPostprocessor.py b/kordac/processors/BeautifyPostprocessor.py index 64e854ad..6d5fda22 100644 --- a/kordac/processors/BeautifyPostprocessor.py +++ b/kordac/processors/BeautifyPostprocessor.py @@ -11,6 +11,8 @@ class BeautifyPostprocessor(Postprocessor): ''' def __init__(self, *args, **kwargs): + ''' Creates a new BeautifyPostprocessor. + ''' super().__init__(*args, **kwargs) self.pre_pattern = re.compile(r'
    .*?
    ', re.DOTALL) self.code_pattern = re.compile(r'(?P.*?)', re.DOTALL) diff --git a/kordac/processors/HeadingBlockProcessor.py b/kordac/processors/HeadingBlockProcessor.py index 4117ccc7..67c22dac 100644 --- a/kordac/processors/HeadingBlockProcessor.py +++ b/kordac/processors/HeadingBlockProcessor.py @@ -14,8 +14,6 @@ def __init__(self, ext, *args, **kwargs): ''' Args: ext: The KordacExtension object. - args: Arguments handed to the super class. - kwargs: Arguments handed to the super class. ''' super().__init__(*args, **kwargs) self.processor = 'heading' diff --git a/kordac/processors/ImageBlockProcessor.py b/kordac/processors/ImageBlockProcessor.py index 4f5ab730..5d5237ca 100644 --- a/kordac/processors/ImageBlockProcessor.py +++ b/kordac/processors/ImageBlockProcessor.py @@ -13,8 +13,6 @@ def __init__(self, ext, *args, **kwargs): Args: ext: The parent node of the element tree that children will reside in. - args: Arguments handed to the super class. - kwargs: Arguments handed to the super class. ''' super().__init__('image', ext, *args, **kwargs) self.pattern = re.compile(ext.processor_info[self.processor]['pattern']) diff --git a/kordac/processors/JinjaPostprocessor.py b/kordac/processors/JinjaPostprocessor.py index c77fb395..28739eb4 100644 --- a/kordac/processors/JinjaPostprocessor.py +++ b/kordac/processors/JinjaPostprocessor.py @@ -9,6 +9,8 @@ class JinjaPostprocessor(Postprocessor): ''' def __init__(self, *args, **kwargs): + ''' Creates a new JinjaPostprocessor. + ''' super().__init__(*args, **kwargs) def run(self, text): diff --git a/kordac/processors/RelativeLinkPattern.py b/kordac/processors/RelativeLinkPattern.py index af537ec4..4d31bd74 100644 --- a/kordac/processors/RelativeLinkPattern.py +++ b/kordac/processors/RelativeLinkPattern.py @@ -28,8 +28,8 @@ def __init__(self, ext, *args, **kwargs): 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. + ''' 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: diff --git a/kordac/processors/RemoveTitlePreprocessor.py b/kordac/processors/RemoveTitlePreprocessor.py index 772203d4..8f7ac9e0 100644 --- a/kordac/processors/RemoveTitlePreprocessor.py +++ b/kordac/processors/RemoveTitlePreprocessor.py @@ -3,7 +3,8 @@ class RemoveTitlePreprocessor(Preprocessor): - '''Removes the first found title from the given document.''' + '''Removes the first found title from the given document. + ''' def __init__(self, ext, *args, **kwargs): ''' diff --git a/kordac/processors/ScratchTreeprocessor.py b/kordac/processors/ScratchTreeprocessor.py index d78d7ca7..51a89bbf 100644 --- a/kordac/processors/ScratchTreeprocessor.py +++ b/kordac/processors/ScratchTreeprocessor.py @@ -24,8 +24,6 @@ def __init__(self, ext, *args, **kwargs): Args: ext: The parent node of the element tree that children will reside in. - args: Arguments handed to the super class. - kwargs: Arguments handed to the super class. ''' super().__init__(*args, **kwargs) self.processor = 'scratch' From 8505d3450c15abd9d9a492a833301cdcf2c1d195 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Mon, 20 Mar 2017 12:02:45 +1300 Subject: [PATCH 49/86] flake8 fixes --- kordac/processors/RemovePostprocessor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kordac/processors/RemovePostprocessor.py b/kordac/processors/RemovePostprocessor.py index 3884ca16..c696fd1c 100644 --- a/kordac/processors/RemovePostprocessor.py +++ b/kordac/processors/RemovePostprocessor.py @@ -21,4 +21,5 @@ def run(self, text): Returns: The document text with all remove tag removed. ''' - return text.replace('\n', '').replace('\n', '').replace('', '').replace('', '') + text = text.replace('\n', '').replace('\n', '') + return text.replace('', '').replace('', '') From 643579a67e566408fc099dae56cdd6264bbb70e0 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Wed, 22 Mar 2017 16:37:08 +1300 Subject: [PATCH 50/86] Lock requirements. --- requirements.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/requirements.txt b/requirements.txt index 0283ef9f..dc3c560a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,9 @@ # Required dependencies for Kordac (installed automatically in setup.py) -markdown>=2.6.8 -bs4>=0.0.1 -Jinja2>=2.9.5 -python-slugify>=1.2.1 +markdown==2.6.8 +beautifulsoup4==4.5.3 +Jinja2==2.9.5 +python-slugify==1.2.1 # Required dependencies for building documentation -sphinx>=1.5.2 -sphinx_rtd_theme>=0.1.9 +sphinx==1.5.2 +sphinx_rtd_theme==0.1.9 From 6c4592d6608dca7376b7a19fb44f2d74223a42ea Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Wed, 22 Mar 2017 18:05:29 +1300 Subject: [PATCH 51/86] Initial documenting of unittests. --- kordac/tests/BaseTest.py | 10 ++--- kordac/tests/BeautifyTest.py | 17 ++++++- kordac/tests/BoxedTextTest.py | 30 ++++++++++++- kordac/tests/ButtonLinkTest.py | 41 ++++++++++++----- kordac/tests/CommentTest.py | 26 +++++++++-- kordac/tests/ConditionalTest.py | 45 +++++++++++++------ ...verride_html.md => example_elif_noelse.md} | 0 ...html => example_elif_noelse_expected.html} | 0 ...html => example_elif_noelse_template.html} | 0 9 files changed, 131 insertions(+), 38 deletions(-) rename kordac/tests/assets/conditional/{doc_example2_override_html.md => example_elif_noelse.md} (100%) rename kordac/tests/assets/conditional/{doc_example2_override_html_expected.html => example_elif_noelse_expected.html} (100%) rename kordac/tests/assets/conditional/{doc_example2_override_html_template.html => example_elif_noelse_template.html} (100%) diff --git a/kordac/tests/BaseTest.py b/kordac/tests/BaseTest.py index cfc40545..259c0372 100644 --- a/kordac/tests/BaseTest.py +++ b/kordac/tests/BaseTest.py @@ -1,24 +1,24 @@ import unittest class BaseTest(unittest.TestCase): - """A base test class for individual test classes""" + '''A base test class for individual test classes.''' def __init__(self, *args, **kwargs): - """Creates BaseTest Case class + '''Creates BaseTest Case class. Create class inheiriting from TestCase, while also storing the path to test files and the maxiumum difference to display on test failures. - """ + ''' unittest.TestCase.__init__(self, *args, **kwargs) self.test_file_path = 'kordac/tests/assets/{test_type}/{filename}' self.maxDiff = None def read_test_file(self, test_type, filename, strip=False): - """Returns a string for a given file + '''Returns a string for a given file. This function reads a file from a given filename in UTF-8 encoding. - """ + ''' file_path = self.test_file_path.format(test_type=test_type, filename=filename) file_object = open(file_path, encoding="utf-8") text = file_object.read() diff --git a/kordac/tests/BeautifyTest.py b/kordac/tests/BeautifyTest.py index c63874f3..699a1d59 100644 --- a/kordac/tests/BeautifyTest.py +++ b/kordac/tests/BeautifyTest.py @@ -6,12 +6,19 @@ from kordac.tests.ProcessorTest import ProcessorTest class BeautifyTest(ProcessorTest): + '''The major concern with beautifying is that preformatted tags and + code blocks are unchanged. The tests here cover these cases. + ''' + def __init__(self, *args, **kwargs): - """Set processor name in class for file names""" + '''Set processor name in class for file names. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'beautify' def test_example_inline_code(self): + '''Tests to see that inline code formatting is unchanged. + ''' test_string = self.read_test_file(self.processor_name, 'example_inline_code.md') converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) @@ -19,6 +26,8 @@ def test_example_inline_code(self): self.assertEqual(expected_string, converted_test_string) def test_example_preformatted_code(self): + '''Tests to ensure that preformatted tag content is unchanged. + ''' test_string = self.read_test_file(self.processor_name, 'example_preformatted_code.md') converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) @@ -26,6 +35,9 @@ def test_example_preformatted_code(self): self.assertEqual(expected_string, converted_test_string) def test_example_preformatted_code_with_extension(self): + '''Tests to ensure that the fenced_code extension does not + change output to retain compatibility. + ''' kordac_extension = KordacExtension([self.processor_name], {}, ['markdown.extensions.fenced_code']) test_string = self.read_test_file(self.processor_name, 'example_preformatted_code_with_extension.md') @@ -34,6 +46,9 @@ def test_example_preformatted_code_with_extension(self): self.assertEqual(expected_string, converted_test_string) def text_example_mixed_code_types(self): + '''Tests that all types of code blocks remain unchanged when + used together. + ''' test_string = self.read_test_file(self.processor_name, 'example_mixed_code_types.md') converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) diff --git a/kordac/tests/BoxedTextTest.py b/kordac/tests/BoxedTextTest.py index 923888d2..226eb66d 100644 --- a/kordac/tests/BoxedTextTest.py +++ b/kordac/tests/BoxedTextTest.py @@ -7,10 +7,15 @@ class BoxedTextTest(ProcessorTest): - """ - """ + '''The BoxedText processor inherits from the generic container. + The tests contained here test that arguments and the output + (html-template) work as expected. + ''' def __init__(self, *args, **kwargs): + '''Sets up a generic container to test that the matches are + occuring appropriately. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'boxed-text' self.ext = Mock() @@ -19,6 +24,9 @@ def __init__(self, *args, **kwargs): self.block_processor = GenericContainerBlockProcessor(self.processor_name, self.ext, Mock()) def test_no_boxed_text(self): + '''Tests that the text containing the processor name is + not matched. + ''' test_string = self.read_test_file(self.processor_name, 'no_boxed_text.md') blocks = self.to_blocks(test_string) @@ -29,6 +37,9 @@ def test_no_boxed_text(self): self.assertEqual(expected_string, converted_test_string) def test_single_boxed_text(self): + '''Tests that the most generic case of a single match is found + with generic content contained within. + ''' test_string = self.read_test_file(self.processor_name, 'single_boxed_text.md') blocks = self.to_blocks(test_string) @@ -39,6 +50,8 @@ def test_single_boxed_text(self): self.assertEqual(expected_string, converted_test_string) def test_indented_boxed_text(self): + '''Tests that the indented argument works as appropriate. + ''' test_string = self.read_test_file(self.processor_name, 'indented_boxed_text.md') blocks = self.to_blocks(test_string) @@ -49,6 +62,9 @@ def test_indented_boxed_text(self): self.assertEqual(expected_string, converted_test_string) def test_multiple_boxed_text(self): + '''Tests that multiple different matches (that are not + within others) are matched and processed correctly. + ''' test_string = self.read_test_file(self.processor_name, 'multiple_boxed_text.md') blocks = self.to_blocks(test_string) @@ -59,6 +75,10 @@ def test_multiple_boxed_text(self): self.assertEqual(expected_string, converted_test_string) def test_recursive_boxed_text(self): + '''Tests that multiple different matches (that are + contained as content of eachother) are matched and + processed correctly. + ''' test_string = self.read_test_file(self.processor_name, 'recursive_boxed_text.md') blocks = self.to_blocks(test_string) @@ -73,6 +93,9 @@ def test_recursive_boxed_text(self): #~ def test_doc_example_basic(self): + '''Tests that the most generic case of a single match is found + with generic content contained within. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') blocks = self.to_blocks(test_string) @@ -83,6 +106,9 @@ def test_doc_example_basic(self): self.assertEqual(expected_string, converted_test_string) def test_doc_example_override_html(self): + '''Tests and shows example of overriding the html of the + processor. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') blocks = self.to_blocks(test_string) diff --git a/kordac/tests/ButtonLinkTest.py b/kordac/tests/ButtonLinkTest.py index 70a943ca..5bd8ebf2 100644 --- a/kordac/tests/ButtonLinkTest.py +++ b/kordac/tests/ButtonLinkTest.py @@ -7,10 +7,15 @@ class ButtonLinkTest(ProcessorTest): - """ - """ + '''The ButtonLink processor inherits from the generic tag procesor. + The tests contained here test that arguments and the output + (html-template) work as expected. + ''' def __init__(self, *args, **kwargs): + '''Sets up a generic tag to test that the matches are + occuring appropriately. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'button-link' self.ext = Mock() @@ -19,6 +24,9 @@ def __init__(self, *args, **kwargs): self.block_processor = GenericTagBlockProcessor(self.processor_name, self.ext, Mock()) def test_no_button(self): + '''Tests that the text containing the processor name is + not matched. + ''' test_string = self.read_test_file(self.processor_name, 'no_button.md') blocks = self.to_blocks(test_string) @@ -28,6 +36,9 @@ def test_no_button(self): self.assertEqual(expected_string, converted_test_string) def test_contains_button(self): + '''Tests that the most generic case of a single match is found + with generic content contained within. + ''' test_string = self.read_test_file(self.processor_name, 'contains_button.md') blocks = self.to_blocks(test_string) @@ -38,6 +49,8 @@ def test_contains_button(self): self.assertEqual(expected_string, converted_test_string) def test_contains_missing_button(self): + '''Tests that paritial matches do not occur. + ''' test_string = self.read_test_file(self.processor_name, 'missing_end_brace.md') blocks = self.to_blocks(test_string) @@ -48,6 +61,8 @@ def test_contains_missing_button(self): self.assertEqual(expected_string, converted_test_string) def test_contains_multiple_buttons(self): + '''Tests that multiple buttons within a document are matched. + ''' test_string = self.read_test_file(self.processor_name, 'contains_multiple_buttons.md') blocks = self.to_blocks(test_string) @@ -59,6 +74,9 @@ def test_contains_multiple_buttons(self): self.assertEqual(expected_string, converted_test_string) def test_contains_file_link_button(self): + '''Tests that the file argument works are expected, + internally linking to a file. + ''' test_string = self.read_test_file(self.processor_name, 'contains_file_link_button.md') blocks = self.to_blocks(test_string) @@ -74,6 +92,9 @@ def test_contains_file_link_button(self): #~ def test_doc_example_basic(self): + '''Tests that the most generic case of a single match is found + with generic content contained within. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') blocks = self.to_blocks(test_string) @@ -84,16 +105,9 @@ def test_doc_example_basic(self): self.assertEqual(expected_string, converted_test_string) def test_doc_example_file(self): - test_string = self.read_test_file(self.processor_name, 'doc_example_file_usage.md') - blocks = self.to_blocks(test_string) - - self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) - expected_string = self.read_test_file(self.processor_name, 'doc_example_file_usage_expected.html', strip=True) - self.assertEqual(expected_string, converted_test_string) - - def test_doc_example_file(self): + '''Tests that file argument for internal files works as + expected. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_file_usage.md') blocks = self.to_blocks(test_string) @@ -104,6 +118,9 @@ def test_doc_example_file(self): self.assertEqual(expected_string, converted_test_string) def test_doc_example_override_html(self): + '''Tests and shows example of overriding the html of the + processor. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') blocks = self.to_blocks(test_string) diff --git a/kordac/tests/CommentTest.py b/kordac/tests/CommentTest.py index 06492a78..1eac9d93 100644 --- a/kordac/tests/CommentTest.py +++ b/kordac/tests/CommentTest.py @@ -6,18 +6,22 @@ from kordac.tests.ProcessorTest import ProcessorTest class CommentTest(ProcessorTest): - """ + '''This test class checks to ensure that comments are removed + without changing the formatting of the document. Inline = single line comment .e.g. {comment hello you look lovely today} - """ + ''' def __init__(self, *args, **kwargs): - """Set processor name in class for file names""" + '''Setup processor name for asset directory. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'comment' self.ext = Mock() self.ext.processor_info = ProcessorTest.loadProcessorInfo(self) def test_no_inline_comment(self): + '''Checks that normal text is unchanged. + ''' test_string = self.read_test_file(self.processor_name, 'no_inline_comment.md') self.assertFalse(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) @@ -27,6 +31,8 @@ def test_no_inline_comment(self): self.assertEqual(expected_string, converted_test_string) def test_text_contains_the_word_comment(self): + '''Checks that words such as comment are not matched. + ''' test_string = self.read_test_file(self.processor_name, 'text_contains_the_word_comment.md') self.assertFalse(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) @@ -36,6 +42,8 @@ def test_text_contains_the_word_comment(self): self.assertEqual(expected_string, converted_test_string) def tests_contains_inline_comment(self): + '''Tests that a simple inline comment is removed. + ''' test_string = self.read_test_file(self.processor_name, 'contains_inline_comment.md') self.assertTrue(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) @@ -45,7 +53,8 @@ def tests_contains_inline_comment(self): self.assertEqual(expected_string, converted_test_string) def test_contains_multiple_inline_comments(self): - #NTS not counting number of matches? + '''Tests that multiple comments can be removed. + ''' test_string = self.read_test_file(self.processor_name, 'contains_multiple_inline_comments.md') self.assertTrue(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) @@ -55,6 +64,11 @@ def test_contains_multiple_inline_comments(self): self.assertEqual(expected_string, converted_test_string) def test_comment_contains_comment(self): + '''Tests that comments containing comments are not matched + since they are illegal. (Because the first closing '}' + would be matched and the second '}' would be left on the + line invalidating the match). + ''' # We expect to match the first closing '}' to enforce simple comments test_string = self.read_test_file(self.processor_name, 'comment_contains_comment.md') @@ -69,6 +83,8 @@ def test_comment_contains_comment(self): #~ def test_doc_example_basic(self): + '''Simple test for a common usage case. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') self.assertTrue(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) @@ -78,6 +94,8 @@ def test_doc_example_basic(self): self.assertEqual(expected_string, converted_test_string) def test_doc_example_multiple(self): + '''Simple test for a common usage case. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_multiple_usage.md') self.assertTrue(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) diff --git a/kordac/tests/ConditionalTest.py b/kordac/tests/ConditionalTest.py index 4234fd46..01ce524e 100644 --- a/kordac/tests/ConditionalTest.py +++ b/kordac/tests/ConditionalTest.py @@ -7,8 +7,13 @@ class ConditionalTest(ProcessorTest): + '''Conditionals expect complex output and need to match + many possible conditions. + ''' def __init__(self, *args, **kwargs): + '''Setup basic information for asset directory. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'conditional' self.ext = Mock() @@ -16,6 +21,8 @@ def __init__(self, *args, **kwargs): self.ext.jinja_templates = {self.processor_name: ProcessorTest.loadJinjaTemplate(self, self.processor_name)} def test_example_basic_else(self): + '''Simple example ensuring else statements works. + ''' test_string = self.read_test_file(self.processor_name, 'example_basic_else_usage.md') blocks = self.to_blocks(test_string) @@ -25,11 +32,29 @@ def test_example_basic_else(self): expected_string = self.read_test_file(self.processor_name, 'example_basic_else_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) + def test_example_elif_noelse(self): + '''Complex example showing multiple elif statements with + no else statement. + ''' + test_string = self.read_test_file(self.processor_name, 'example_elif_noelse.md') + blocks = self.to_blocks(test_string) + + self.assertListEqual([True, False, True, False, True, False, True], [ConditionalProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + + html_template = self.read_test_file(self.processor_name, 'example_elif_noelse_template.html', strip=True) + kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) + + converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + expected_string = self.read_test_file(self.processor_name, 'example_elif_noelse_expected.html', strip=True) + self.assertEqual(expected_string, converted_test_string) + #~ # Doc Tests #~ def test_doc_example_basic(self): + '''Basic example showing only a single if statement + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') blocks = self.to_blocks(test_string) @@ -40,6 +65,9 @@ def test_doc_example_basic(self): self.assertEqual(expected_string, converted_test_string) def test_doc_example_complex(self): + '''Complex example using multiple elifs and an else + statement. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_complex_usage.md') blocks = self.to_blocks(test_string) @@ -50,6 +78,9 @@ def test_doc_example_complex(self): self.assertEqual(expected_string, converted_test_string) def test_doc_example_override_html(self): + '''Complex example using all features and checking that it + works with custom templates. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') blocks = self.to_blocks(test_string) @@ -61,17 +92,3 @@ def test_doc_example_override_html(self): converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - - - def test_doc_example2_override_html(self): - test_string = self.read_test_file(self.processor_name, 'doc_example2_override_html.md') - blocks = self.to_blocks(test_string) - - self.assertListEqual([True, False, True, False, True, False, True], [ConditionalProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - - html_template = self.read_test_file(self.processor_name, 'doc_example2_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) - - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) - expected_string = self.read_test_file(self.processor_name, 'doc_example2_override_html_expected.html', strip=True) - self.assertEqual(expected_string, converted_test_string) diff --git a/kordac/tests/assets/conditional/doc_example2_override_html.md b/kordac/tests/assets/conditional/example_elif_noelse.md similarity index 100% rename from kordac/tests/assets/conditional/doc_example2_override_html.md rename to kordac/tests/assets/conditional/example_elif_noelse.md diff --git a/kordac/tests/assets/conditional/doc_example2_override_html_expected.html b/kordac/tests/assets/conditional/example_elif_noelse_expected.html similarity index 100% rename from kordac/tests/assets/conditional/doc_example2_override_html_expected.html rename to kordac/tests/assets/conditional/example_elif_noelse_expected.html diff --git a/kordac/tests/assets/conditional/doc_example2_override_html_template.html b/kordac/tests/assets/conditional/example_elif_noelse_template.html similarity index 100% rename from kordac/tests/assets/conditional/doc_example2_override_html_template.html rename to kordac/tests/assets/conditional/example_elif_noelse_template.html From 4f8f203924bddfa31905a34bc2ae863b99a2acb4 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Thu, 23 Mar 2017 17:30:04 +1300 Subject: [PATCH 52/86] WIP updating docstring in tests. --- kordac/tests/ConfigurationTest.py | 48 ++++--- kordac/tests/FrameTest.py | 14 ++ kordac/tests/GlossaryLinkTest.py | 36 ++++- kordac/tests/HeadingTest.py | 136 ++++++++++-------- kordac/tests/ImageTest.py | 99 ++++++------- kordac/tests/InteractiveTest.py | 16 ++- kordac/tests/assets/image/no_image.md | 1 - .../tests/assets/image/no_image_expected.html | 3 - 8 files changed, 225 insertions(+), 128 deletions(-) delete mode 100644 kordac/tests/assets/image/no_image.md delete mode 100644 kordac/tests/assets/image/no_image_expected.html diff --git a/kordac/tests/ConfigurationTest.py b/kordac/tests/ConfigurationTest.py index 5d57fb5c..9e782c50 100644 --- a/kordac/tests/ConfigurationTest.py +++ b/kordac/tests/ConfigurationTest.py @@ -6,20 +6,20 @@ from collections import defaultdict class ConfigurationTest(BaseTest): - """Test configuration methods of Kordac + '''Test configuration methods of Kordac - These are not true unit tests, as they create the complete Kordac system, - however we are using the unittest framework for ease of use and simplicity - of our testing suite. - """ + These are not true unit tests, as they create the complete Kordac + system, however we are using the unittest framework for ease of + use and simplicity of our testing suite. + ''' def __init__(self, *args, **kwargs): - """Creates BaseTest Case class + '''Creates BaseTest Case class Create class inheiriting from TestCase, while also storing - the path to test files and the maxiumum difference to display on - test failures. - """ + the path to test files and the maxiumum difference to display + on test failures. + ''' BaseTest.__init__(self, *args, **kwargs) self.test_name = 'configuration' self.maxDiff = None @@ -29,7 +29,9 @@ def __init__(self, *args, **kwargs): } def test_multiple_calls(self): - """Checks all fields of KordacResult are correct for multiple Kordac calls""" + '''Checks all fields of KordacResult are correct for multiple + Kordac calls. + ''' test_cases = [ ('all_processors.md', KordacResult( @@ -121,7 +123,9 @@ def test_multiple_calls(self): def test_default_processors_on_creation(self): - """Checks if all expected default processors work on default creation""" + '''Checks if all expected default processors work on default + creation. + ''' kordac = Kordac() # kordac.clear_templates() test_string = self.read_test_file(self.test_name, 'all_processors.md') @@ -130,7 +134,8 @@ def test_default_processors_on_creation(self): self.assertEqual(expected_string, converted_test_string) def test_custom_processors_on_creation(self): - """Checks if system only uses specified processsors""" + """Checks if system only uses specified processors. + """ processors = {'panel', 'image'} kordac = Kordac(processors=processors) test_string = self.read_test_file(self.test_name, 'all_processors.md') @@ -139,7 +144,8 @@ def test_custom_processors_on_creation(self): self.assertEqual(expected_string, converted_test_string) def test_custom_processors_after_creation(self): - """Checks if extension correct changes processors""" + """Checks if extension correct changes processors. + """ kordac = Kordac() processors = Kordac.processor_defaults() processors.add('example_processor') @@ -154,7 +160,9 @@ def test_custom_processors_after_creation(self): self.assertEqual(expected_string, converted_test_string) def test_unique_custom_processors(self): - """Checks if unique processors are stored when duplicates provided""" + """Checks if unique processors are stored when duplicates + provided. + """ processors = ['comment', 'comment', 'comment'] kordac = Kordac(processors=processors) self.assertEqual(kordac.kordac_extension.processors, set(processors)) @@ -166,7 +174,8 @@ def test_unique_custom_processors(self): self.assertTrue(kordac.kordac_extension.processors, processors) def test_custom_templates_on_creation(self): - """Checks custom templates are used when given on creation""" + """Checks custom templates are used when given on creation. + """ kordac = Kordac(html_templates=self.custom_templates) test_string = self.read_test_file(self.test_name, 'all_processors.md') converted_test_string = kordac.convert(test_string).html_string @@ -174,7 +183,8 @@ def test_custom_templates_on_creation(self): self.assertEqual(expected_string, converted_test_string) def test_custom_templates_after_creation(self): - """Checks custom templates are used when given after creation""" + """Checks custom templates are used when given after creation. + """ kordac = Kordac() kordac.update_templates(self.custom_templates) test_string = self.read_test_file(self.test_name, 'all_processors.md') @@ -183,7 +193,8 @@ def test_custom_templates_after_creation(self): self.assertEqual(expected_string, converted_test_string) def test_reset_templates_after_custom(self): - """Checks custom templates are reset when given at creation""" + """Checks custom templates are reset when given at creation. + """ kordac = Kordac(html_templates=self.custom_templates) kordac.clear_templates() test_string = self.read_test_file(self.test_name, 'all_processors.md') @@ -192,6 +203,9 @@ def test_reset_templates_after_custom(self): self.assertEqual(expected_string, converted_test_string) def test_multiline_custom_templates(self): + """Checks that multiple multiline custom templates are loaded + and used correctly. + """ custom_templates = { "image": """
    diff --git a/kordac/tests/FrameTest.py b/kordac/tests/FrameTest.py index e891f4dd..16e1b016 100644 --- a/kordac/tests/FrameTest.py +++ b/kordac/tests/FrameTest.py @@ -7,8 +7,15 @@ from kordac.tests.ProcessorTest import ProcessorTest class FrameTest(ProcessorTest): + '''The iframe processor inherits from the generic tag procesor. + The tests contained here test that arguments and the output + (html-template) work as expected. + ''' def __init__(self, *args, **kwargs): + '''Sets up a generic tag to test that the matches are + occuring appropriately. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'iframe' self.ext = Mock() @@ -17,6 +24,9 @@ def __init__(self, *args, **kwargs): self.block_processor = GenericTagBlockProcessor(self.processor_name, self.ext, Mock()) def test_example_no_link(self): + '''Tests that the text containing the processor name is + not matched. + ''' test_string = self.read_test_file(self.processor_name, 'example_no_link.md') blocks = self.to_blocks(test_string) @@ -30,6 +40,8 @@ def test_example_no_link(self): #~ def test_doc_example_basic(self): + '''A generic example of common usage. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') blocks = self.to_blocks(test_string) @@ -40,6 +52,8 @@ def test_doc_example_basic(self): self.assertEqual(expected_string, converted_test_string) def test_doc_example_override_html(self): + '''A example showing how to override the html template. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') blocks = self.to_blocks(test_string) diff --git a/kordac/tests/GlossaryLinkTest.py b/kordac/tests/GlossaryLinkTest.py index e3f5775f..10ac7818 100644 --- a/kordac/tests/GlossaryLinkTest.py +++ b/kordac/tests/GlossaryLinkTest.py @@ -7,9 +7,14 @@ class GlossaryLinkTest(ProcessorTest): + '''The GlossaryLink processor changes the extension so to output + a special result. Special things to note about this processor is + it is inline, and stores references found in the extension class. + ''' def __init__(self, *args, **kwargs): - """Set processor name in class for file names""" + '''Setup basic information for asset directory. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'glossary-link' self.ext = Mock() @@ -17,6 +22,9 @@ def __init__(self, *args, **kwargs): self.ext.jinja_templates = {self.processor_name: ProcessorTest.loadJinjaTemplate(self, self.processor_name)} def test_single_word_term(self): + '''Tests that a single glossary link functions + as expected. + ''' test_string = self.read_test_file(self.processor_name, 'single_word_term.md') processor = GlossaryLinkPattern(self.ext, self.md.parser) @@ -31,6 +39,8 @@ def test_single_word_term(self): self.assertDictEqual(expected_glossary_terms, glossary_terms) def test_multiple_word_term(self): + '''Tests that multiple glossary links are processed. + ''' test_string = self.read_test_file(self.processor_name, 'multiple_word_term.md') processor = GlossaryLinkPattern(self.ext, self.md.parser) @@ -45,6 +55,9 @@ def test_multiple_word_term(self): self.assertDictEqual(expected_glossary_terms, glossary_terms) def test_reference_text_given(self): + '''Tests that the reference argument is processed + and that details are stored in the final result. + ''' test_string = self.read_test_file(self.processor_name, 'reference_text_given.md') processor = GlossaryLinkPattern(self.ext, self.md.parser) @@ -62,6 +75,9 @@ def test_reference_text_given(self): self.assertDictEqual(expected_glossary_terms, glossary_terms) def test_leading_inline_text(self): + '''Tests that glossary links are matched and processed + even when there is text before the tag. + ''' test_string = self.read_test_file(self.processor_name, 'leading_inline_text.md') processor = GlossaryLinkPattern(self.ext, self.md.parser) @@ -76,6 +92,9 @@ def test_leading_inline_text(self): self.assertDictEqual(expected_glossary_terms, glossary_terms) def test_trailing_inline_text(self): + '''Tests that glossary links are matched and processed + even when there is text after the tag. + ''' test_string = self.read_test_file(self.processor_name, 'trailing_inline_text.md') processor = GlossaryLinkPattern(self.ext, self.md.parser) @@ -90,6 +109,9 @@ def test_trailing_inline_text(self): self.assertDictEqual(expected_glossary_terms, glossary_terms) def test_leading_and_trailing_inline_text(self): + '''Tests that glossary links are matched and processed + even when there is text before and after the tag. + ''' test_string = self.read_test_file(self.processor_name, 'leading_and_trailing_inline_text.md') processor = GlossaryLinkPattern(self.ext, self.md.parser) @@ -104,6 +126,10 @@ def test_leading_and_trailing_inline_text(self): self.assertDictEqual(expected_glossary_terms, glossary_terms) def test_multiple_terms(self): + '''Tests that multiple glossary tags are matched and + that tags with the reference argument store information + for the final result. + ''' test_string = self.read_test_file(self.processor_name, 'multiple_terms.md') processor = GlossaryLinkPattern(self.ext, self.md.parser) @@ -121,6 +147,10 @@ def test_multiple_terms(self): self.assertDictEqual(expected_glossary_terms, glossary_terms) def test_multiple_reference_text(self): + '''Tests that when the reference argument is used in + multiple tags that all references are stored for the + final kordac result. + ''' test_string = self.read_test_file(self.processor_name, 'multiple_reference_text.md') processor = GlossaryLinkPattern(self.ext, self.md.parser) @@ -145,6 +175,8 @@ def test_multiple_reference_text(self): #~ def test_doc_example_basic(self): + '''A basic example of common useage. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') processor = GlossaryLinkPattern(self.ext, self.md.parser) @@ -159,6 +191,8 @@ def test_doc_example_basic(self): self.assertDictEqual(expected_glossary_terms, glossary_terms) def test_doc_example_override_html(self): + '''A basic example of overriding the html-template. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') processor = GlossaryLinkPattern(self.ext, self.md.parser) diff --git a/kordac/tests/HeadingTest.py b/kordac/tests/HeadingTest.py index 89196f94..b4aa6104 100644 --- a/kordac/tests/HeadingTest.py +++ b/kordac/tests/HeadingTest.py @@ -8,8 +8,16 @@ from kordac.utils.HeadingNode import HeadingNode class HeadingTest(ProcessorTest): + '''The heading processor is a unique processor that replaces the + functionality of the default markdown (#) heading. We allow for + an html override and the final result also outputs a tree + representing the layout of the headings. A consideration when + testing is that slugs of headings should all be unique. + ''' def __init__(self, *args, **kwargs): + '''Setup for asset loading and match checking. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'heading' self.ext = Mock() @@ -17,6 +25,9 @@ def __init__(self, *args, **kwargs): self.ext.jinja_templates = {self.processor_name: ProcessorTest.loadJinjaTemplate(self, self.processor_name)} def test_example_blank(self): + '''Checks to see that if no headings exist the output result + is empty. + ''' test_string = self.read_test_file(self.processor_name, 'example_blank.md') blocks = self.to_blocks(test_string) @@ -30,6 +41,8 @@ def test_example_blank(self): self.assertIsNone(tree) def test_single_heading(self): + '''Checks the simplist case of a single heading. + ''' test_string = self.read_test_file(self.processor_name, 'example_single_heading.md') blocks = self.to_blocks(test_string) @@ -49,11 +62,74 @@ def test_single_heading(self): ) self.assertTupleEqual(tree, expected_tree) + def test_multiple_roots_zero_level(self): + '''Test complex usage of heading where root level nodes + may be of varying levels until an H1 is used. + environment. + ''' + test_string = self.read_test_file(self.processor_name, 'multiple_roots_zero_level.md') + blocks = self.to_blocks(test_string) + + self.assertListEqual([True, True, True, True, True, True, True], [HeadingBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + + html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) + kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) + + converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + expected_string = self.read_test_file(self.processor_name, 'multiple_roots_zero_level_expected.html', strip=True) + self.assertEqual(expected_string, converted_test_string) + + tree = kordac_extension.get_heading_tree() + expected_tree = (HeadingNode(title='This is an H4', + title_slug='this-is-an-h4', + level=4, + children=() + ), + HeadingNode(title='This is an H2', + title_slug='this-is-an-h2', + level=2, + children=( + HeadingNode( + title='This is an H3', + title_slug='this-is-an-h3', + level=3, + children=() + ), + ) + ), + HeadingNode(title='This is an H1', + title_slug='this-is-an-h1', + level=1, + children=( + HeadingNode( + title='This is an H3', + title_slug='this-is-an-h3-2', + level=3, + children=() + ), + HeadingNode(title='This is an H2', + title_slug='this-is-an-h2-2', + level=2, + children=( + HeadingNode(title='This is an H4', + title_slug='this-is-an-h4-2', + level=4, + children=() + ), + ) + ), + ) + ), + ) + self.assertTupleEqual(tree, expected_tree) + #~ # Doc Tests #~ def test_doc_example_basic(self): + '''An example of simplistic useage. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') blocks = self.to_blocks(test_string) @@ -88,6 +164,9 @@ def test_doc_example_basic(self): def test_doc_example_override_html(self): + '''An example of complex useage, involving multiple H1s + and shows html overriding. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') blocks = self.to_blocks(test_string) @@ -147,60 +226,3 @@ def test_doc_example_override_html(self): ) self.assertTupleEqual(tree, expected_tree) - - def test_multiple_roots_zero_level(self): - test_string = self.read_test_file(self.processor_name, 'multiple_roots_zero_level.md') - blocks = self.to_blocks(test_string) - - self.assertListEqual([True, True, True, True, True, True, True], [HeadingBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - - html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) - - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) - expected_string = self.read_test_file(self.processor_name, 'multiple_roots_zero_level_expected.html', strip=True) - self.assertEqual(expected_string, converted_test_string) - - tree = kordac_extension.get_heading_tree() - expected_tree = (HeadingNode(title='This is an H4', - title_slug='this-is-an-h4', - level=4, - children=() - ), - HeadingNode(title='This is an H2', - title_slug='this-is-an-h2', - level=2, - children=( - HeadingNode( - title='This is an H3', - title_slug='this-is-an-h3', - level=3, - children=() - ), - ) - ), - HeadingNode(title='This is an H1', - title_slug='this-is-an-h1', - level=1, - children=( - HeadingNode( - title='This is an H3', - title_slug='this-is-an-h3-2', - level=3, - children=() - ), - HeadingNode(title='This is an H2', - title_slug='this-is-an-h2-2', - level=2, - children=( - HeadingNode(title='This is an H4', - title_slug='this-is-an-h4-2', - level=4, - children=() - ), - ) - ), - ) - ), - ) - self.assertTupleEqual(tree, expected_tree) diff --git a/kordac/tests/ImageTest.py b/kordac/tests/ImageTest.py index 33d1be63..86e6471a 100644 --- a/kordac/tests/ImageTest.py +++ b/kordac/tests/ImageTest.py @@ -7,9 +7,16 @@ from kordac.tests.ProcessorTest import ProcessorTest class ImageTest(ProcessorTest): + '''The image processor is a simple tag with a multitude of + different possible arguments that modify output slightly. + Internally linked file features need to be considered + when testing images, such that required files are modified + and need to be checked to see if updated correctly. + ''' def __init__(self, *args, **kwargs): - """Set processor name in class for file names""" + '''Set processor name in class for file names. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'image' self.ext = Mock() @@ -18,6 +25,10 @@ def __init__(self, *args, **kwargs): self.ext.required_files = defaultdict(set) def test_internal_image(self): + '''Tests to ensure that an internally reference image + produces the desired output, including changing the + expected images of the kordac extension. + ''' test_string = self.read_test_file(self.processor_name, 'internal_image.md') blocks = self.to_blocks(test_string) @@ -34,6 +45,9 @@ def test_internal_image(self): self.assertSetEqual(expected_images, images) def test_external_image(self): + '''Tests that external images are processed and that + the expected images are unchanged. + ''' test_string = self.read_test_file(self.processor_name, 'external_image.md') blocks = self.to_blocks(test_string) @@ -44,6 +58,8 @@ def test_external_image(self): self.assertEqual(expected_string, converted_test_string) def test_default_image(self): + '''Tests that old image tags retain compatability. + ''' test_string = self.read_test_file(self.processor_name, 'default_image.md') blocks = self.to_blocks(test_string) @@ -60,6 +76,9 @@ def test_default_image(self): self.assertSetEqual(expected_images, images) def test_contains_multiple_images(self): + '''Tests that multiple internal images are processed correctly + and that the expected images are updated. + ''' test_string = self.read_test_file(self.processor_name, 'contains_multiple_images.md') blocks = self.to_blocks(test_string) @@ -77,21 +96,10 @@ def test_contains_multiple_images(self): } self.assertSetEqual(expected_images, images) - def test_no_image(self): - test_string = self.read_test_file(self.processor_name, 'no_image.md') - blocks = self.to_blocks(test_string) - - self.assertListEqual([False], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) - expected_string = self.read_test_file(self.processor_name, 'no_image_expected.html', strip=True) - self.assertEqual(expected_string, converted_test_string) - - images = self.kordac_extension.required_files['images'] - expected_images = set() - self.assertSetEqual(expected_images, images) - def test_text_contains_the_word_image(self): + '''Tests that text containing the processor name is + not matched erroneously. + ''' test_string = self.read_test_file(self.processor_name, 'text_contains_the_word_image.md') blocks = self.to_blocks(test_string) @@ -106,6 +114,9 @@ def test_text_contains_the_word_image(self): self.assertSetEqual(expected_images, images) def test_contains_image_and_text_contains_word_image(self): + '''Tests that text containing the processor name does + not affect processing of actual image tags. + ''' test_string = self.read_test_file(self.processor_name, 'contains_image_and_text_contains_word_image.md') blocks = self.to_blocks(test_string) @@ -122,6 +133,8 @@ def test_contains_image_and_text_contains_word_image(self): self.assertSetEqual(expected_images, images) def test_contains_hover_text(self): + '''Tests that argument for hover-text produces expected output. + ''' test_string = self.read_test_file(self.processor_name, 'contains_hover_text.md') blocks = self.to_blocks(test_string) @@ -138,6 +151,8 @@ def test_contains_hover_text(self): self.assertSetEqual(expected_images, images) def test_contains_caption_link(self): + '''Tests that argument for caption-link produces expected output. + ''' test_string = self.read_test_file(self.processor_name, 'contains_caption_link.md') blocks = self.to_blocks(test_string) @@ -154,6 +169,8 @@ def test_contains_caption_link(self): self.assertSetEqual(expected_images, images) def test_contains_alt(self): + '''Tests that argument for alt produces expected output. + ''' test_string = self.read_test_file(self.processor_name, 'contains_alt.md') blocks = self.to_blocks(test_string) @@ -170,6 +187,8 @@ def test_contains_alt(self): self.assertSetEqual(expected_images, images) def test_contains_caption(self): + '''Tests that argument for caption produces expected output. + ''' test_string = self.read_test_file(self.processor_name, 'contains_caption.md') blocks = self.to_blocks(test_string) @@ -186,6 +205,8 @@ def test_contains_caption(self): self.assertSetEqual(expected_images, images) def test_contains_source(self): + '''Tests that argument for source produces expected output. + ''' test_string = self.read_test_file(self.processor_name, 'contains_source.md') blocks = self.to_blocks(test_string) @@ -202,6 +223,9 @@ def test_contains_source(self): self.assertSetEqual(expected_images, images) def test_align_left(self): + '''Tests that argument for align produces expected output + when set to left. + ''' test_string = self.read_test_file(self.processor_name, 'align_left.md') blocks = self.to_blocks(test_string) @@ -218,6 +242,9 @@ def test_align_left(self): self.assertSetEqual(expected_images, images) def test_align_right(self): + '''Tests that argument for align produces expected output + when set to right. + ''' test_string = self.read_test_file(self.processor_name, 'align_right.md') blocks = self.to_blocks(test_string) @@ -234,6 +261,9 @@ def test_align_right(self): self.assertSetEqual(expected_images, images) def test_align_center(self): + '''Tests that argument for align produces expected output + when set to center. + ''' test_string = self.read_test_file(self.processor_name, 'align_center.md') blocks = self.to_blocks(test_string) @@ -249,44 +279,12 @@ def test_align_center(self): } self.assertSetEqual(expected_images, images) - # ~ - # System Tests - # ~ - - def test_internal_image_required(self): - test_string = self.read_test_file(self.processor_name, 'internal_image.md') - blocks = self.to_blocks(test_string) - - self.assertListEqual([False, True, False], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) - - images = self.kordac_extension.required_files['images'] - expected_images = { - 'pixel-diamond.png' - } - self.assertSetEqual(expected_images, images) - - def test_multiple_internal_image_required(self): - test_string = self.read_test_file(self.processor_name, 'multiple_internal_image.md') - blocks = self.to_blocks(test_string) - - self.assertListEqual([False, True, True, True, False], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) - - images = self.kordac_extension.required_files['images'] - expected_images = { - 'pixel-diamond.png', - 'Lipsum.png' - } - self.assertSetEqual(expected_images, images) - #~ # Doc Tests #~ def test_doc_example_basic(self): + '''Basic example of common usage.''' test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') blocks = self.to_blocks(test_string) @@ -301,6 +299,8 @@ def test_doc_example_basic(self): self.assertSetEqual(expected_images, images) def test_doc_example_override_html(self): + '''Basic example showing how to override the html-template. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') blocks = self.to_blocks(test_string) @@ -318,6 +318,9 @@ def test_doc_example_override_html(self): self.assertSetEqual(expected_images, images) def test_doc_example_2_override_html(self): + '''Basic example showing how to override the html-template + for relative files in a specific file only. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_2_override_html.md') blocks = self.to_blocks(test_string) diff --git a/kordac/tests/InteractiveTest.py b/kordac/tests/InteractiveTest.py index dfeed2fa..60612a95 100644 --- a/kordac/tests/InteractiveTest.py +++ b/kordac/tests/InteractiveTest.py @@ -7,9 +7,15 @@ from kordac.tests.ProcessorTest import ProcessorTest class InteractiveTest(ProcessorTest): + '''The interactive processor is a simple tag with a complex + output that relies on external systems. + Internally linked file features need to be considered + when testing images, such that required files are modified + and need to be checked to see if updated correctly. + ''' def __init__(self, *args, **kwargs): - """Set processor name in class for file names""" + '''Set processor name in class for file names.''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'interactive' self.ext = Mock() @@ -18,6 +24,8 @@ def __init__(self, *args, **kwargs): self.ext.required_files = defaultdict(set) def test_doc_example_in_page(self): + '''Example of an in-page interactive. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_in_page_usage.md') blocks = self.to_blocks(test_string) @@ -28,6 +36,8 @@ def test_doc_example_in_page(self): self.assertEqual(expected_string, converted_test_string) def test_doc_example_whole_page(self): + '''Example of an whole-page interactive. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_whole_page_usage.md') blocks = self.to_blocks(test_string) @@ -38,6 +48,8 @@ def test_doc_example_whole_page(self): self.assertEqual(expected_string, converted_test_string) def test_doc_example_iframe(self): + '''Example of an iframe interactive. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_iframe_usage.md') blocks = self.to_blocks(test_string) @@ -48,6 +60,8 @@ def test_doc_example_iframe(self): self.assertEqual(expected_string, converted_test_string) def test_doc_example_override_html(self): + '''Example showing overriding the html-template. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') blocks = self.to_blocks(test_string) diff --git a/kordac/tests/assets/image/no_image.md b/kordac/tests/assets/image/no_image.md deleted file mode 100644 index c87562ea..00000000 --- a/kordac/tests/assets/image/no_image.md +++ /dev/null @@ -1 +0,0 @@ -This algorithm is a little more complicated, but is very powerful. To do this algorithm with the sorting interactive, start by randomly choosing a box and placing it on the scales. Now compare every other box to the one you selected; heavier boxes should be put on the right of the second row and lighter boxes are put on the left. When you are done, place the box you were comparing everything else to between these two groups, but to help you keep track of things, put it in the row below. The following example shows how it might look after this step. Note that the selected block is in the right place for the final sorted order, and everything on either side will remain on the side that it is on. \ No newline at end of file diff --git a/kordac/tests/assets/image/no_image_expected.html b/kordac/tests/assets/image/no_image_expected.html deleted file mode 100644 index c2af0b52..00000000 --- a/kordac/tests/assets/image/no_image_expected.html +++ /dev/null @@ -1,3 +0,0 @@ -

    - This algorithm is a little more complicated, but is very powerful. To do this algorithm with the sorting interactive, start by randomly choosing a box and placing it on the scales. Now compare every other box to the one you selected; heavier boxes should be put on the right of the second row and lighter boxes are put on the left. When you are done, place the box you were comparing everything else to between these two groups, but to help you keep track of things, put it in the row below. The following example shows how it might look after this step. Note that the selected block is in the right place for the final sorted order, and everything on either side will remain on the side that it is on. -

    From 678e3f105dd076dfae25fc387f1adbcb71deb8a3 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Fri, 24 Mar 2017 18:57:09 +1300 Subject: [PATCH 53/86] WIP documentation updates. --- kordac/tests/PanelTest.py | 36 +++++++++++++++++++++- kordac/tests/ProcessorTest.py | 33 ++++++++++++++++----- kordac/tests/RelativeLinkTest.py | 46 +++++++++++++++++++++++++++-- kordac/tests/RemoveTitleTest.py | 30 +++++++++++++++++-- kordac/tests/SaveTitleTest.py | 23 +++++++++++++-- kordac/tests/ScratchTest.py | 25 ++++++++++++++++ kordac/tests/SmokeTests.py | 29 ++++++++++-------- kordac/tests/TableOfContentsTest.py | 12 ++++++++ kordac/tests/VideoTest.py | 5 ++-- kordac/tests/start_tests.py | 10 ++++++- 10 files changed, 219 insertions(+), 30 deletions(-) diff --git a/kordac/tests/PanelTest.py b/kordac/tests/PanelTest.py index 4cadc0ac..524610ff 100644 --- a/kordac/tests/PanelTest.py +++ b/kordac/tests/PanelTest.py @@ -7,9 +7,15 @@ from kordac.tests.ProcessorTest import ProcessorTest class PanelTest(ProcessorTest): + '''The panel processor inherits from the generic container. + The tests contained here test that arguments and the output + (html-template) work as expected. + ''' def __init__(self, *args, **kwargs): - """Set processor name in class for file names""" + '''Sets up a generic container to test that the matches are + occuring appropriately and configure the asset directory. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'panel' self.ext = Mock() @@ -18,6 +24,8 @@ def __init__(self, *args, **kwargs): self.block_processor = GenericContainerBlockProcessor(self.processor_name, self.ext, Mock()) def test_parses_blank(self): + '''Tests that a blank panel is processed with empty content. + ''' test_string = self.read_test_file(self.processor_name, 'parses_blank.md') blocks = self.to_blocks(test_string) @@ -28,6 +36,8 @@ def test_parses_blank(self): self.assertEqual(expected_string, converted_test_string) def test_parses_no_blank_lines_single_paragraph(self): + '''Tests that a block of text as content is added to the panel. + ''' test_string = self.read_test_file(self.processor_name, 'parses_no_blank_lines_single_paragraph.md') blocks = self.to_blocks(test_string) @@ -38,6 +48,8 @@ def test_parses_no_blank_lines_single_paragraph(self): self.assertEqual(expected_string, converted_test_string) def test_parses_expanded_panel(self): + '''Tests that the expanded argument works as expected. + ''' test_string = self.read_test_file(self.processor_name, 'parses_expanded_panel.md') blocks = self.to_blocks(test_string) @@ -48,6 +60,8 @@ def test_parses_expanded_panel(self): self.assertEqual(expected_string, converted_test_string) def test_parses_always_expanded_panel(self): + '''Tests the the always expanded argument works as expected. + ''' test_string = self.read_test_file(self.processor_name, 'parses_always_expanded_panel.md') blocks = self.to_blocks(test_string) @@ -58,6 +72,9 @@ def test_parses_always_expanded_panel(self): self.assertEqual(expected_string, converted_test_string) def test_parses_blank_lines_multiple_paragraphs(self): + '''Tests that multiple blocks of text as the content are + processed correctly. + ''' test_string = self.read_test_file(self.processor_name, 'parses_blank_lines_multiple_paragraphs.md') blocks = self.to_blocks(test_string) @@ -68,6 +85,8 @@ def test_parses_blank_lines_multiple_paragraphs(self): self.assertEqual(expected_string, converted_test_string) def test_contains_multiple_panels(self): + '''Tests that multiple panels are processed correctly. + ''' test_string = self.read_test_file(self.processor_name, 'contains_multiple_panels.md') blocks = self.to_blocks(test_string) @@ -78,6 +97,8 @@ def test_contains_multiple_panels(self): self.assertEqual(expected_string, converted_test_string) def test_contains_inner_panel(self): + '''Tests that panels can contain other panels. + ''' test_string = self.read_test_file(self.processor_name, 'contains_inner_panel.md') blocks = self.to_blocks(test_string) @@ -88,6 +109,9 @@ def test_contains_inner_panel(self): self.assertEqual(expected_string, converted_test_string) def test_missing_start_tag(self): + '''Tests that TagNotMatchedErrors are thown when an end tag is + encountered alone. + ''' test_string = self.read_test_file(self.processor_name, 'missing_start_tag.md') blocks = self.to_blocks(test_string) @@ -96,6 +120,9 @@ def test_missing_start_tag(self): self.assertRaises(TagNotMatchedError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) def test_missing_end_tag(self): + '''Tests that TagNotMatchedErrors are thown when an end tag is + encountered alone. + ''' test_string = self.read_test_file(self.processor_name, 'missing_end_tag.md') blocks = self.to_blocks(test_string) @@ -104,6 +131,9 @@ def test_missing_end_tag(self): self.assertRaises(TagNotMatchedError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) def test_missing_tag_inner(self): + '''Tests that if inner tags are missing that the + TagNotMatchedErrors are thown. + ''' test_string = self.read_test_file(self.processor_name, 'missing_tag_inner.md') blocks = self.to_blocks(test_string) @@ -116,6 +146,8 @@ def test_missing_tag_inner(self): #~ def test_doc_example_basic(self): + '''Example of the common usecase. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') blocks = self.to_blocks(test_string) @@ -126,6 +158,8 @@ def test_doc_example_basic(self): self.assertEqual(expected_string, converted_test_string) def test_doc_example_override_html(self): + '''Example of overriding the html-template. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') blocks = self.to_blocks(test_string) diff --git a/kordac/tests/ProcessorTest.py b/kordac/tests/ProcessorTest.py index 901e5886..d1d4b668 100644 --- a/kordac/tests/ProcessorTest.py +++ b/kordac/tests/ProcessorTest.py @@ -7,18 +7,25 @@ from kordac.tests.BaseTest import BaseTest class ProcessorTest(BaseTest): - """A base test class for individual test classes""" + '''A base test class for individual test classes. + ''' def __init__(self, *args, **kwargs): - """Creates BaseTest Case class + '''Creates BaseTest Case class Create class inheiriting from TestCase, while also storing - the path to test files and the maxiumum difference to display on - test failures. - """ + the path to test files and the maxiumum difference to display + on test failures. + ''' BaseTest.__init__(self, *args, **kwargs) def loadJinjaTemplate(self, template): + '''Loads a jinja template from the given processor name. + Args: + template: the processor name to load the template. + Returns: + A jinja template. + ''' env = Environment( loader=PackageLoader('kordac', 'html-templates'), autoescape=select_autoescape(['html']) @@ -27,19 +34,29 @@ def loadJinjaTemplate(self, template): return jinja_template def loadProcessorInfo(self): + '''Loads the processor info similar to the kordac extension. + ''' pattern_data = open('kordac/processor-info.json').read() return json.loads(pattern_data) def to_blocks(self, string): - ''' Returns a list of strings as markdown blocks. - - See ParseChunk of markdown.blockparser.BlockParser for how text in chunked. + '''See ParseChunk of markdown.blockparser.BlockParser + for how text in chunked. + Args: + string: The string to break into blocks. + Returns: + A list of strings as markdown blocks. ''' return string.split('\n\n') def setUp(self): + '''Runs before each testcase, creates a kordac extensions + and a markdown instance for running tests. + ''' self.kordac_extension = KordacExtension([self.processor_name], {}) self.md = markdown.Markdown(extensions=[self.kordac_extension]) def tearDown(self): + '''Runs after each testcase. + ''' self.md = None diff --git a/kordac/tests/RelativeLinkTest.py b/kordac/tests/RelativeLinkTest.py index 24b38397..3b273816 100644 --- a/kordac/tests/RelativeLinkTest.py +++ b/kordac/tests/RelativeLinkTest.py @@ -6,10 +6,13 @@ from kordac.tests.ProcessorTest import ProcessorTest class RelativeLinkTest(ProcessorTest): - """Tests to check the 'relative-link' pattern works as intended.""" + '''Tests to check the 'relative-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 file names""" + '''Set processor name in class for asset file retrieval.''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'relative-link' self.ext = Mock() @@ -17,6 +20,8 @@ def __init__(self, *args, **kwargs): self.ext.jinja_templates = {self.processor_name: ProcessorTest.loadJinjaTemplate(self, self.processor_name)} def test_basic_usage(self): + '''Test common usage case. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') processor = RelativeLinkPattern(self.ext, self.md.parser) @@ -27,6 +32,8 @@ def test_basic_usage(self): self.assertEqual(expected_string, converted_test_string) def test_long_path(self): + '''Tests that long paths less than 31 characters work. + ''' test_string = self.read_test_file(self.processor_name, 'long_path.md') processor = RelativeLinkPattern(self.ext, self.md.parser) @@ -37,6 +44,8 @@ def test_long_path(self): self.assertEqual(expected_string, converted_test_string) def test_multiple_links(self): + ''' + ''' test_string = self.read_test_file(self.processor_name, 'multiple_links.md') processor = RelativeLinkPattern(self.ext, self.md.parser) @@ -47,6 +56,8 @@ def test_multiple_links(self): self.assertEqual(expected_string, converted_test_string) def test_ignore_http_schema(self): + '''Tests that non-relative links are not matched. + ''' test_string = self.read_test_file(self.processor_name, 'http_schema.md') processor = RelativeLinkPattern(self.ext, self.md.parser) @@ -57,6 +68,9 @@ def test_ignore_http_schema(self): self.assertEqual(expected_string, converted_test_string) def test_http_text(self): + '''Tests that text that is similiar to an ignore is + not ignored. + ''' test_string = self.read_test_file(self.processor_name, 'http_text.md') processor = RelativeLinkPattern(self.ext, self.md.parser) @@ -67,6 +81,8 @@ def test_http_text(self): self.assertEqual(expected_string, converted_test_string) def test_ignore_https_schema(self): + '''Tests that non-relative links are not matched. + ''' test_string = self.read_test_file(self.processor_name, 'https_schema.md') processor = RelativeLinkPattern(self.ext, self.md.parser) @@ -77,6 +93,9 @@ def test_ignore_https_schema(self): self.assertEqual(expected_string, converted_test_string) def test_https_text(self): + '''Tests that text that is similiar to an ignore is + not ignored. + ''' test_string = self.read_test_file(self.processor_name, 'https_text.md') processor = RelativeLinkPattern(self.ext, self.md.parser) @@ -87,6 +106,8 @@ def test_https_text(self): self.assertEqual(expected_string, converted_test_string) def test_ignore_ftp_schema(self): + '''Tests that non-relative links are not matched. + ''' test_string = self.read_test_file(self.processor_name, 'ftp_schema.md') processor = RelativeLinkPattern(self.ext, self.md.parser) @@ -97,6 +118,9 @@ def test_ignore_ftp_schema(self): self.assertEqual(expected_string, converted_test_string) def test_ftp_text(self): + '''Tests that text that is similiar to an ignore is + not ignored. + ''' test_string = self.read_test_file(self.processor_name, 'ftp_text.md') processor = RelativeLinkPattern(self.ext, self.md.parser) @@ -107,6 +131,8 @@ def test_ftp_text(self): self.assertEqual(expected_string, converted_test_string) def test_ignore_ftps_schema(self): + '''Tests that non-relative links are not matched. + ''' test_string = self.read_test_file(self.processor_name, 'ftps_schema.md') processor = RelativeLinkPattern(self.ext, self.md.parser) @@ -117,6 +143,9 @@ def test_ignore_ftps_schema(self): self.assertEqual(expected_string, converted_test_string) def test_ftps_text(self): + '''Tests that text that is similiar to an ignore is + not ignored. + ''' test_string = self.read_test_file(self.processor_name, 'ftps_text.md') processor = RelativeLinkPattern(self.ext, self.md.parser) @@ -127,6 +156,8 @@ def test_ftps_text(self): self.assertEqual(expected_string, converted_test_string) def test_ignore_mailto_schema(self): + '''Tests that non-relative links are not matched. + ''' test_string = self.read_test_file(self.processor_name, 'mailto_schema.md') processor = RelativeLinkPattern(self.ext, self.md.parser) @@ -137,6 +168,9 @@ def test_ignore_mailto_schema(self): self.assertEqual(expected_string, converted_test_string) def test_mailto_text(self): + '''Tests that text that is similiar to an ignore is + not ignored. + ''' test_string = self.read_test_file(self.processor_name, 'mailto_text.md') processor = RelativeLinkPattern(self.ext, self.md.parser) @@ -148,6 +182,8 @@ def test_mailto_text(self): def test_ignore_news_schema(self): + '''Tests that non-relative links are not matched. + ''' test_string = self.read_test_file(self.processor_name, 'news_schema.md') processor = RelativeLinkPattern(self.ext, self.md.parser) @@ -158,6 +194,9 @@ def test_ignore_news_schema(self): self.assertEqual(expected_string, converted_test_string) def test_news_text(self): + '''Tests that text that is similiar to an ignore is + not ignored. + ''' test_string = self.read_test_file(self.processor_name, 'news_text.md') processor = RelativeLinkPattern(self.ext, self.md.parser) @@ -168,6 +207,9 @@ def test_news_text(self): self.assertEqual(expected_string, converted_test_string) def test_www_text(self): + '''Tests that text that is similiar to an ignore is + not ignored. + ''' test_string = self.read_test_file(self.processor_name, 'www_text.md') processor = RelativeLinkPattern(self.ext, self.md.parser) diff --git a/kordac/tests/RemoveTitleTest.py b/kordac/tests/RemoveTitleTest.py index 33b3eb57..bd70abb5 100644 --- a/kordac/tests/RemoveTitleTest.py +++ b/kordac/tests/RemoveTitleTest.py @@ -5,16 +5,20 @@ from kordac.tests.ProcessorTest import ProcessorTest class RemoveTitleTest(ProcessorTest): - """Tests to check the 'remove-title' preprocesser works as intended.""" + '''Tests to check the 'remove-title' preprocesser works as intended. + ''' def __init__(self, *args, **kwargs): - """Set processor name in class for file names""" + '''Set processor name in class for asset file retrieval. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'remove-title' self.ext = Mock() self.ext.processor_info = ProcessorTest.loadProcessorInfo(self) def test_basic_usage(self): + '''Tests that common usecase works as expected. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') processor = RemoveTitlePreprocessor(self.ext, self.md.parser) @@ -25,6 +29,9 @@ def test_basic_usage(self): self.assertEqual(expected_string, converted_test_string) def test_multiple_headings(self): + '''Tests that multiple matches of the common usecase are + found and processed. + ''' test_string = self.read_test_file(self.processor_name, 'multiple_headings.md') processor = RemoveTitlePreprocessor(self.ext, self.md.parser) @@ -35,6 +42,9 @@ def test_multiple_headings(self): self.assertEqual(expected_string, converted_test_string) def test_multiple_level_one_headings(self): + '''Tests that only the first of the level one headings is + removed. + ''' test_string = self.read_test_file(self.processor_name, 'multiple_level_one_headings.md') processor = RemoveTitlePreprocessor(self.ext, self.md.parser) @@ -45,6 +55,9 @@ def test_multiple_level_one_headings(self): self.assertEqual(expected_string, converted_test_string) def test_no_headings(self): + '''Tests that the text of a document with no heading is + unchanged. + ''' test_string = self.read_test_file(self.processor_name, 'no_headings.md') processor = RemoveTitlePreprocessor(self.ext, self.md.parser) @@ -55,6 +68,9 @@ def test_no_headings(self): self.assertEqual(expected_string, converted_test_string) def test_level_two_heading(self): + '''Tests that a level two heading is also removed if found + first. + ''' test_string = self.read_test_file(self.processor_name, 'level_two_heading.md') processor = RemoveTitlePreprocessor(self.ext, self.md.parser) @@ -65,6 +81,10 @@ def test_level_two_heading(self): self.assertEqual(expected_string, converted_test_string) def test_no_heading_permalink(self): + '''Tests that generic text with a permalink is uneffected. + (So that there is no assumption of removing the first + permalink) + ''' test_string = self.read_test_file(self.processor_name, 'no_heading_permalink.md') processor = RemoveTitlePreprocessor(self.ext, self.md.parser) @@ -75,6 +95,9 @@ def test_no_heading_permalink(self): self.assertEqual(expected_string, converted_test_string) def test_no_space_title(self): + '''Tests that the all the heading is removed if spaces + are present. + ''' test_string = self.read_test_file(self.processor_name, 'no_space_title.md') processor = RemoveTitlePreprocessor(self.ext, self.md.parser) @@ -88,6 +111,9 @@ def test_no_space_title(self): # SYSTEM TESTS def test_processor_off(self): + '''Tests that disabling the processor, leaves the document + unchanged. + ''' # Create Kordac extension without processor enabled (off by default) kordac_extension = KordacExtension() test_string = self.read_test_file(self.processor_name, 'processor_off.md') diff --git a/kordac/tests/SaveTitleTest.py b/kordac/tests/SaveTitleTest.py index d9d21fa8..d1be6ad0 100644 --- a/kordac/tests/SaveTitleTest.py +++ b/kordac/tests/SaveTitleTest.py @@ -5,16 +5,19 @@ from kordac.tests.ProcessorTest import ProcessorTest class SaveTitleTest(ProcessorTest): - """Tests to check the 'save-title' preprocesser works as intended.""" + '''Tests to check the 'save-title' preprocesser works as intended. + ''' def __init__(self, *args, **kwargs): - """Set processor name in class for file names""" + '''Set processor name in class for file names.''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'save-title' self.ext = Mock() self.ext.processor_info = ProcessorTest.loadProcessorInfo(self) def test_basic_usage(self): + '''Tests the common usage case functions as expected. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') processor = SaveTitlePreprocessor(self.ext, self.md.parser) @@ -25,6 +28,8 @@ def test_basic_usage(self): self.assertEqual(expected_string, self.kordac_extension.title) def test_multiple_headings(self): + '''Tests that only the first of multiple headings is saved. + ''' test_string = self.read_test_file(self.processor_name, 'multiple_headings.md') processor = SaveTitlePreprocessor(self.ext, self.md.parser) @@ -35,6 +40,8 @@ def test_multiple_headings(self): self.assertEqual(expected_string, self.kordac_extension.title) def test_multiple_level_one_headings(self): + '''Tests that only the first of multiple headings is saved. + ''' test_string = self.read_test_file(self.processor_name, 'multiple_level_one_headings.md') processor = SaveTitlePreprocessor(self.ext, self.md.parser) @@ -45,6 +52,8 @@ def test_multiple_level_one_headings(self): self.assertEqual(expected_string, self.kordac_extension.title) def test_no_headings(self): + '''Tests that if there is no heading that the title remains none. + ''' test_string = self.read_test_file(self.processor_name, 'no_headings.md') processor = SaveTitlePreprocessor(self.ext, self.md.parser) @@ -54,6 +63,8 @@ def test_no_headings(self): self.assertIsNone(self.kordac_extension.title) def test_level_two_heading(self): + '''Tests that the first heading is saved regardless of level. + ''' test_string = self.read_test_file(self.processor_name, 'level_two_heading.md') processor = SaveTitlePreprocessor(self.ext, self.md.parser) @@ -64,6 +75,8 @@ def test_level_two_heading(self): self.assertEqual(expected_string, self.kordac_extension.title) def test_no_heading_permalink(self): + '''Tests that the first permalink is not matched erroneously. + ''' test_string = self.read_test_file(self.processor_name, 'no_heading_permalink.md') processor = SaveTitlePreprocessor(self.ext, self.md.parser) @@ -73,6 +86,9 @@ def test_no_heading_permalink(self): self.assertIsNone(self.kordac_extension.title) def test_no_space_title(self): + '''Tests that space in the title does not + change the saving behaviour. + ''' test_string = self.read_test_file(self.processor_name, 'no_space_title.md') processor = SaveTitlePreprocessor(self.ext, self.md.parser) @@ -85,6 +101,9 @@ def test_no_space_title(self): # SYSTEM TESTS def test_no_result_processor_off(self): + '''Tests that disabling the processor correctly + functions. + ''' # Create Kordac extension without processor enabled kordac_extension = KordacExtension() test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') diff --git a/kordac/tests/ScratchTest.py b/kordac/tests/ScratchTest.py index e1a196fd..14292f55 100644 --- a/kordac/tests/ScratchTest.py +++ b/kordac/tests/ScratchTest.py @@ -7,16 +7,27 @@ from kordac.tests.ProcessorTest import ProcessorTest class ScratchTest(ProcessorTest): + '''Scratch blocks are unique in that they override behaviour in + markdown and behaviour in markdown extensions, while also retaining + compatiability. + ''' def __init__(self, *args, **kwargs): + '''Sets name for loading test assets. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'scratch' def setUp(self): + '''Overrides the generic setup to load the fenced_code + extension by default (as this is the desired usecase). + ''' self.kordac_extension = KordacExtension([self.processor_name], {}, ['markdown.extensions.fenced_code']) #~ # Doc Tests #~ def test_doc_example_basic(self): + '''An example of common useage. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.kordac_extension]) @@ -34,6 +45,8 @@ def test_doc_example_basic(self): self.assertSetEqual(actual, expected) 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') html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) @@ -56,6 +69,8 @@ def test_doc_example_override_html(self): # Other Tests #~ def test_example_standard_markdown_block(self): + '''Tests that even without extensions it behaves as expected. + ''' kordac_extension = KordacExtension([self.processor_name], {}, []) test_string = self.read_test_file(self.processor_name, 'example_standard_markdown_block.md') @@ -74,6 +89,8 @@ def test_example_standard_markdown_block(self): self.assertSetEqual(actual, expected) def test_example_separate_blocks(self): + '''Tests that code separated by whitespace is still processed. + ''' test_string = self.read_test_file(self.processor_name, 'example_separate_blocks.md') converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.kordac_extension]) @@ -92,6 +109,8 @@ def test_example_separate_blocks(self): def test_example_multiple_codeblocks(self): + '''Tests that multiple codeblocks are processed independently. + ''' test_string = self.read_test_file(self.processor_name, 'example_multiple_codeblocks.md') converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.kordac_extension]) @@ -117,6 +136,9 @@ def test_example_multiple_codeblocks(self): self.assertSetEqual(actual, expected) def test_example_multiple_codeblocks_2(self): + '''Tests that enabling the codehilite extension does not effect + the functionality. (Loads the compatiability processor). + ''' extensions = ['markdown.extensions.codehilite', 'markdown.extensions.fenced_code'] kordac_extension = KordacExtension([self.processor_name], {}, extensions) test_string = self.read_test_file(self.processor_name, 'example_multiple_codeblocks_2.md') @@ -144,6 +166,9 @@ def test_example_multiple_codeblocks_2(self): self.assertSetEqual(actual, expected) def test_example_other_code(self): + '''Tests that other codeblocks that are not scratch codeblocks + are not erroneously matched. + ''' test_string = self.read_test_file(self.processor_name, 'example_other_code.md') converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.kordac_extension]) diff --git a/kordac/tests/SmokeTests.py b/kordac/tests/SmokeTests.py index c73d4421..8563efb7 100644 --- a/kordac/tests/SmokeTests.py +++ b/kordac/tests/SmokeTests.py @@ -2,25 +2,21 @@ from kordac import Kordac class SmokeDocsTest(unittest.TestCase): - """Tests that docs build if they are found.""" + '''Tests that docs build if they are found.''' def __init__(self, *args, **kwargs): unittest.TestCase.__init__(self, *args, **kwargs) self.maxDiff = None self.build_path = "docs/build" - def setUp(self): - pass - - def tearDown(self): - pass - @unittest.skipIf( - not os.path.isdir("docs") and os.name not in ['nt', 'posix'], - "Docs are not present") + not os.path.isdir('docs') and os.name not in ['nt', 'posix'], + 'Docs are not present') def test_compile_docs(self): + '''This test is skipped if the docs directory is not found. + ''' system = os.name - # TODO: Cleanup old build + command = None if system == 'nt': command = 'make.bat' @@ -28,7 +24,7 @@ def test_compile_docs(self): command = 'make' if command is None: - self.fail("Unknown operating system, but test still run. This should never happen.") + self.fail('Unknown operating system, but test still run. This should never happen.') p = subprocess.Popen([command, 'clean'], cwd='docs', stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=None) p.wait(timeout=10) # Will throw exception if times out @@ -39,7 +35,7 @@ def test_compile_docs(self): self.assertEqual(p.returncode, 0) # Success returncode class SmokeFileTest(unittest.TestCase): - """Tests opening of files and that kordac generates some output.""" + '''Tests opening of files and that kordac generates some output.''' def __init__(self, *args, **kwargs): unittest.TestCase.__init__(self, *args, **kwargs) @@ -48,12 +44,18 @@ def __init__(self, *args, **kwargs): self.assets_template = 'kordac/tests/assets/smoke/{}' def setUp(self): + '''Run before any testcases. + ''' self.kordac = Kordac() def tearDown(self): + '''Run after any testcases. + ''' self.kordac = None def test_compile_files(self): + '''Tests that some example files are converted. + ''' for chapter in ['algorithms.md', 'introduction.md']: with open(self.assets_template.format(chapter), 'r') as f: text = f.read() @@ -65,6 +67,9 @@ def test_compile_files(self): self.assertTrue(len(result.html_string) > 0) def test_compile_files_custom(self): + '''Tests that some example files are converted with custom + html-templates. + ''' custom_templates = { 'image': '', 'boxed-text': '
    ' diff --git a/kordac/tests/TableOfContentsTest.py b/kordac/tests/TableOfContentsTest.py index 5d3dd5f4..76766239 100644 --- a/kordac/tests/TableOfContentsTest.py +++ b/kordac/tests/TableOfContentsTest.py @@ -7,7 +7,15 @@ class TableOfContentsTest(ProcessorTest): + '''The table-of-contents processor inherits from the generic + tag procesor. The tests contained here test that arguments + and the output (html-template) work as expected. + ''' + def __init__(self, *args, **kwargs): + '''Sets up a generic tag to test that the matches are + occuring appropriately. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'table-of-contents' self.ext = Mock() @@ -19,6 +27,8 @@ def __init__(self, *args, **kwargs): # Doc Tests #~ def test_doc_example_basic(self): + '''A generic example of common usage. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') blocks = self.to_blocks(test_string) @@ -29,6 +39,8 @@ def test_doc_example_basic(self): self.assertEqual(expected_string, converted_test_string) def test_doc_example_override_html(self): + '''A example showing how to override the html template. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') blocks = self.to_blocks(test_string) diff --git a/kordac/tests/VideoTest.py b/kordac/tests/VideoTest.py index 87c0583c..cc49817f 100644 --- a/kordac/tests/VideoTest.py +++ b/kordac/tests/VideoTest.py @@ -12,7 +12,9 @@ class VideoTest(ProcessorTest): def __init__(self, *args, **kwargs): - """Set processor name in class for file names""" + '''Sets up a processor name and info for accessing testing + assets. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'video' self.ext = Mock() @@ -157,4 +159,3 @@ def test_doc_example_override_html(self): converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - diff --git a/kordac/tests/start_tests.py b/kordac/tests/start_tests.py index 79895e86..0516189d 100644 --- a/kordac/tests/start_tests.py +++ b/kordac/tests/start_tests.py @@ -22,6 +22,9 @@ from kordac.tests.BeautifyTest import BeautifyTest def parse_args(): + '''Parses the arguments for running the test suite, these are + useful for developing when parts of verto are known to fail. + ''' opts = optparse.OptionParser( usage='Run the command `python -m kordac.tests.start_tests` from the level above the kordac directory.', description="Verifies that Kordac is functional compared to the testing suite.") opts.add_option('--travis', @@ -37,18 +40,23 @@ def parse_args(): return options, arguments def smoke_suite(): + '''Builds the smoke tests. + ''' return unittest.TestSuite(( unittest.makeSuite(SmokeDocsTest), unittest.makeSuite(SmokeFileTest), )) def system_suite(): + '''Builds specific system tests. + ''' return unittest.TestSuite(( unittest.makeSuite(ConfigurationTest) )) def unit_suite(): - # NTS what order should these go in? + '''Builds unittests. (Not really unittests). + ''' return unittest.TestSuite(( unittest.makeSuite(SaveTitleTest), unittest.makeSuite(RemoveTitleTest), From c01b8c0ac04eb24116eb1868e169eb21f5e62a0f Mon Sep 17 00:00:00 2001 From: Hayden Jackson Date: Mon, 27 Mar 2017 12:40:39 +1300 Subject: [PATCH 54/86] WIP document tests. --- kordac/tests/VideoTest.py | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/kordac/tests/VideoTest.py b/kordac/tests/VideoTest.py index cc49817f..f2c99eb1 100644 --- a/kordac/tests/VideoTest.py +++ b/kordac/tests/VideoTest.py @@ -10,6 +10,10 @@ class VideoTest(ProcessorTest): + '''The Video processor is similar to the a generic tag + except that it requires custom validation for Video + urls to extract identifiers and embedded properly. + ''' def __init__(self, *args, **kwargs): '''Sets up a processor name and info for accessing testing @@ -26,6 +30,9 @@ def __init__(self, *args, **kwargs): self.ext.processor_info = ProcessorTest.loadProcessorInfo(self) def test_contains_no_video(self): + '''Tests that input that doesn't use the video processor tag is + unchanged. + ''' test_string = self.read_test_file(self.processor_name, 'contains_no_video.md') blocks = self.to_blocks(test_string) @@ -36,6 +43,8 @@ def test_contains_no_video(self): self.assertEqual(converted_test_string, expected_file_string) def test_youtube_embed_link(self): + '''Tests youtube embed links are properly embedded. + ''' test_string = self.read_test_file(self.processor_name, 'youtube_embed_link.md') blocks = self.to_blocks(test_string) @@ -47,6 +56,8 @@ def test_youtube_embed_link(self): self.assertEqual(converted_test_string, expected_file_string) def test_youtube_watch_link(self): + '''Tests that youtube links are converted into embedded form. + ''' test_string = self.read_test_file(self.processor_name, 'youtube_watch_link.md') blocks = self.to_blocks(test_string) @@ -57,6 +68,8 @@ def test_youtube_watch_link(self): self.assertEqual(converted_test_string, expected_file_string) def test_youtube_be_link(self): + '''Tests that short youtube links are embedded. + ''' test_string = self.read_test_file(self.processor_name, 'youtube_be_link.md') blocks = self.to_blocks(test_string) @@ -67,6 +80,8 @@ def test_youtube_be_link(self): self.assertEqual(converted_test_string, expected_file_string) def test_vimeo_link(self): + '''Tests that vimeo links are converted into embedded form. + ''' test_string = self.read_test_file(self.processor_name, 'vimeo_link.md') blocks = self.to_blocks(test_string) @@ -77,6 +92,8 @@ def test_vimeo_link(self): self.assertEqual(converted_test_string, expected_file_string) def test_vimeo_player_link(self): + '''Tests that the vimeo player links are embedded. + ''' test_string = self.read_test_file(self.processor_name, 'vimeo_player_link.md') blocks = self.to_blocks(test_string) @@ -87,6 +104,8 @@ def test_vimeo_player_link(self): self.assertEqual(converted_test_string, expected_file_string) def test_multiple_youtube_links(self): + '''Tests output of multiple youtube links. + ''' test_string = self.read_test_file(self.processor_name, 'multiple_youtube_links.md') blocks = self.to_blocks(test_string) @@ -97,6 +116,8 @@ def test_multiple_youtube_links(self): self.assertEqual(converted_test_string, expected_file_string) def test_multiple_vimeo_links(self): + '''Tests output of multiple vimeo links. + ''' test_string = self.read_test_file(self.processor_name, 'multiple_vimeo_links.md') blocks = self.to_blocks(test_string) @@ -107,6 +128,9 @@ def test_multiple_vimeo_links(self): self.assertEqual(converted_test_string, expected_file_string) def test_youtube_and_vimeo_links(self): + '''Test that youtube links and vimeo links work together in the + same document. + ''' test_string = self.read_test_file(self.processor_name, 'youtube_and_vimeo_links.md') blocks = self.to_blocks(test_string) @@ -117,6 +141,9 @@ def test_youtube_and_vimeo_links(self): self.assertEqual(converted_test_string, expected_file_string) def test_unsupported_video_type(self): + '''Tests that links to other websites result in an + UnsupportedVideoPlayerError exception. + ''' test_string = self.read_test_file(self.processor_name, 'unsupported_video_type.md') blocks = self.to_blocks(test_string) @@ -125,6 +152,9 @@ def test_unsupported_video_type(self): self.assertRaises(UnsupportedVideoPlayerError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) def test_missing_identifier(self): + '''Tests that a youtube link without an identifier will throw + the NoVideoIdentifierError exception. + ''' test_string = self.read_test_file(self.processor_name, 'missing_identifier.md') blocks = self.to_blocks(test_string) @@ -132,12 +162,12 @@ def test_missing_identifier(self): self.assertRaises(NoVideoIdentifierError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) - #~ # Doc Tests #~ - def test_doc_example_basic(self): + '''A generic example of common usage. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') blocks = self.to_blocks(test_string) @@ -148,6 +178,8 @@ def test_doc_example_basic(self): self.assertEqual(expected_string, converted_test_string) def test_doc_example_override_html(self): + '''A example showing how to override the html template. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') blocks = self.to_blocks(test_string) From b9f0f358134eddf2044053e460b7dad62d986f9e Mon Sep 17 00:00:00 2001 From: Hayden Jackson Date: Mon, 27 Mar 2017 16:43:32 +1300 Subject: [PATCH 55/86] Updated build test to work on a windows os. --- docs/make.bat | 14 +++++++++++++- kordac/tests/SmokeTests.py | 33 +++++++++++++++++---------------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/docs/make.bat b/docs/make.bat index 3aab57a4..732568aa 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -1,12 +1,23 @@ @ECHO OFF - +setlocal pushd %~dp0 REM Command file for Sphinx documentation + if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) +if "%SPHINXOPTS%" == "" ( + if not "%1" == "SPHINXOPTS" goto :skip +) +shift /1 +set SPHINXOPTS=%1 +set SPHINXOPTS=%SPHINXOPTS:~1,-1% +shift /1 +:skip + + set SOURCEDIR=source set BUILDDIR=build set SPHINXPROJ=Kordac @@ -34,3 +45,4 @@ goto end :end popd +endlocal diff --git a/kordac/tests/SmokeTests.py b/kordac/tests/SmokeTests.py index 8563efb7..66422076 100644 --- a/kordac/tests/SmokeTests.py +++ b/kordac/tests/SmokeTests.py @@ -9,28 +9,29 @@ def __init__(self, *args, **kwargs): self.maxDiff = None self.build_path = "docs/build" - @unittest.skipIf( - not os.path.isdir('docs') and os.name not in ['nt', 'posix'], - 'Docs are not present') + @unittest.skipIf(not os.path.isdir('docs') and os.name not in ['nt', 'posix'], 'Docs are not present') def test_compile_docs(self): '''This test is skipped if the docs directory is not found. ''' - system = os.name - - command = None - if system == 'nt': - command = 'make.bat' - elif system == 'posix': - command = 'make' - - if command is None: - self.fail('Unknown operating system, but test still run. This should never happen.') - - p = subprocess.Popen([command, 'clean'], cwd='docs', stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=None) + cwd = os.path.abspath('docs') + command = 'make' + options = 'SPHINXOPTS=\'-W\'' + + p = subprocess.Popen([command, 'clean'], + cwd=cwd, + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=None, + shell=True) p.wait(timeout=10) # Will throw exception if times out self.assertEqual(p.returncode, 0) # Success returncode - p = subprocess.Popen([command, 'SPHINXOPTS=\'-W\'', 'html'], cwd='docs', stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=None) + p = subprocess.Popen([command, options, 'html'], + cwd=cwd, + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=None, + shell=True) p.wait(timeout=10) # Will throw exception if times out self.assertEqual(p.returncode, 0) # Success returncode From 0a2e3387b78b1358ecee836377fea65cf5597e1e Mon Sep 17 00:00:00 2001 From: Hayden Jackson Date: Mon, 27 Mar 2017 17:15:29 +1300 Subject: [PATCH 56/86] System test now tests all processors. --- kordac/Kordac.py | 17 +++--- .../processors/InteractiveBlockProcessor.py | 3 +- kordac/tests/ConfigurationTest.py | 34 ++++++++--- .../assets/configuration/all_processors.md | 33 +++++++++++ .../all_processors_custom_expected.html | 57 ------------------- .../all_processors_custom_html_expected.html | 40 +++++++++++++ ...ll_processors_except_comment_expected.html | 40 +++++++++++++ .../all_processors_expected.html | 40 +++++++++++++ .../custom_processors_expected.html | 43 ++++++++++++++ .../multiline_templates_expected.html | 40 +++++++++++++ 10 files changed, 272 insertions(+), 75 deletions(-) delete mode 100644 kordac/tests/assets/configuration/all_processors_custom_expected.html diff --git a/kordac/Kordac.py b/kordac/Kordac.py index efff8279..8b20c9bf 100644 --- a/kordac/Kordac.py +++ b/kordac/Kordac.py @@ -2,20 +2,21 @@ from kordac.KordacExtension import KordacExtension DEFAULT_PROCESSORS = frozenset({ - 'save-title', - 'comment', - 'button-link', - 'panel', - 'image', - 'relative-link', 'boxed-text', 'button-link', + 'comment', + 'conditional', 'glossary-link', 'heading', - 'interactive', 'iframe', + 'image', + 'interactive', + 'panel', + 'relative-link', + 'save-title', + 'scratch', 'table-of-contents', - 'scratch' + 'video' }) diff --git a/kordac/processors/InteractiveBlockProcessor.py b/kordac/processors/InteractiveBlockProcessor.py index 59c936bd..f56d3e8c 100644 --- a/kordac/processors/InteractiveBlockProcessor.py +++ b/kordac/processors/InteractiveBlockProcessor.py @@ -19,6 +19,7 @@ def __init__(self, ext, *args, **kwargs): self.relative_file_template = ext.jinja_templates['relative-file-link'] self.scripts = ext.required_files["page_scripts"] self.required = ext.required_files["interactives"] + self.required_images = ext.required_files["images"] def test(self, parent, block): ''' Tests a block to see if the run method should be applied. @@ -74,7 +75,7 @@ def run(self, parent, blocks): external_path_match = re.search(r'^http', file_path) if external_path_match is None: # internal image - self.required.add(file_path) + self.required_images.add(file_path) file_path = self.relative_file_template.render({'file_path': file_path}) context = dict() diff --git a/kordac/tests/ConfigurationTest.py b/kordac/tests/ConfigurationTest.py index 9e782c50..8ee7dbe2 100644 --- a/kordac/tests/ConfigurationTest.py +++ b/kordac/tests/ConfigurationTest.py @@ -1,5 +1,6 @@ import unittest from kordac.Kordac import Kordac, KordacResult +from kordac.processors.ScratchTreeprocessor import ScratchImageMetaData from kordac.utils.HeadingNode import HeadingNode import jinja2 from kordac.tests.BaseTest import BaseTest @@ -38,17 +39,33 @@ def test_multiple_calls(self): html_string=self.read_test_file(self.test_name, 'all_processors_expected.html', strip=True), title='Example Title', required_files={ - 'interactives': set(), - 'images': set(), + 'interactives': { + 'binary-cards' + }, + 'images': { + 'binary-cards/thumbnail.png' + }, 'page_scripts': set(), - 'scratch_images': 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( - title='Example Title', - title_slug='example-title', - level=1, - children=() - ),), + title='Example Title', + title_slug='example-title', + level=1, + children=(), + ), + HeadingNode( + title='Example Title 2', + title_slug='example-title-2', + level=1, + children=() + ), + ), required_glossary_terms=defaultdict(list) ) ), @@ -127,7 +144,6 @@ def test_default_processors_on_creation(self): creation. ''' kordac = Kordac() - # kordac.clear_templates() test_string = self.read_test_file(self.test_name, 'all_processors.md') converted_test_string = kordac.convert(test_string).html_string expected_string = self.read_test_file(self.test_name, 'all_processors_expected.html', strip=True) diff --git a/kordac/tests/assets/configuration/all_processors.md b/kordac/tests/assets/configuration/all_processors.md index 460963ed..b3178d32 100644 --- a/kordac/tests/assets/configuration/all_processors.md +++ b/kordac/tests/assets/configuration/all_processors.md @@ -2,6 +2,8 @@ This is a sentence. +# Example Title 2 + {comment This is a comment for other authors to read} Check out this [resource](resource/134). @@ -21,3 +23,34 @@ This text is the panel's contents. Put your introduction to what bits are here. {boxed-text end} + +{button-link link="http://www.google.com" text="Visit Google"} + +{conditional if condition="version == 'teacher'"} + +This is text that only teachers should see. + +{conditional end} + +It's worth considering which {glossary-link term="algorithm"}algorithms{glossary-link end} should be used. + +{iframe link="https://github.com/"} + +{interactive name="binary-cards" type="iframe" parameters="digits=5&start=BBBBB"} + + scratch + 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 + +{table-of-contents} + +{video url="https://www.youtube.com/watch?v=dQw4w9WgXcQ"} diff --git a/kordac/tests/assets/configuration/all_processors_custom_expected.html b/kordac/tests/assets/configuration/all_processors_custom_expected.html deleted file mode 100644 index 1f2fcdb3..00000000 --- a/kordac/tests/assets/configuration/all_processors_custom_expected.html +++ /dev/null @@ -1,57 +0,0 @@ -

    - - {{ chapter.number }}. - - Example Title -

    -

    - This is a sentence. -

    -

    - {comment This is a comment for other authors to read} -

    -

    - Check out this - - resource - - . -

    -
    -
    - - Teacher Note: - - Guides for Algorithms -
    -
    -

    - This text is the panel's contents. -

    -
    -
    -
    - -

    - Placeholder image -

    -

    - - Source - -

    -
    -

    - {boxed-text} -

    -

    - - Computer Science Report for 2.44 - -

    -

    - Put your introduction to what bits are here. -

    -

    - {boxed-text end} -

    diff --git a/kordac/tests/assets/configuration/all_processors_custom_html_expected.html b/kordac/tests/assets/configuration/all_processors_custom_html_expected.html index 43ced5f2..68a8e410 100644 --- a/kordac/tests/assets/configuration/all_processors_custom_html_expected.html +++ b/kordac/tests/assets/configuration/all_processors_custom_html_expected.html @@ -7,6 +7,12 @@

    This is a sentence.

    +

    + + {{ chapter.number }}. + + Example Title 2 +

    Check out this @@ -38,3 +44,37 @@

    Put your introduction to what bits are here.

    + + Visit Google + +{% if version == 'teacher' %} +

    + This is text that only teachers should see. +

    +{% endif %} +

    + It's worth considering which + + algorithms + + should be used. +

    + + +
    + + +
    +{{ table_of_contents }} +
    + +
    diff --git a/kordac/tests/assets/configuration/all_processors_except_comment_expected.html b/kordac/tests/assets/configuration/all_processors_except_comment_expected.html index dc2ca477..ddac6ed5 100644 --- a/kordac/tests/assets/configuration/all_processors_except_comment_expected.html +++ b/kordac/tests/assets/configuration/all_processors_except_comment_expected.html @@ -7,6 +7,12 @@

    This is a sentence.

    +

    + + {{ chapter.number }}. + + Example Title 2 +

    {comment This is a comment for other authors to read}

    @@ -51,3 +57,37 @@

    Put your introduction to what bits are here.

    + + Visit Google + +{% if version == 'teacher' %} +

    + This is text that only teachers should see. +

    +{% endif %} +

    + It's worth considering which + + algorithms + + should be used. +

    + + +
    + + +
    +{{ table_of_contents }} +
    + +
    diff --git a/kordac/tests/assets/configuration/all_processors_expected.html b/kordac/tests/assets/configuration/all_processors_expected.html index 1a89f841..283046a3 100644 --- a/kordac/tests/assets/configuration/all_processors_expected.html +++ b/kordac/tests/assets/configuration/all_processors_expected.html @@ -7,6 +7,12 @@

    This is a sentence.

    +

    + + {{ chapter.number }}. + + Example Title 2 +

    Check out this @@ -48,3 +54,37 @@

    Put your introduction to what bits are here.

    +
    + Visit Google + +{% if version == 'teacher' %} +

    + This is text that only teachers should see. +

    +{% endif %} +

    + It's worth considering which + + algorithms + + should be used. +

    + + +
    + + +
    +{{ table_of_contents }} +
    + +
    diff --git a/kordac/tests/assets/configuration/custom_processors_expected.html b/kordac/tests/assets/configuration/custom_processors_expected.html index 529e3d79..498a46ed 100644 --- a/kordac/tests/assets/configuration/custom_processors_expected.html +++ b/kordac/tests/assets/configuration/custom_processors_expected.html @@ -4,6 +4,9 @@

    This is a sentence.

    +

    + Example Title 2 +

    {comment This is a comment for other authors to read}

    @@ -52,3 +55,43 @@

    {boxed-text end}

    +

    + {button-link link="http://www.google.com" text="Visit Google"} +

    +

    + {conditional if condition="version == 'teacher'"} +

    +

    + This is text that only teachers should see. +

    +

    + {conditional end} +

    +

    + It's worth considering which {glossary-link term="algorithm"}algorithms{glossary-link end} should be used. +

    +

    + {iframe link="https://github.com/"} +

    +

    + {interactive name="binary-cards" type="iframe" parameters="digits=5&start=BBBBB"} +

    +
    scratch
    +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} +

    +

    + {video url="https://www.youtube.com/watch?v=dQw4w9WgXcQ"} +

    diff --git a/kordac/tests/assets/configuration/multiline_templates_expected.html b/kordac/tests/assets/configuration/multiline_templates_expected.html index 024b92a3..b3ba5d68 100644 --- a/kordac/tests/assets/configuration/multiline_templates_expected.html +++ b/kordac/tests/assets/configuration/multiline_templates_expected.html @@ -7,6 +7,12 @@

    This is a sentence.

    +

    + + 2.0.0.0.0.0. + + Example Title 2 +

    Check out this @@ -42,3 +48,37 @@

    +
    + Visit Google + +{% if version == 'teacher' %} +

    + This is text that only teachers should see. +

    +{% endif %} +

    + It's worth considering which + + algorithms + + should be used. +

    + + +
    + + +
    +{{ table_of_contents }} +
    + +
    From 7525107407d2019068429f91806c4690c6d87f28 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Tue, 28 Mar 2017 11:33:19 +1300 Subject: [PATCH 57/86] Added test for comments within a container block. --- kordac/tests/CommentTest.py | 12 ++++++++++++ .../assets/comment/comment_within_block_container.md | 5 +++++ .../comment_within_block_container_expected.html | 10 ++++++++++ 3 files changed, 27 insertions(+) create mode 100644 kordac/tests/assets/comment/comment_within_block_container.md create mode 100644 kordac/tests/assets/comment/comment_within_block_container_expected.html diff --git a/kordac/tests/CommentTest.py b/kordac/tests/CommentTest.py index 1eac9d93..04141066 100644 --- a/kordac/tests/CommentTest.py +++ b/kordac/tests/CommentTest.py @@ -78,6 +78,18 @@ def test_comment_contains_comment(self): expected_string = self.read_test_file(self.processor_name, 'comment_contains_comment_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) + def test_comment_within_block_container(self): + '''Tests that comments are removed from containers. + ''' + kordac_extension = KordacExtension([self.processor_name, 'panel'], {}) + test_string = self.read_test_file(self.processor_name, 'comment_within_block_container.md') + + self.assertTrue(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + expected_string = self.read_test_file(self.processor_name, 'comment_within_block_container_expected.html', strip=True) + self.assertEqual(expected_string, converted_test_string) + #~ # Doc Tests #~ diff --git a/kordac/tests/assets/comment/comment_within_block_container.md b/kordac/tests/assets/comment/comment_within_block_container.md new file mode 100644 index 00000000..89a0bd6c --- /dev/null +++ b/kordac/tests/assets/comment/comment_within_block_container.md @@ -0,0 +1,5 @@ +{panel type="lipsum" title="Lipsum Lorem"} + +{comment This is a comment for other authors to read} + +{panel end} diff --git a/kordac/tests/assets/comment/comment_within_block_container_expected.html b/kordac/tests/assets/comment/comment_within_block_container_expected.html new file mode 100644 index 00000000..af6d002b --- /dev/null +++ b/kordac/tests/assets/comment/comment_within_block_container_expected.html @@ -0,0 +1,10 @@ +
    +
    + + Lipsum Lorem + +
    +
    +
    +
    +
    From 88516ed497752306a931c64f9073722619e9c2fe Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Tue, 28 Mar 2017 14:20:04 +1300 Subject: [PATCH 58/86] Tests and bug fixes for conditional processor. --- kordac/processor-info.json | 5 ++ kordac/processors/ConditionalProcessor.py | 51 ++++++++-------- kordac/tests/ConditionalTest.py | 58 +++++++++++++++++++ .../conditional/else_then_elif_error.md | 13 +++++ .../assets/conditional/example_single_elif.md | 9 +++ .../example_single_elif_expected.html | 9 +++ .../missing_end_statement_error.md | 11 ++++ .../conditional/missing_if_statement_error.md | 5 ++ .../assets/conditional/multiple_else_error.md | 13 +++++ 9 files changed, 149 insertions(+), 25 deletions(-) create mode 100644 kordac/tests/assets/conditional/else_then_elif_error.md create mode 100644 kordac/tests/assets/conditional/example_single_elif.md create mode 100644 kordac/tests/assets/conditional/example_single_elif_expected.html create mode 100644 kordac/tests/assets/conditional/missing_end_statement_error.md create mode 100644 kordac/tests/assets/conditional/missing_if_statement_error.md create mode 100644 kordac/tests/assets/conditional/multiple_else_error.md diff --git a/kordac/processor-info.json b/kordac/processor-info.json index 5191f29b..ea8da305 100644 --- a/kordac/processor-info.json +++ b/kordac/processor-info.json @@ -60,6 +60,7 @@ }, "conditional": { "class": "custom", + "pattern": "(^|\\n) *\\{conditional ?(?P[^\\}]*)\\} *(\\n|$)", "arguments": { "condition": { "required": false, @@ -76,6 +77,10 @@ "else": { "required": false, "dependencies": [] + }, + "end": { + "required": false, + "dependencies": [] } } }, diff --git a/kordac/processors/ConditionalProcessor.py b/kordac/processors/ConditionalProcessor.py index 669edf9e..ad3baf8c 100644 --- a/kordac/processors/ConditionalProcessor.py +++ b/kordac/processors/ConditionalProcessor.py @@ -1,10 +1,10 @@ -from kordac.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor +from markdown.blockprocessors import BlockProcessor from kordac.processors.errors.TagNotMatchedError import TagNotMatchedError from kordac.processors.utils import etree, parse_arguments, parse_flag, blocks_to_string from collections import OrderedDict +import re - -class ConditionalProcessor(GenericContainerBlockProcessor): +class ConditionalProcessor(BlockProcessor): ''' Searches a Document for conditional tags e.g. {conditonal flag condition=""} The processor matches the following `elif` and `else` statements in the document and @@ -16,7 +16,14 @@ def __init__(self, ext, *args, **kwargs): Args: ext: An instance of the KordacExtension. ''' - super().__init__('conditional', ext, *args, **kwargs) + super().__init__(*args, **kwargs) + self.processor = 'conditional' + self.pattern = re.compile(ext.processor_info[self.processor]['pattern']) + self.arguments = ext.processor_info[self.processor]['arguments'] + template_name = ext.processor_info.get('template_name', self.processor) + self.template = ext.jinja_templates[template_name] + self.template_parameters = ext.processor_info[self.processor].get('template_parameters', None) + def test(self, parent, block): ''' Tests if the block if it contains any type of conditional @@ -28,8 +35,7 @@ def test(self, parent, block): Returns: Return true if any conditional tag is found. ''' - return (self.p_start.search(block) is not None - or self.p_end.search(block) is not None) + return self.pattern.search(block) is not None def run(self, parent, blocks): ''' Replaces all conditionals with the given html template. @@ -48,20 +54,16 @@ def run(self, parent, blocks): block = blocks.pop(0) context = dict() - start_tag = self.p_start.search(block) - end_tag = self.p_end.search(block) - - if ((start_tag is None and end_tag is not None) - or (start_tag and end_tag and start_tag.end() > end_tag.start())): - raise TagNotMatchedError(self.processor, block, 'end tag found before start tag') - + start_tag = self.pattern.search(block) is_if = parse_flag('if', start_tag.group('args')) # elif or else before an if conditional if not is_if: is_elif = parse_flag('elif', start_tag.group('args')) is_else = parse_flag('else', start_tag.group('args')) - msg = '{} conditional found before if'.format('elif' if is_elif else 'else' if is_else else 'unrecognised') + is_end = parse_flag('end', start_tag.group('args')) + string = 'elif' if is_elif else 'else' if is_else else 'end' if is_end else 'unrecognised' + msg = '{} conditional found before if'.format(string) raise TagNotMatchedError(self.processor, block, msg) # Put left overs back on blocks, should be empty though @@ -99,6 +101,11 @@ def run(self, parent, blocks): context['has_else'] = has_else context['else_content'] = else_content + if (next_tag is None + or (next_tag is not None and not parse_flag('end', next_tag.group('args')))): + msg = 'end conditional not found' + raise TagNotMatchedError(self.processor, block, msg) + # Render template and compile into an element html_string = self.template.render(context) node = etree.fromstring(html_string) @@ -132,34 +139,28 @@ def get_content(self, blocks): block = blocks.pop(0) # Do we have either a start or end tag - next_tag = self.p_start.search(block) - end_tag = self.p_end.search(block) + next_tag = self.pattern.search(block) is_if = next_tag is not None and parse_flag('if', next_tag.group('args')) is_elif = next_tag is not None and parse_flag('elif', next_tag.group('args')) is_else = next_tag is not None and parse_flag('else', next_tag.group('args')) + is_end = next_tag is not None and parse_flag('end', next_tag.group('args')) # Keep track of how many inner boxed-text start tags we have seen if is_if: inner_if_tags += 1 if inner_if_tags != inner_end_tags: - if end_tag is not None: + if is_end: inner_end_tags += 1 - end_tag = None - elif is_elif or is_else: + elif is_elif or is_else or is_end: if block[:next_tag.start()].strip() != '': content_blocks.append(block[:next_tag.start()]) the_rest = block[next_tag.end():] break - elif end_tag is not None: - if block[:end_tag.start()].strip() != '': - content_blocks.append(block[:end_tag.start()]) - the_rest = block[end_tag.end():] - break content_blocks.append(block) - if the_rest.strip() != '': + if the_rest and the_rest.strip() != '': blocks.insert(0, the_rest) # Keep anything off the end, should be empty though if inner_if_tags != inner_end_tags: diff --git a/kordac/tests/ConditionalTest.py b/kordac/tests/ConditionalTest.py index 01ce524e..c334dcbb 100644 --- a/kordac/tests/ConditionalTest.py +++ b/kordac/tests/ConditionalTest.py @@ -3,6 +3,7 @@ from kordac.KordacExtension import KordacExtension from kordac.processors.ConditionalProcessor import ConditionalProcessor +from kordac.processors.errors.TagNotMatchedError import TagNotMatchedError from kordac.tests.ProcessorTest import ProcessorTest @@ -48,6 +49,63 @@ def test_example_elif_noelse(self): expected_string = self.read_test_file(self.processor_name, 'example_elif_noelse_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) + def test_example_single_elif(self): + '''Example showing a single elif statement with no + else statement. + ''' + test_string = self.read_test_file(self.processor_name, 'example_single_elif.md') + blocks = self.to_blocks(test_string) + + self.assertListEqual([True, False, True, False, True], [ConditionalProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + + converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + expected_string = self.read_test_file(self.processor_name, 'example_single_elif_expected.html', strip=True) + self.assertEqual(expected_string, converted_test_string) + + def test_multiple_else_error(self): + '''Ensures that the TagNotMatchedError is thrown when + multiple else statements are given. + ''' + test_string = self.read_test_file(self.processor_name, 'multiple_else_error.md') + blocks = self.to_blocks(test_string) + + self.assertListEqual([True, False, True, False, True, False, True], [ConditionalProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + + self.assertRaises(TagNotMatchedError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) + + def test_else_then_elif_error(self): + '''Ensures that the TagNotMatchedError is thrown when + elifs are given after the else statement. + ''' + test_string = self.read_test_file(self.processor_name, 'else_then_elif_error.md') + blocks = self.to_blocks(test_string) + + self.assertListEqual([True, False, True, False, True, False, True], [ConditionalProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + + self.assertRaises(TagNotMatchedError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) + + def test_missing_end_statement_error(self): + '''Ensures that the TagNotMatchedError is thrown + when the end statement is not matched. + ''' + test_string = self.read_test_file(self.processor_name, 'missing_end_statement_error.md') + blocks = self.to_blocks(test_string) + + self.assertListEqual([True, False, True, False, True, False], [ConditionalProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + + self.assertRaises(TagNotMatchedError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) + + def test_missing_if_statement_error(self): + '''Ensures that the TagNotMatchedError is thrown + when an else/elif is given before an if statement. + ''' + test_string = self.read_test_file(self.processor_name, 'missing_if_statement_error.md') + blocks = self.to_blocks(test_string) + + self.assertListEqual([True, False, True], [ConditionalProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + + self.assertRaises(TagNotMatchedError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) + #~ # Doc Tests #~ diff --git a/kordac/tests/assets/conditional/else_then_elif_error.md b/kordac/tests/assets/conditional/else_then_elif_error.md new file mode 100644 index 00000000..cf093a1d --- /dev/null +++ b/kordac/tests/assets/conditional/else_then_elif_error.md @@ -0,0 +1,13 @@ +{conditional if condition="version == 'teacher'"} + +This is text that only teachers should see. + +{conditional else} + +This is text that everyone else should see. + +{conditional elif condition="version == 'instructor'"} + +This is text that only instuctors should see. + +{conditional end} diff --git a/kordac/tests/assets/conditional/example_single_elif.md b/kordac/tests/assets/conditional/example_single_elif.md new file mode 100644 index 00000000..71d1c540 --- /dev/null +++ b/kordac/tests/assets/conditional/example_single_elif.md @@ -0,0 +1,9 @@ +{conditional if condition="version == 'teacher'"} + +This is text that only teachers should see. + +{conditional elif condition="version == 'instructor'"} + +This is text that only instuctors should see. + +{conditional end} diff --git a/kordac/tests/assets/conditional/example_single_elif_expected.html b/kordac/tests/assets/conditional/example_single_elif_expected.html new file mode 100644 index 00000000..6ac6ab2d --- /dev/null +++ b/kordac/tests/assets/conditional/example_single_elif_expected.html @@ -0,0 +1,9 @@ +{% if version == 'teacher' %} +

    + This is text that only teachers should see. +

    +{% elif version == 'instructor' %} +

    + This is text that only instuctors should see. +

    +{% endif %} diff --git a/kordac/tests/assets/conditional/missing_end_statement_error.md b/kordac/tests/assets/conditional/missing_end_statement_error.md new file mode 100644 index 00000000..fcd47d66 --- /dev/null +++ b/kordac/tests/assets/conditional/missing_end_statement_error.md @@ -0,0 +1,11 @@ +{conditional if condition="version == 'teacher'"} + +This is text that only teachers should see. + +{conditional elif condition="version == 'instructor'"} + +This is text that only instuctors should see. + +{conditional else} + +This is text that everyone else should see. diff --git a/kordac/tests/assets/conditional/missing_if_statement_error.md b/kordac/tests/assets/conditional/missing_if_statement_error.md new file mode 100644 index 00000000..73b32612 --- /dev/null +++ b/kordac/tests/assets/conditional/missing_if_statement_error.md @@ -0,0 +1,5 @@ +{conditional else} + +This is text that everyone else should see. + +{conditional end} diff --git a/kordac/tests/assets/conditional/multiple_else_error.md b/kordac/tests/assets/conditional/multiple_else_error.md new file mode 100644 index 00000000..e59378cf --- /dev/null +++ b/kordac/tests/assets/conditional/multiple_else_error.md @@ -0,0 +1,13 @@ +{conditional if condition="version == 'teacher'"} + +This is text that only teachers should see. + +{conditional else} + +This is text that everyone else should see. + +{conditional else} + +This is text that everyone else should see. + +{conditional end} From fc7a2a737606bb4768533e127d380e743bdf2b36 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Tue, 28 Mar 2017 14:25:40 +1300 Subject: [PATCH 59/86] Conditional flake8 fixes --- kordac/processors/ConditionalProcessor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kordac/processors/ConditionalProcessor.py b/kordac/processors/ConditionalProcessor.py index ad3baf8c..d658c6d2 100644 --- a/kordac/processors/ConditionalProcessor.py +++ b/kordac/processors/ConditionalProcessor.py @@ -4,6 +4,7 @@ from collections import OrderedDict import re + class ConditionalProcessor(BlockProcessor): ''' Searches a Document for conditional tags e.g. {conditonal flag condition=""} The processor matches @@ -24,7 +25,6 @@ def __init__(self, ext, *args, **kwargs): self.template = ext.jinja_templates[template_name] self.template_parameters = ext.processor_info[self.processor].get('template_parameters', None) - def test(self, parent, block): ''' Tests if the block if it contains any type of conditional types. From a7a8265f2f92caa88852e969771657e3760fe9e9 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Tue, 28 Mar 2017 15:02:10 +1300 Subject: [PATCH 60/86] Image tests for errors, and parameter values. --- kordac/processor-info.json | 5 ++-- .../processors/errors/ArgumentMissingError.py | 2 +- .../processors/errors/ArgumentValueError.py | 21 ++++++++++++++++ kordac/processors/utils.py | 11 ++++++--- kordac/tests/ImageTest.py | 24 +++++++++++++++++++ .../assets/image/align_undefined_error.md | 1 + .../tests/assets/image/caption_link_error.md | 1 + 7 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 kordac/processors/errors/ArgumentValueError.py create mode 100644 kordac/tests/assets/image/align_undefined_error.md create mode 100644 kordac/tests/assets/image/caption_link_error.md diff --git a/kordac/processor-info.json b/kordac/processor-info.json index ea8da305..ee1acc73 100644 --- a/kordac/processor-info.json +++ b/kordac/processor-info.json @@ -136,7 +136,7 @@ }, "caption-link": { "required": false, - "dependencies": [] + "dependencies": ["caption"] }, "source": { "required": false, @@ -144,7 +144,8 @@ }, "alignment": { "required": false, - "dependencies": [] + "dependencies": [], + "values": ["left", "center", "right"] }, "hover-text": { "required": false, diff --git a/kordac/processors/errors/ArgumentMissingError.py b/kordac/processors/errors/ArgumentMissingError.py index 811f0086..11c62c04 100644 --- a/kordac/processors/errors/ArgumentMissingError.py +++ b/kordac/processors/errors/ArgumentMissingError.py @@ -2,7 +2,7 @@ class ArgumentMissingError(Error): - '''Exception raised when a custom markdown tag in not matched. + '''Exception raised a required or dependent argument is not found. Attributes: tag: tag which was not matched diff --git a/kordac/processors/errors/ArgumentValueError.py b/kordac/processors/errors/ArgumentValueError.py new file mode 100644 index 00000000..918a15dc --- /dev/null +++ b/kordac/processors/errors/ArgumentValueError.py @@ -0,0 +1,21 @@ +from kordac.processors.errors.Error import Error + + +class ArgumentValueError(Error): + '''Exception raised when an argument is not one of the required + values. + + Attributes: + tag: tag which was not matched + block: block where tag was not matched + argument: the argument that was not found + value: the value that was not matched + message: explanation of why error was thrown + ''' + + def __init__(self, tag, argument, value, message): + super().__init__(message) + self.tag = tag + self.argument = argument + self.value = value + self.message = message diff --git a/kordac/processors/utils.py b/kordac/processors/utils.py index 1a725fab..91797dd3 100644 --- a/kordac/processors/utils.py +++ b/kordac/processors/utils.py @@ -2,6 +2,7 @@ from markdown.util import etree # noqa: F401 from collections import OrderedDict, defaultdict from kordac.processors.errors.ArgumentMissingError import ArgumentMissingError +from kordac.processors.errors.ArgumentValueError import ArgumentValueError def parse_argument(argument_key, arguments, default=None): @@ -66,15 +67,19 @@ def parse_arguments(processor, inputs, arguments): elif not is_required and (is_arg or is_flag): dependencies = argument_info.get('dependencies', []) for other_argument in dependencies: - if not (parse_argument(other_argument, inputs, None) is not None - or parse_flag(other_argument, inputs) is not None): + 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) if is_flag: argument_values[argument] = True elif is_arg: - argument_values[argument] = parse_argument(argument, inputs, None) + value = parse_argument(argument, inputs, None) + if argument_info.get('values', None) and value not in argument_info['values']: + message = "{} is not one of {}".format(value, argument_info['values']) + raise ArgumentValueError(processor, argument, value, message) + argument_values[argument] = value return argument_values diff --git a/kordac/tests/ImageTest.py b/kordac/tests/ImageTest.py index 86e6471a..dd5c1e80 100644 --- a/kordac/tests/ImageTest.py +++ b/kordac/tests/ImageTest.py @@ -4,6 +4,8 @@ from kordac.KordacExtension import KordacExtension from kordac.processors.ImageBlockProcessor import ImageBlockProcessor +from kordac.processors.errors.ArgumentMissingError import ArgumentMissingError +from kordac.processors.errors.ArgumentValueError import ArgumentValueError from kordac.tests.ProcessorTest import ProcessorTest class ImageTest(ProcessorTest): @@ -279,6 +281,28 @@ def test_align_center(self): } self.assertSetEqual(expected_images, images) + def test_caption_link_error(self): + '''Tests that the argument for caption-link throughs the + ArgumentMissingError when caption is not provided. + ''' + test_string = self.read_test_file(self.processor_name, 'caption_link_error.md') + blocks = self.to_blocks(test_string) + + self.assertListEqual([True], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + + self.assertRaises(ArgumentMissingError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) + + def test_align_undefined_error(self): + '''Tests that undefined align value produces + the ArgumentValueError. + ''' + test_string = self.read_test_file(self.processor_name, 'align_undefined_error.md') + blocks = self.to_blocks(test_string) + + self.assertListEqual([True], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + + self.assertRaises(ArgumentValueError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) + #~ # Doc Tests #~ diff --git a/kordac/tests/assets/image/align_undefined_error.md b/kordac/tests/assets/image/align_undefined_error.md new file mode 100644 index 00000000..d8d24505 --- /dev/null +++ b/kordac/tests/assets/image/align_undefined_error.md @@ -0,0 +1 @@ +{image file-path="computer-studying-turing-test.png" alignment="around-about-here"} diff --git a/kordac/tests/assets/image/caption_link_error.md b/kordac/tests/assets/image/caption_link_error.md new file mode 100644 index 00000000..7d9206d5 --- /dev/null +++ b/kordac/tests/assets/image/caption_link_error.md @@ -0,0 +1 @@ +{image file-path="computer-studying-turing-test.png" caption-link="example.com"} From 7a184c988e955d76c57d3aece0a77dfe451f7eb6 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Tue, 28 Mar 2017 16:02:15 +1300 Subject: [PATCH 61/86] Added required files to interactive tests. --- .../processors/InteractiveBlockProcessor.py | 24 +++++++------- kordac/tests/ConfigurationTest.py | 4 +-- kordac/tests/InteractiveTest.py | 32 +++++++++++++++++++ 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/kordac/processors/InteractiveBlockProcessor.py b/kordac/processors/InteractiveBlockProcessor.py index f56d3e8c..6b3b7340 100644 --- a/kordac/processors/InteractiveBlockProcessor.py +++ b/kordac/processors/InteractiveBlockProcessor.py @@ -67,23 +67,25 @@ def run(self, parent, blocks): if interactive_type == 'in-page': self.scripts.add('interactive/{}/scripts.html'.format(name)) - self.required.add(name) - - file_path = argument_values.get('thumbnail', None) - if file_path is None: - file_path = "{}/thumbnail.png".format(name) - - external_path_match = re.search(r'^http', file_path) - if external_path_match is None: # internal image - self.required_images.add(file_path) - file_path = self.relative_file_template.render({'file_path': file_path}) + if interactive_type != 'whole-page': + self.required.add(name) context = dict() context['type'] = interactive_type context['name'] = name context['text'] = text context['parameters'] = parameters - context['file_path'] = file_path + + if interactive_type == 'whole-page': + file_path = argument_values.get('thumbnail', None) + if file_path is None: + file_path = "{}/thumbnail.png".format(name) + + external_path_match = re.search(r'^http', file_path) + if external_path_match is None: # internal image + self.required_images.add(file_path) + file_path = self.relative_file_template.render({'file_path': file_path}) + context['file_path'] = file_path html_string = self.template.render(context) node = etree.fromstring(html_string) diff --git a/kordac/tests/ConfigurationTest.py b/kordac/tests/ConfigurationTest.py index 8ee7dbe2..026981b2 100644 --- a/kordac/tests/ConfigurationTest.py +++ b/kordac/tests/ConfigurationTest.py @@ -42,9 +42,7 @@ def test_multiple_calls(self): 'interactives': { 'binary-cards' }, - 'images': { - 'binary-cards/thumbnail.png' - }, + 'images': set(), 'page_scripts': set(), 'scratch_images': { ScratchImageMetaData( diff --git a/kordac/tests/InteractiveTest.py b/kordac/tests/InteractiveTest.py index 60612a95..ac5e731b 100644 --- a/kordac/tests/InteractiveTest.py +++ b/kordac/tests/InteractiveTest.py @@ -35,6 +35,18 @@ def test_doc_example_in_page(self): expected_string = self.read_test_file(self.processor_name, 'doc_example_in_page_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) + required_files={ + 'interactives': { + 'binary-cards' + }, + 'images': set(), + 'page_scripts': { + 'interactive/binary-cards/scripts.html' + }, + 'scratch_images': set() + } + self.assertEqual(self.kordac_extension.required_files, required_files) + def test_doc_example_whole_page(self): '''Example of an whole-page interactive. ''' @@ -47,6 +59,16 @@ def test_doc_example_whole_page(self): expected_string = self.read_test_file(self.processor_name, 'doc_example_whole_page_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) + required_files={ + 'interactives': set(), + 'images': { + 'binary-cards/thumbnail.png' + }, + 'page_scripts': set(), + 'scratch_images': set() + } + self.assertEqual(self.kordac_extension.required_files, required_files) + def test_doc_example_iframe(self): '''Example of an iframe interactive. ''' @@ -59,6 +81,16 @@ def test_doc_example_iframe(self): expected_string = self.read_test_file(self.processor_name, 'doc_example_iframe_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) + required_files={ + 'interactives': { + 'binary-cards' + }, + 'images': set(), + 'page_scripts': set(), + 'scratch_images': set() + } + self.assertEqual(self.kordac_extension.required_files, required_files) + def test_doc_example_override_html(self): '''Example showing overriding the html-template. ''' From 60d0cbb613260a2ad0ea33a94419b93b5766a87a Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Tue, 28 Mar 2017 16:19:24 +1300 Subject: [PATCH 62/86] Updated set values for parameters. --- kordac/processor-info.json | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/kordac/processor-info.json b/kordac/processor-info.json index ee1acc73..407c1ed7 100644 --- a/kordac/processor-info.json +++ b/kordac/processor-info.json @@ -4,7 +4,8 @@ "arguments": { "indented": { "required": false, - "dependencies": [] + "dependencies": [], + "values": ["yes", "no"] } }, "template_name": "boxed-text", @@ -32,7 +33,8 @@ }, "file": { "required": false, - "dependencies": [] + "dependencies": [], + "values": ["yes", "no"] } }, "template_parameters": { @@ -162,7 +164,8 @@ }, "type": { "required": true, - "dependencies": [] + "dependencies": [], + "values": ["in-page", "whole-page", "iframe"] }, "text": { "required": false, @@ -191,7 +194,8 @@ "required": false }, "expanded": { - "required": false + "required": false, + "values": ["true", "always", "false"] } }, "template_parameters": { From 833164a13f01c9966320cfd731f146dfe2a6d550 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Tue, 28 Mar 2017 16:48:49 +1300 Subject: [PATCH 63/86] Updated documentation to cover values property. --- docs/source/contributing.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 0a9f3702..b07d7c78 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -156,6 +156,7 @@ The ``argument`` parameter is a dictionary (or object) containing argument name, - ``required``: ``true`` if the argument must be set or ``false`` otherwise. - (Optional) ``dependencies``: A list of argument-names that must also be set if this argument is used. + - (Optional) ``values``: A list of values of which the argument may take. If the argument does not have the value in this list the ArgumentValueError exception is raised. These arguments are transformed for use in the html-template by the ``template_parameters`` attribute. This attribute is similar to the ``argument`` attribute by containing parameter name, parameter-info pairs. Where the parameter-info contains the attributes: From d36cae9299474839074a3cead07312fff974a55f Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Wed, 29 Mar 2017 11:50:00 +1300 Subject: [PATCH 64/86] Fixes as per cs-fieldguide issues with links. --- kordac/processors/RelativeLinkPattern.py | 3 ++- kordac/processors/utils.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/kordac/processors/RelativeLinkPattern.py b/kordac/processors/RelativeLinkPattern.py index 4d31bd74..79a7e43a 100644 --- a/kordac/processors/RelativeLinkPattern.py +++ b/kordac/processors/RelativeLinkPattern.py @@ -1,5 +1,6 @@ from markdown.inlinepatterns import Pattern from markdown.util import etree +from html import escape import re @@ -36,7 +37,7 @@ def handleMatch(self, match): An element tree node to be appended to the html tree. ''' context = dict() - context['link_path'] = match.group('link_url') + context['link_path'] = escape(match.group('link_url')) context['text'] = match.group('link_text') html_string = self.template.render(context) diff --git a/kordac/processors/utils.py b/kordac/processors/utils.py index 91797dd3..5d369f08 100644 --- a/kordac/processors/utils.py +++ b/kordac/processors/utils.py @@ -17,7 +17,7 @@ def parse_argument(argument_key, arguments, default=None): ''' result = re.search(r'(^|\s+){}="([^"]*("(?<=\\")[^"]*)*)"'.format(argument_key), arguments) if result: - argument_value = result.group(2) + argument_value = result.group(2).replace(r'\"', r'"') else: argument_value = default return argument_value From 58cfa06369be0e85794bfc755f289ac87b14cd51 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Wed, 29 Mar 2017 13:22:55 +1300 Subject: [PATCH 65/86] Fix merge bug. --- kordac/processor-info.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/kordac/processor-info.json b/kordac/processor-info.json index 83454678..19f7365c 100644 --- a/kordac/processor-info.json +++ b/kordac/processor-info.json @@ -5,8 +5,6 @@ "indented": { "required": false, "dependencies": [] - } - }, } }, "template_name": "boxed-text", From f1eb063d5770b9e087a466f8f960161f02982e55 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Wed, 29 Mar 2017 16:05:47 +1300 Subject: [PATCH 66/86] Activate style preprocessor for whitespace around blocks. --- kordac/KordacExtension.py | 1 + kordac/processor-info.json | 2 +- kordac/processors/StylePreprocessor.py | 26 +++---------------- kordac/processors/errors/StyleError.py | 3 ++- kordac/tests/StyleTest.py | 25 +++++++++++++++--- kordac/tests/VideoTest.py | 3 +-- .../style/doc_example_block_whitespace.md | 2 +- .../style/doc_example_block_whitespace_2.md | 2 +- .../tests/assets/video/youtube_embed_link.md | 4 ++- .../video/youtube_embed_link_expected.html | 8 ++++-- 10 files changed, 40 insertions(+), 36 deletions(-) diff --git a/kordac/KordacExtension.py b/kordac/KordacExtension.py index c15871e9..eec34f56 100644 --- a/kordac/KordacExtension.py +++ b/kordac/KordacExtension.py @@ -92,6 +92,7 @@ def update_processors(processors, markdown_processors): update_processors(self.treeprocessors, md.treeprocessors) update_processors(self.postprocessors, md.postprocessors) + md.preprocessors.add('style', StylePreprocessor(self, md), '_begin') md.postprocessors.add('remove', RemovePostprocessor(md), '_end') md.postprocessors.add('beautify', BeautifyPostprocessor(md), '_end') md.postprocessors.add('jinja', JinjaPostprocessor(md), '_end') diff --git a/kordac/processor-info.json b/kordac/processor-info.json index 19f7365c..e2ffc441 100644 --- a/kordac/processor-info.json +++ b/kordac/processor-info.json @@ -227,7 +227,7 @@ "inline_pattern": "\\{{{inline} ?([^\\}}]*)\\}}", "strings": { "inline": ["glossary-link"], - "block": ["comment", "panel", "video", "image", "interactive", "button-link", "boxed-text"] + "block": ["boxed-text", "button-link", "comment", "conditional", "iframe", "image", "interactive", "panel", "table-of-contents", "video"] } }, "title": { diff --git a/kordac/processors/StylePreprocessor.py b/kordac/processors/StylePreprocessor.py index d17d7d5e..94f80ae5 100644 --- a/kordac/processors/StylePreprocessor.py +++ b/kordac/processors/StylePreprocessor.py @@ -1,8 +1,8 @@ from kordac.processors.errors.StyleError import StyleError from markdown.preprocessors import Preprocessor -from collections import OrderedDict import re + class StylePreprocessor(Preprocessor): ''' Parses the document for custom tags and validates they meet our required style rules. @@ -24,16 +24,6 @@ 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'] - def test(self, lines): - '''All documents always need to be processed. - - Args: - lines: A string of Markdown text. - Returns: - True - ''' - return True - def run(self, lines): ''' Validates lines and raising StyleErrors when rules are not upheld. @@ -48,7 +38,8 @@ def run(self, lines): block_match = c.search(line) if block_match is not None: # Grab important lines and their numbers - line_nums, error_lines = zip(*map(lambda x: (x[0] + 1, x[1].strip()), (list(enumerate(lines))[max(0, i - 1): i + 2]))) + important_lines = (list(enumerate(lines))[max(0, i - 1): i + 2]) + line_nums, error_lines = zip(*map(lambda x: (x[0] + 1, x[1].strip()), important_lines)) # Remove all empty lines Should only be one line left if len([line for line in error_lines if line != '']) != 1: @@ -60,15 +51,4 @@ def run(self, lines): if not char.isspace(): raise StyleError(line_nums, error_lines, "Blocks must be the only thing on the line.") - # for inline_string in self.inline_strings: - # c = re.compile(self.inline_pattern.format(**{'inline': inline_string})) - # inline_match = c.search(line) - # if inline_match is not None: - # start_index, end_index = inline_match.span() - # - # if not ((start_index - 1) >= 0 and line[start_index - 1].isspace() or (start_index - 1) < 0): - # raise StyleError([i], [line], "Inline must be separated by whitespace.") - # if not ((end_index + 1) < len(line) and line[end_index + 1].isspace() or (end_index + 1) >= len(line)): - # raise StyleError([i], [line], "Inline must be separated by whitespace.") - return lines diff --git a/kordac/processors/errors/StyleError.py b/kordac/processors/errors/StyleError.py index d189a5f1..9a33e2d8 100644 --- a/kordac/processors/errors/StyleError.py +++ b/kordac/processors/errors/StyleError.py @@ -1,6 +1,7 @@ from kordac.processors.errors.Error import Error -class StyleError(Exception): + +class StyleError(Error): """Exception raised when a Style rule is broken. Attributes: diff --git a/kordac/tests/StyleTest.py b/kordac/tests/StyleTest.py index 1e1c43ec..756321f1 100644 --- a/kordac/tests/StyleTest.py +++ b/kordac/tests/StyleTest.py @@ -7,47 +7,64 @@ from kordac.tests.ProcessorTest import ProcessorTest class StyleTest(ProcessorTest): - """ - Inline = single line comment .e.g. {comment hello you look lovely today} - """ + '''Checks that failures are raised correctly. + ''' def __init__(self, *args, **kwargs): - """Set processor name in class for file names""" + '''Setup name for asset file location. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'style' self.ext = Mock() self.ext.processor_info = ProcessorTest.loadProcessorInfo(self) def test_doc_example_block_whitespace(self): + '''Test before an after a block. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_block_whitespace.md') with self.assertRaises(StyleError): converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) def test_doc_example_block_whitespace_1(self): + '''Test no whitespace before an after content in + a block container. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_block_whitespace_1.md') with self.assertRaises(StyleError): converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) def test_doc_example_block_whitespace_2(self): + '''Test no whitespace before a block tag. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_block_whitespace_2.md') with self.assertRaises(StyleError): converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) def test_doc_example_block_whitespace_3(self): + '''Test no whitespace after a block tag. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_block_whitespace_3.md') with self.assertRaises(StyleError): converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) def test_doc_example_block_solitary(self): + '''Test extra text after a tag that should be + solitary. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_block_solitary.md') with self.assertRaises(StyleError): converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) def test_doc_example_block_solitary_1(self): + '''Test extra text before a tag that should be + solitary. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_block_solitary_1.md') with self.assertRaises(StyleError): converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) def test_doc_example_block_valid(self): + '''A valid example of using container tags. + ''' test_string = self.read_test_file(self.processor_name, 'doc_example_block_valid.md') converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) diff --git a/kordac/tests/VideoTest.py b/kordac/tests/VideoTest.py index 87c0583c..cc27a2a2 100644 --- a/kordac/tests/VideoTest.py +++ b/kordac/tests/VideoTest.py @@ -37,7 +37,7 @@ def test_youtube_embed_link(self): test_string = self.read_test_file(self.processor_name, 'youtube_embed_link.md') blocks = self.to_blocks(test_string) - self.assertListEqual([False, True, False, False, False, False], [VideoBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) + self.assertListEqual([False, True, False, False, False, False, False, False], [VideoBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) expected_file_string = self.read_test_file(self.processor_name, 'youtube_embed_link_expected.html', strip=True) @@ -157,4 +157,3 @@ def test_doc_example_override_html(self): converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - diff --git a/kordac/tests/assets/style/doc_example_block_whitespace.md b/kordac/tests/assets/style/doc_example_block_whitespace.md index a6881abf..e8c58b28 100644 --- a/kordac/tests/assets/style/doc_example_block_whitespace.md +++ b/kordac/tests/assets/style/doc_example_block_whitespace.md @@ -1,5 +1,5 @@ This is not valid {panel} This is not valid -panel end} +{panel end} This is not valid diff --git a/kordac/tests/assets/style/doc_example_block_whitespace_2.md b/kordac/tests/assets/style/doc_example_block_whitespace_2.md index 07efbff8..50a2f4ca 100644 --- a/kordac/tests/assets/style/doc_example_block_whitespace_2.md +++ b/kordac/tests/assets/style/doc_example_block_whitespace_2.md @@ -1,4 +1,4 @@ This is not valid {panel} -panel end} +{panel end} diff --git a/kordac/tests/assets/video/youtube_embed_link.md b/kordac/tests/assets/video/youtube_embed_link.md index 924efedd..b7605f64 100644 --- a/kordac/tests/assets/video/youtube_embed_link.md +++ b/kordac/tests/assets/video/youtube_embed_link.md @@ -5,6 +5,7 @@ Run length encoding (RLE) is a technique that isn't so widely used these days, but it's a great way to get a feel for some of the issues around using compression. {panel type="teacher-note" summary="Who uses run length encoding?"} + [Run-length_encoding](https://en.wikipedia.org/wiki/Run-length_encoding) was widely used when black and white images were the norm. One of its key roles was as the compression method that made Fax (facsimile) machines possible in a standard that was adopted in 1980. The pixels in a fax image are only black or white, and typically there are long runs of white pixels in the margins, so RLE is particularly effective. @@ -13,4 +14,5 @@ Also, the method is very simple, and in the 1980s this was important since it re Run length encoding is still used as part of JPEG compression, although not to code runs of pixels (in a photo it's unusual to have runs of exactly the same colour). We have introduced RLE here because it is a practical approach to compression, and most importantly it shows the key benefits and problems that arise in compression. -{panel end} \ No newline at end of file + +{panel end} diff --git a/kordac/tests/assets/video/youtube_embed_link_expected.html b/kordac/tests/assets/video/youtube_embed_link_expected.html index f1f61126..8a4202e2 100644 --- a/kordac/tests/assets/video/youtube_embed_link_expected.html +++ b/kordac/tests/assets/video/youtube_embed_link_expected.html @@ -10,6 +10,8 @@

    {panel type="teacher-note" summary="Who uses run length encoding?"} +

    +

    Run-length_encoding @@ -23,5 +25,7 @@

    We have introduced RLE here because it is a practical approach to compression, and most importantly it shows the key benefits and problems that arise in compression. -{panel end} -

    \ No newline at end of file +

    +

    + {panel end} +

    From aac9f340b43ca90bc49833a0947891b5e3f7f7c1 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Thu, 30 Mar 2017 14:05:54 +1300 Subject: [PATCH 67/86] Added options for splitting and randomising codeblocks. --- kordac/html-templates/scratch.html | 8 +++-- kordac/processor-info.json | 1 + kordac/processors/ScratchTreeprocessor.py | 34 +++++++++++++++---- .../doc_example_basic_usage_expected.html | 2 +- .../doc_example_override_html_expected.html | 2 +- .../doc_example_override_html_template.html | 6 ++-- .../example_multiple_codeblocks_expected.html | 6 ++-- ...xample_multiple_codeblocks_expected_2.html | 6 ++-- .../scratch/example_other_code_expected.html | 2 +- .../example_separate_blocks_expected.html | 2 +- ...mple_standard_markdown_block_expected.html | 2 +- 11 files changed, 48 insertions(+), 23 deletions(-) diff --git a/kordac/html-templates/scratch.html b/kordac/html-templates/scratch.html index f2e7ebf6..c00cc825 100644 --- a/kordac/html-templates/scratch.html +++ b/kordac/html-templates/scratch.html @@ -1,4 +1,6 @@ -
    - - +
    + {% for hash in images -%} + + + {% endfor -%}
    diff --git a/kordac/processor-info.json b/kordac/processor-info.json index 5191f29b..b4bdc0b5 100644 --- a/kordac/processor-info.json +++ b/kordac/processor-info.json @@ -217,6 +217,7 @@ }, "scratch": { "class": "custom", + "pattern": "^scratch(?P(\\|[^\\|]+)*)($|\\n)", "scratch-compatibility": { "pattern": "(?P^(?:~{3,}|`{3,}))[ ]*scratch?[ ]*(hl_lines=(?P\"|')(?P.*?)(?P=quot))?[ ]*}?[ ]*\n(?P.*?)(?<=\n)(?P=fence)[ ]*$" } diff --git a/kordac/processors/ScratchTreeprocessor.py b/kordac/processors/ScratchTreeprocessor.py index 51a89bbf..29e98864 100644 --- a/kordac/processors/ScratchTreeprocessor.py +++ b/kordac/processors/ScratchTreeprocessor.py @@ -2,6 +2,8 @@ from kordac.processors.utils import etree from collections import namedtuple from hashlib import sha256 +from random import shuffle +import re class ScratchImageMetaData(namedtuple('ScratchImageMetaData', 'hash, text')): @@ -27,6 +29,7 @@ def __init__(self, ext, *args, **kwargs): ''' super().__init__(*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 @@ -64,15 +67,32 @@ def process_html(self, node): node: The possible pre node of a code block. ''' children = list(node) - if (len(children) == 1 and children[0].tag == 'code' - and ((children[0].text.strip().startswith('scratch\n')) - or ('class' in children[0].attrib.keys() and children[0].attrib['class'] == 'scratch'))): + if (len(children) == 1 and children[0].tag == 'code'): + language = children[0].attrib['class'] if 'class' in children[0].attrib.keys() else children[0].text.strip() + + match = self.pattern.match(language) + if match is not None: + options = list(filter(None, match.group('options').split('|'))) content = children[0].text.strip() if content.startswith('scratch\n'): - content = content[len('scratch\n'):] - content_hash = ScratchTreeprocessor.hash_content(content) - self.update_required_images(content_hash, content) - html_string = self.template.render({'hash': content_hash}) + content = content[match.end():] + + content_blocks = [] + if 'split' in options: + content_blocks = content.split('\n\n') + else: + content_blocks.append(content) + + images = [] + for block in content_blocks: + content_hash = ScratchTreeprocessor.hash_content(block) + self.update_required_images(content_hash, block) + images.append(content_hash) + + if 'random' in options: + shuffle(content_blocks) + + html_string = self.template.render({'images': images}) new_node = etree.fromstring(html_string) node.tag = "remove" diff --git a/kordac/tests/assets/scratch/doc_example_basic_usage_expected.html b/kordac/tests/assets/scratch/doc_example_basic_usage_expected.html index bcc48fe0..a8b838f4 100644 --- a/kordac/tests/assets/scratch/doc_example_basic_usage_expected.html +++ b/kordac/tests/assets/scratch/doc_example_basic_usage_expected.html @@ -1,4 +1,4 @@ -
    +
    diff --git a/kordac/tests/assets/scratch/doc_example_override_html_expected.html b/kordac/tests/assets/scratch/doc_example_override_html_expected.html index bfea6660..0b5a143d 100644 --- a/kordac/tests/assets/scratch/doc_example_override_html_expected.html +++ b/kordac/tests/assets/scratch/doc_example_override_html_expected.html @@ -1,4 +1,4 @@ -
    +
    diff --git a/kordac/tests/assets/scratch/doc_example_override_html_template.html b/kordac/tests/assets/scratch/doc_example_override_html_template.html index 012e811c..275dc10f 100644 --- a/kordac/tests/assets/scratch/doc_example_override_html_template.html +++ b/kordac/tests/assets/scratch/doc_example_override_html_template.html @@ -1,3 +1,5 @@ -
    - +
    + {% for hash in images -%} + + {% endfor -%}
    diff --git a/kordac/tests/assets/scratch/example_multiple_codeblocks_expected.html b/kordac/tests/assets/scratch/example_multiple_codeblocks_expected.html index 792a4c07..91fd4b54 100644 --- a/kordac/tests/assets/scratch/example_multiple_codeblocks_expected.html +++ b/kordac/tests/assets/scratch/example_multiple_codeblocks_expected.html @@ -1,21 +1,21 @@

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

    -
    +

    Which then easily builds into:

    -
    +

    Finally they can create complex code like so:

    -
    +
    diff --git a/kordac/tests/assets/scratch/example_multiple_codeblocks_expected_2.html b/kordac/tests/assets/scratch/example_multiple_codeblocks_expected_2.html index a36cbc13..3e3fa15b 100644 --- a/kordac/tests/assets/scratch/example_multiple_codeblocks_expected_2.html +++ b/kordac/tests/assets/scratch/example_multiple_codeblocks_expected_2.html @@ -1,15 +1,15 @@

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

    -
    +
    -
    +
    -
    +
    diff --git a/kordac/tests/assets/scratch/example_other_code_expected.html b/kordac/tests/assets/scratch/example_other_code_expected.html index f1105efa..8138975e 100644 --- a/kordac/tests/assets/scratch/example_other_code_expected.html +++ b/kordac/tests/assets/scratch/example_other_code_expected.html @@ -1,4 +1,4 @@ -
    +
    diff --git a/kordac/tests/assets/scratch/example_separate_blocks_expected.html b/kordac/tests/assets/scratch/example_separate_blocks_expected.html index 4509c3f9..e79b712d 100644 --- a/kordac/tests/assets/scratch/example_separate_blocks_expected.html +++ b/kordac/tests/assets/scratch/example_separate_blocks_expected.html @@ -1,4 +1,4 @@ -
    +
    diff --git a/kordac/tests/assets/scratch/example_standard_markdown_block_expected.html b/kordac/tests/assets/scratch/example_standard_markdown_block_expected.html index 90c4abcc..95350504 100644 --- a/kordac/tests/assets/scratch/example_standard_markdown_block_expected.html +++ b/kordac/tests/assets/scratch/example_standard_markdown_block_expected.html @@ -1,7 +1,7 @@

    Codeblock follows:

    -
    +
    From 37136829f5f5786b72a2e17502d6ac7fedd31e33 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Thu, 30 Mar 2017 14:29:13 +1300 Subject: [PATCH 68/86] flake8 fixes --- kordac/processors/ScratchTreeprocessor.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kordac/processors/ScratchTreeprocessor.py b/kordac/processors/ScratchTreeprocessor.py index 29e98864..e2342e19 100644 --- a/kordac/processors/ScratchTreeprocessor.py +++ b/kordac/processors/ScratchTreeprocessor.py @@ -68,7 +68,9 @@ def process_html(self, node): ''' children = list(node) if (len(children) == 1 and children[0].tag == 'code'): - language = children[0].attrib['class'] if 'class' in children[0].attrib.keys() else children[0].text.strip() + language = (children[0].attrib['class'] + if 'class' in children[0].attrib.keys() + else children[0].text.strip()) match = self.pattern.match(language) if match is not None: From 1f98a7c6d669d9718ff030261638ab401adacf0e Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Thu, 30 Mar 2017 15:37:25 +1300 Subject: [PATCH 69/86] Added tests, and injected support for options into fenced code. --- kordac/KordacExtension.py | 6 ++- .../ScratchCompatibilityPreprocessor.py | 9 ++++ kordac/processors/ScratchTreeprocessor.py | 2 +- kordac/tests/ScratchTest.py | 41 ++++++++++++++++++- .../example_random_split_codeblocks.md | 23 +++++++++++ .../scratch/example_split_codeblocks.md | 23 +++++++++++ .../example_split_codeblocks_expected.html | 11 +++++ 7 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 kordac/tests/assets/scratch/example_random_split_codeblocks.md create mode 100644 kordac/tests/assets/scratch/example_split_codeblocks.md create mode 100644 kordac/tests/assets/scratch/example_split_codeblocks_expected.html diff --git a/kordac/KordacExtension.py b/kordac/KordacExtension.py index f6f4b335..ed235154 100644 --- a/kordac/KordacExtension.py +++ b/kordac/KordacExtension.py @@ -15,7 +15,7 @@ from kordac.processors.JinjaPostprocessor import JinjaPostprocessor from kordac.processors.HeadingBlockProcessor import HeadingBlockProcessor from kordac.processors.ScratchTreeprocessor import ScratchTreeprocessor -from kordac.processors.ScratchCompatibilityPreprocessor import ScratchCompatibilityPreprocessor +from kordac.processors.ScratchCompatibilityPreprocessor import ScratchCompatibilityPreprocessor, FENCED_BLOCK_RE_OVERRIDE from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor from kordac.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor @@ -97,6 +97,10 @@ def update_processors(processors, markdown_processors): # Compatibility modules md.postprocessors['raw_html'].isblocklevel = lambda html: is_block_level(html, BLOCK_LEVEL_ELEMENTS) + if ('fenced_code_block' in self.compatibility + and 'scratch' in self.processors): + md.preprocessors['fenced_code_block'].FENCED_BLOCK_RE = FENCED_BLOCK_RE_OVERRIDE + if ('hilite' in self.compatibility and 'fenced_code_block' in self.compatibility and 'scratch' in self.processors): diff --git a/kordac/processors/ScratchCompatibilityPreprocessor.py b/kordac/processors/ScratchCompatibilityPreprocessor.py index e9f9dbe6..16deb3e7 100644 --- a/kordac/processors/ScratchCompatibilityPreprocessor.py +++ b/kordac/processors/ScratchCompatibilityPreprocessor.py @@ -1,6 +1,15 @@ from markdown.preprocessors import Preprocessor import re +#Enable support for | so that languages can be passed options +FENCED_BLOCK_RE_OVERRIDE = re.compile( +r'''(?P^(?:~{3,}|`{3,}))[ ]* +(\{?\.?(?P[\w#.+-\|]*))?[ ]* +(hl_lines=(?P"|')(?P.*?)(?P=quot))?[ ]* +}?[ ]*\n +(?P.*?)(?<=\n) +(?P=fence)[ ]*$''', +re.MULTILINE | re.DOTALL | re.VERBOSE) class ScratchCompatibilityPreprocessor(Preprocessor): '''Should only be active if using the scratch processor and the diff --git a/kordac/processors/ScratchTreeprocessor.py b/kordac/processors/ScratchTreeprocessor.py index e2342e19..7078ca3e 100644 --- a/kordac/processors/ScratchTreeprocessor.py +++ b/kordac/processors/ScratchTreeprocessor.py @@ -92,7 +92,7 @@ def process_html(self, node): images.append(content_hash) if 'random' in options: - shuffle(content_blocks) + shuffle(images) html_string = self.template.render({'images': images}) new_node = etree.fromstring(html_string) diff --git a/kordac/tests/ScratchTest.py b/kordac/tests/ScratchTest.py index e1a196fd..25a8378a 100644 --- a/kordac/tests/ScratchTest.py +++ b/kordac/tests/ScratchTest.py @@ -90,7 +90,6 @@ def test_example_separate_blocks(self): } self.assertSetEqual(actual, expected) - def test_example_multiple_codeblocks(self): test_string = self.read_test_file(self.processor_name, 'example_multiple_codeblocks.md') @@ -143,6 +142,46 @@ def test_example_multiple_codeblocks_2(self): } self.assertSetEqual(actual, expected) + 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.kordac_extension]) + expected_string = self.read_test_file(self.processor_name, 'example_split_codeblocks_expected.html', strip=True) + self.assertEqual(expected_string, converted_test_string) + + # Should really test result a better way + actual = self.kordac_extension.required_files['scratch_images'] + expected = { + 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, expected) + + def test_example_random_split_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_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.kordac_extension]) + outputs.add(converted_test_string) + self.assertFalse(len(outputs) == 1) + def test_example_other_code(self): test_string = self.read_test_file(self.processor_name, 'example_other_code.md') diff --git a/kordac/tests/assets/scratch/example_random_split_codeblocks.md b/kordac/tests/assets/scratch/example_random_split_codeblocks.md new file mode 100644 index 00000000..20cd991b --- /dev/null +++ b/kordac/tests/assets/scratch/example_random_split_codeblocks.md @@ -0,0 +1,23 @@ +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/kordac/tests/assets/scratch/example_split_codeblocks.md b/kordac/tests/assets/scratch/example_split_codeblocks.md new file mode 100644 index 00000000..86b941e4 --- /dev/null +++ b/kordac/tests/assets/scratch/example_split_codeblocks.md @@ -0,0 +1,23 @@ +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/kordac/tests/assets/scratch/example_split_codeblocks_expected.html b/kordac/tests/assets/scratch/example_split_codeblocks_expected.html new file mode 100644 index 00000000..df6997f6 --- /dev/null +++ b/kordac/tests/assets/scratch/example_split_codeblocks_expected.html @@ -0,0 +1,11 @@ +

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

    +
    + + + + + + +
    From f2feeb7e8af930c418a0275c795ae6d9c5ff9e78 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Thu, 30 Mar 2017 15:42:24 +1300 Subject: [PATCH 70/86] Tests that split holds for default codeblocks. --- kordac/tests/ScratchTest.py | 28 +++++++++++++++++++ .../example_split_codeblocks_default.md | 22 +++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 kordac/tests/assets/scratch/example_split_codeblocks_default.md diff --git a/kordac/tests/ScratchTest.py b/kordac/tests/ScratchTest.py index 25a8378a..569e877b 100644 --- a/kordac/tests/ScratchTest.py +++ b/kordac/tests/ScratchTest.py @@ -170,6 +170,34 @@ def test_example_split_codeblocks(self): } self.assertSetEqual(actual, expected) + def test_example_split_codeblocks_default(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_default.md') + + converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.kordac_extension]) + expected_string = self.read_test_file(self.processor_name, 'example_split_codeblocks_expected.html', strip=True) + self.assertEqual(expected_string, converted_test_string) + + # Should really test result a better way + actual = self.kordac_extension.required_files['scratch_images'] + expected = { + 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, expected) + def test_example_random_split_codeblocks(self): '''Tests that scratch images are arranged randomly given the random option is given. diff --git a/kordac/tests/assets/scratch/example_split_codeblocks_default.md b/kordac/tests/assets/scratch/example_split_codeblocks_default.md new file mode 100644 index 00000000..ec4746ce --- /dev/null +++ b/kordac/tests/assets/scratch/example_split_codeblocks_default.md @@ -0,0 +1,22 @@ +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 From f2e4f238cb42b22de932d7b431feff0e54507d37 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Thu, 30 Mar 2017 16:46:03 +1300 Subject: [PATCH 71/86] random option without split, refactoring, tests --- kordac/KordacExtension.py | 5 +- kordac/processor-info.json | 4 +- .../ScratchCompatibilityPreprocessor.py | 9 ++- kordac/processors/ScratchTreeprocessor.py | 25 +++---- kordac/tests/ScratchTest.py | 69 ++++++++++++------- .../scratch/example_random_codeblocks.md | 23 +++++++ 6 files changed, 86 insertions(+), 49 deletions(-) create mode 100644 kordac/tests/assets/scratch/example_random_codeblocks.md diff --git a/kordac/KordacExtension.py b/kordac/KordacExtension.py index ed235154..d52621ad 100644 --- a/kordac/KordacExtension.py +++ b/kordac/KordacExtension.py @@ -15,7 +15,8 @@ from kordac.processors.JinjaPostprocessor import JinjaPostprocessor from kordac.processors.HeadingBlockProcessor import HeadingBlockProcessor from kordac.processors.ScratchTreeprocessor import ScratchTreeprocessor -from kordac.processors.ScratchCompatibilityPreprocessor import ScratchCompatibilityPreprocessor, FENCED_BLOCK_RE_OVERRIDE +from kordac.processors.ScratchCompatibilityPreprocessor import ScratchCompatibilityPreprocessor +from kordac.processors.ScratchCompatibilityPreprocessor import FENCED_BLOCK_RE_OVERRIDE from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor from kordac.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor @@ -99,7 +100,7 @@ def update_processors(processors, markdown_processors): if ('fenced_code_block' in self.compatibility and 'scratch' in self.processors): - md.preprocessors['fenced_code_block'].FENCED_BLOCK_RE = FENCED_BLOCK_RE_OVERRIDE + md.preprocessors['fenced_code_block'].FENCED_BLOCK_RE = FENCED_BLOCK_RE_OVERRIDE if ('hilite' in self.compatibility and 'fenced_code_block' in self.compatibility diff --git a/kordac/processor-info.json b/kordac/processor-info.json index b4bdc0b5..18187dd5 100644 --- a/kordac/processor-info.json +++ b/kordac/processor-info.json @@ -217,9 +217,9 @@ }, "scratch": { "class": "custom", - "pattern": "^scratch(?P(\\|[^\\|]+)*)($|\\n)", + "pattern": "^scratch(?P(\\|[^\\|\\n$]+)*) *($|\\n)", "scratch-compatibility": { - "pattern": "(?P^(?:~{3,}|`{3,}))[ ]*scratch?[ ]*(hl_lines=(?P\"|')(?P.*?)(?P=quot))?[ ]*}?[ ]*\n(?P.*?)(?<=\n)(?P=fence)[ ]*$" + "pattern": "(?P^(?:~{3,}|`{3,}))[ ]*scratch((\\|[^\\|\\n$]+)*)[ ]*(hl_lines=(?P\"|')(?P.*?)(?P=quot))?[ ]*}?[ ]*\n(?P.*?)(?<=\n)(?P=fence)[ ]*$" } }, "title": { diff --git a/kordac/processors/ScratchCompatibilityPreprocessor.py b/kordac/processors/ScratchCompatibilityPreprocessor.py index 16deb3e7..54d3bcbe 100644 --- a/kordac/processors/ScratchCompatibilityPreprocessor.py +++ b/kordac/processors/ScratchCompatibilityPreprocessor.py @@ -1,15 +1,14 @@ from markdown.preprocessors import Preprocessor import re -#Enable support for | so that languages can be passed options -FENCED_BLOCK_RE_OVERRIDE = re.compile( -r'''(?P^(?:~{3,}|`{3,}))[ ]* +# Enable support for | so that languages can be passed options +FENCED_BLOCK_RE_OVERRIDE = re.compile(r'''(?P^(?:~{3,}|`{3,}))[ ]* (\{?\.?(?P[\w#.+-\|]*))?[ ]* (hl_lines=(?P"|')(?P.*?)(?P=quot))?[ ]* }?[ ]*\n (?P.*?)(?<=\n) -(?P=fence)[ ]*$''', -re.MULTILINE | re.DOTALL | re.VERBOSE) +(?P=fence)[ ]*$''', re.MULTILINE | re.DOTALL | re.VERBOSE) + class ScratchCompatibilityPreprocessor(Preprocessor): '''Should only be active if using the scratch processor and the diff --git a/kordac/processors/ScratchTreeprocessor.py b/kordac/processors/ScratchTreeprocessor.py index 7078ca3e..bd18dfb7 100644 --- a/kordac/processors/ScratchTreeprocessor.py +++ b/kordac/processors/ScratchTreeprocessor.py @@ -1,6 +1,7 @@ from markdown.treeprocessors import Treeprocessor from kordac.processors.utils import etree from collections import namedtuple +from functools import reduce from hashlib import sha256 from random import shuffle import re @@ -68,22 +69,21 @@ def process_html(self, node): ''' children = list(node) if (len(children) == 1 and children[0].tag == 'code'): - language = (children[0].attrib['class'] - if 'class' in children[0].attrib.keys() - else children[0].text.strip()) + content = children[0].text.strip() + language = children[0].attrib.get('class', content) + language_in_content = 'class' not in children[0].attrib.keys() - match = self.pattern.match(language) + match = self.pattern.search(language) if match is not None: options = list(filter(None, match.group('options').split('|'))) - content = children[0].text.strip() - if content.startswith('scratch\n'): + if language_in_content: content = content[match.end():] - content_blocks = [] - if 'split' in options: - content_blocks = content.split('\n\n') - else: - content_blocks.append(content) + 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: @@ -91,9 +91,6 @@ def process_html(self, node): self.update_required_images(content_hash, block) images.append(content_hash) - if 'random' in options: - shuffle(images) - html_string = self.template.render({'images': images}) new_node = etree.fromstring(html_string) diff --git a/kordac/tests/ScratchTest.py b/kordac/tests/ScratchTest.py index 569e877b..5b190df0 100644 --- a/kordac/tests/ScratchTest.py +++ b/kordac/tests/ScratchTest.py @@ -170,37 +170,52 @@ def test_example_split_codeblocks(self): } self.assertSetEqual(actual, expected) - def test_example_split_codeblocks_default(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_default.md') + def test_example_split_codeblocks_default(self): + '''Tests that scratch images are split if the split option is + given on the language. + ''' + kordac_extension = KordacExtension([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=[kordac_extension]) + expected_string = self.read_test_file(self.processor_name, 'example_split_codeblocks_expected.html', strip=True) + self.assertEqual(expected_string, converted_test_string) + + # Should really test result a better way + actual = kordac_extension.required_files['scratch_images'] + expected = { + 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, expected) + + 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.kordac_extension]) - expected_string = self.read_test_file(self.processor_name, 'example_split_codeblocks_expected.html', strip=True) - self.assertEqual(expected_string, converted_test_string) - - # Should really test result a better way - actual = self.kordac_extension.required_files['scratch_images'] - expected = { - 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, expected) + outputs.add(converted_test_string) + self.assertEqual(len(self.kordac_extension.required_files['scratch_images']), 1) + self.kordac_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 option is given. + the random and split option is given. ''' test_string = self.read_test_file(self.processor_name, 'example_random_split_codeblocks.md') @@ -208,6 +223,8 @@ def test_example_random_split_codeblocks(self): 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.kordac_extension]) outputs.add(converted_test_string) + self.assertEqual(len(self.kordac_extension.required_files['scratch_images']), 3) + self.kordac_extension.clear_saved_data() self.assertFalse(len(outputs) == 1) def test_example_other_code(self): diff --git a/kordac/tests/assets/scratch/example_random_codeblocks.md b/kordac/tests/assets/scratch/example_random_codeblocks.md new file mode 100644 index 00000000..077d8000 --- /dev/null +++ b/kordac/tests/assets/scratch/example_random_codeblocks.md @@ -0,0 +1,23 @@ +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 +``` From b15d67305053affb10c86333152f4f399fb77ccc Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Thu, 30 Mar 2017 16:59:45 +1300 Subject: [PATCH 72/86] Add compatibility with codehilite extension. --- kordac/processor-info.json | 2 +- .../ScratchCompatibilityPreprocessor.py | 2 +- kordac/tests/ScratchTest.py | 27 +++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/kordac/processor-info.json b/kordac/processor-info.json index 18187dd5..bf96e352 100644 --- a/kordac/processor-info.json +++ b/kordac/processor-info.json @@ -219,7 +219,7 @@ "class": "custom", "pattern": "^scratch(?P(\\|[^\\|\\n$]+)*) *($|\\n)", "scratch-compatibility": { - "pattern": "(?P^(?:~{3,}|`{3,}))[ ]*scratch((\\|[^\\|\\n$]+)*)[ ]*(hl_lines=(?P\"|')(?P.*?)(?P=quot))?[ ]*}?[ ]*\n(?P.*?)(?<=\n)(?P=fence)[ ]*$" + "pattern": "(?P^(?:~{3,}|`{3,}))[ ]*scratch(?P(\\|[^\\|\\n$]+)*)[ ]*(hl_lines=(?P\"|')(?P.*?)(?P=quot))?[ ]*}?[ ]*\n(?P.*?)(?<=\n)(?P=fence)[ ]*$" } }, "title": { diff --git a/kordac/processors/ScratchCompatibilityPreprocessor.py b/kordac/processors/ScratchCompatibilityPreprocessor.py index 54d3bcbe..b07f3f47 100644 --- a/kordac/processors/ScratchCompatibilityPreprocessor.py +++ b/kordac/processors/ScratchCompatibilityPreprocessor.py @@ -43,7 +43,7 @@ def run(self, lines): text = "\n".join(lines) match = self.pattern.search(text) while match is not None: - code = '
    {0}
    '.format(self._escape(match.group('code'))) + code = '
    {0}
    '.format(self._escape(match.group('code')), match.group('options')) placeholder = self.markdown.htmlStash.store(code, safe=True) text = text[:match.start()] + '\n' + placeholder + '\n' + text[match.end():] match = self.pattern.search(text) diff --git a/kordac/tests/ScratchTest.py b/kordac/tests/ScratchTest.py index 5b190df0..5d9f7514 100644 --- a/kordac/tests/ScratchTest.py +++ b/kordac/tests/ScratchTest.py @@ -199,6 +199,33 @@ def test_example_split_codeblocks_default(self): } self.assertSetEqual(actual, expected) + def test_example_split_codeblocks_compatibility(self): + extensions = ['markdown.extensions.codehilite', 'markdown.extensions.fenced_code'] + kordac_extension = KordacExtension([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 + [kordac_extension]) + expected_string = self.read_test_file(self.processor_name, 'example_split_codeblocks_expected.html', strip=True) + self.assertEqual(expected_string, converted_test_string) + + # Should really test result a better way + actual = kordac_extension.required_files['scratch_images'] + expected = { + 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, expected) + def test_example_random_codeblocks(self): '''Tests that scratch images are arranged randomly given the random option is given. From d7928bd00e40a10262b98e5c6426165581c3126f Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Fri, 31 Mar 2017 10:13:46 +1300 Subject: [PATCH 73/86] documentation for options. --- docs/source/processors/scratch.rst | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/source/processors/scratch.rst b/docs/source/processors/scratch.rst index 15e84b63..5873c718 100644 --- a/docs/source/processors/scratch.rst +++ b/docs/source/processors/scratch.rst @@ -54,6 +54,26 @@ The resulting HTML would be: .. literalinclude:: ../../../kordac/tests/assets/scratch/doc_example_basic_usage_expected.html :language: html +.. _scratch_options: + +Options +*************************************** +Options that change the output behaviour can be specified by appending them after the language separated by ``:``. The options avaliable are: + +- ``split`` - This option turns separate Scratch blocks (which are dictated by an empty line) into separate images. +- ``random`` - This parameter randomises the order of separate Scratch blocks (which are dictated by an empty line). + + +For example options can be used like: + +.. literalinclude:: ../../../kordac/tests/assets/scratch/example_split_codeblocks.md + :language: none + +Or for more than one option: + +.. literalinclude:: ../../../kordac/tests/assets/scratch/example_random_split_codeblocks.md + :language: none + .. _accessing-scratch-image-data: Accessing Scratch image data @@ -95,7 +115,7 @@ Overriding HTML for Scratch When overriding the HTML for Scratch code, the following Jinja2 placeholders are available: -- ``{{ hash }}`` - The hash of the Scratch code used in the expected filename. +- ``{{ hash }}`` - A list of hashes of the Scratch code-blocks used in the expected filename(s). **Example** From 15d903d174a0890afc6b474eed6d005f777a4f7c Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Fri, 31 Mar 2017 10:22:06 +1300 Subject: [PATCH 74/86] Update to use colon instead of pipe. (I still prefer pipe). --- kordac/processor-info.json | 4 ++-- kordac/processors/ScratchCompatibilityPreprocessor.py | 2 +- kordac/processors/ScratchTreeprocessor.py | 2 +- kordac/tests/assets/scratch/example_random_codeblocks.md | 2 +- .../tests/assets/scratch/example_random_split_codeblocks.md | 2 +- kordac/tests/assets/scratch/example_split_codeblocks.md | 2 +- .../tests/assets/scratch/example_split_codeblocks_default.md | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/kordac/processor-info.json b/kordac/processor-info.json index bf96e352..5d4ed950 100644 --- a/kordac/processor-info.json +++ b/kordac/processor-info.json @@ -217,9 +217,9 @@ }, "scratch": { "class": "custom", - "pattern": "^scratch(?P(\\|[^\\|\\n$]+)*) *($|\\n)", + "pattern": "^scratch(?P(:[^:\\n$]+)*) *($|\\n)", "scratch-compatibility": { - "pattern": "(?P^(?:~{3,}|`{3,}))[ ]*scratch(?P(\\|[^\\|\\n$]+)*)[ ]*(hl_lines=(?P\"|')(?P.*?)(?P=quot))?[ ]*}?[ ]*\n(?P.*?)(?<=\n)(?P=fence)[ ]*$" + "pattern": "(?P^(?:~{3,}|`{3,}))[ ]*scratch(?P(:[^:\\n$]+)*)[ ]*(hl_lines=(?P\"|')(?P.*?)(?P=quot))?[ ]*}?[ ]*\n(?P.*?)(?<=\n)(?P=fence)[ ]*$" } }, "title": { diff --git a/kordac/processors/ScratchCompatibilityPreprocessor.py b/kordac/processors/ScratchCompatibilityPreprocessor.py index b07f3f47..e7803a57 100644 --- a/kordac/processors/ScratchCompatibilityPreprocessor.py +++ b/kordac/processors/ScratchCompatibilityPreprocessor.py @@ -3,7 +3,7 @@ # Enable support for | so that languages can be passed options FENCED_BLOCK_RE_OVERRIDE = re.compile(r'''(?P^(?:~{3,}|`{3,}))[ ]* -(\{?\.?(?P[\w#.+-\|]*))?[ ]* +(\{?\.?(?P[\w#.+-:]*))?[ ]* (hl_lines=(?P"|')(?P.*?)(?P=quot))?[ ]* }?[ ]*\n (?P.*?)(?<=\n) diff --git a/kordac/processors/ScratchTreeprocessor.py b/kordac/processors/ScratchTreeprocessor.py index bd18dfb7..ee4dfbc1 100644 --- a/kordac/processors/ScratchTreeprocessor.py +++ b/kordac/processors/ScratchTreeprocessor.py @@ -75,7 +75,7 @@ def process_html(self, node): match = self.pattern.search(language) if match is not None: - options = list(filter(None, match.group('options').split('|'))) + options = list(filter(None, match.group('options').split(':'))) if language_in_content: content = content[match.end():] diff --git a/kordac/tests/assets/scratch/example_random_codeblocks.md b/kordac/tests/assets/scratch/example_random_codeblocks.md index 077d8000..5e8f5765 100644 --- a/kordac/tests/assets/scratch/example_random_codeblocks.md +++ b/kordac/tests/assets/scratch/example_random_codeblocks.md @@ -1,6 +1,6 @@ Scratch is great for kids you can great simple code like: -```scratch|random +```scratch:random when flag clicked say [Hi] diff --git a/kordac/tests/assets/scratch/example_random_split_codeblocks.md b/kordac/tests/assets/scratch/example_random_split_codeblocks.md index 20cd991b..20d540c2 100644 --- a/kordac/tests/assets/scratch/example_random_split_codeblocks.md +++ b/kordac/tests/assets/scratch/example_random_split_codeblocks.md @@ -1,6 +1,6 @@ Scratch is great for kids you can great simple code like: -```scratch|split|random +```scratch:split:random when flag clicked say [Hi] diff --git a/kordac/tests/assets/scratch/example_split_codeblocks.md b/kordac/tests/assets/scratch/example_split_codeblocks.md index 86b941e4..4a4d6d72 100644 --- a/kordac/tests/assets/scratch/example_split_codeblocks.md +++ b/kordac/tests/assets/scratch/example_split_codeblocks.md @@ -1,6 +1,6 @@ Scratch is great for kids you can great simple code like: -```scratch|split +```scratch:split when flag clicked say [Hi] diff --git a/kordac/tests/assets/scratch/example_split_codeblocks_default.md b/kordac/tests/assets/scratch/example_split_codeblocks_default.md index ec4746ce..cdab90b1 100644 --- a/kordac/tests/assets/scratch/example_split_codeblocks_default.md +++ b/kordac/tests/assets/scratch/example_split_codeblocks_default.md @@ -1,6 +1,6 @@ Scratch is great for kids you can great simple code like: - scratch|split + scratch:split when flag clicked say [Hi] From 5c2c737cfa0708003441f35ba6d13f6d584657a8 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Fri, 31 Mar 2017 10:28:25 +1300 Subject: [PATCH 75/86] flake8 fixes. --- kordac/processors/ScratchCompatibilityPreprocessor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kordac/processors/ScratchCompatibilityPreprocessor.py b/kordac/processors/ScratchCompatibilityPreprocessor.py index e7803a57..8a18bb10 100644 --- a/kordac/processors/ScratchCompatibilityPreprocessor.py +++ b/kordac/processors/ScratchCompatibilityPreprocessor.py @@ -29,6 +29,7 @@ def __init__(self, ext, *args, **kwargs): self.processor = 'scratch-compatibility' self.pattern = re.compile(ext.processor_info['scratch'][self.processor]['pattern'], re.DOTALL | re.MULTILINE) + self.CODE_FORMAT = '
    {0}
    ' def run(self, lines): ''' Inherited from Preprocessor, removes scratch codeblocks @@ -43,7 +44,7 @@ def run(self, lines): text = "\n".join(lines) match = self.pattern.search(text) while match is not None: - code = '
    {0}
    '.format(self._escape(match.group('code')), match.group('options')) + code = self.CODE_FORMAT.format(self._escape(match.group('code')), match.group('options')) placeholder = self.markdown.htmlStash.store(code, safe=True) text = text[:match.start()] + '\n' + placeholder + '\n' + text[match.end():] match = self.pattern.search(text) From 53e522d0c461c205b8cb7b821cf80ba2cefcea20 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Fri, 31 Mar 2017 11:25:33 +1300 Subject: [PATCH 76/86] Rename to verto --- .codeclimate.yml | 2 +- .flake8 | 2 +- .github/ISSUE_TEMPLATE.md | 2 +- .github/PULL_REQUEST_TEMPLATE.md | 2 +- .travis.yml | 2 +- CONTRIBUTING.md | 14 +-- MANIFEST.in | 2 +- README.rst | 30 +++--- docs/Makefile | 2 +- docs/make.bat | 2 +- docs/source/changelog.rst | 14 +-- docs/source/conf.py | 16 ++-- docs/source/contributing.rst | 90 +++++++++--------- docs/source/extensions.rst | 10 +- docs/source/index.rst | 8 +- docs/source/install.rst | 10 +- docs/source/processors/boxed-text.rst | 12 +-- docs/source/processors/button-link.rst | 20 ++-- docs/source/processors/comment.rst | 8 +- docs/source/processors/conditional.rst | 16 ++-- docs/source/processors/glossary-link.rst | 24 ++--- docs/source/processors/heading.rst | 14 +-- docs/source/processors/iframe.rst | 14 +-- docs/source/processors/image.rst | 24 ++--- docs/source/processors/interactive.rst | 32 +++---- docs/source/processors/panel.rst | 14 +-- docs/source/processors/relative-link.rst | 12 +-- docs/source/processors/remove-title.rst | 12 +-- docs/source/processors/save-title.rst | 10 +- docs/source/processors/scratch.rst | 24 ++--- docs/source/processors/table-of-contents.rst | 14 +-- docs/source/processors/video.rst | 22 ++--- docs/source/usage.rst | 74 +++++++------- .../button-link/doc_example_override_html.md | 1 - .../doc_example_override_html_expected.html | 3 - requirements.txt | 2 +- setup.py | 8 +- kordac/Kordac.py => verto/Verto.py | 34 +++---- .../VertoExtension.py | 50 +++++----- {kordac => verto}/__init__.py | 2 +- .../html-templates/boxed-text.html | 0 .../html-templates/button-link.html | 0 .../html-templates/conditional.html | 0 .../html-templates/glossary-link.html | 0 {kordac => verto}/html-templates/heading.html | 0 {kordac => verto}/html-templates/iframe.html | 0 {kordac => verto}/html-templates/image.html | 0 .../html-templates/interactive.html | 0 {kordac => verto}/html-templates/panel.html | 0 .../html-templates/relative-file-link.html | 0 .../html-templates/relative-link.html | 0 {kordac => verto}/html-templates/scratch.html | 0 .../html-templates/table-of-contents.html | 0 .../html-templates/video-vimeo.html | 0 .../html-templates/video-youtube.html | 0 {kordac => verto}/html-templates/video.html | 0 .../images/verto-logo.png | Bin {kordac => verto}/processor-info.json | 0 .../processors/BeautifyPostprocessor.py | 0 .../processors/CommentPreprocessor.py | 0 .../processors/ConditionalProcessor.py | 8 +- .../GenericContainerBlockProcessor.py | 6 +- .../processors/GenericTagBlockProcessor.py | 4 +- .../processors/GlossaryLinkPattern.py | 2 +- .../processors/HeadingBlockProcessor.py | 6 +- .../processors/ImageBlockProcessor.py | 8 +- .../processors/InteractiveBlockProcessor.py | 10 +- .../processors/JinjaPostprocessor.py | 0 .../processors/RelativeLinkPattern.py | 0 .../processors/RemovePostprocessor.py | 0 .../processors/RemoveTitlePreprocessor.py | 2 +- .../processors/SaveTitlePreprocessor.py | 6 +- .../ScratchCompatibilityPreprocessor.py | 2 +- .../processors/ScratchTreeprocessor.py | 6 +- .../processors/VideoBlockProcessor.py | 10 +- {kordac => verto}/processors/__init__.py | 0 .../processors/errors/ArgumentMissingError.py | 2 +- {kordac => verto}/processors/errors/Error.py | 0 .../errors/InvalidParameterError.py | 2 +- .../processors/errors/NoSourceLinkError.py | 2 +- .../errors/NoVideoIdentifierError.py | 2 +- .../processors/errors/TagNotMatchedError.py | 2 +- .../errors/UnsupportedVideoPlayerError.py | 2 +- .../processors/errors/__init__.py | 0 {kordac => verto}/processors/utils.py | 2 +- {kordac => verto}/tests/BaseTest.py | 2 +- {kordac => verto}/tests/BeautifyTest.py | 16 ++-- {kordac => verto}/tests/BoxedTextTest.py | 22 ++--- {kordac => verto}/tests/ButtonLinkTest.py | 26 ++--- {kordac => verto}/tests/CommentTest.py | 20 ++-- {kordac => verto}/tests/ConditionalTest.py | 20 ++-- {kordac => verto}/tests/ConfigurationTest.py | 80 ++++++++-------- {kordac => verto}/tests/FrameTest.py | 16 ++-- {kordac => verto}/tests/GlossaryLinkTest.py | 48 +++++----- {kordac => verto}/tests/HeadingTest.py | 32 +++---- {kordac => verto}/tests/ImageTest.py | 88 ++++++++--------- {kordac => verto}/tests/InteractiveTest.py | 16 ++-- {kordac => verto}/tests/PanelTest.py | 34 +++---- {kordac => verto}/tests/ProcessorTest.py | 12 +-- {kordac => verto}/tests/RelativeLinkTest.py | 38 ++++---- {kordac => verto}/tests/RemoveTitleTest.py | 26 ++--- {kordac => verto}/tests/SaveTitleTest.py | 42 ++++---- {kordac => verto}/tests/ScratchTest.py | 42 ++++---- {kordac => verto}/tests/SmokeTests.py | 18 ++-- .../tests/TableOfContentsTest.py | 12 +-- {kordac => verto}/tests/VideoTest.py | 40 ++++---- {kordac => verto}/tests/__init__.py | 0 .../assets/beautify/example_inline_code.md | 0 .../example_inline_code_expected.html | 0 .../beautify/example_mixed_code_types.md | 0 .../example_mixed_code_types_expected.html | 0 .../beautify/example_preformatted_code.md | 0 .../example_preformatted_code_expected.html | 0 ...xample_preformatted_code_with_extension.md | 0 ...ormatted_code_with_extension_expected.html | 0 .../boxed-text/doc_example_basic_usage.md | 0 .../doc_example_basic_usage_expected.html | 0 .../boxed-text/doc_example_override_html.md | 0 .../doc_example_override_html_expected.html | 0 .../doc_example_override_html_template.html | 0 .../assets/boxed-text/indented_boxed_text.md | 0 .../indented_boxed_text_expected.html | 0 .../assets/boxed-text/multiple_boxed_text.md | 0 .../multiple_boxed_text_expected.html | 0 .../tests/assets/boxed-text/no_boxed_text.md | 0 .../boxed-text/no_boxed_text_expected.html | 0 .../assets/boxed-text/recursive_boxed_text.md | 0 .../recursive_boxed_text_expected.html | 0 .../assets/boxed-text/single_boxed_text.md | 0 .../single_boxed_text_expected.html | 0 .../assets/button-link/contains_button.md | 0 .../button-link/contains_button_expected.html | 0 .../button-link/contains_file_link_button.md | 0 .../contains_file_link_button_expected.html | 0 .../button-link/contains_multiple_buttons.md | 0 .../contains_multiple_buttons_expected.html | 0 .../button-link/doc_example_basic_usage.md | 0 .../doc_example_basic_usage_expected.html | 0 .../button-link/doc_example_file_usage.md | 0 .../doc_example_file_usage_expected.html | 0 .../button-link/doc_example_override_html.md | 1 + .../doc_example_override_html_expected.html | 3 + .../doc_example_override_html_template.html | 0 .../assets/button-link/missing_end_brace.md | 0 .../missing_end_brace_expected.html | 0 .../tests/assets/button-link/no_button.md | 0 .../button-link/no_button_expected.html | 0 .../comment/comment_contains_comment.md | 0 .../comment_contains_comment_expected.html | 0 .../assets/comment/contains_inline_comment.md | 0 .../contains_inline_comment_expected.html | 0 .../contains_multiple_inline_comments.md | 0 ...ins_multiple_inline_comments_expected.html | 0 .../assets/comment/doc_example_basic_usage.md | 0 .../doc_example_basic_usage_expected.html | 0 .../comment/doc_example_multiple_usage.md | 0 .../doc_example_multiple_usage_expected.html | 0 .../tests/assets/comment/no_inline_comment.md | 0 .../comment/no_inline_comment_expected.html | 0 .../comment/text_contains_the_word_comment.md | 0 ...xt_contains_the_word_comment_expected.html | 0 .../conditional/doc_example2_override_html.md | 0 .../doc_example2_override_html_expected.html | 0 .../doc_example2_override_html_template.html | 0 .../conditional/doc_example_basic_usage.md | 0 .../doc_example_basic_usage_expected.html | 0 .../conditional/doc_example_complex_usage.md | 0 .../doc_example_complex_usage_expected.html | 0 .../conditional/doc_example_override_html.md | 0 .../doc_example_override_html_expected.html | 0 .../doc_example_override_html_template.html | 0 .../conditional/example_basic_else_usage.md | 0 .../example_basic_else_usage_expected.html | 0 .../assets/configuration/all_processors.md | 0 .../all_processors_custom_expected.html | 0 .../all_processors_custom_html_expected.html | 0 ...ll_processors_except_comment_expected.html | 0 .../all_processors_expected.html | 0 .../custom_processors_expected.html | 0 .../multiline_templates_expected.html | 0 .../assets/configuration/some_processors.md | 0 .../assets/configuration/some_processors_2.md | 0 .../some_processors_2_expected.html | 0 .../some_processors_expected.html | 0 .../glossary-link/doc_example_basic_usage.md | 0 .../doc_example_basic_usage_expected.html | 0 .../doc_example_override_html.md | 0 .../doc_example_override_html_expected.html | 0 .../doc_example_override_html_template.html | 0 .../leading_and_trailing_inline_text.md | 0 ...ing_and_trailing_inline_text_expected.html | 0 .../glossary-link/leading_inline_text.md | 0 .../leading_inline_text_expected.html | 0 .../glossary-link/multiple_reference_text.md | 0 .../multiple_reference_text_expected.html | 0 .../assets/glossary-link/multiple_terms.md | 0 .../multiple_terms_expected.html | 0 .../glossary-link/multiple_word_term.md | 0 .../multiple_word_term_expected.html | 0 .../glossary-link/reference_text_given.md | 0 .../reference_text_given_expected.html | 0 .../assets/glossary-link/single_word_term.md | 0 .../single_word_term_expected.html | 0 .../glossary-link/trailing_inline_text.md | 0 .../trailing_inline_text_expected.html | 0 .../assets/heading/doc_example_basic_usage.md | 0 .../doc_example_basic_usage_expected.html | 0 .../heading/doc_example_override_html.md | 0 .../doc_example_override_html_expected.html | 0 .../doc_example_override_html_template.html | 0 .../tests/assets/heading/example_blank.md | 0 .../heading/example_blank_expected.html | 0 .../assets/heading/example_single_heading.md | 0 .../example_single_heading_expected.html | 0 .../heading/multiple_roots_zero_level.md | 0 .../multiple_roots_zero_level_expected.html | 0 .../assets/iframe/doc_example_basic_usage.md | 0 .../doc_example_basic_usage_expected.html | 0 .../iframe/doc_example_override_html.md | 0 .../doc_example_override_html_expected.html | 0 .../doc_example_override_html_template.html | 0 .../tests/assets/iframe/example_no_link.md | 0 .../tests/assets/image/align_center.md | 0 .../assets/image/align_center_expected.html | 0 .../tests/assets/image/align_left.md | 0 .../assets/image/align_left_expected.html | 0 .../tests/assets/image/align_right.md | 0 .../assets/image/align_right_expected.html | 0 .../tests/assets/image/contains_alt.md | 0 .../assets/image/contains_alt_expected.html | 0 .../tests/assets/image/contains_caption.md | 0 .../image/contains_caption_expected.html | 0 .../assets/image/contains_caption_link.md | 0 .../image/contains_caption_link_expected.html | 0 .../tests/assets/image/contains_hover_text.md | 0 .../image/contains_hover_text_expected.html | 0 .../tests/assets/image/contains_image.md | 0 ...ains_image_and_text_contains_word_image.md | 0 ...and_text_contains_word_image_expected.html | 0 .../assets/image/contains_image_expected.html | 0 .../assets/image/contains_multiple_images.md | 0 .../contains_multiple_images_expected.html | 0 .../tests/assets/image/contains_source.md | 0 .../image/contains_source_expected.html | 0 .../tests/assets/image/default_image.md | 0 .../assets/image/default_image_expected.html | 0 .../image/doc_example_2_override_html.md | 0 .../doc_example_2_override_html_expected.html | 0 .../doc_example_2_override_html_template.html | 0 ...example_2_override_link_html_template.html | 0 .../assets/image/doc_example_basic_usage.md | 0 .../doc_example_basic_usage_expected.html | 0 .../assets/image/doc_example_override_html.md | 0 .../doc_example_override_html_expected.html | 0 .../doc_example_override_html_template.html | 0 .../tests/assets/image/external_image.md | 0 .../assets/image/external_image_expected.html | 0 .../tests/assets/image/internal_image.md | 0 .../assets/image/internal_image_expected.html | 0 .../assets/image/multiple_internal_image.md | 0 .../tests/assets/image/no_image.md | 0 .../tests/assets/image/no_image_expected.html | 0 .../image/text_contains_the_word_image.md | 0 ...text_contains_the_word_image_expected.html | 0 .../interactive/doc_example_iframe_usage.md | 0 .../doc_example_iframe_usage_expected.html | 0 .../interactive/doc_example_in_page_usage.md | 0 .../doc_example_in_page_usage_expected.html | 0 .../interactive/doc_example_override_html.md | 0 .../doc_example_override_html_expected.html | 0 .../doc_example_override_html_template.html | 0 .../doc_example_whole_page_usage.md | 0 ...doc_example_whole_page_usage_expected.html | 0 .../assets/panel/contains_inner_panel.md | 0 .../panel/contains_inner_panel_expected.html | 0 .../assets/panel/contains_multiple_panels.md | 0 .../contains_multiple_panels_expected.html | 0 .../assets/panel/doc_example_basic_usage.md | 0 .../doc_example_basic_usage_expected.html | 0 .../assets/panel/doc_example_override_html.md | 0 .../doc_example_override_html_expected.html | 0 .../doc_example_override_html_template.html | 0 .../tests/assets/panel/missing_end_tag.md | 0 .../tests/assets/panel/missing_start_tag.md | 0 .../tests/assets/panel/missing_tag_inner.md | 0 .../panel/parses_always_expanded_panel.md | 0 ...parses_always_expanded_panel_expected.html | 0 .../tests/assets/panel/parses_blank.md | 0 .../assets/panel/parses_blank_expected.html | 0 .../parses_blank_lines_multiple_paragraphs.md | 0 ...nk_lines_multiple_paragraphs_expected.html | 0 .../assets/panel/parses_expanded_panel.md | 0 .../panel/parses_expanded_panel_expected.html | 0 .../parses_no_blank_lines_single_paragraph.md | 0 ...blank_lines_single_paragraph_expected.html | 0 .../relative-link/doc_example_basic_usage.md | 0 .../doc_example_basic_usage_expected.html | 0 .../doc_example_override_html.md | 0 .../doc_example_override_html_expected.html | 0 .../doc_example_override_html_template.html | 0 .../tests/assets/relative-link/ftp_schema.md | 0 .../relative-link/ftp_schema_expected.html | 0 .../tests/assets/relative-link/ftp_text.md | 0 .../relative-link/ftp_text_expected.html | 0 .../tests/assets/relative-link/ftps_schema.md | 0 .../relative-link/ftps_schema_expected.html | 0 .../tests/assets/relative-link/ftps_text.md | 0 .../relative-link/ftps_text_expected.html | 0 .../tests/assets/relative-link/http_schema.md | 0 .../relative-link/http_schema_expected.html | 0 .../tests/assets/relative-link/http_text.md | 0 .../relative-link/http_text_expected.html | 0 .../assets/relative-link/https_schema.md | 0 .../relative-link/https_schema_expected.html | 0 .../tests/assets/relative-link/https_text.md | 0 .../relative-link/https_text_expected.html | 0 .../tests/assets/relative-link/long_path.md | 0 .../relative-link/long_path_expected.html | 0 .../assets/relative-link/mailto_schema.md | 0 .../relative-link/mailto_schema_expected.html | 0 .../tests/assets/relative-link/mailto_text.md | 0 .../relative-link/mailto_text_expected.html | 0 .../assets/relative-link/multiple_links.md | 0 .../multiple_links_expected.html | 0 .../tests/assets/relative-link/news_schema.md | 0 .../relative-link/news_schema_expected.html | 0 .../tests/assets/relative-link/news_text.md | 0 .../relative-link/news_text_expected.html | 0 .../tests/assets/relative-link/www_text.md | 0 .../relative-link/www_text_expected.html | 0 .../remove-title/doc_example_basic_usage.md | 0 .../doc_example_basic_usage_expected.html | 0 .../assets/remove-title/level_two_heading.md | 0 .../level_two_heading_expected.html | 0 .../assets/remove-title/multiple_headings.md | 0 .../multiple_headings_expected.html | 0 .../multiple_level_one_headings.md | 0 .../multiple_level_one_headings_expected.html | 0 .../remove-title/no_heading_permalink.md | 0 .../no_heading_permalink_expected.html | 0 .../tests/assets/remove-title/no_headings.md | 0 .../remove-title/no_headings_expected.html | 0 .../assets/remove-title/no_space_title.md | 0 .../remove-title/no_space_title_expected.html | 0 .../assets/remove-title/processor_off.md | 0 .../remove-title/processor_off_expected.html | 0 .../save-title/doc_example_basic_usage.md | 0 .../doc_example_basic_usage_expected.html | 0 .../assets/save-title/level_two_heading.md | 0 .../level_two_heading_expected.html | 0 .../assets/save-title/multiple_headings.md | 0 .../multiple_headings_expected.html | 0 .../save-title/multiple_level_one_headings.md | 0 .../multiple_level_one_headings_expected.html | 0 .../assets/save-title/no_heading_permalink.md | 0 .../tests/assets/save-title/no_headings.md | 0 .../tests/assets/save-title/no_space_title.md | 0 .../save-title/no_space_title_expected.html | 0 .../assets/scratch/doc_example_basic_usage.md | 0 .../doc_example_basic_usage_expected.html | 0 .../scratch/doc_example_override_html.md | 0 .../doc_example_override_html_expected.html | 0 .../doc_example_override_html_template.html | 0 .../scratch/example_multiple_codeblocks.md | 0 .../scratch/example_multiple_codeblocks_2.md | 0 .../example_multiple_codeblocks_expected.html | 0 ...xample_multiple_codeblocks_expected_2.html | 0 .../assets/scratch/example_other_code.md | 0 .../scratch/example_other_code_expected.html | 0 .../assets/scratch/example_separate_blocks.md | 0 .../example_separate_blocks_expected.html | 0 .../example_standard_markdown_block.md | 0 ...mple_standard_markdown_block_expected.html | 0 .../tests/assets/smoke/algorithms.md | 0 .../tests/assets/smoke/introduction.md | 0 .../doc_example_basic_usage.md | 0 .../doc_example_basic_usage_expected.html | 0 .../doc_example_override_html.md | 0 .../doc_example_override_html_expected.html | 0 .../doc_example_override_html_template.html | 0 .../assets/video/contains_multiple_videos.md | 0 .../contains_multiple_videos_expected.html | 0 .../tests/assets/video/contains_no_video.md | 0 .../video/contains_no_video_expected.html | 0 .../assets/video/contains_vimeo_video.md | 0 .../video/contains_vimeo_video_expected.html | 0 .../assets/video/doc_example_basic_usage.md | 0 .../doc_example_basic_usage_expected.html | 0 .../assets/video/doc_example_override_html.md | 0 .../doc_example_override_html_expected.html | 0 .../doc_example_override_html_template.html | 0 ...xample_override_html_youtube_template.html | 0 .../tests/assets/video/missing_identifier.md | 0 .../assets/video/multiple_vimeo_links.md | 0 .../video/multiple_vimeo_links_expected.html | 0 .../assets/video/multiple_youtube_links.md | 0 .../multiple_youtube_links_expected.html | 0 .../assets/video/unsupported_video_type.md | 0 .../tests/assets/video/vimeo_link.md | 0 .../assets/video/vimeo_link_expected.html | 0 .../tests/assets/video/vimeo_player_link.md | 0 .../video/vimeo_player_link_expected.html | 0 .../assets/video/youtube_and_vimeo_links.md | 0 .../youtube_and_vimeo_links_expected.html | 0 .../tests/assets/video/youtube_be_link.md | 0 .../video/youtube_be_link_expected.html | 0 .../tests/assets/video/youtube_embed_link.md | 0 .../video/youtube_embed_link_expected.html | 0 .../tests/assets/video/youtube_watch_link.md | 0 .../video/youtube_watch_link_expected.html | 0 {kordac => verto}/tests/start_tests.py | 40 ++++---- {kordac => verto}/utils/HeadingNode.py | 0 {kordac => verto}/utils/UniqueSlugify.py | 0 {kordac => verto}/utils/__init__.py | 0 {kordac => verto}/utils/overrides.py | 0 415 files changed, 716 insertions(+), 716 deletions(-) delete mode 100644 kordac/tests/assets/button-link/doc_example_override_html.md delete mode 100644 kordac/tests/assets/button-link/doc_example_override_html_expected.html rename kordac/Kordac.py => verto/Verto.py (83%) rename kordac/KordacExtension.py => verto/VertoExtension.py (83%) rename {kordac => verto}/__init__.py (58%) rename {kordac => verto}/html-templates/boxed-text.html (100%) rename {kordac => verto}/html-templates/button-link.html (100%) rename {kordac => verto}/html-templates/conditional.html (100%) rename {kordac => verto}/html-templates/glossary-link.html (100%) rename {kordac => verto}/html-templates/heading.html (100%) rename {kordac => verto}/html-templates/iframe.html (100%) rename {kordac => verto}/html-templates/image.html (100%) rename {kordac => verto}/html-templates/interactive.html (100%) rename {kordac => verto}/html-templates/panel.html (100%) rename {kordac => verto}/html-templates/relative-file-link.html (100%) rename {kordac => verto}/html-templates/relative-link.html (100%) rename {kordac => verto}/html-templates/scratch.html (100%) rename {kordac => verto}/html-templates/table-of-contents.html (100%) rename {kordac => verto}/html-templates/video-vimeo.html (100%) rename {kordac => verto}/html-templates/video-youtube.html (100%) rename {kordac => verto}/html-templates/video.html (100%) rename kordac/images/kordac-logo.png => verto/images/verto-logo.png (100%) rename {kordac => verto}/processor-info.json (100%) rename {kordac => verto}/processors/BeautifyPostprocessor.py (100%) rename {kordac => verto}/processors/CommentPreprocessor.py (100%) rename {kordac => verto}/processors/ConditionalProcessor.py (95%) rename {kordac => verto}/processors/GenericContainerBlockProcessor.py (94%) rename {kordac => verto}/processors/GenericTagBlockProcessor.py (94%) rename {kordac => verto}/processors/GlossaryLinkPattern.py (97%) rename {kordac => verto}/processors/HeadingBlockProcessor.py (97%) rename {kordac => verto}/processors/ImageBlockProcessor.py (91%) rename {kordac => verto}/processors/InteractiveBlockProcessor.py (90%) rename {kordac => verto}/processors/JinjaPostprocessor.py (100%) rename {kordac => verto}/processors/RelativeLinkPattern.py (100%) rename {kordac => verto}/processors/RemovePostprocessor.py (100%) rename {kordac => verto}/processors/RemoveTitlePreprocessor.py (95%) rename {kordac => verto}/processors/SaveTitlePreprocessor.py (87%) rename {kordac => verto}/processors/ScratchCompatibilityPreprocessor.py (97%) rename {kordac => verto}/processors/ScratchTreeprocessor.py (95%) rename {kordac => verto}/processors/VideoBlockProcessor.py (90%) rename {kordac => verto}/processors/__init__.py (100%) rename {kordac => verto}/processors/errors/ArgumentMissingError.py (90%) rename {kordac => verto}/processors/errors/Error.py (100%) rename {kordac => verto}/processors/errors/InvalidParameterError.py (90%) rename {kordac => verto}/processors/errors/NoSourceLinkError.py (89%) rename {kordac => verto}/processors/errors/NoVideoIdentifierError.py (89%) rename {kordac => verto}/processors/errors/TagNotMatchedError.py (89%) rename {kordac => verto}/processors/errors/UnsupportedVideoPlayerError.py (89%) rename {kordac => verto}/processors/errors/__init__.py (100%) rename {kordac => verto}/processors/utils.py (98%) rename {kordac => verto}/tests/BaseTest.py (92%) rename {kordac => verto}/tests/BeautifyTest.py (80%) rename {kordac => verto}/tests/BoxedTextTest.py (89%) rename {kordac => verto}/tests/ButtonLinkTest.py (90%) rename {kordac => verto}/tests/CommentTest.py (90%) rename {kordac => verto}/tests/ConditionalTest.py (86%) rename {kordac => verto}/tests/ConfigurationTest.py (78%) rename {kordac => verto}/tests/FrameTest.py (80%) rename {kordac => verto}/tests/GlossaryLinkTest.py (86%) rename {kordac => verto}/tests/HeadingTest.py (91%) rename {kordac => verto}/tests/ImageTest.py (86%) rename {kordac => verto}/tests/InteractiveTest.py (87%) rename {kordac => verto}/tests/PanelTest.py (89%) rename {kordac => verto}/tests/ProcessorTest.py (75%) rename {kordac => verto}/tests/RelativeLinkTest.py (92%) rename {kordac => verto}/tests/RemoveTitleTest.py (88%) rename {kordac => verto}/tests/SaveTitleTest.py (76%) rename {kordac => verto}/tests/ScratchTest.py (83%) rename {kordac => verto}/tests/SmokeTests.py (86%) rename {kordac => verto}/tests/TableOfContentsTest.py (83%) rename {kordac => verto}/tests/VideoTest.py (88%) rename {kordac => verto}/tests/__init__.py (100%) rename {kordac => verto}/tests/assets/beautify/example_inline_code.md (100%) rename {kordac => verto}/tests/assets/beautify/example_inline_code_expected.html (100%) rename {kordac => verto}/tests/assets/beautify/example_mixed_code_types.md (100%) rename {kordac => verto}/tests/assets/beautify/example_mixed_code_types_expected.html (100%) rename {kordac => verto}/tests/assets/beautify/example_preformatted_code.md (100%) rename {kordac => verto}/tests/assets/beautify/example_preformatted_code_expected.html (100%) rename {kordac => verto}/tests/assets/beautify/example_preformatted_code_with_extension.md (100%) rename {kordac => verto}/tests/assets/beautify/example_preformatted_code_with_extension_expected.html (100%) rename {kordac => verto}/tests/assets/boxed-text/doc_example_basic_usage.md (100%) rename {kordac => verto}/tests/assets/boxed-text/doc_example_basic_usage_expected.html (100%) rename {kordac => verto}/tests/assets/boxed-text/doc_example_override_html.md (100%) rename {kordac => verto}/tests/assets/boxed-text/doc_example_override_html_expected.html (100%) rename {kordac => verto}/tests/assets/boxed-text/doc_example_override_html_template.html (100%) rename {kordac => verto}/tests/assets/boxed-text/indented_boxed_text.md (100%) rename {kordac => verto}/tests/assets/boxed-text/indented_boxed_text_expected.html (100%) rename {kordac => verto}/tests/assets/boxed-text/multiple_boxed_text.md (100%) rename {kordac => verto}/tests/assets/boxed-text/multiple_boxed_text_expected.html (100%) rename {kordac => verto}/tests/assets/boxed-text/no_boxed_text.md (100%) rename {kordac => verto}/tests/assets/boxed-text/no_boxed_text_expected.html (100%) rename {kordac => verto}/tests/assets/boxed-text/recursive_boxed_text.md (100%) rename {kordac => verto}/tests/assets/boxed-text/recursive_boxed_text_expected.html (100%) rename {kordac => verto}/tests/assets/boxed-text/single_boxed_text.md (100%) rename {kordac => verto}/tests/assets/boxed-text/single_boxed_text_expected.html (100%) rename {kordac => verto}/tests/assets/button-link/contains_button.md (100%) rename {kordac => verto}/tests/assets/button-link/contains_button_expected.html (100%) rename {kordac => verto}/tests/assets/button-link/contains_file_link_button.md (100%) rename {kordac => verto}/tests/assets/button-link/contains_file_link_button_expected.html (100%) rename {kordac => verto}/tests/assets/button-link/contains_multiple_buttons.md (100%) rename {kordac => verto}/tests/assets/button-link/contains_multiple_buttons_expected.html (100%) rename {kordac => verto}/tests/assets/button-link/doc_example_basic_usage.md (100%) rename {kordac => verto}/tests/assets/button-link/doc_example_basic_usage_expected.html (100%) rename {kordac => verto}/tests/assets/button-link/doc_example_file_usage.md (100%) rename {kordac => verto}/tests/assets/button-link/doc_example_file_usage_expected.html (100%) create mode 100644 verto/tests/assets/button-link/doc_example_override_html.md create mode 100644 verto/tests/assets/button-link/doc_example_override_html_expected.html rename {kordac => verto}/tests/assets/button-link/doc_example_override_html_template.html (100%) rename {kordac => verto}/tests/assets/button-link/missing_end_brace.md (100%) rename {kordac => verto}/tests/assets/button-link/missing_end_brace_expected.html (100%) rename {kordac => verto}/tests/assets/button-link/no_button.md (100%) rename {kordac => verto}/tests/assets/button-link/no_button_expected.html (100%) rename {kordac => verto}/tests/assets/comment/comment_contains_comment.md (100%) rename {kordac => verto}/tests/assets/comment/comment_contains_comment_expected.html (100%) rename {kordac => verto}/tests/assets/comment/contains_inline_comment.md (100%) rename {kordac => verto}/tests/assets/comment/contains_inline_comment_expected.html (100%) rename {kordac => verto}/tests/assets/comment/contains_multiple_inline_comments.md (100%) rename {kordac => verto}/tests/assets/comment/contains_multiple_inline_comments_expected.html (100%) rename {kordac => verto}/tests/assets/comment/doc_example_basic_usage.md (100%) rename {kordac => verto}/tests/assets/comment/doc_example_basic_usage_expected.html (100%) rename {kordac => verto}/tests/assets/comment/doc_example_multiple_usage.md (100%) rename {kordac => verto}/tests/assets/comment/doc_example_multiple_usage_expected.html (100%) rename {kordac => verto}/tests/assets/comment/no_inline_comment.md (100%) rename {kordac => verto}/tests/assets/comment/no_inline_comment_expected.html (100%) rename {kordac => verto}/tests/assets/comment/text_contains_the_word_comment.md (100%) rename {kordac => verto}/tests/assets/comment/text_contains_the_word_comment_expected.html (100%) rename {kordac => verto}/tests/assets/conditional/doc_example2_override_html.md (100%) rename {kordac => verto}/tests/assets/conditional/doc_example2_override_html_expected.html (100%) rename {kordac => verto}/tests/assets/conditional/doc_example2_override_html_template.html (100%) rename {kordac => verto}/tests/assets/conditional/doc_example_basic_usage.md (100%) rename {kordac => verto}/tests/assets/conditional/doc_example_basic_usage_expected.html (100%) rename {kordac => verto}/tests/assets/conditional/doc_example_complex_usage.md (100%) rename {kordac => verto}/tests/assets/conditional/doc_example_complex_usage_expected.html (100%) rename {kordac => verto}/tests/assets/conditional/doc_example_override_html.md (100%) rename {kordac => verto}/tests/assets/conditional/doc_example_override_html_expected.html (100%) rename {kordac => verto}/tests/assets/conditional/doc_example_override_html_template.html (100%) rename {kordac => verto}/tests/assets/conditional/example_basic_else_usage.md (100%) rename {kordac => verto}/tests/assets/conditional/example_basic_else_usage_expected.html (100%) rename {kordac => verto}/tests/assets/configuration/all_processors.md (100%) rename {kordac => verto}/tests/assets/configuration/all_processors_custom_expected.html (100%) rename {kordac => verto}/tests/assets/configuration/all_processors_custom_html_expected.html (100%) rename {kordac => verto}/tests/assets/configuration/all_processors_except_comment_expected.html (100%) rename {kordac => verto}/tests/assets/configuration/all_processors_expected.html (100%) rename {kordac => verto}/tests/assets/configuration/custom_processors_expected.html (100%) rename {kordac => verto}/tests/assets/configuration/multiline_templates_expected.html (100%) rename {kordac => verto}/tests/assets/configuration/some_processors.md (100%) rename {kordac => verto}/tests/assets/configuration/some_processors_2.md (100%) rename {kordac => verto}/tests/assets/configuration/some_processors_2_expected.html (100%) rename {kordac => verto}/tests/assets/configuration/some_processors_expected.html (100%) rename {kordac => verto}/tests/assets/glossary-link/doc_example_basic_usage.md (100%) rename {kordac => verto}/tests/assets/glossary-link/doc_example_basic_usage_expected.html (100%) rename {kordac => verto}/tests/assets/glossary-link/doc_example_override_html.md (100%) rename {kordac => verto}/tests/assets/glossary-link/doc_example_override_html_expected.html (100%) rename {kordac => verto}/tests/assets/glossary-link/doc_example_override_html_template.html (100%) rename {kordac => verto}/tests/assets/glossary-link/leading_and_trailing_inline_text.md (100%) rename {kordac => verto}/tests/assets/glossary-link/leading_and_trailing_inline_text_expected.html (100%) rename {kordac => verto}/tests/assets/glossary-link/leading_inline_text.md (100%) rename {kordac => verto}/tests/assets/glossary-link/leading_inline_text_expected.html (100%) rename {kordac => verto}/tests/assets/glossary-link/multiple_reference_text.md (100%) rename {kordac => verto}/tests/assets/glossary-link/multiple_reference_text_expected.html (100%) rename {kordac => verto}/tests/assets/glossary-link/multiple_terms.md (100%) rename {kordac => verto}/tests/assets/glossary-link/multiple_terms_expected.html (100%) rename {kordac => verto}/tests/assets/glossary-link/multiple_word_term.md (100%) rename {kordac => verto}/tests/assets/glossary-link/multiple_word_term_expected.html (100%) rename {kordac => verto}/tests/assets/glossary-link/reference_text_given.md (100%) rename {kordac => verto}/tests/assets/glossary-link/reference_text_given_expected.html (100%) rename {kordac => verto}/tests/assets/glossary-link/single_word_term.md (100%) rename {kordac => verto}/tests/assets/glossary-link/single_word_term_expected.html (100%) rename {kordac => verto}/tests/assets/glossary-link/trailing_inline_text.md (100%) rename {kordac => verto}/tests/assets/glossary-link/trailing_inline_text_expected.html (100%) rename {kordac => verto}/tests/assets/heading/doc_example_basic_usage.md (100%) rename {kordac => verto}/tests/assets/heading/doc_example_basic_usage_expected.html (100%) rename {kordac => verto}/tests/assets/heading/doc_example_override_html.md (100%) rename {kordac => verto}/tests/assets/heading/doc_example_override_html_expected.html (100%) rename {kordac => verto}/tests/assets/heading/doc_example_override_html_template.html (100%) rename {kordac => verto}/tests/assets/heading/example_blank.md (100%) rename {kordac => verto}/tests/assets/heading/example_blank_expected.html (100%) rename {kordac => verto}/tests/assets/heading/example_single_heading.md (100%) rename {kordac => verto}/tests/assets/heading/example_single_heading_expected.html (100%) rename {kordac => verto}/tests/assets/heading/multiple_roots_zero_level.md (100%) rename {kordac => verto}/tests/assets/heading/multiple_roots_zero_level_expected.html (100%) rename {kordac => verto}/tests/assets/iframe/doc_example_basic_usage.md (100%) rename {kordac => verto}/tests/assets/iframe/doc_example_basic_usage_expected.html (100%) rename {kordac => verto}/tests/assets/iframe/doc_example_override_html.md (100%) rename {kordac => verto}/tests/assets/iframe/doc_example_override_html_expected.html (100%) rename {kordac => verto}/tests/assets/iframe/doc_example_override_html_template.html (100%) rename {kordac => verto}/tests/assets/iframe/example_no_link.md (100%) rename {kordac => verto}/tests/assets/image/align_center.md (100%) rename {kordac => verto}/tests/assets/image/align_center_expected.html (100%) rename {kordac => verto}/tests/assets/image/align_left.md (100%) rename {kordac => verto}/tests/assets/image/align_left_expected.html (100%) rename {kordac => verto}/tests/assets/image/align_right.md (100%) rename {kordac => verto}/tests/assets/image/align_right_expected.html (100%) rename {kordac => verto}/tests/assets/image/contains_alt.md (100%) rename {kordac => verto}/tests/assets/image/contains_alt_expected.html (100%) rename {kordac => verto}/tests/assets/image/contains_caption.md (100%) rename {kordac => verto}/tests/assets/image/contains_caption_expected.html (100%) rename {kordac => verto}/tests/assets/image/contains_caption_link.md (100%) rename {kordac => verto}/tests/assets/image/contains_caption_link_expected.html (100%) rename {kordac => verto}/tests/assets/image/contains_hover_text.md (100%) rename {kordac => verto}/tests/assets/image/contains_hover_text_expected.html (100%) rename {kordac => verto}/tests/assets/image/contains_image.md (100%) rename {kordac => verto}/tests/assets/image/contains_image_and_text_contains_word_image.md (100%) rename {kordac => verto}/tests/assets/image/contains_image_and_text_contains_word_image_expected.html (100%) rename {kordac => verto}/tests/assets/image/contains_image_expected.html (100%) rename {kordac => verto}/tests/assets/image/contains_multiple_images.md (100%) rename {kordac => verto}/tests/assets/image/contains_multiple_images_expected.html (100%) rename {kordac => verto}/tests/assets/image/contains_source.md (100%) rename {kordac => verto}/tests/assets/image/contains_source_expected.html (100%) rename {kordac => verto}/tests/assets/image/default_image.md (100%) rename {kordac => verto}/tests/assets/image/default_image_expected.html (100%) rename {kordac => verto}/tests/assets/image/doc_example_2_override_html.md (100%) rename {kordac => verto}/tests/assets/image/doc_example_2_override_html_expected.html (100%) rename {kordac => verto}/tests/assets/image/doc_example_2_override_html_template.html (100%) rename {kordac => verto}/tests/assets/image/doc_example_2_override_link_html_template.html (100%) rename {kordac => verto}/tests/assets/image/doc_example_basic_usage.md (100%) rename {kordac => verto}/tests/assets/image/doc_example_basic_usage_expected.html (100%) rename {kordac => verto}/tests/assets/image/doc_example_override_html.md (100%) rename {kordac => verto}/tests/assets/image/doc_example_override_html_expected.html (100%) rename {kordac => verto}/tests/assets/image/doc_example_override_html_template.html (100%) rename {kordac => verto}/tests/assets/image/external_image.md (100%) rename {kordac => verto}/tests/assets/image/external_image_expected.html (100%) rename {kordac => verto}/tests/assets/image/internal_image.md (100%) rename {kordac => verto}/tests/assets/image/internal_image_expected.html (100%) rename {kordac => verto}/tests/assets/image/multiple_internal_image.md (100%) rename {kordac => verto}/tests/assets/image/no_image.md (100%) rename {kordac => verto}/tests/assets/image/no_image_expected.html (100%) rename {kordac => verto}/tests/assets/image/text_contains_the_word_image.md (100%) rename {kordac => verto}/tests/assets/image/text_contains_the_word_image_expected.html (100%) rename {kordac => verto}/tests/assets/interactive/doc_example_iframe_usage.md (100%) rename {kordac => verto}/tests/assets/interactive/doc_example_iframe_usage_expected.html (100%) rename {kordac => verto}/tests/assets/interactive/doc_example_in_page_usage.md (100%) rename {kordac => verto}/tests/assets/interactive/doc_example_in_page_usage_expected.html (100%) rename {kordac => verto}/tests/assets/interactive/doc_example_override_html.md (100%) rename {kordac => verto}/tests/assets/interactive/doc_example_override_html_expected.html (100%) rename {kordac => verto}/tests/assets/interactive/doc_example_override_html_template.html (100%) rename {kordac => verto}/tests/assets/interactive/doc_example_whole_page_usage.md (100%) rename {kordac => verto}/tests/assets/interactive/doc_example_whole_page_usage_expected.html (100%) rename {kordac => verto}/tests/assets/panel/contains_inner_panel.md (100%) rename {kordac => verto}/tests/assets/panel/contains_inner_panel_expected.html (100%) rename {kordac => verto}/tests/assets/panel/contains_multiple_panels.md (100%) rename {kordac => verto}/tests/assets/panel/contains_multiple_panels_expected.html (100%) rename {kordac => verto}/tests/assets/panel/doc_example_basic_usage.md (100%) rename {kordac => verto}/tests/assets/panel/doc_example_basic_usage_expected.html (100%) rename {kordac => verto}/tests/assets/panel/doc_example_override_html.md (100%) rename {kordac => verto}/tests/assets/panel/doc_example_override_html_expected.html (100%) rename {kordac => verto}/tests/assets/panel/doc_example_override_html_template.html (100%) rename {kordac => verto}/tests/assets/panel/missing_end_tag.md (100%) rename {kordac => verto}/tests/assets/panel/missing_start_tag.md (100%) rename {kordac => verto}/tests/assets/panel/missing_tag_inner.md (100%) rename {kordac => verto}/tests/assets/panel/parses_always_expanded_panel.md (100%) rename {kordac => verto}/tests/assets/panel/parses_always_expanded_panel_expected.html (100%) rename {kordac => verto}/tests/assets/panel/parses_blank.md (100%) rename {kordac => verto}/tests/assets/panel/parses_blank_expected.html (100%) rename {kordac => verto}/tests/assets/panel/parses_blank_lines_multiple_paragraphs.md (100%) rename {kordac => verto}/tests/assets/panel/parses_blank_lines_multiple_paragraphs_expected.html (100%) rename {kordac => verto}/tests/assets/panel/parses_expanded_panel.md (100%) rename {kordac => verto}/tests/assets/panel/parses_expanded_panel_expected.html (100%) rename {kordac => verto}/tests/assets/panel/parses_no_blank_lines_single_paragraph.md (100%) rename {kordac => verto}/tests/assets/panel/parses_no_blank_lines_single_paragraph_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/doc_example_basic_usage.md (100%) rename {kordac => verto}/tests/assets/relative-link/doc_example_basic_usage_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/doc_example_override_html.md (100%) rename {kordac => verto}/tests/assets/relative-link/doc_example_override_html_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/doc_example_override_html_template.html (100%) rename {kordac => verto}/tests/assets/relative-link/ftp_schema.md (100%) rename {kordac => verto}/tests/assets/relative-link/ftp_schema_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/ftp_text.md (100%) rename {kordac => verto}/tests/assets/relative-link/ftp_text_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/ftps_schema.md (100%) rename {kordac => verto}/tests/assets/relative-link/ftps_schema_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/ftps_text.md (100%) rename {kordac => verto}/tests/assets/relative-link/ftps_text_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/http_schema.md (100%) rename {kordac => verto}/tests/assets/relative-link/http_schema_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/http_text.md (100%) rename {kordac => verto}/tests/assets/relative-link/http_text_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/https_schema.md (100%) rename {kordac => verto}/tests/assets/relative-link/https_schema_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/https_text.md (100%) rename {kordac => verto}/tests/assets/relative-link/https_text_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/long_path.md (100%) rename {kordac => verto}/tests/assets/relative-link/long_path_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/mailto_schema.md (100%) rename {kordac => verto}/tests/assets/relative-link/mailto_schema_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/mailto_text.md (100%) rename {kordac => verto}/tests/assets/relative-link/mailto_text_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/multiple_links.md (100%) rename {kordac => verto}/tests/assets/relative-link/multiple_links_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/news_schema.md (100%) rename {kordac => verto}/tests/assets/relative-link/news_schema_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/news_text.md (100%) rename {kordac => verto}/tests/assets/relative-link/news_text_expected.html (100%) rename {kordac => verto}/tests/assets/relative-link/www_text.md (100%) rename {kordac => verto}/tests/assets/relative-link/www_text_expected.html (100%) rename {kordac => verto}/tests/assets/remove-title/doc_example_basic_usage.md (100%) rename {kordac => verto}/tests/assets/remove-title/doc_example_basic_usage_expected.html (100%) rename {kordac => verto}/tests/assets/remove-title/level_two_heading.md (100%) rename {kordac => verto}/tests/assets/remove-title/level_two_heading_expected.html (100%) rename {kordac => verto}/tests/assets/remove-title/multiple_headings.md (100%) rename {kordac => verto}/tests/assets/remove-title/multiple_headings_expected.html (100%) rename {kordac => verto}/tests/assets/remove-title/multiple_level_one_headings.md (100%) rename {kordac => verto}/tests/assets/remove-title/multiple_level_one_headings_expected.html (100%) rename {kordac => verto}/tests/assets/remove-title/no_heading_permalink.md (100%) rename {kordac => verto}/tests/assets/remove-title/no_heading_permalink_expected.html (100%) rename {kordac => verto}/tests/assets/remove-title/no_headings.md (100%) rename {kordac => verto}/tests/assets/remove-title/no_headings_expected.html (100%) rename {kordac => verto}/tests/assets/remove-title/no_space_title.md (100%) rename {kordac => verto}/tests/assets/remove-title/no_space_title_expected.html (100%) rename {kordac => verto}/tests/assets/remove-title/processor_off.md (100%) rename {kordac => verto}/tests/assets/remove-title/processor_off_expected.html (100%) rename {kordac => verto}/tests/assets/save-title/doc_example_basic_usage.md (100%) rename {kordac => verto}/tests/assets/save-title/doc_example_basic_usage_expected.html (100%) rename {kordac => verto}/tests/assets/save-title/level_two_heading.md (100%) rename {kordac => verto}/tests/assets/save-title/level_two_heading_expected.html (100%) rename {kordac => verto}/tests/assets/save-title/multiple_headings.md (100%) rename {kordac => verto}/tests/assets/save-title/multiple_headings_expected.html (100%) rename {kordac => verto}/tests/assets/save-title/multiple_level_one_headings.md (100%) rename {kordac => verto}/tests/assets/save-title/multiple_level_one_headings_expected.html (100%) rename {kordac => verto}/tests/assets/save-title/no_heading_permalink.md (100%) rename {kordac => verto}/tests/assets/save-title/no_headings.md (100%) rename {kordac => verto}/tests/assets/save-title/no_space_title.md (100%) rename {kordac => verto}/tests/assets/save-title/no_space_title_expected.html (100%) rename {kordac => verto}/tests/assets/scratch/doc_example_basic_usage.md (100%) rename {kordac => verto}/tests/assets/scratch/doc_example_basic_usage_expected.html (100%) rename {kordac => verto}/tests/assets/scratch/doc_example_override_html.md (100%) rename {kordac => verto}/tests/assets/scratch/doc_example_override_html_expected.html (100%) rename {kordac => verto}/tests/assets/scratch/doc_example_override_html_template.html (100%) rename {kordac => verto}/tests/assets/scratch/example_multiple_codeblocks.md (100%) rename {kordac => verto}/tests/assets/scratch/example_multiple_codeblocks_2.md (100%) rename {kordac => verto}/tests/assets/scratch/example_multiple_codeblocks_expected.html (100%) rename {kordac => verto}/tests/assets/scratch/example_multiple_codeblocks_expected_2.html (100%) rename {kordac => verto}/tests/assets/scratch/example_other_code.md (100%) rename {kordac => verto}/tests/assets/scratch/example_other_code_expected.html (100%) rename {kordac => verto}/tests/assets/scratch/example_separate_blocks.md (100%) rename {kordac => verto}/tests/assets/scratch/example_separate_blocks_expected.html (100%) rename {kordac => verto}/tests/assets/scratch/example_standard_markdown_block.md (100%) rename {kordac => verto}/tests/assets/scratch/example_standard_markdown_block_expected.html (100%) rename {kordac => verto}/tests/assets/smoke/algorithms.md (100%) rename {kordac => verto}/tests/assets/smoke/introduction.md (100%) rename {kordac => verto}/tests/assets/table-of-contents/doc_example_basic_usage.md (100%) rename {kordac => verto}/tests/assets/table-of-contents/doc_example_basic_usage_expected.html (100%) rename {kordac => verto}/tests/assets/table-of-contents/doc_example_override_html.md (100%) rename {kordac => verto}/tests/assets/table-of-contents/doc_example_override_html_expected.html (100%) rename {kordac => verto}/tests/assets/table-of-contents/doc_example_override_html_template.html (100%) rename {kordac => verto}/tests/assets/video/contains_multiple_videos.md (100%) rename {kordac => verto}/tests/assets/video/contains_multiple_videos_expected.html (100%) rename {kordac => verto}/tests/assets/video/contains_no_video.md (100%) rename {kordac => verto}/tests/assets/video/contains_no_video_expected.html (100%) rename {kordac => verto}/tests/assets/video/contains_vimeo_video.md (100%) rename {kordac => verto}/tests/assets/video/contains_vimeo_video_expected.html (100%) rename {kordac => verto}/tests/assets/video/doc_example_basic_usage.md (100%) rename {kordac => verto}/tests/assets/video/doc_example_basic_usage_expected.html (100%) rename {kordac => verto}/tests/assets/video/doc_example_override_html.md (100%) rename {kordac => verto}/tests/assets/video/doc_example_override_html_expected.html (100%) rename {kordac => verto}/tests/assets/video/doc_example_override_html_template.html (100%) rename {kordac => verto}/tests/assets/video/doc_example_override_html_youtube_template.html (100%) rename {kordac => verto}/tests/assets/video/missing_identifier.md (100%) rename {kordac => verto}/tests/assets/video/multiple_vimeo_links.md (100%) rename {kordac => verto}/tests/assets/video/multiple_vimeo_links_expected.html (100%) rename {kordac => verto}/tests/assets/video/multiple_youtube_links.md (100%) rename {kordac => verto}/tests/assets/video/multiple_youtube_links_expected.html (100%) rename {kordac => verto}/tests/assets/video/unsupported_video_type.md (100%) rename {kordac => verto}/tests/assets/video/vimeo_link.md (100%) rename {kordac => verto}/tests/assets/video/vimeo_link_expected.html (100%) rename {kordac => verto}/tests/assets/video/vimeo_player_link.md (100%) rename {kordac => verto}/tests/assets/video/vimeo_player_link_expected.html (100%) rename {kordac => verto}/tests/assets/video/youtube_and_vimeo_links.md (100%) rename {kordac => verto}/tests/assets/video/youtube_and_vimeo_links_expected.html (100%) rename {kordac => verto}/tests/assets/video/youtube_be_link.md (100%) rename {kordac => verto}/tests/assets/video/youtube_be_link_expected.html (100%) rename {kordac => verto}/tests/assets/video/youtube_embed_link.md (100%) rename {kordac => verto}/tests/assets/video/youtube_embed_link_expected.html (100%) rename {kordac => verto}/tests/assets/video/youtube_watch_link.md (100%) rename {kordac => verto}/tests/assets/video/youtube_watch_link_expected.html (100%) rename {kordac => verto}/tests/start_tests.py (69%) rename {kordac => verto}/utils/HeadingNode.py (100%) rename {kordac => verto}/utils/UniqueSlugify.py (100%) rename {kordac => verto}/utils/__init__.py (100%) rename {kordac => verto}/utils/overrides.py (100%) diff --git a/.codeclimate.yml b/.codeclimate.yml index 0ad1cde3..0e14468e 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -27,4 +27,4 @@ ratings: paths: - "**.py" exclude_paths: -- "kordac/tests/*" +- "verto/tests/*" diff --git a/.flake8 b/.flake8 index 1cdb0993..29221de8 100644 --- a/.flake8 +++ b/.flake8 @@ -14,7 +14,7 @@ exclude = docs, # This contains tests that we don't want to check - kordac/tests, + verto/tests, show-source = True statistics = True diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 05c3ea76..7eac8f3c 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -12,7 +12,7 @@ Clearly and concisely describe the issue or suggestion here: *Change the space in the box to an `x` for those that apply. You can also fill these out after creating the issue.* -- [ ] I have linked any relevant [existing issues/suggestions](https://github.com/uccser/kordac/issues) in the description above (include `#???` in your description to reference an issue, where `???` is the issue number) +- [ ] I have linked any relevant [existing issues/suggestions](https://github.com/uccser/verto/issues) in the description above (include `#???` in your description to reference an issue, where `???` is the issue number) If this is a code related issue, please include the following in your description: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index aa44dc8b..3ca58488 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -13,7 +13,7 @@ Describe the big picture of your changes here to communicate to the maintainers *Change the space in the box to an `x` for those that apply. You can also fill these out after creating the pull request. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your change.* - [ ] I have read the [contribution guidelines](.github/CONTRIBUTING.md) -- [ ] I have linked any relevant [existing issues/suggestions](https://github.com/uccser/kordac/issues) in the description above (include `#???` in your description to reference an issue, where `???` is the issue number) +- [ ] I have linked any relevant [existing issues/suggestions](https://github.com/uccser/verto/issues) in the description above (include `#???` in your description to reference an issue, where `???` is the issue number) - [ ] I have run the test suite and all tests passed - [ ] I have added necessary documentation (if appropriate) diff --git a/.travis.yml b/.travis.yml index d49463fe..e4afa667 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ install: # Runs test suite script: - flake8 - - python -m kordac.tests.start_tests --travis + - python -m verto.tests.start_tests --travis # Stop email notifications but post to organisation Slack channel notifications: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9edb8f8d..612b6dad 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,10 +1,10 @@ # Contributing Guide -Welcome to the Kordac developer community! We have spent many months developing this project, and we would love for you to get involved! +Welcome to the Verto developer community! We have spent many months developing this project, and we would love for you to get involved! -We've written a technical guide about how Kordac works and how to contribute [here](kordac.readthedocs.io/en/develop/contributing.html). These docs should give you a good overview of how Kordac is pieced together. +We've written a technical guide about how Verto works and how to contribute [here](verto.readthedocs.io/en/develop/contributing.html). These docs should give you a good overview of how Verto is pieced together. -Below are a few more general notes to remember while you are working on Kordac. +Below are a few more general notes to remember while you are working on Verto. ### Code of Conduct @@ -14,14 +14,14 @@ Please report unacceptable behavior to [csse-education-research@canterbury.ac.nz ### Reporting issues -This section guides you through submitting an issue for Kordac. +This section guides you through submitting an issue for Verto. Following these guidelines helps maintainers and the community understand your findings. -Before submitting an issue, please take a look at the [issues](https://github.com/uccser/kordac/issues) on the repository to check it hasn't already been reported. +Before submitting an issue, please take a look at the [issues](https://github.com/uccser/verto/issues) on the repository to check it hasn't already been reported. ### Your first code contribution -Unsure where to begin contributing to Kordac? Take a look at the [issues](https://github.com/uccser/kordac/issues) on the repository. +Unsure where to begin contributing to Verto? Take a look at the [issues](https://github.com/uccser/verto/issues) on the repository. ### Pull requests @@ -30,7 +30,7 @@ Unsure where to begin contributing to Kordac? Take a look at the [issues](https: - Your pull request should be on a new branch from our `develop` branch (unless it's something tiny like a typo). The naming conventions of branches should be descriptive of the new addition/modification. Ideally they would specify their namespace as well, for example: - `processor/image` - `issue/234` -- Linked any relevant [existing issues](https://github.com/uccser/kordac/issues). +- Linked any relevant [existing issues](https://github.com/uccser/verto/issues). - Run the test suite and all tests passed - Added necessary documentation (if appropriate). diff --git a/MANIFEST.in b/MANIFEST.in index a001eff5..2f4ad2a1 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ include *.txt include *.md -recursive-include kordac *.html *.py *.png *.conf *.md *.json +recursive-include verto *.html *.py *.png *.conf *.md *.json diff --git a/README.rst b/README.rst index fcc8e2a0..72e86eec 100644 --- a/README.rst +++ b/README.rst @@ -1,23 +1,23 @@ -.. figure:: kordac/images/kordac-logo.png - :alt: Kordac Logo +.. figure:: verto/images/verto-logo.png + :alt: Verto Logo |Build Status| |Code Climate Status| -Kordac is an extension of the Python Markdown package, which allows +Verto is an extension of the Python Markdown package, which allows authors to include complex HTML elements with simple text tags in their Markdown files. Documentation ------------- -Installation and usage documentation for Kordac can be found on +Installation and usage documentation for Verto can be found on `ReadTheDocs`_, and can also be built from the documentation source within the ``docs/`` directory of the development distribution. License ------- -Kordac is licensed under the MIT License. Read the `license file`_ for +Verto is licensed under the MIT License. Read the `license file`_ for more details. Bugs and feature requests @@ -36,19 +36,19 @@ The changelog is available within the `documentation`_. **How do I install the development version as local package?** -1. ``$ git clone https://github.com/uccser/kordac.git`` -2. ``$ cd kordac`` +1. ``$ git clone https://github.com/uccser/verto.git`` +2. ``$ cd verto`` 3. ``$ pip3 install .`` -.. _ReadTheDocs: http://kordac.readthedocs.io/en/latest/ -.. _documentation: http://kordac.readthedocs.io/en/latest/changelog.html +.. _ReadTheDocs: http://verto.readthedocs.io/en/latest/ +.. _documentation: http://verto.readthedocs.io/en/latest/changelog.html .. _license file: LICENSE.md -.. _existing and closed issues: https://github.com/uccser/kordac/issues -.. _open a new issue: https://github.com/uccser/kordac/issues/new +.. _existing and closed issues: https://github.com/uccser/verto/issues +.. _open a new issue: https://github.com/uccser/verto/issues/new -.. |Build Status| image:: https://travis-ci.org/uccser/kordac.svg?branch=master - :target: https://travis-ci.org/uccser/kordac +.. |Build Status| image:: https://travis-ci.org/uccser/verto.svg?branch=master + :target: https://travis-ci.org/uccser/verto -.. |Code Climate Status| image:: https://codeclimate.com/github/uccser/kordac/badges/gpa.svg - :target: https://codeclimate.com/github/uccser/kordac +.. |Code Climate Status| image:: https://codeclimate.com/github/uccser/verto/badges/gpa.svg + :target: https://codeclimate.com/github/uccser/verto :alt: Code Climate diff --git a/docs/Makefile b/docs/Makefile index f2b92518..cd8ae93d 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -4,7 +4,7 @@ # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build -SPHINXPROJ = Kordac +SPHINXPROJ = Verto SOURCEDIR = source BUILDDIR = build diff --git a/docs/make.bat b/docs/make.bat index 3aab57a4..9df4a789 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -9,7 +9,7 @@ if "%SPHINXBUILD%" == "" ( ) set SOURCEDIR=source set BUILDDIR=build -set SPHINXPROJ=Kordac +set SPHINXPROJ=Verto if "%1" == "" goto help diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 67694181..8680c515 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -10,7 +10,7 @@ Fixes: 0.3.0 ======================================= -Third prerelease of the Kordac converter. +Third prerelease of the Verto converter. Adds support for the following processors: @@ -22,14 +22,14 @@ Adds support for the following processors: Fixes: - - Kordac now orders tags correctly in the markdown pipeline. - - System tests for multiple calls to Kordac and for multi-line templates. - - Glossary tags now correctly store slugs for the Kordac result as per documentation. + - Verto now orders tags correctly in the markdown pipeline. + - System tests for multiple calls to Verto and for multi-line templates. + - Glossary tags now correctly store slugs for the Verto result as per documentation. 0.2.0 ======================================= -Second prerelease of the Kordac converter. +Second prerelease of the Verto converter. Adds support for the following processors: @@ -42,7 +42,7 @@ Adds basic support for Code Climate. Fixes: -- Kordac default processors can be accessed via a static method. +- Verto default processors can be accessed via a static method. - Required and optional arguments are now explicitly matched against input. - Made tag parameters consistently use dashes as separators. - Tests for previous processors now explicitly test matches. @@ -52,7 +52,7 @@ Fixes: 0.1.0 ======================================= -Initial prerelease of Kordac converter. +Initial prerelease of Verto converter. Includes the following processors: diff --git a/docs/source/conf.py b/docs/source/conf.py index d285517e..c5779ff5 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# Kordac documentation build configuration file, created by +# Verto documentation build configuration file, created by # sphinx-quickstart on Mon Jan 30 17:06:19 2017. # # This file is execfile()d with the current directory set to its @@ -20,7 +20,7 @@ import os import sys sys.path.insert(0, os.path.abspath('../../')) -from kordac import __version__ +from verto import __version__ # -- General configuration ------------------------------------------------ @@ -47,7 +47,7 @@ master_doc = 'index' # General information about the project. -project = 'Kordac' +project = 'Verto' copyright = '2017 University of Canterbury Computer Science Education Research Group' author = 'Hayley vas Waas, Jack Morgan, Hayden Jackson, Jordan Griffiths' @@ -103,7 +103,7 @@ # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. -htmlhelp_basename = 'Kordacdoc' +htmlhelp_basename = 'Vertodoc' # -- Options for LaTeX output --------------------------------------------- @@ -130,7 +130,7 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'Kordac.tex', 'Kordac Documentation', + (master_doc, 'Verto.tex', 'Verto Documentation', 'Hayley vas Waas, Jack Morgan', 'manual'), ] @@ -140,7 +140,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'kordac', 'Kordac Documentation', + (master_doc, 'verto', 'Verto Documentation', [author], 1) ] @@ -151,7 +151,7 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'Kordac', 'Kordac Documentation', - author, 'Kordac', 'One line description of project.', + (master_doc, 'Verto', 'Verto Documentation', + author, 'Verto', 'One line description of project.', 'Miscellaneous'), ] diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 0a9f3702..b84a14ca 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -1,15 +1,15 @@ -Contributing to Kordac +Contributing to Verto ####################################### -Welcome to the Kordac developer community! We have spent many months developing this project, and we would love for you to get involved! The following documentation has been written to help you get a grasp on how Kordac is pieced together to make contributing as simple and straight forward as possible. Please feel free to fix bugs and/or suggest new features and improvements to the system (or the docs) by making a pull request. +Welcome to the Verto developer community! We have spent many months developing this project, and we would love for you to get involved! The following documentation has been written to help you get a grasp on how Verto is pieced together to make contributing as simple and straight forward as possible. Please feel free to fix bugs and/or suggest new features and improvements to the system (or the docs) by making a pull request. -Kordac was created to be used by two much larger projects (the `CS Unplugged`_ and `CS Field Guide`_ websites) as the markdown-to-html converter. The tags we chose are designed to allow authors of these two projects to easily write material without technical elements getting in the way. It is therefore important to us that Kordac remains as simple and robust as possible, please keep this in mind if you decide to work on Kordac with us. +Verto was created to be used by two much larger projects (the `CS Unplugged`_ and `CS Field Guide`_ websites) as the markdown-to-html converter. The tags we chose are designed to allow authors of these two projects to easily write material without technical elements getting in the way. It is therefore important to us that Verto remains as simple and robust as possible, please keep this in mind if you decide to work on Verto with us. -The git repository for Kordac can be found `here`_, jump in and take a look around! +The git repository for Verto can be found `here`_, jump in and take a look around! .. note:: - The two projects that Kordac was developed for are Django projects, so you may come across HTML (in templates, test cases etc) that contains Django syntax. + The two projects that Verto was developed for are Django projects, so you may come across HTML (in templates, test cases etc) that contains Django syntax. For example, below is the expected output for a for a image tag test: @@ -19,13 +19,13 @@ The git repository for Kordac can be found `here`_, jump in and take a look arou Lipsum
    - This does not mean that Kordac is only suitable for Django projects, as it's just a matter of customising the relevant HTMl templates. + This does not mean that Verto is only suitable for Django projects, as it's just a matter of customising the relevant HTMl templates. Issue Reporting and Bug Fixes ======================================= -If you come across a bug in Kordac, please `report it on the repo issue tracker`_. +If you come across a bug in Verto, please `report it on the repo issue tracker`_. If you choose to fix the bug for us, consider adding the relevant tests to the Test Suite (detailed further down this page) to help us catch any future bugs. @@ -33,23 +33,23 @@ If you choose to fix the bug for us, consider adding the relevant tests to the T The Code Base ======================================= -If you would like to contribute to Kordac, `create a fork of the repository`_. +If you would like to contribute to Verto, `create a fork of the repository`_. Overview ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Before reading this section, make sure you have read :doc:`how to use ` (or even better, have already used Kordac!). +Before reading this section, make sure you have read :doc:`how to use ` (or even better, have already used Verto!). Terminology *************************************** -There are a couple of terms we use when describing Kordac to become familiar with: +There are a couple of terms we use when describing Verto to become familiar with: - **Tag** - This refers to the custom markdown syntax that Kordac processes. + This refers to the custom markdown syntax that Verto processes. For example: @@ -59,7 +59,7 @@ There are a couple of terms we use when describing Kordac to become familiar wit {image file-path="img/totally-real-image.png" alt="process me"} - are examples of the ``comment`` and ``image`` tags in Kordac. + are examples of the ``comment`` and ``image`` tags in Verto. - **Processor** @@ -74,10 +74,10 @@ Below is a basic overview of the project structure: .. code-block:: none ├── docs/ - ├── kordac/ + ├── verto/ │   ├── html-templates/ - │   ├── KordacExtension.py - │   ├── Kordac.py + │   ├── VertoExtension.py + │   ├── Verto.py │   ├── processor-info.json │   ├── processors/ │   │   └── errors/ @@ -88,10 +88,10 @@ Below is a basic overview of the project structure: The items of interest are: -- ``Kordac()`` - The convertor object itself. This is what a user will use to create a Kordac converter, and what is used to define a custom processor list, custom html templates and custom Markdown Extensions to use. +- ``Verto()`` - The convertor object itself. This is what a user will use to create a Verto converter, and what is used to define a custom processor list, custom html templates and custom Markdown Extensions to use. -- ``KordacResult()`` (found in ``Kordac.py``) - The object returned by ``Kordac()`` containing: +- ``VertoResult()`` (found in ``Verto.py``) - The object returned by ``Verto()`` containing: - Converted html string - Title @@ -100,7 +100,7 @@ The items of interest are: - Required glossary terms -- ``KordacExtension()`` - This is the main class of the project, and inherits the ``Extension`` class from Markdown. It loads all of the processor information, loads the template files and clears and populates the attributes to be returned by the ``KordacResult`` object. +- ``VertoExtension()`` - This is the main class of the project, and inherits the ``Extension`` class from Markdown. It loads all of the processor information, loads the template files and clears and populates the attributes to be returned by the ``VertoResult`` object. - ``Processors/`` - There is a different processor for each tag. A processor uses it's corresponding description loaded from ``processor-info.json`` to find matches in the text, and uses the given arguments in the matched tag to populate and output it's html template. @@ -111,7 +111,7 @@ The items of interest are: - ``tests/`` - explained in the Test Suite section further down the page. -It is important to note that Kordac is not just a Markdown Extension, it is a wrapper for Python Markdown. ``KordacExtension`` **is** an extension for Python Markdown. We have created a wrapper because we wanted to not only convert text, but also extract information from the text as it was being converted (recall ``KordacResult()`` listed above). +It is important to note that Verto is not just a Markdown Extension, it is a wrapper for Python Markdown. ``VertoExtension`` **is** an extension for Python Markdown. We have created a wrapper because we wanted to not only convert text, but also extract information from the text as it was being converted (recall ``VertoResult()`` listed above). Creating a New Processor @@ -130,7 +130,7 @@ In all cases new processors should: - Examples - Examples of overriding the html -We recommend writing documentation and test cases before you even write the processor itself as this will give you a clear idea of how a processor in Kordac should behave. +We recommend writing documentation and test cases before you even write the processor itself as this will give you a clear idea of how a processor in Verto should behave. Generic Processors ************************************** @@ -215,17 +215,17 @@ A generic tag processor, is a simple single line tag that uses the given argumen And has the following html-template: -.. literalinclude:: ../../kordac/html-templates/button-link.html +.. literalinclude:: ../../verto/html-templates/button-link.html :language: css+jinja This enables the following markdown: -.. literalinclude:: ../../kordac/tests/assets/button-link/doc_example_basic_usage.md +.. literalinclude:: ../../verto/tests/assets/button-link/doc_example_basic_usage.md :language: none To generate the output: -.. literalinclude:: ../../kordac/tests/assets/button-link/doc_example_basic_usage_expected.html +.. literalinclude:: ../../verto/tests/assets/button-link/doc_example_basic_usage_expected.html :language: html A generic container processor, a pair of matching tags where one opens the container and one closes the container. The start tag gives the arguments as parameters to an html template. The end tag is used to capture the content between the tags to be used as an additional parameter to the html template. An example of a processor that uses the generic container processor is the :ref:`boxed-text ` processor which is described in the json as: @@ -255,17 +255,17 @@ A generic container processor, a pair of matching tags where one opens the conta And has the following html-template: -.. literalinclude:: ../../kordac/html-templates/boxed-text.html +.. literalinclude:: ../../verto/html-templates/boxed-text.html :language: css+jinja This enables the following markdown: -.. literalinclude:: ../../kordac/tests/assets/boxed-text/doc_example_basic_usage.md +.. literalinclude:: ../../verto/tests/assets/boxed-text/doc_example_basic_usage.md :language: none To generate the output: -.. literalinclude:: ../../kordac/tests/assets/boxed-text/doc_example_basic_usage_expected.html +.. literalinclude:: ../../verto/tests/assets/boxed-text/doc_example_basic_usage_expected.html :language: html Custom Processors @@ -273,17 +273,17 @@ Custom Processors To create a custom processor, the ``class`` attribute of the processor in the ``processor-info.json`` file must be ``"custom"``. A good place to start when programming a new processor is the `Extension API`_ page of the Python Markdown docs, and you can also read the `source code`_ itself. -There are several different kinds of processors in Python Markdown, each serving a slightly different purpose. We recommend reading the API docs to determine which processor best suits your purpose. Kordac currently makes use of ``preprocessor``, ``blockprocessor``, ``inlinepattern``, ``treeprocessor`` and ``postprocessor``, but you are welcome to use another type of processor if it better suits the task. +There are several different kinds of processors in Python Markdown, each serving a slightly different purpose. We recommend reading the API docs to determine which processor best suits your purpose. Verto currently makes use of ``preprocessor``, ``blockprocessor``, ``inlinepattern``, ``treeprocessor`` and ``postprocessor``, but you are welcome to use another type of processor if it better suits the task. -The order of the processors matters and is defined when each processor is added to the ``OrderedDict`` in ``KordacExtension.py``. +The order of the processors matters and is defined when each processor is added to the ``OrderedDict`` in ``VertoExtension.py``. Each processor should try to be as independent of every other processor as possible. Sometimes this is not possible, and in this case compatibility should occur in the processor that happens last (i.e. the downstream processor). That is output should be consistent based on input, not the other way round (e.g. ``codehilite`` and ``fenced_code``). The logic for each processor belongs in the ``processors/`` directory, and there are several other places where processors details need to be listed. These are: - The processor's relevant information (regex pattern, required parameters etc) should be included in ``processor-info.json`` -- If it should be a default processor, it should be added to the frozenset of ``DEFAULT_PROCESSORS`` in ``Kordac.py`` -- The relevant list in ``extendMarkdown()`` in ``KordacExtension.py`` (see `OrderedDict in the Markdown API docs`_ for manipulating processor order) +- If it should be a default processor, it should be added to the frozenset of ``DEFAULT_PROCESSORS`` in ``Verto.py`` +- The relevant list in ``extendMarkdown()`` in ``VertoExtension.py`` (see `OrderedDict in the Markdown API docs`_ for manipulating processor order) - The processor's template should be added to ``html-templates`` using the Jinja2 template engine syntax for variable parameters .. _the-test-suite: @@ -295,7 +295,7 @@ To start the test suite: .. code-block:: bash - $ python3 -m kordac.tests.start_tests + $ python3 -m verto.tests.start_tests This will execute the Smoke, System and then Unit tests. @@ -308,7 +308,7 @@ We are now focusing on our project structure diagram from earlier: .. code-block:: none - └── kordac/ + └── verto/ └── tests/ ├── assets/ ├── BaseTest.py @@ -321,7 +321,7 @@ The items of interest are: - ``BaseTest())`` - This class is inherited by nearly every other test file, and contains a method to read a given test asset file. -- ``ConfigurationTest()`` - This is the test class for testing different configurations of ``Kordac()`` (e.g. using a custom list of processors and/or custom html templates). This class inherits the ``BaseTest`` class. +- ``ConfigurationTest()`` - This is the test class for testing different configurations of ``Verto()`` (e.g. using a custom list of processors and/or custom html templates). This class inherits the ``BaseTest`` class. - ``ProcessorTest.py`` - This is the class inherited by all processor test classes. It contains several useful methods for testing processors, including those for loading templates and processor info. @@ -337,7 +337,7 @@ Adding Tests When writing a new test function, it is important that the method name is as descriptive as possible. The method name should also be prefixed with ``test_`` as the test suite will only execute methods with this prefix. -If you have added a new processor to ``Kordac``, then a corresponding test suite also needs to be added. This test suite should be added to the ``unit_suite()`` function in ``start_tests.py``. The section below has details on how to write a processor test. +If you have added a new processor to ``Verto``, then a corresponding test suite also needs to be added. This test suite should be added to the ``unit_suite()`` function in ``start_tests.py``. The section below has details on how to write a processor test. Processor Tests @@ -349,7 +349,7 @@ A test method will typically follow the same sequence of steps: 1. Retrieve the test string (there is a ``read_test_file()`` method provided by the ``ProcessorTest`` class) 2. Confirm there are (not) matches to the regex in the test string -3. Convert the test string using the ``kordac_extension`` (provided by the ``SetUp()`` method in ``ProcessorTest``) +3. Convert the test string using the ``verto_extension`` (provided by the ``SetUp()`` method in ``ProcessorTest``) 4. Load the expected converted result 5. Check the converted result is the same as the expected result @@ -359,14 +359,14 @@ Testing Assets Most tests will load an asset file. This file contains example Markdown text (and therefore has a ``.md`` extension). For comparing the converted result of this Markdown file with it's expected output, a corresponding "expected" file should be created. The expected file should have the same name as the corresponding test file, with ``expected`` appended to the file name (and has a ``.html`` extension). -These asset files should be placed in ``kordac/tests/assets//``. +These asset files should be placed in ``verto/tests/assets//``. For example: .. code-block:: none - kordac/tests/assets/boxed-text/no_boxed_text.md - kordac/tests/assets/boxed-text/no_boxed_text_expected.html + verto/tests/assets/boxed-text/no_boxed_text.md + verto/tests/assets/boxed-text/no_boxed_text_expected.html .. note:: - Asset files should have discriptive names, and in many cases will have the same name as the method they are used in. @@ -374,24 +374,24 @@ For example: Creating a release ======================================= -This is our current process for creating and publishing a Kordac release. This +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. -2. Update the version number [1]_ within ``kordac/__init__.py``. +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. 6. Create the release on `GitHub`_ on the tagged commit. -7. Upload a new version of Kordac to PyPI. +7. Upload a new version of Verto to PyPI. -.. [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 Kordac it was built from. +.. [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/kordac -.. _report it on the repo issue tracker: https://github.com/uccser/kordac/issues +.. _here: https://github.com/uccser/verto +.. _report it on the repo issue tracker: https://github.com/uccser/verto/issues .. _create a fork of the repository: https://help.github.com/articles/fork-a-repo/ .. _Extension API: https://pythonhosted.org/Markdown/extensions/api.html .. _source code: https://github.com/waylan/Python-Markdown @@ -399,4 +399,4 @@ can only be performed by repository administrators .. _Create a release branch: http://nvie.com/posts/a-successful-git-branching-model/#creating-a-release-branch .. _log an issue: https://github.com/uccser/cs-field-guide/issues/new .. _Complete the release branch: http://nvie.com/posts/a-successful-git-branching-model/#finishing-a-release-branch -.. _GitHub: https://github.com/uccser/kordac/releases/ +.. _GitHub: https://github.com/uccser/verto/releases/ diff --git a/docs/source/extensions.rst b/docs/source/extensions.rst index 08cbe8ae..a2ae7c9a 100644 --- a/docs/source/extensions.rst +++ b/docs/source/extensions.rst @@ -1,10 +1,10 @@ Extensions ####################################### -As Kordac is an extension of the Python Markdown package, you should be able to include any extension for the original package. -This page details using extensions with Kordac, plus listing a few useful extensions that we recommend. +As Verto is an extension of the Python Markdown package, you should be able to include any extension for the original package. +This page details using extensions with Verto, plus listing a few useful extensions that we recommend. -To include a package, pass a list of extensions to the ``extensions`` keyword when creating the Kordac object. For example: +To include a package, pass a list of extensions to the ``extensions`` keyword when creating the Verto object. For example: .. code-block:: python @@ -14,14 +14,14 @@ To include a package, pass a list of extensions to the ``extensions`` keyword wh 'markdown.extensions.sane_lists', mdx_math.MathExtension(enable_dollar_delimiter=True) ] - converter = Kordac(extensions=extra_extensions) + converter = Verto(extensions=extra_extensions) A list of extensions for the Markdown package can be found `in their official documentation `_. Math ======================================= -Math can be rendered by including the `Python Markdown Math `_ package, and passing it through to Kordac as an extension to use. +Math can be rendered by including the `Python Markdown Math `_ package, and passing it through to Verto as an extension to use. A guide on how to install and use the extension can be found in the package's `README file `_. Fenced Code diff --git a/docs/source/index.rst b/docs/source/index.rst index f3d5904b..85c0536a 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,14 +1,14 @@ -Welcome to Kordac +Welcome to Verto ################# -Kordac is an extension of the Python `Markdown `_ package, which allows authors to include complex HTML elements with simple text tags in their Markdown files. +Verto is an extension of the Python `Markdown `_ package, which allows authors to include complex HTML elements with simple text tags in their Markdown files. For example: .. code-block:: python - >>> import kordac - >>> converter = kordac.Kordac() + >>> import verto + >>> converter = verto.Verto() >>> result = converter.convert('{video url="https://www.youtube.com/watch?v=dQw4w9WgXcQ"}') >>> result.html_string "" diff --git a/docs/source/install.rst b/docs/source/install.rst index 3dcd8bfd..65e05b95 100644 --- a/docs/source/install.rst +++ b/docs/source/install.rst @@ -1,12 +1,12 @@ -Installing Kordac +Installing Verto ####################################### -Currently Kordac is only able to be installed locally. +Currently Verto is only able to be installed locally. -The following commands in Terminal will download and install Kordac ready for use: +The following commands in Terminal will download and install Verto ready for use: .. code-block:: none - $ git clone https://github.com/uccser/kordac.git - $ cd kordac + $ git clone https://github.com/uccser/verto.git + $ cd verto $ pip3 install . diff --git a/docs/source/processors/boxed-text.rst b/docs/source/processors/boxed-text.rst index 1730b207..ec0620c4 100644 --- a/docs/source/processors/boxed-text.rst +++ b/docs/source/processors/boxed-text.rst @@ -7,7 +7,7 @@ Boxed Text You can enclose text inside of a box using the following text tag: -.. literalinclude:: ../../../kordac/tests/assets/boxed-text/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/boxed-text/doc_example_basic_usage.md :language: none Optional Tag Parameters @@ -17,12 +17,12 @@ Optional Tag Parameters The default HTML for button links is: -.. literalinclude:: ../../../kordac/html-templates/boxed-text.html +.. literalinclude:: ../../../verto/html-templates/boxed-text.html :language: css+jinja Using the example tag above, the resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/boxed-text/doc_example_basic_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/boxed-text/doc_example_basic_usage_expected.html :language: html Overriding HTML for Boxed Text @@ -37,15 +37,15 @@ When overriding the HTML for boxed text, the following Jinja2 placeholders are a For example, providing the following HTML: -.. literalinclude:: ../../../kordac/tests/assets/boxed-text/doc_example_override_html_template.html +.. literalinclude:: ../../../verto/tests/assets/boxed-text/doc_example_override_html_template.html :language: css+jinja with the following tag: -.. literalinclude:: ../../../kordac/tests/assets/boxed-text/doc_example_override_html.md +.. literalinclude:: ../../../verto/tests/assets/boxed-text/doc_example_override_html.md :language: none would result in: -.. literalinclude:: ../../../kordac/tests/assets/boxed-text/doc_example_override_html_expected.html +.. literalinclude:: ../../../verto/tests/assets/boxed-text/doc_example_override_html_expected.html :language: html diff --git a/docs/source/processors/button-link.rst b/docs/source/processors/button-link.rst index 6365858b..7243b517 100644 --- a/docs/source/processors/button-link.rst +++ b/docs/source/processors/button-link.rst @@ -7,7 +7,7 @@ Button Link You can create a link on a button using the following text tag: -.. literalinclude:: ../../../kordac/tests/assets/button-link/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/button-link/doc_example_basic_usage.md :language: none Required Tag Parameters @@ -28,31 +28,31 @@ Optional Tag Parameters The default HTML for button links is: -.. literalinclude:: ../../../kordac/html-templates/button-link.html +.. literalinclude:: ../../../verto/html-templates/button-link.html :language: css+jinja **Example 1** Using the following tag: -.. literalinclude:: ../../../kordac/tests/assets/button-link/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/button-link/doc_example_basic_usage.md :language: none The resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/button-link/doc_example_basic_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/button-link/doc_example_basic_usage_expected.html :language: html **Example 2** Using the following tag: -.. literalinclude:: ../../../kordac/tests/assets/button-link/doc_example_file_usage.md +.. literalinclude:: ../../../verto/tests/assets/button-link/doc_example_file_usage.md :language: none The resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/button-link/doc_example_file_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/button-link/doc_example_file_usage_expected.html :language: css+jinja Overriding HTML for Button Link @@ -65,22 +65,22 @@ When overriding the HTML for button links, the following Jinja2 placeholders are If the ``file`` parameter is set to ``yes``, the link is passed through the ``relative-image-link.html`` template. The default HTML for relative images is: -.. literalinclude:: ../../../kordac/html-templates/relative-file-link.html +.. literalinclude:: ../../../verto/html-templates/relative-file-link.html :language: css+jinja **Example** For example, providing the following HTML: -.. literalinclude:: ../../../kordac/tests/assets/button-link/doc_example_override_html_template.html +.. literalinclude:: ../../../verto/tests/assets/button-link/doc_example_override_html_template.html :language: css+jinja with the following tag: -.. literalinclude:: ../../../kordac/tests/assets/button-link/doc_example_override_html.md +.. literalinclude:: ../../../verto/tests/assets/button-link/doc_example_override_html.md :language: none would result in: -.. literalinclude:: ../../../kordac/tests/assets/button-link/doc_example_override_html_expected.html +.. literalinclude:: ../../../verto/tests/assets/button-link/doc_example_override_html_expected.html :language: html diff --git a/docs/source/processors/comment.rst b/docs/source/processors/comment.rst index 4bc2a94a..b3bc9290 100644 --- a/docs/source/processors/comment.rst +++ b/docs/source/processors/comment.rst @@ -5,7 +5,7 @@ Comment You can include comments in the source text that are deleted before conversion: -.. literalinclude:: ../../../kordac/tests/assets/comment/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/comment/doc_example_basic_usage.md :language: none Comment tags have no parameters or HTML templates associated with them. @@ -14,10 +14,10 @@ Comment tags have no parameters or HTML templates associated with them. The following text: -.. literalinclude:: ../../../kordac/tests/assets/comment/doc_example_multiple_usage.md +.. literalinclude:: ../../../verto/tests/assets/comment/doc_example_multiple_usage.md :language: none -would result in (after Kordac has finished conversion): +would result in (after Verto has finished conversion): -.. literalinclude:: ../../../kordac/tests/assets/comment/doc_example_multiple_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/comment/doc_example_multiple_usage_expected.html :language: html diff --git a/docs/source/processors/conditional.rst b/docs/source/processors/conditional.rst index 49a6218e..d7ac94d1 100644 --- a/docs/source/processors/conditional.rst +++ b/docs/source/processors/conditional.rst @@ -5,7 +5,7 @@ Conditional You can include an conditional using the following text tag: -.. literalinclude:: ../../../kordac/tests/assets/conditional/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/conditional/doc_example_basic_usage.md :language: none .. note:: @@ -48,24 +48,24 @@ To create a set of conditional text tags, follow the following steps: Here is a more complicated example: -.. literalinclude:: ../../../kordac/tests/assets/conditional/doc_example_complex_usage.md +.. literalinclude:: ../../../verto/tests/assets/conditional/doc_example_complex_usage.md :language: none **Example** The default HTML for a conditional is: -.. literalinclude:: ../../../kordac/html-templates/conditional.html +.. literalinclude:: ../../../verto/html-templates/conditional.html :language: css+jinja Using the following example tag: -.. literalinclude:: ../../../kordac/tests/assets/conditional/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/conditional/doc_example_basic_usage.md :language: none The resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/conditional/doc_example_basic_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/conditional/doc_example_basic_usage_expected.html :language: html Overriding HTML for Conditional @@ -83,15 +83,15 @@ When overriding the HTML for conditionals, the following Jinja2 placeholders are For example, if you wanted to output a mako template you would providing the following HTML: -.. literalinclude:: ../../../kordac/tests/assets/conditional/doc_example_override_html_template.html +.. literalinclude:: ../../../verto/tests/assets/conditional/doc_example_override_html_template.html :language: css+jinja with the following tag: -.. literalinclude:: ../../../kordac/tests/assets/conditional/doc_example_override_html.md +.. literalinclude:: ../../../verto/tests/assets/conditional/doc_example_override_html.md :language: none would result in: -.. literalinclude:: ../../../kordac/tests/assets/conditional/doc_example_override_html_expected.html +.. literalinclude:: ../../../verto/tests/assets/conditional/doc_example_override_html_expected.html :language: html diff --git a/docs/source/processors/glossary-link.rst b/docs/source/processors/glossary-link.rst index a3486816..654c210f 100644 --- a/docs/source/processors/glossary-link.rst +++ b/docs/source/processors/glossary-link.rst @@ -5,7 +5,7 @@ Glossary Link You can include a link to a glossary term using the following text tag: -.. literalinclude:: ../../../kordac/tests/assets/glossary-link/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/glossary-link/doc_example_basic_usage.md :language: none .. note:: @@ -17,7 +17,7 @@ Required Tag Parameters - ``term`` - The slug of the term to link to in the glossary (for example ``binary-search``). - - Each term encountered is added to the required glossary terms stored by Kordac. The set of terms can be accessed after conversion, see :ref:`accessing_kordac_data`. + - Each term encountered is added to the required glossary terms stored by Verto. The set of terms can be accessed after conversion, see :ref:`accessing_verto_data`. - When using the default HTML template, the term is stored in a `data attribute`_ named ``data-glossary-term``. Optional Tag Parameters @@ -27,11 +27,11 @@ Optional Tag Parameters - If back reference text is included, then an ID should be generated for the link. Currently the ID is generated as ``glossary-`` + the term slug. If successive back links for the same term are found then an incrementing number is appended to the generated ID. - The back reference text and ID are stored in the required glossary terms, and can be accessed after conversion, see :ref:`accessing_kordac_data`. + The back reference text and ID are stored in the required glossary terms, and can be accessed after conversion, see :ref:`accessing_verto_data`. .. warning:: - The IDs generated assume no other Kordac generated HTML is included on the same page. If two (or more) separate conversions of Markdown by Kordac are displayed on the same page, there may be ID conflicts. + The IDs generated assume no other Verto generated HTML is included on the same page. If two (or more) separate conversions of Markdown by Verto are displayed on the same page, there may be ID conflicts. .. note:: @@ -39,29 +39,29 @@ Optional Tag Parameters The default HTML for glossary links is: -.. literalinclude:: ../../../kordac/html-templates/glossary-link.html +.. literalinclude:: ../../../verto/html-templates/glossary-link.html :language: css+jinja Using the following example tag: -.. literalinclude:: ../../../kordac/tests/assets/glossary-link/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/glossary-link/doc_example_basic_usage.md :language: none The resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/glossary-link/doc_example_basic_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/glossary-link/doc_example_basic_usage_expected.html :language: html Possible Glossary Usage with Django *************************************** -While Kordac will generate links for glossary terms from the HTML template, these links will not work by themselves. +While Verto will generate links for glossary terms from the HTML template, these links will not work by themselves. The expected usage is to display the links on a webpage and when a user clicks a link, a JavaScript handler will catch the click. The handler can view the term in the ``data-glossary-term`` attribute and send a request to a database to retrieve the term's definition and associated data. The handler can then display this information via popup/modal/etc once it recieves the data. -Kordac also provides the back reference text and ID for terms in the required glossary terms which can be accessed after conversion (see :ref:`accessing_kordac_data`). +Verto also provides the back reference text and ID for terms in the required glossary terms which can be accessed after conversion (see :ref:`accessing_verto_data`). This data can be added to the database before the web server is run for displaying to users. Overriding HTML for Glossary Links @@ -79,17 +79,17 @@ For example, we wish to create glossary links that link to a static glossary pag By providing the following HTML: -.. literalinclude:: ../../../kordac/tests/assets/glossary-link/doc_example_override_html_template.html +.. literalinclude:: ../../../verto/tests/assets/glossary-link/doc_example_override_html_template.html :language: css+jinja with the following tag: -.. literalinclude:: ../../../kordac/tests/assets/glossary-link/doc_example_override_html.md +.. literalinclude:: ../../../verto/tests/assets/glossary-link/doc_example_override_html.md :language: none would result in: -.. literalinclude:: ../../../kordac/tests/assets/glossary-link/doc_example_override_html_expected.html +.. literalinclude:: ../../../verto/tests/assets/glossary-link/doc_example_override_html_expected.html :language: html .. _data attribute: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-* diff --git a/docs/source/processors/heading.rst b/docs/source/processors/heading.rst index 6389d254..d2ec5301 100644 --- a/docs/source/processors/heading.rst +++ b/docs/source/processors/heading.rst @@ -12,24 +12,24 @@ This processor an ID to each heading which allows for linking to a heading, and You may create a heading by using the following format: -.. literalinclude:: ../../../kordac/tests/assets/heading/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/heading/doc_example_basic_usage.md :language: none The default HTML for headings is: -.. literalinclude:: ../../../kordac/html-templates/heading.html +.. literalinclude:: ../../../verto/html-templates/heading.html :language: css+jinja **Example** Using the following tag: -.. literalinclude:: ../../../kordac/tests/assets/heading/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/heading/doc_example_basic_usage.md :language: none The resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/heading/doc_example_basic_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/heading/doc_example_basic_usage_expected.html :language: html @@ -55,15 +55,15 @@ The ``level`` parameters are useful for generating levels trails so that users k For example, providing the following HTML: -.. literalinclude:: ../../../kordac/tests/assets/heading/doc_example_override_html_template.html +.. literalinclude:: ../../../verto/tests/assets/heading/doc_example_override_html_template.html :language: css+jinja with the following markdown: -.. literalinclude:: ../../../kordac/tests/assets/heading/doc_example_override_html.md +.. literalinclude:: ../../../verto/tests/assets/heading/doc_example_override_html.md :language: none would result in: -.. literalinclude:: ../../../kordac/tests/assets/heading/doc_example_override_html_expected.html +.. literalinclude:: ../../../verto/tests/assets/heading/doc_example_override_html_expected.html :language: html diff --git a/docs/source/processors/iframe.rst b/docs/source/processors/iframe.rst index f781225e..96a1ab22 100644 --- a/docs/source/processors/iframe.rst +++ b/docs/source/processors/iframe.rst @@ -5,7 +5,7 @@ Embed iframe You can embed a link within an ``iframe`` using the following text tag: -.. literalinclude:: ../../../kordac/tests/assets/iframe/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/iframe/doc_example_basic_usage.md :language: none Required Tag Parameters @@ -15,19 +15,19 @@ Required Tag Parameters The default HTML for iframe is: -.. literalinclude:: ../../../kordac/html-templates/iframe.html +.. literalinclude:: ../../../verto/html-templates/iframe.html :language: css+jinja **Example** Using the following tag: -.. literalinclude:: ../../../kordac/tests/assets/iframe/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/iframe/doc_example_basic_usage.md :language: none The resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/iframe/doc_example_basic_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/iframe/doc_example_basic_usage_expected.html :language: html Overriding HTML for Emedding iframes @@ -41,15 +41,15 @@ When overriding the HTML for iframes, the following Jinja2 placeholders are avai For example, providing the following HTML: -.. literalinclude:: ../../../kordac/tests/assets/iframe/doc_example_override_html_template.html +.. literalinclude:: ../../../verto/tests/assets/iframe/doc_example_override_html_template.html :language: css+jinja with the following tag: -.. literalinclude:: ../../../kordac/tests/assets/iframe/doc_example_override_html.md +.. literalinclude:: ../../../verto/tests/assets/iframe/doc_example_override_html.md :language: none would result in: -.. literalinclude:: ../../../kordac/tests/assets/iframe/doc_example_override_html_expected.html +.. literalinclude:: ../../../verto/tests/assets/iframe/doc_example_override_html_expected.html :language: html diff --git a/docs/source/processors/image.rst b/docs/source/processors/image.rst index ade5046f..560de5a5 100644 --- a/docs/source/processors/image.rst +++ b/docs/source/processors/image.rst @@ -14,7 +14,7 @@ Required Tag Parameters - ``file-path`` - The path to the image. - - Each file-path provided is added to the ``images`` set in required files stored by Kordac. The set of filepaths can be accessed after conversion, see :ref:`accessing_kordac_data`. + - Each file-path provided is added to the ``images`` set in required files stored by Verto. The set of filepaths can be accessed after conversion, see :ref:`accessing_verto_data`. - **Note:** If the given link is a relative (a link that doesn't start with ``http:``), the link will be rendered with a Django static command. For example, the link ``images/example.png`` would be rendered as ``{% static 'images/example.png' %}`` This can be overriden, see the override section below. Optional Tag Parameters @@ -29,17 +29,17 @@ Optional Tag Parameters The default HTML for image is: -.. literalinclude:: ../../../kordac/html-templates/image.html +.. literalinclude:: ../../../verto/html-templates/image.html :language: css+jinja Using the following example tag: -.. literalinclude:: ../../../kordac/tests/assets/image/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/image/doc_example_basic_usage.md :language: none The resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/image/doc_example_basic_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/image/doc_example_basic_usage_expected.html :language: html Overriding HTML for Images @@ -58,24 +58,24 @@ When overriding the HTML for images, the following Jinja2 placeholders are avail If the ``file_path`` provided is an relative link, the link is passed through the ``relative-image-link.html`` template. The default HTML for relative images is: -.. literalinclude:: ../../../kordac/html-templates/relative-file-link.html +.. literalinclude:: ../../../verto/html-templates/relative-file-link.html :language: css+jinja **Example 1** For example, providing the following HTML: -.. literalinclude:: ../../../kordac/tests/assets/image/doc_example_override_html_template.html +.. literalinclude:: ../../../verto/tests/assets/image/doc_example_override_html_template.html :language: css+jinja with the following tag: -.. literalinclude:: ../../../kordac/tests/assets/image/doc_example_override_html.md +.. literalinclude:: ../../../verto/tests/assets/image/doc_example_override_html.md :language: none would result in: -.. literalinclude:: ../../../kordac/tests/assets/image/doc_example_override_html_expected.html +.. literalinclude:: ../../../verto/tests/assets/image/doc_example_override_html_expected.html :language: html **Example 2** @@ -84,20 +84,20 @@ If you know all relative images are located within a specific folder, you could For example, providing the following HTML for ``image.html``: -.. literalinclude:: ../../../kordac/tests/assets/image/doc_example_2_override_html_template.html +.. literalinclude:: ../../../verto/tests/assets/image/doc_example_2_override_html_template.html :language: css+jinja and providing the following HTML for ``relative-file-link.html``: -.. literalinclude:: ../../../kordac/tests/assets/image/doc_example_2_override_link_html_template.html +.. literalinclude:: ../../../verto/tests/assets/image/doc_example_2_override_link_html_template.html :language: css+jinja with the following tag: -.. literalinclude:: ../../../kordac/tests/assets/image/doc_example_2_override_html.md +.. literalinclude:: ../../../verto/tests/assets/image/doc_example_2_override_html.md :language: none would result in: -.. literalinclude:: ../../../kordac/tests/assets/image/doc_example_2_override_html_expected.html +.. literalinclude:: ../../../verto/tests/assets/image/doc_example_2_override_html_expected.html :language: html diff --git a/docs/source/processors/interactive.rst b/docs/source/processors/interactive.rst index 898eaffa..7382d7e3 100644 --- a/docs/source/processors/interactive.rst +++ b/docs/source/processors/interactive.rst @@ -11,14 +11,14 @@ Interactives can be small examples to display within the text (for example: `animations comparing sorting algorithms`_) to larger interactives that require a whole page to view (for example: `viewing pixels of an image`_.). -By using the interactive tag, Kordac can include or link to an interactive -within a page. Kordac does not directly include the interactive, but creates +By using the interactive tag, Verto can include or link to an interactive +within a page. Verto does not directly include the interactive, but creates Django commands for a Django system to render the interactive or link to interactive as requested. You can include an interactive using the following text tag: -.. literalinclude:: ../../../kordac/tests/assets/interactive/doc_example_in_page_usage.md +.. literalinclude:: ../../../verto/tests/assets/interactive/doc_example_in_page_usage.md :language: none Required Tag Parameters @@ -70,13 +70,13 @@ Optional Tag Parameters This can be overriden, see the override section below. - Each ``thumbnail`` provided is added to the ``images`` set in required - files stored by Kordac. + files stored by Verto. The set of filepaths can be accessed after conversion, - see :ref:`accessing_kordac_data`. + see :ref:`accessing_verto_data`. The default HTML for button links is: -.. literalinclude:: ../../../kordac/html-templates/interactive.html +.. literalinclude:: ../../../verto/html-templates/interactive.html :language: css+jinja Examples @@ -86,36 +86,36 @@ Examples Using the following example tag: -.. literalinclude:: ../../../kordac/tests/assets/interactive/doc_example_in_page_usage.md +.. literalinclude:: ../../../verto/tests/assets/interactive/doc_example_in_page_usage.md :language: none The resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/interactive/doc_example_in_page_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/interactive/doc_example_in_page_usage_expected.html :language: html **whole-page example** Using the following example tag: -.. literalinclude:: ../../../kordac/tests/assets/interactive/doc_example_whole_page_usage.md +.. literalinclude:: ../../../verto/tests/assets/interactive/doc_example_whole_page_usage.md :language: none The resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/interactive/doc_example_whole_page_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/interactive/doc_example_whole_page_usage_expected.html :language: html **iframe example** Using the following example tag: -.. literalinclude:: ../../../kordac/tests/assets/interactive/doc_example_iframe_usage.md +.. literalinclude:: ../../../verto/tests/assets/interactive/doc_example_iframe_usage.md :language: none The resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/interactive/doc_example_iframe_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/interactive/doc_example_iframe_usage_expected.html :language: html Overriding HTML for Interactives @@ -133,7 +133,7 @@ When overriding the HTML for interactives, the following Jinja2 placeholders are If the ``file_path`` provided is an relative link, the link is passed through the ``relative-image-link.html`` template. The default HTML for relative images is: -.. literalinclude:: ../../../kordac/html-templates/relative-file-link.html +.. literalinclude:: ../../../verto/html-templates/relative-file-link.html :language: css+jinja **Example** @@ -143,17 +143,17 @@ thumbnail. For example, providing the following HTML: -.. literalinclude:: ../../../kordac/tests/assets/interactive/doc_example_override_html_template.html +.. literalinclude:: ../../../verto/tests/assets/interactive/doc_example_override_html_template.html :language: css+jinja with the following tag: -.. literalinclude:: ../../../kordac/tests/assets/interactive/doc_example_override_html.md +.. literalinclude:: ../../../verto/tests/assets/interactive/doc_example_override_html.md :language: none would result in: -.. literalinclude:: ../../../kordac/tests/assets/interactive/doc_example_override_html_expected.html +.. literalinclude:: ../../../verto/tests/assets/interactive/doc_example_override_html_expected.html :language: html .. _Computer Science Field Guide: https://github.com/uccser/cs-field-guide diff --git a/docs/source/processors/panel.rst b/docs/source/processors/panel.rst index 7cb8593e..b7efc6ac 100644 --- a/docs/source/processors/panel.rst +++ b/docs/source/processors/panel.rst @@ -5,7 +5,7 @@ Panel You can include an panel using the following text tag: -.. literalinclude:: ../../../kordac/tests/assets/panel/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/panel/doc_example_basic_usage.md :language: none Required Tag Parameters @@ -29,17 +29,17 @@ Optional Tag Parameters The default HTML for a panel is: -.. literalinclude:: ../../../kordac/html-templates/panel.html +.. literalinclude:: ../../../verto/html-templates/panel.html :language: css+jinja Using the following example tag: -.. literalinclude:: ../../../kordac/tests/assets/panel/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/panel/doc_example_basic_usage.md :language: none The resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/panel/doc_example_basic_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/panel/doc_example_basic_usage_expected.html :language: html Overriding HTML for Panels @@ -57,15 +57,15 @@ When overriding the HTML for images, the following Jinja2 placeholders are avail For example, providing the following HTML: -.. literalinclude:: ../../../kordac/tests/assets/panel/doc_example_override_html_template.html +.. literalinclude:: ../../../verto/tests/assets/panel/doc_example_override_html_template.html :language: css+jinja with the following tag: -.. literalinclude:: ../../../kordac/tests/assets/panel/doc_example_override_html.md +.. literalinclude:: ../../../verto/tests/assets/panel/doc_example_override_html.md :language: none would result in: -.. literalinclude:: ../../../kordac/tests/assets/panel/doc_example_override_html_expected.html +.. literalinclude:: ../../../verto/tests/assets/panel/doc_example_override_html_expected.html :language: html diff --git a/docs/source/processors/relative-link.rst b/docs/source/processors/relative-link.rst index 0de78460..91b265ab 100644 --- a/docs/source/processors/relative-link.rst +++ b/docs/source/processors/relative-link.rst @@ -8,17 +8,17 @@ When the resulting HTML is rendered with Django, the Django system can insert th The default HTML for relative links is: -.. literalinclude:: ../../../kordac/html-templates/relative-link.html +.. literalinclude:: ../../../verto/html-templates/relative-link.html :language: css+jinja Using the following example tag: -.. literalinclude:: ../../../kordac/tests/assets/relative-link/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/relative-link/doc_example_basic_usage.md :language: none The resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/relative-link/doc_example_basic_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/relative-link/doc_example_basic_usage_expected.html :language: html Overriding HTML for Relative Links @@ -34,15 +34,15 @@ For this example, we wish to create HTML to be used in a static site system (not For example, providing the following HTML template: -.. literalinclude:: ../../../kordac/tests/assets/relative-link/doc_example_override_html_template.html +.. literalinclude:: ../../../verto/tests/assets/relative-link/doc_example_override_html_template.html :language: css+jinja with the following Markdown: -.. literalinclude:: ../../../kordac/tests/assets/relative-link/doc_example_override_html.md +.. literalinclude:: ../../../verto/tests/assets/relative-link/doc_example_override_html.md :language: none would result in: -.. literalinclude:: ../../../kordac/tests/assets/relative-link/doc_example_override_html_expected.html +.. literalinclude:: ../../../verto/tests/assets/relative-link/doc_example_override_html_expected.html :language: html diff --git a/docs/source/processors/remove-title.rst b/docs/source/processors/remove-title.rst index 895f6625..ee4c3d36 100644 --- a/docs/source/processors/remove-title.rst +++ b/docs/source/processors/remove-title.rst @@ -8,25 +8,25 @@ This preprocessor runs after the ``save-title`` preprocessor if present. Once it finds a heading on a line, it deletes that line of text. This preprocessor is **not** turned on by default. -To use ``remove-title``, it needs to be explicity provided in the ``processors`` parameter when creating the Kordac converter, or given in the ``update_processors`` method (see example below). +To use ``remove-title``, it needs to be explicity provided in the ``processors`` parameter when creating the Verto converter, or given in the ``update_processors`` method (see example below). **Example** With the following text saved in ``example_string``: -.. literalinclude:: ../../../kordac/tests/assets/remove-title/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/remove-title/doc_example_basic_usage.md :language: none .. code-block:: python - import kordac - converter = kordac.Kordac() - tags = kordac.tag_defaults() + import verto + converter = verto.Verto() + tags = verto.tag_defaults() tags.add('remove-title') converter.update_tags(tags) result = converter.convert(example_string) The ``html_string`` value in ``result`` would be: -.. literalinclude:: ../../../kordac/tests/assets/remove-title/doc_example_basic_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/remove-title/doc_example_basic_usage_expected.html :language: none diff --git a/docs/source/processors/save-title.rst b/docs/source/processors/save-title.rst index 4a7b8c22..f107e8a6 100644 --- a/docs/source/processors/save-title.rst +++ b/docs/source/processors/save-title.rst @@ -4,23 +4,23 @@ Save Title **Tag name:** ``save-title`` This preprocessor runs before any conversion of Markdown and searches for the first heading in the provided Markdown text. -Once it finds a heading, it saves the text for that heading in the ``title`` attribute of the ``KordacResult`` object. +Once it finds a heading, it saves the text for that heading in the ``title`` attribute of the ``VertoResult`` object. **Example** With the following text saved in ``example_string``: -.. literalinclude:: ../../../kordac/tests/assets/save-title/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/save-title/doc_example_basic_usage.md :language: none .. code-block:: python - import kordac - converter = kordac.Kordac() + import verto + converter = verto.Verto() result = converter.convert(example_string) print(result.title) would result in: -.. literalinclude:: ../../../kordac/tests/assets/save-title/doc_example_basic_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/save-title/doc_example_basic_usage_expected.html :language: none diff --git a/docs/source/processors/scratch.rst b/docs/source/processors/scratch.rst index 15e84b63..df7287b0 100644 --- a/docs/source/processors/scratch.rst +++ b/docs/source/processors/scratch.rst @@ -4,14 +4,14 @@ Scratch .. note:: The following examples assume usage of the fenced code extension, by having - ``markdown.extensions.fenced_code`` in the list of extensions given to Kordac. + ``markdown.extensions.fenced_code`` in the list of extensions given to Verto. **Processor name:** ``scratch`` You can include an image of Scratch blocks using `Scratch Block Plugin notation`_ using the following notation: -.. literalinclude:: ../../../kordac/tests/assets/scratch/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/scratch/doc_example_basic_usage.md :language: none to produce the following image: @@ -19,7 +19,7 @@ to produce the following image: .. image:: ../images/scratch_blocks_example.png The syntax is the same for default Markdown code blocks. The only difference -is that Kordac handles the content differently due to the ``scratch`` language +is that Verto handles the content differently due to the ``scratch`` language set at the start. .. note:: @@ -34,24 +34,24 @@ You can also generate Scratch block text from a published Scratch project at .. warning:: - Kordac doesn't create the Scratch images, but saves data for another system + Verto doesn't create the Scratch images, but saves data for another system (for example: Django) to create the images. See :ref:`accessing-scratch-image-data` section below. The default HTML for button links is: -.. literalinclude:: ../../../kordac/html-templates/scratch.html +.. literalinclude:: ../../../verto/html-templates/scratch.html :language: css+jinja Using the following example tag: -.. literalinclude:: ../../../kordac/tests/assets/scratch/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/scratch/doc_example_basic_usage.md :language: none The resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/scratch/doc_example_basic_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/scratch/doc_example_basic_usage_expected.html :language: html .. _accessing-scratch-image-data: @@ -59,7 +59,7 @@ The resulting HTML would be: Accessing Scratch image data *************************************** -When Kordac encounters a code block with the Scratch language (see example +When Verto encounters a code block with the Scratch language (see example above), it doesn't not generate the image but saves the enclosed text and hash of the text in the ``required_files`` attribute under the key ``scratch_images``. @@ -86,7 +86,7 @@ two Scratch blocks, where the ``scratch_images`` key points to a set of The processor replaces the text with an image linked to the expected location of the image. -After Kordac has completed a conversion, you will need to retrieve this data +After Verto has completed a conversion, you will need to retrieve this data from ``required_files`` and render it to an image in the expected location. The `scratchblocks`_ renderer on GitHub allows of rendering to an SVG or PNG. @@ -101,17 +101,17 @@ When overriding the HTML for Scratch code, the following Jinja2 placeholders are For example, providing the following HTML: -.. literalinclude:: ../../../kordac/tests/assets/scratch/doc_example_override_html_template.html +.. literalinclude:: ../../../verto/tests/assets/scratch/doc_example_override_html_template.html :language: css+jinja with the following tag: -.. literalinclude:: ../../../kordac/tests/assets/scratch/doc_example_override_html.md +.. literalinclude:: ../../../verto/tests/assets/scratch/doc_example_override_html.md :language: none would result in: -.. literalinclude:: ../../../kordac/tests/assets/scratch/doc_example_override_html_expected.html +.. literalinclude:: ../../../verto/tests/assets/scratch/doc_example_override_html_expected.html :language: html .. _Scratch Block Plugin notation: https://wiki.scratch.mit.edu/wiki/Block_Plugin diff --git a/docs/source/processors/table-of-contents.rst b/docs/source/processors/table-of-contents.rst index ee379a83..64597c5e 100644 --- a/docs/source/processors/table-of-contents.rst +++ b/docs/source/processors/table-of-contents.rst @@ -6,7 +6,7 @@ Table of Contents You can create a placeholder for a web framework (for example: Django) to insert a table of contents by using the following tag: -.. literalinclude:: ../../../kordac/tests/assets/table-of-contents/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/table-of-contents/doc_example_basic_usage.md :language: none Tag Parameters @@ -18,12 +18,12 @@ There are no required or optional tag parameters for table of contents. Using the following tag: -.. literalinclude:: ../../../kordac/tests/assets/table-of-contents/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/table-of-contents/doc_example_basic_usage.md :language: none The resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/table-of-contents/doc_example_basic_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/table-of-contents/doc_example_basic_usage_expected.html :language: html Overriding HTML for Table of Contents @@ -34,22 +34,22 @@ of contents. The default HTML for table of contents is: -.. literalinclude:: ../../../kordac/html-templates/table-of-contents.html +.. literalinclude:: ../../../verto/html-templates/table-of-contents.html :language: css+jinja **Example** For example, providing the following HTML: -.. literalinclude:: ../../../kordac/tests/assets/table-of-contents/doc_example_override_html_template.html +.. literalinclude:: ../../../verto/tests/assets/table-of-contents/doc_example_override_html_template.html :language: css+jinja with the following tag: -.. literalinclude:: ../../../kordac/tests/assets/table-of-contents/doc_example_override_html.md +.. literalinclude:: ../../../verto/tests/assets/table-of-contents/doc_example_override_html.md :language: none would result in: -.. literalinclude:: ../../../kordac/tests/assets/table-of-contents/doc_example_override_html_expected.html +.. literalinclude:: ../../../verto/tests/assets/table-of-contents/doc_example_override_html_expected.html :language: html diff --git a/docs/source/processors/video.rst b/docs/source/processors/video.rst index 97ac037e..940674cf 100644 --- a/docs/source/processors/video.rst +++ b/docs/source/processors/video.rst @@ -5,7 +5,7 @@ Video You can include an video using the following text tag: -.. literalinclude:: ../../../kordac/tests/assets/video/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/video/doc_example_basic_usage.md :language: none Required Tag Parameters @@ -13,42 +13,42 @@ Required Tag Parameters - ``url`` - The video embed URL for the video. Currently only YouTube and Vimeo videos are supported. - - **For YouTube videos:** Provide the URL in any of the following formats and Kordac will automatically create the embed link. YouTube videos have related videos hidden at video end by default. + - **For YouTube videos:** Provide the URL in any of the following formats and Verto will automatically create the embed link. YouTube videos have related videos hidden at video end by default. - ``https://www.youtube.com/watch?v=dQw4w9WgXcQ`` - Standard URL - ``https://youtu.be/dQw4w9WgXcQ`` - Shortened URL - ``https://www.youtube.com/embed/dQw4w9WgXcQ`` - Embed URL - - **For Vimeo videos:** Provide the URL in any of the following formats and Kordac will automatically create the embed link. + - **For Vimeo videos:** Provide the URL in any of the following formats and Verto will automatically create the embed link. - ``https://vimeo.com/94502406`` - Standard URL - ``https://player.vimeo.com/video/94502406``- Embed URL The default HTML for a video is: -.. literalinclude:: ../../../kordac/html-templates/video.html +.. literalinclude:: ../../../verto/html-templates/video.html :language: css+jinja If the URL provided is YouTube video, the video identifier is extracted and is passed through the ``video-youtube.html`` template: -.. literalinclude:: ../../../kordac/html-templates/video-youtube.html +.. literalinclude:: ../../../verto/html-templates/video-youtube.html :language: css+jinja If the URL provided is YouTube video, the video identifier is extracted and is passed through the ``video-vimeo.html`` template: -.. literalinclude:: ../../../kordac/html-templates/video-vimeo.html +.. literalinclude:: ../../../verto/html-templates/video-vimeo.html :language: css+jinja **Example** Using the following example tag: -.. literalinclude:: ../../../kordac/tests/assets/video/doc_example_basic_usage.md +.. literalinclude:: ../../../verto/tests/assets/video/doc_example_basic_usage.md :language: none The resulting HTML would be: -.. literalinclude:: ../../../kordac/tests/assets/video/doc_example_basic_usage_expected.html +.. literalinclude:: ../../../verto/tests/assets/video/doc_example_basic_usage_expected.html :language: html Overriding HTML for Videos @@ -70,15 +70,15 @@ In the ``video-vimeo.html``, the following Jinja2 placeholders are available: For example, providing the following HTML for ``video-youtube.html``: -.. literalinclude:: ../../../kordac/tests/assets/video/doc_example_override_html_youtube_template.html +.. literalinclude:: ../../../verto/tests/assets/video/doc_example_override_html_youtube_template.html :language: css+jinja with the following tag: -.. literalinclude:: ../../../kordac/tests/assets/video/doc_example_override_html.md +.. literalinclude:: ../../../verto/tests/assets/video/doc_example_override_html.md :language: none would result in: -.. literalinclude:: ../../../kordac/tests/assets/video/doc_example_override_html_expected.html +.. literalinclude:: ../../../verto/tests/assets/video/doc_example_override_html_expected.html :language: html diff --git a/docs/source/usage.rst b/docs/source/usage.rst index 61276199..a6fdcbda 100644 --- a/docs/source/usage.rst +++ b/docs/source/usage.rst @@ -1,78 +1,78 @@ -Using Kordac +Using Verto ####################################### -.. currentmodule:: Kordac +.. currentmodule:: Verto -Using Kordac to convert Markdown is a process of: +Using Verto to convert Markdown is a process of: -1. Importing the installed Kordac package. -2. Creating a Kordac converter. -3. Passing Markdown text through the Kordac ``convert`` method and saving the result object. +1. Importing the installed Verto package. +2. Creating a Verto converter. +3. Passing Markdown text through the Verto ``convert`` method and saving the result object. 4. Accessing data from the result object. -Step 1: Importing Kordac +Step 1: Importing Verto ======================================= -If Kordac has been installed correctly, importing the package can be completed by: +If Verto has been installed correctly, importing the package can be completed by: .. code-block:: python - import kordac + import verto -Step 2: Creating Kordac converter +Step 2: Creating Verto converter ======================================= -Once the module is imported, you can create a Kordac converter creating an Kordac object: +Once the module is imported, you can create a Verto converter creating an Verto object: .. code-block:: python - converter = kordac.Kordac() + converter = verto.Verto() -``Kordac()`` has optional parameters to customise the converter. These are: +``Verto()`` has optional parameters to customise the converter. These are: - ``processors`` - A set of processor names given as strings for the converter to use. If this parameter is not given, the default processors are used. If ``processors`` is provided, all processors not listed are skipped. - - *For example:* Creating a Kordac converter that only deletes comment tags would be done by the following command: + - *For example:* Creating a Verto converter that only deletes comment tags would be done by the following command: .. code-block:: python - converter = kordac.Kordac(processors={"comment"}) + converter = verto.Verto(processors={"comment"}) - ``html_templates`` - A dictionary of HTML templates to override existing HTML templates for processors. The dictionary contains processor names given as a string as keys mapping HTML strings as values. The documentation page for each processor specificies how to create custom HTML for that processor. - - *For example:* Creating a Kordac converter that uses ```` as custom HTML for ``image`` tags would be done by the following command: + - *For example:* Creating a Verto converter that uses ```` as custom HTML for ``image`` tags would be done by the following command: .. code-block:: python - converter = kordac.Kordac(html_templates={'image': ''}) + converter = verto.Verto(html_templates={'image': ''}) - ``extensions`` - A list of extra Markdown extensions to run in the converter. Details on how to use this parameter can be found on the :doc:`extensions` page. Step 3: Convert Markdown with converter ======================================= -To convert Markdown to HTML with a Kordac converter, we call the ``convert()`` method. The method returns a ``KordacResult`` object. +To convert Markdown to HTML with a Verto converter, we call the ``convert()`` method. The method returns a ``VertoResult`` object. .. code-block:: python text = """ This **is** a line of Markdown. - {comment This is a comment using a Kordac tag} + {comment This is a comment using a Verto tag} This is a *different* line of Markdown. """ result = converter.convert(text) -.. _accessing_kordac_data: +.. _accessing_verto_data: -Step 4: Accessing KordacResult data +Step 4: Accessing VertoResult data ======================================= -The ``KordacResult`` object contains several attributes which can be accessed using the dot notation. Continuing from our previous example, the following command would print the converted HTML. +The ``VertoResult`` object contains several attributes which can be accessed using the dot notation. Continuing from our previous example, the following command would print the converted HTML. .. code-block:: python @@ -80,9 +80,9 @@ The ``KordacResult`` object contains several attributes which can be accessed us The following attributes are available: -- ``html_string`` - A resulting string of HTML after conversion by Kordac. +- ``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 Kordac 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`}``). +- ``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. @@ -116,48 +116,48 @@ The following attributes are available: [] } -Configuring Kordac converter after creation +Configuring Verto converter after creation =============================================== -The following functions allow you to change the processors or HTML templates used in conversion by the Kordac converter after its creation. +The following functions allow you to change the processors or HTML templates used in conversion by the Verto converter after its creation. Changing processors ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automethod:: kordac.Kordac.update_processors(processors) +.. automethod:: verto.Verto.update_processors(processors) -.. automethod:: kordac.Kordac.processor_defaults(processors) +.. automethod:: verto.Verto.processor_defaults(processors) 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: .. code-block:: python - processors = Kordac.processor_defaults() + processors = Verto.processor_defaults() processors.remove('video') - converter = Kordac(processors=processors) + converter = Verto(processors=processors) - Or with an existing Kordac instance ``converter``: + Or with an existing Verto instance ``converter``: .. code-block:: python - processors = Kordac.processor_defaults() + processors = Verto.processor_defaults() processors.remove('video') converter.update_processors(processors) Changing HTML templates ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automethod:: kordac.Kordac.update_templates(html_templates) +.. automethod:: verto.Verto.update_templates(html_templates) -.. automethod:: kordac.Kordac.clear_templates() +.. automethod:: verto.Verto.clear_templates() Full list of package methods ======================================= -.. autoclass:: kordac.Kordac() +.. autoclass:: verto.Verto() :members: __init__, convert, update_processors, processor_defaults, update_templates, clear_templates -.. autoclass:: kordac.Kordac.KordacResult() +.. autoclass:: verto.Verto.VertoResult() .. attribute:: html_string @@ -169,4 +169,4 @@ Full list of package methods .. attribute:: required_files - A dictionary of files encountered in a Kordac 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`}``). + 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`}``). diff --git a/kordac/tests/assets/button-link/doc_example_override_html.md b/kordac/tests/assets/button-link/doc_example_override_html.md deleted file mode 100644 index de8a5a18..00000000 --- a/kordac/tests/assets/button-link/doc_example_override_html.md +++ /dev/null @@ -1 +0,0 @@ -{button-link link="https://github.com/uccser/kordac" text="Kordac on GitHub"} diff --git a/kordac/tests/assets/button-link/doc_example_override_html_expected.html b/kordac/tests/assets/button-link/doc_example_override_html_expected.html deleted file mode 100644 index e796187d..00000000 --- a/kordac/tests/assets/button-link/doc_example_override_html_expected.html +++ /dev/null @@ -1,3 +0,0 @@ - - Kordac on GitHub - diff --git a/requirements.txt b/requirements.txt index dc3c560a..2c105801 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -# Required dependencies for Kordac (installed automatically in setup.py) +# Required dependencies for Verto (installed automatically in setup.py) markdown==2.6.8 beautifulsoup4==4.5.3 Jinja2==2.9.5 diff --git a/setup.py b/setup.py index 93ff5bbb..566518a8 100644 --- a/setup.py +++ b/setup.py @@ -1,16 +1,16 @@ from setuptools import setup, find_packages import sys -from kordac import __version__ +from verto import __version__ if not sys.version_info[0] == 3: sys.exit("Sorry, currently only Python 3 is supported.") setup( - name='kordac', + name='verto', version=__version__, - description='Kordac is an extension of the Python Markdown package, which allows authors to include complex HTML elements with simple text tags in their Markdown.', + 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=open('README.rst').read(), - url='https://github.com/uccser/kordac', + url='https://github.com/uccser/verto', author='University of Canterbury Computer Science Education Research Group', license='MIT', classifiers=[ diff --git a/kordac/Kordac.py b/verto/Verto.py similarity index 83% rename from kordac/Kordac.py rename to verto/Verto.py index efff8279..b491f0bd 100644 --- a/kordac/Kordac.py +++ b/verto/Verto.py @@ -1,5 +1,5 @@ import markdown -from kordac.KordacExtension import KordacExtension +from verto.VertoExtension import VertoExtension DEFAULT_PROCESSORS = frozenset({ 'save-title', @@ -19,13 +19,13 @@ }) -class Kordac(object): +class Verto(object): '''A converter object for converting markdown with complex elements to HTML. ''' def __init__(self, processors=DEFAULT_PROCESSORS, html_templates={}, extensions=[]): - '''Creates a Kordac object. + '''Creates a Verto object. Args: processors: A set of processor names given as strings for which @@ -45,33 +45,33 @@ def __init__(self, processors=DEFAULT_PROCESSORS, html_templates={}, extensions= self.create_converter() def create_converter(self): - '''Create the Kordac extension and converter for future use.''' - self.kordac_extension = KordacExtension( + '''Create the Verto extension and converter for future use.''' + self.verto_extension = VertoExtension( processors=self.processors, html_templates=self.html_templates, extensions=self.extensions ) - all_extensions = self.extensions + [self.kordac_extension] + all_extensions = self.extensions + [self.verto_extension] self.converter = markdown.Markdown(extensions=all_extensions) def convert(self, text): - '''Return a KordacResult object after converting + '''Return a VertoResult object after converting the given markdown string. Args: text: A string of Markdown text to be converted. Returns: - A KordacResult object. + A VertoResult object. ''' - self.kordac_extension.clear_saved_data() + self.verto_extension.clear_saved_data() html_string = self.converter.convert(text) - result = KordacResult( + result = VertoResult( html_string=html_string, - title=self.kordac_extension.title, - required_files=self.kordac_extension.required_files, - heading_tree=self.kordac_extension.get_heading_tree(), - required_glossary_terms=self.kordac_extension.glossary_terms + title=self.verto_extension.title, + required_files=self.verto_extension.required_files, + heading_tree=self.verto_extension.get_heading_tree(), + required_glossary_terms=self.verto_extension.glossary_terms ) return result @@ -121,13 +121,13 @@ def update_processors(self, processors=DEFAULT_PROCESSORS): self.create_converter() -class KordacResult(object): - '''Object created by Kordac containing the result data +class VertoResult(object): + '''Object created by Verto containing the result data after a conversion by run. ''' def __init__(self, html_string, title, required_files, heading_tree, required_glossary_terms): - '''Create a KordacResult object. + '''Create a VertoResult object. Args: html_string: A string of HTML text. diff --git a/kordac/KordacExtension.py b/verto/VertoExtension.py similarity index 83% rename from kordac/KordacExtension.py rename to verto/VertoExtension.py index f6f4b335..96d4a883 100644 --- a/kordac/KordacExtension.py +++ b/verto/VertoExtension.py @@ -1,27 +1,27 @@ from markdown.extensions import Extension import markdown.util as utils -from kordac.processors.CommentPreprocessor import CommentPreprocessor -from kordac.processors.VideoBlockProcessor import VideoBlockProcessor -from kordac.processors.ImageBlockProcessor import ImageBlockProcessor -from kordac.processors.InteractiveBlockProcessor import InteractiveBlockProcessor -from kordac.processors.RelativeLinkPattern import RelativeLinkPattern -from kordac.processors.RemoveTitlePreprocessor import RemoveTitlePreprocessor -from kordac.processors.SaveTitlePreprocessor import SaveTitlePreprocessor -from kordac.processors.GlossaryLinkPattern import GlossaryLinkPattern -from kordac.processors.BeautifyPostprocessor import BeautifyPostprocessor -from kordac.processors.ConditionalProcessor import ConditionalProcessor -from kordac.processors.RemovePostprocessor import RemovePostprocessor -from kordac.processors.JinjaPostprocessor import JinjaPostprocessor -from kordac.processors.HeadingBlockProcessor import HeadingBlockProcessor -from kordac.processors.ScratchTreeprocessor import ScratchTreeprocessor -from kordac.processors.ScratchCompatibilityPreprocessor import ScratchCompatibilityPreprocessor -from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor -from kordac.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor - -from kordac.utils.UniqueSlugify import UniqueSlugify -from kordac.utils.HeadingNode import HeadingNode -from kordac.utils.overrides import is_block_level, BLOCK_LEVEL_ELEMENTS +from verto.processors.CommentPreprocessor import CommentPreprocessor +from verto.processors.VideoBlockProcessor import VideoBlockProcessor +from verto.processors.ImageBlockProcessor import ImageBlockProcessor +from verto.processors.InteractiveBlockProcessor import InteractiveBlockProcessor +from verto.processors.RelativeLinkPattern import RelativeLinkPattern +from verto.processors.RemoveTitlePreprocessor import RemoveTitlePreprocessor +from verto.processors.SaveTitlePreprocessor import SaveTitlePreprocessor +from verto.processors.GlossaryLinkPattern import GlossaryLinkPattern +from verto.processors.BeautifyPostprocessor import BeautifyPostprocessor +from verto.processors.ConditionalProcessor import ConditionalProcessor +from verto.processors.RemovePostprocessor import RemovePostprocessor +from verto.processors.JinjaPostprocessor import JinjaPostprocessor +from verto.processors.HeadingBlockProcessor import HeadingBlockProcessor +from verto.processors.ScratchTreeprocessor import ScratchTreeprocessor +from verto.processors.ScratchCompatibilityPreprocessor import ScratchCompatibilityPreprocessor +from verto.processors.GenericTagBlockProcessor import GenericTagBlockProcessor +from verto.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor + +from verto.utils.UniqueSlugify import UniqueSlugify +from verto.utils.HeadingNode import HeadingNode +from verto.utils.overrides import is_block_level, BLOCK_LEVEL_ELEMENTS from collections import defaultdict, OrderedDict from os import listdir @@ -32,10 +32,10 @@ from jinja2 import Environment, PackageLoader, select_autoescape -class KordacExtension(Extension): - '''The Kordac markdown extension which enables all the processors, +class VertoExtension(Extension): + '''The Verto markdown extension which enables all the processors, and extracts all the important information to expose externally to - the Kordac converter. + the Verto converter. ''' def __init__(self, processors=[], html_templates={}, extensions=[], *args, **kwargs): @@ -127,7 +127,7 @@ def loadJinjaTemplates(self, custom_templates): ''' templates = {} env = Environment( - loader=PackageLoader('kordac', 'html-templates'), + loader=PackageLoader('verto', 'html-templates'), autoescape=select_autoescape(['html']) ) for file in listdir(os.path.join(os.path.dirname(__file__), 'html-templates')): diff --git a/kordac/__init__.py b/verto/__init__.py similarity index 58% rename from kordac/__init__.py rename to verto/__init__.py index 341e6af7..9adcccd2 100644 --- a/kordac/__init__.py +++ b/verto/__init__.py @@ -1,4 +1,4 @@ # flake8: noqa -from .Kordac import Kordac +from .Verto import Verto __version__ = '0.3.1' diff --git a/kordac/html-templates/boxed-text.html b/verto/html-templates/boxed-text.html similarity index 100% rename from kordac/html-templates/boxed-text.html rename to verto/html-templates/boxed-text.html diff --git a/kordac/html-templates/button-link.html b/verto/html-templates/button-link.html similarity index 100% rename from kordac/html-templates/button-link.html rename to verto/html-templates/button-link.html diff --git a/kordac/html-templates/conditional.html b/verto/html-templates/conditional.html similarity index 100% rename from kordac/html-templates/conditional.html rename to verto/html-templates/conditional.html diff --git a/kordac/html-templates/glossary-link.html b/verto/html-templates/glossary-link.html similarity index 100% rename from kordac/html-templates/glossary-link.html rename to verto/html-templates/glossary-link.html diff --git a/kordac/html-templates/heading.html b/verto/html-templates/heading.html similarity index 100% rename from kordac/html-templates/heading.html rename to verto/html-templates/heading.html diff --git a/kordac/html-templates/iframe.html b/verto/html-templates/iframe.html similarity index 100% rename from kordac/html-templates/iframe.html rename to verto/html-templates/iframe.html diff --git a/kordac/html-templates/image.html b/verto/html-templates/image.html similarity index 100% rename from kordac/html-templates/image.html rename to verto/html-templates/image.html diff --git a/kordac/html-templates/interactive.html b/verto/html-templates/interactive.html similarity index 100% rename from kordac/html-templates/interactive.html rename to verto/html-templates/interactive.html diff --git a/kordac/html-templates/panel.html b/verto/html-templates/panel.html similarity index 100% rename from kordac/html-templates/panel.html rename to verto/html-templates/panel.html diff --git a/kordac/html-templates/relative-file-link.html b/verto/html-templates/relative-file-link.html similarity index 100% rename from kordac/html-templates/relative-file-link.html rename to verto/html-templates/relative-file-link.html diff --git a/kordac/html-templates/relative-link.html b/verto/html-templates/relative-link.html similarity index 100% rename from kordac/html-templates/relative-link.html rename to verto/html-templates/relative-link.html diff --git a/kordac/html-templates/scratch.html b/verto/html-templates/scratch.html similarity index 100% rename from kordac/html-templates/scratch.html rename to verto/html-templates/scratch.html diff --git a/kordac/html-templates/table-of-contents.html b/verto/html-templates/table-of-contents.html similarity index 100% rename from kordac/html-templates/table-of-contents.html rename to verto/html-templates/table-of-contents.html diff --git a/kordac/html-templates/video-vimeo.html b/verto/html-templates/video-vimeo.html similarity index 100% rename from kordac/html-templates/video-vimeo.html rename to verto/html-templates/video-vimeo.html diff --git a/kordac/html-templates/video-youtube.html b/verto/html-templates/video-youtube.html similarity index 100% rename from kordac/html-templates/video-youtube.html rename to verto/html-templates/video-youtube.html diff --git a/kordac/html-templates/video.html b/verto/html-templates/video.html similarity index 100% rename from kordac/html-templates/video.html rename to verto/html-templates/video.html diff --git a/kordac/images/kordac-logo.png b/verto/images/verto-logo.png similarity index 100% rename from kordac/images/kordac-logo.png rename to verto/images/verto-logo.png diff --git a/kordac/processor-info.json b/verto/processor-info.json similarity index 100% rename from kordac/processor-info.json rename to verto/processor-info.json diff --git a/kordac/processors/BeautifyPostprocessor.py b/verto/processors/BeautifyPostprocessor.py similarity index 100% rename from kordac/processors/BeautifyPostprocessor.py rename to verto/processors/BeautifyPostprocessor.py diff --git a/kordac/processors/CommentPreprocessor.py b/verto/processors/CommentPreprocessor.py similarity index 100% rename from kordac/processors/CommentPreprocessor.py rename to verto/processors/CommentPreprocessor.py diff --git a/kordac/processors/ConditionalProcessor.py b/verto/processors/ConditionalProcessor.py similarity index 95% rename from kordac/processors/ConditionalProcessor.py rename to verto/processors/ConditionalProcessor.py index 669edf9e..10c89a5b 100644 --- a/kordac/processors/ConditionalProcessor.py +++ b/verto/processors/ConditionalProcessor.py @@ -1,6 +1,6 @@ -from kordac.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor -from kordac.processors.errors.TagNotMatchedError import TagNotMatchedError -from kordac.processors.utils import etree, parse_arguments, parse_flag, blocks_to_string +from verto.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor +from verto.processors.errors.TagNotMatchedError import TagNotMatchedError +from verto.processors.utils import etree, parse_arguments, parse_flag, blocks_to_string from collections import OrderedDict @@ -14,7 +14,7 @@ class ConditionalProcessor(GenericContainerBlockProcessor): def __init__(self, ext, *args, **kwargs): ''' Args: - ext: An instance of the KordacExtension. + ext: An instance of the VertoExtension. ''' super().__init__('conditional', ext, *args, **kwargs) diff --git a/kordac/processors/GenericContainerBlockProcessor.py b/verto/processors/GenericContainerBlockProcessor.py similarity index 94% rename from kordac/processors/GenericContainerBlockProcessor.py rename to verto/processors/GenericContainerBlockProcessor.py index f3f0f1b5..0a037bb4 100644 --- a/kordac/processors/GenericContainerBlockProcessor.py +++ b/verto/processors/GenericContainerBlockProcessor.py @@ -1,6 +1,6 @@ from markdown.blockprocessors import BlockProcessor -from kordac.processors.errors.TagNotMatchedError import TagNotMatchedError -from kordac.processors.utils import etree, parse_arguments, process_parameters, blocks_to_string +from verto.processors.errors.TagNotMatchedError import TagNotMatchedError +from verto.processors.utils import etree, parse_arguments, process_parameters, blocks_to_string import re @@ -8,7 +8,7 @@ class GenericContainerBlockProcessor(BlockProcessor): def __init__(self, processor, ext, *args, **kwargs): ''' Args: - ext: An instance of the Kordac Extension. + ext: An instance of the Verto Extension. ''' super().__init__(*args, **kwargs) self.processor = processor diff --git a/kordac/processors/GenericTagBlockProcessor.py b/verto/processors/GenericTagBlockProcessor.py similarity index 94% rename from kordac/processors/GenericTagBlockProcessor.py rename to verto/processors/GenericTagBlockProcessor.py index 1414be08..c8a9aeb1 100644 --- a/kordac/processors/GenericTagBlockProcessor.py +++ b/verto/processors/GenericTagBlockProcessor.py @@ -1,5 +1,5 @@ from markdown.blockprocessors import BlockProcessor -from kordac.processors.utils import etree, parse_arguments, process_parameters +from verto.processors.utils import etree, parse_arguments, process_parameters import re @@ -10,7 +10,7 @@ class GenericTagBlockProcessor(BlockProcessor): def __init__(self, processor, ext, *args, **kwargs): ''' Args: - ext: An instance of the Kordac Extension. + ext: An instance of the Verto Extension. ''' super().__init__(*args, **kwargs) self.processor = processor diff --git a/kordac/processors/GlossaryLinkPattern.py b/verto/processors/GlossaryLinkPattern.py similarity index 97% rename from kordac/processors/GlossaryLinkPattern.py rename to verto/processors/GlossaryLinkPattern.py index d3677ee6..0c94dff7 100644 --- a/kordac/processors/GlossaryLinkPattern.py +++ b/verto/processors/GlossaryLinkPattern.py @@ -1,5 +1,5 @@ from markdown.inlinepatterns import Pattern -from kordac.processors.utils import etree, parse_arguments +from verto.processors.utils import etree, parse_arguments import re diff --git a/kordac/processors/HeadingBlockProcessor.py b/verto/processors/HeadingBlockProcessor.py similarity index 97% rename from kordac/processors/HeadingBlockProcessor.py rename to verto/processors/HeadingBlockProcessor.py index 67c22dac..97e9fd4d 100644 --- a/kordac/processors/HeadingBlockProcessor.py +++ b/verto/processors/HeadingBlockProcessor.py @@ -1,6 +1,6 @@ from markdown.blockprocessors import BlockProcessor from markdown.util import etree -from kordac.utils.HeadingNode import DynamicHeadingNode +from verto.utils.HeadingNode import DynamicHeadingNode import re @@ -13,7 +13,7 @@ class HeadingBlockProcessor(BlockProcessor): def __init__(self, ext, *args, **kwargs): ''' Args: - ext: The KordacExtension object. + ext: The VertoExtension object. ''' super().__init__(*args, **kwargs) self.processor = 'heading' @@ -42,7 +42,7 @@ def test(self, parent, block): def run(self, parent, blocks): ''' Processes the block matching the heading and adding to the - html tree and the kordac heading tree. + html tree and the verto heading tree. Args: parent: The parent node of the element tree that children diff --git a/kordac/processors/ImageBlockProcessor.py b/verto/processors/ImageBlockProcessor.py similarity index 91% rename from kordac/processors/ImageBlockProcessor.py rename to verto/processors/ImageBlockProcessor.py index 5d5237ca..e4a3fef4 100644 --- a/kordac/processors/ImageBlockProcessor.py +++ b/verto/processors/ImageBlockProcessor.py @@ -1,11 +1,11 @@ -from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor -from kordac.processors.utils import etree, parse_arguments +from verto.processors.GenericTagBlockProcessor import GenericTagBlockProcessor +from verto.processors.utils import etree, parse_arguments import re class ImageBlockProcessor(GenericTagBlockProcessor): ''' Searches a Document for image tags e.g. {image file-path=""} - adding any internal images to the kordac extension final result. + adding any internal images to the verto extension final result. ''' def __init__(self, ext, *args, **kwargs): @@ -33,7 +33,7 @@ def test(self, parent, block): def run(self, parent, blocks): ''' Processes the block matching the image pattern, adding - any internal images to the KordacExtension result. + any internal images to the VertoExtension result. Args: parent: The parent node of the element tree that children diff --git a/kordac/processors/InteractiveBlockProcessor.py b/verto/processors/InteractiveBlockProcessor.py similarity index 90% rename from kordac/processors/InteractiveBlockProcessor.py rename to verto/processors/InteractiveBlockProcessor.py index 59c936bd..0440d760 100644 --- a/kordac/processors/InteractiveBlockProcessor.py +++ b/verto/processors/InteractiveBlockProcessor.py @@ -1,6 +1,6 @@ -from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor -from kordac.processors.errors.InvalidParameterError import InvalidParameterError -from kordac.processors.utils import etree, parse_arguments +from verto.processors.GenericTagBlockProcessor import GenericTagBlockProcessor +from verto.processors.errors.InvalidParameterError import InvalidParameterError +from verto.processors.utils import etree, parse_arguments import re @@ -13,7 +13,7 @@ class InteractiveBlockProcessor(GenericTagBlockProcessor): def __init__(self, ext, *args, **kwargs): ''' Args: - ext: An instance of the Kordac Extension. + ext: An instance of the Verto Extension. ''' super().__init__('interactive', ext, *args, **kwargs) self.relative_file_template = ext.jinja_templates['relative-file-link'] @@ -34,7 +34,7 @@ def test(self, parent, block): def run(self, parent, blocks): ''' Processes the block matching the heading and adding to the - html tree and the kordac heading tree. + html tree and the verto heading tree. Args: parent: The parent node of the element tree that children diff --git a/kordac/processors/JinjaPostprocessor.py b/verto/processors/JinjaPostprocessor.py similarity index 100% rename from kordac/processors/JinjaPostprocessor.py rename to verto/processors/JinjaPostprocessor.py diff --git a/kordac/processors/RelativeLinkPattern.py b/verto/processors/RelativeLinkPattern.py similarity index 100% rename from kordac/processors/RelativeLinkPattern.py rename to verto/processors/RelativeLinkPattern.py diff --git a/kordac/processors/RemovePostprocessor.py b/verto/processors/RemovePostprocessor.py similarity index 100% rename from kordac/processors/RemovePostprocessor.py rename to verto/processors/RemovePostprocessor.py diff --git a/kordac/processors/RemoveTitlePreprocessor.py b/verto/processors/RemoveTitlePreprocessor.py similarity index 95% rename from kordac/processors/RemoveTitlePreprocessor.py rename to verto/processors/RemoveTitlePreprocessor.py index 8f7ac9e0..1cb3e0d8 100644 --- a/kordac/processors/RemoveTitlePreprocessor.py +++ b/verto/processors/RemoveTitlePreprocessor.py @@ -9,7 +9,7 @@ class RemoveTitlePreprocessor(Preprocessor): def __init__(self, ext, *args, **kwargs): ''' Args: - ext: An instance of the KordacExtension. + ext: An instance of the VertoExtension. ''' super().__init__(*args, **kwargs) self.ext = ext diff --git a/kordac/processors/SaveTitlePreprocessor.py b/verto/processors/SaveTitlePreprocessor.py similarity index 87% rename from kordac/processors/SaveTitlePreprocessor.py rename to verto/processors/SaveTitlePreprocessor.py index 789e8db2..2f52fd0d 100644 --- a/kordac/processors/SaveTitlePreprocessor.py +++ b/verto/processors/SaveTitlePreprocessor.py @@ -4,13 +4,13 @@ class SaveTitlePreprocessor(Preprocessor): ''' Saves the first title found in the document to - the KordacExtension as part of the final result. + the VertoExtension as part of the final result. ''' def __init__(self, ext, *args, **kwargs): ''' Args: - ext: An instance of the KordacExtension. + ext: An instance of the VertoExtension. ''' super().__init__(*args, **kwargs) self.ext = ext @@ -29,7 +29,7 @@ def test(self, lines): def run(self, lines): ''' Finds the first title and saves it to the - KordacExtension for the final result. + VertoExtension for the final result. Args: lines: A list of strings that form the document. diff --git a/kordac/processors/ScratchCompatibilityPreprocessor.py b/verto/processors/ScratchCompatibilityPreprocessor.py similarity index 97% rename from kordac/processors/ScratchCompatibilityPreprocessor.py rename to verto/processors/ScratchCompatibilityPreprocessor.py index e9f9dbe6..4c391cec 100644 --- a/kordac/processors/ScratchCompatibilityPreprocessor.py +++ b/verto/processors/ScratchCompatibilityPreprocessor.py @@ -15,7 +15,7 @@ class ScratchCompatibilityPreprocessor(Preprocessor): def __init__(self, ext, *args, **kwargs): ''' Args: - ext: An instance of the Kordac Extension. + ext: An instance of the Verto Extension. ''' super().__init__(*args, **kwargs) self.processor = 'scratch-compatibility' diff --git a/kordac/processors/ScratchTreeprocessor.py b/verto/processors/ScratchTreeprocessor.py similarity index 95% rename from kordac/processors/ScratchTreeprocessor.py rename to verto/processors/ScratchTreeprocessor.py index 51a89bbf..38693319 100644 --- a/kordac/processors/ScratchTreeprocessor.py +++ b/verto/processors/ScratchTreeprocessor.py @@ -1,5 +1,5 @@ from markdown.treeprocessors import Treeprocessor -from kordac.processors.utils import etree +from verto.processors.utils import etree from collections import namedtuple from hashlib import sha256 @@ -15,7 +15,7 @@ class ScratchImageMetaData(namedtuple('ScratchImageMetaData', 'hash, text')): class ScratchTreeprocessor(Treeprocessor): ''' Searches a Document for codeblocks with the scratch language. - These are then processed into the kordac result and hashed for + These are then processed into the verto result and hashed for another program in the pipeline to retrieve or create into images. ''' @@ -92,7 +92,7 @@ def hash_content(text): return sha256(text.encode('utf8')).hexdigest() def update_required_images(self, content_hash, text): - '''Adds the scratch code and hash to the kordac result. + '''Adds the scratch code and hash to the verto result. Args: content_hash: The image hash. diff --git a/kordac/processors/VideoBlockProcessor.py b/verto/processors/VideoBlockProcessor.py similarity index 90% rename from kordac/processors/VideoBlockProcessor.py rename to verto/processors/VideoBlockProcessor.py index 151e39a9..2cabe09c 100644 --- a/kordac/processors/VideoBlockProcessor.py +++ b/verto/processors/VideoBlockProcessor.py @@ -1,7 +1,7 @@ -from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor -from kordac.processors.errors.NoVideoIdentifierError import NoVideoIdentifierError -from kordac.processors.errors.UnsupportedVideoPlayerError import UnsupportedVideoPlayerError -from kordac.processors.utils import etree, parse_arguments +from verto.processors.GenericTagBlockProcessor import GenericTagBlockProcessor +from verto.processors.errors.NoVideoIdentifierError import NoVideoIdentifierError +from verto.processors.errors.UnsupportedVideoPlayerError import UnsupportedVideoPlayerError +from verto.processors.utils import etree, parse_arguments import re @@ -13,7 +13,7 @@ class VideoBlockProcessor(GenericTagBlockProcessor): def __init__(self, ext, *args, **kwargs): ''' Args: - ext: An instance of the Kordac Extension. + ext: An instance of the Verto Extension. ''' super().__init__('video', ext, *args, **kwargs) self.pattern = re.compile(ext.processor_info[self.processor]['pattern']) diff --git a/kordac/processors/__init__.py b/verto/processors/__init__.py similarity index 100% rename from kordac/processors/__init__.py rename to verto/processors/__init__.py diff --git a/kordac/processors/errors/ArgumentMissingError.py b/verto/processors/errors/ArgumentMissingError.py similarity index 90% rename from kordac/processors/errors/ArgumentMissingError.py rename to verto/processors/errors/ArgumentMissingError.py index 811f0086..78e05a02 100644 --- a/kordac/processors/errors/ArgumentMissingError.py +++ b/verto/processors/errors/ArgumentMissingError.py @@ -1,4 +1,4 @@ -from kordac.processors.errors.Error import Error +from verto.processors.errors.Error import Error class ArgumentMissingError(Error): diff --git a/kordac/processors/errors/Error.py b/verto/processors/errors/Error.py similarity index 100% rename from kordac/processors/errors/Error.py rename to verto/processors/errors/Error.py diff --git a/kordac/processors/errors/InvalidParameterError.py b/verto/processors/errors/InvalidParameterError.py similarity index 90% rename from kordac/processors/errors/InvalidParameterError.py rename to verto/processors/errors/InvalidParameterError.py index 692d0b23..db14f473 100644 --- a/kordac/processors/errors/InvalidParameterError.py +++ b/verto/processors/errors/InvalidParameterError.py @@ -1,4 +1,4 @@ -from kordac.processors.errors.Error import Error +from verto.processors.errors.Error import Error class InvalidParameterError(Error): diff --git a/kordac/processors/errors/NoSourceLinkError.py b/verto/processors/errors/NoSourceLinkError.py similarity index 89% rename from kordac/processors/errors/NoSourceLinkError.py rename to verto/processors/errors/NoSourceLinkError.py index a74021d9..e2c1106f 100644 --- a/kordac/processors/errors/NoSourceLinkError.py +++ b/verto/processors/errors/NoSourceLinkError.py @@ -1,4 +1,4 @@ -from kordac.processors.errors.Error import Error +from verto.processors.errors.Error import Error class NoSourceLinkError(Error): diff --git a/kordac/processors/errors/NoVideoIdentifierError.py b/verto/processors/errors/NoVideoIdentifierError.py similarity index 89% rename from kordac/processors/errors/NoVideoIdentifierError.py rename to verto/processors/errors/NoVideoIdentifierError.py index 2b1d0fc0..7fd73a65 100644 --- a/kordac/processors/errors/NoVideoIdentifierError.py +++ b/verto/processors/errors/NoVideoIdentifierError.py @@ -1,4 +1,4 @@ -from kordac.processors.errors.Error import Error +from verto.processors.errors.Error import Error class NoVideoIdentifierError(Error): diff --git a/kordac/processors/errors/TagNotMatchedError.py b/verto/processors/errors/TagNotMatchedError.py similarity index 89% rename from kordac/processors/errors/TagNotMatchedError.py rename to verto/processors/errors/TagNotMatchedError.py index 86d5f8fd..b3b44f54 100644 --- a/kordac/processors/errors/TagNotMatchedError.py +++ b/verto/processors/errors/TagNotMatchedError.py @@ -1,4 +1,4 @@ -from kordac.processors.errors.Error import Error +from verto.processors.errors.Error import Error class TagNotMatchedError(Error): diff --git a/kordac/processors/errors/UnsupportedVideoPlayerError.py b/verto/processors/errors/UnsupportedVideoPlayerError.py similarity index 89% rename from kordac/processors/errors/UnsupportedVideoPlayerError.py rename to verto/processors/errors/UnsupportedVideoPlayerError.py index dd3bc4b3..bd6982e7 100644 --- a/kordac/processors/errors/UnsupportedVideoPlayerError.py +++ b/verto/processors/errors/UnsupportedVideoPlayerError.py @@ -1,4 +1,4 @@ -from kordac.processors.errors.Error import Error +from verto.processors.errors.Error import Error class UnsupportedVideoPlayerError(Error): diff --git a/kordac/processors/errors/__init__.py b/verto/processors/errors/__init__.py similarity index 100% rename from kordac/processors/errors/__init__.py rename to verto/processors/errors/__init__.py diff --git a/kordac/processors/utils.py b/verto/processors/utils.py similarity index 98% rename from kordac/processors/utils.py rename to verto/processors/utils.py index 1a725fab..c442ca23 100644 --- a/kordac/processors/utils.py +++ b/verto/processors/utils.py @@ -1,7 +1,7 @@ import re from markdown.util import etree # noqa: F401 from collections import OrderedDict, defaultdict -from kordac.processors.errors.ArgumentMissingError import ArgumentMissingError +from verto.processors.errors.ArgumentMissingError import ArgumentMissingError def parse_argument(argument_key, arguments, default=None): diff --git a/kordac/tests/BaseTest.py b/verto/tests/BaseTest.py similarity index 92% rename from kordac/tests/BaseTest.py rename to verto/tests/BaseTest.py index cfc40545..d712ffc7 100644 --- a/kordac/tests/BaseTest.py +++ b/verto/tests/BaseTest.py @@ -11,7 +11,7 @@ def __init__(self, *args, **kwargs): test failures. """ unittest.TestCase.__init__(self, *args, **kwargs) - self.test_file_path = 'kordac/tests/assets/{test_type}/{filename}' + self.test_file_path = 'verto/tests/assets/{test_type}/{filename}' self.maxDiff = None def read_test_file(self, test_type, filename, strip=False): diff --git a/kordac/tests/BeautifyTest.py b/verto/tests/BeautifyTest.py similarity index 80% rename from kordac/tests/BeautifyTest.py rename to verto/tests/BeautifyTest.py index c63874f3..de6e2dbf 100644 --- a/kordac/tests/BeautifyTest.py +++ b/verto/tests/BeautifyTest.py @@ -1,9 +1,9 @@ import markdown from unittest.mock import Mock -from kordac.KordacExtension import KordacExtension -from kordac.processors.CommentPreprocessor import CommentPreprocessor -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.CommentPreprocessor import CommentPreprocessor +from verto.tests.ProcessorTest import ProcessorTest class BeautifyTest(ProcessorTest): def __init__(self, *args, **kwargs): @@ -14,28 +14,28 @@ def __init__(self, *args, **kwargs): def test_example_inline_code(self): test_string = self.read_test_file(self.processor_name, 'example_inline_code.md') - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'example_inline_code_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) def test_example_preformatted_code(self): test_string = self.read_test_file(self.processor_name, 'example_preformatted_code.md') - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'example_preformatted_code_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) def test_example_preformatted_code_with_extension(self): - kordac_extension = KordacExtension([self.processor_name], {}, ['markdown.extensions.fenced_code']) + verto_extension = VertoExtension([self.processor_name], {}, ['markdown.extensions.fenced_code']) test_string = self.read_test_file(self.processor_name, 'example_preformatted_code_with_extension.md') - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension, 'markdown.extensions.fenced_code']) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension, 'markdown.extensions.fenced_code']) expected_string = self.read_test_file(self.processor_name, 'example_preformatted_code_with_extension_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) def text_example_mixed_code_types(self): test_string = self.read_test_file(self.processor_name, 'example_mixed_code_types.md') - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'example_mixed_code_types_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) diff --git a/kordac/tests/BoxedTextTest.py b/verto/tests/BoxedTextTest.py similarity index 89% rename from kordac/tests/BoxedTextTest.py rename to verto/tests/BoxedTextTest.py index 923888d2..30120982 100644 --- a/kordac/tests/BoxedTextTest.py +++ b/verto/tests/BoxedTextTest.py @@ -1,9 +1,9 @@ import markdown from unittest.mock import Mock -from kordac.KordacExtension import KordacExtension -from kordac.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor +from verto.tests.ProcessorTest import ProcessorTest class BoxedTextTest(ProcessorTest): @@ -24,7 +24,7 @@ def test_no_boxed_text(self): self.assertListEqual([False, False, False, False], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'no_boxed_text_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -34,7 +34,7 @@ def test_single_boxed_text(self): self.assertListEqual([True, False, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'single_boxed_text_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -44,7 +44,7 @@ def test_indented_boxed_text(self): self.assertListEqual([True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'indented_boxed_text_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -54,7 +54,7 @@ def test_multiple_boxed_text(self): self.assertListEqual([True, False, True, False, True, False, True, False], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'multiple_boxed_text_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -64,7 +64,7 @@ def test_recursive_boxed_text(self): self.assertListEqual([True, False, True, False, True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'recursive_boxed_text_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -78,7 +78,7 @@ def test_doc_example_basic(self): self.assertListEqual([True, False, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -89,8 +89,8 @@ def test_doc_example_override_html(self): self.assertListEqual([True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) + verto_extension = VertoExtension([self.processor_name], html_templates={self.processor_name: html_template}) - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) diff --git a/kordac/tests/ButtonLinkTest.py b/verto/tests/ButtonLinkTest.py similarity index 90% rename from kordac/tests/ButtonLinkTest.py rename to verto/tests/ButtonLinkTest.py index 70a943ca..cbc87b20 100644 --- a/kordac/tests/ButtonLinkTest.py +++ b/verto/tests/ButtonLinkTest.py @@ -1,9 +1,9 @@ import markdown from unittest.mock import Mock -from kordac.KordacExtension import KordacExtension -from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.GenericTagBlockProcessor import GenericTagBlockProcessor +from verto.tests.ProcessorTest import ProcessorTest class ButtonLinkTest(ProcessorTest): @@ -23,7 +23,7 @@ def test_no_button(self): blocks = self.to_blocks(test_string) self.assertListEqual([False] * 7, [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'no_button_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -33,7 +33,7 @@ def test_contains_button(self): self.assertListEqual([False, True, False], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_button_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -43,7 +43,7 @@ def test_contains_missing_button(self): self.assertListEqual([False, False, False], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'missing_end_brace_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -53,7 +53,7 @@ def test_contains_multiple_buttons(self): self.assertListEqual([False, True, False, False, True, False, False, True, False, False , True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_multiple_buttons_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -64,7 +64,7 @@ def test_contains_file_link_button(self): self.assertListEqual([False, True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_file_link_button_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -79,7 +79,7 @@ def test_doc_example_basic(self): self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -89,7 +89,7 @@ def test_doc_example_file(self): self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_file_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -99,7 +99,7 @@ def test_doc_example_file(self): self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_file_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -110,8 +110,8 @@ def test_doc_example_override_html(self): self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) + verto_extension = VertoExtension([self.processor_name], html_templates={self.processor_name: html_template}) - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) diff --git a/kordac/tests/CommentTest.py b/verto/tests/CommentTest.py similarity index 90% rename from kordac/tests/CommentTest.py rename to verto/tests/CommentTest.py index 06492a78..1922a11c 100644 --- a/kordac/tests/CommentTest.py +++ b/verto/tests/CommentTest.py @@ -1,9 +1,9 @@ import markdown from unittest.mock import Mock -from kordac.KordacExtension import KordacExtension -from kordac.processors.CommentPreprocessor import CommentPreprocessor -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.CommentPreprocessor import CommentPreprocessor +from verto.tests.ProcessorTest import ProcessorTest class CommentTest(ProcessorTest): """ @@ -22,7 +22,7 @@ def test_no_inline_comment(self): self.assertFalse(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'no_inline_comment_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -31,7 +31,7 @@ def test_text_contains_the_word_comment(self): self.assertFalse(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'text_contains_the_word_comment_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -40,7 +40,7 @@ def tests_contains_inline_comment(self): self.assertTrue(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_inline_comment_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -50,7 +50,7 @@ def test_contains_multiple_inline_comments(self): self.assertTrue(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_multiple_inline_comments_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -60,7 +60,7 @@ def test_comment_contains_comment(self): self.assertFalse(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'comment_contains_comment_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -73,7 +73,7 @@ def test_doc_example_basic(self): self.assertTrue(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -82,6 +82,6 @@ def test_doc_example_multiple(self): self.assertTrue(CommentPreprocessor(self.ext, self.md.parser).test(test_string), msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_multiple_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) diff --git a/kordac/tests/ConditionalTest.py b/verto/tests/ConditionalTest.py similarity index 86% rename from kordac/tests/ConditionalTest.py rename to verto/tests/ConditionalTest.py index 4234fd46..99e73cba 100644 --- a/kordac/tests/ConditionalTest.py +++ b/verto/tests/ConditionalTest.py @@ -1,9 +1,9 @@ import markdown from unittest.mock import Mock -from kordac.KordacExtension import KordacExtension -from kordac.processors.ConditionalProcessor import ConditionalProcessor -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.ConditionalProcessor import ConditionalProcessor +from verto.tests.ProcessorTest import ProcessorTest class ConditionalTest(ProcessorTest): @@ -21,7 +21,7 @@ def test_example_basic_else(self): self.assertListEqual([True, False, True, False, True], [ConditionalProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'example_basic_else_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -35,7 +35,7 @@ def test_doc_example_basic(self): self.assertListEqual([True, False, True], [ConditionalProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -45,7 +45,7 @@ def test_doc_example_complex(self): self.assertListEqual([True, False, True, False, True, False, True, False, True], [ConditionalProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_complex_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -56,9 +56,9 @@ def test_doc_example_override_html(self): self.assertListEqual([True, False, True, False, True, False, True], [ConditionalProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) + verto_extension = VertoExtension([self.processor_name], html_templates={self.processor_name: html_template}) - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -70,8 +70,8 @@ def test_doc_example2_override_html(self): self.assertListEqual([True, False, True, False, True, False, True], [ConditionalProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example2_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) + verto_extension = VertoExtension([self.processor_name], html_templates={self.processor_name: html_template}) - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example2_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) diff --git a/kordac/tests/ConfigurationTest.py b/verto/tests/ConfigurationTest.py similarity index 78% rename from kordac/tests/ConfigurationTest.py rename to verto/tests/ConfigurationTest.py index 5d57fb5c..0796f8c5 100644 --- a/kordac/tests/ConfigurationTest.py +++ b/verto/tests/ConfigurationTest.py @@ -1,14 +1,14 @@ import unittest -from kordac.Kordac import Kordac, KordacResult -from kordac.utils.HeadingNode import HeadingNode +from verto.Verto import Verto, VertoResult +from verto.utils.HeadingNode import HeadingNode import jinja2 -from kordac.tests.BaseTest import BaseTest +from verto.tests.BaseTest import BaseTest from collections import defaultdict class ConfigurationTest(BaseTest): - """Test configuration methods of Kordac + """Test configuration methods of Verto - These are not true unit tests, as they create the complete Kordac system, + These are not true unit tests, as they create the complete Verto system, however we are using the unittest framework for ease of use and simplicity of our testing suite. """ @@ -29,10 +29,10 @@ def __init__(self, *args, **kwargs): } def test_multiple_calls(self): - """Checks all fields of KordacResult are correct for multiple Kordac calls""" + """Checks all fields of VertoResult are correct for multiple Verto calls""" test_cases = [ ('all_processors.md', - KordacResult( + VertoResult( html_string=self.read_test_file(self.test_name, 'all_processors_expected.html', strip=True), title='Example Title', required_files={ @@ -51,7 +51,7 @@ def test_multiple_calls(self): ) ), ('some_processors.md', - KordacResult( + VertoResult( html_string=self.read_test_file(self.test_name, 'some_processors_expected.html', strip=True), title='Another Example Title', required_files={ @@ -78,7 +78,7 @@ def test_multiple_calls(self): ) ), ('some_processors_2.md', - KordacResult( + VertoResult( html_string=self.read_test_file(self.test_name, 'some_processors_2_expected.html', strip=True), title='Another Example Title', required_files={ @@ -110,84 +110,84 @@ def test_multiple_calls(self): ] for test in test_cases: - kordac = Kordac() + verto = Verto() test_string = self.read_test_file(self.test_name, test[0]) - kordac_result = kordac.convert(test_string) + verto_result = verto.convert(test_string) - self.assertEqual(kordac_result.title, test[1].title) - self.assertEqual(kordac_result.required_files, test[1].required_files) - self.assertTupleEqual(kordac_result.heading_tree, test[1].heading_tree) - self.assertDictEqual(kordac_result.required_glossary_terms, test[1].required_glossary_terms) + self.assertEqual(verto_result.title, test[1].title) + self.assertEqual(verto_result.required_files, test[1].required_files) + self.assertTupleEqual(verto_result.heading_tree, test[1].heading_tree) + self.assertDictEqual(verto_result.required_glossary_terms, test[1].required_glossary_terms) def test_default_processors_on_creation(self): """Checks if all expected default processors work on default creation""" - kordac = Kordac() - # kordac.clear_templates() + verto = Verto() + # verto.clear_templates() test_string = self.read_test_file(self.test_name, 'all_processors.md') - converted_test_string = kordac.convert(test_string).html_string + converted_test_string = verto.convert(test_string).html_string expected_string = self.read_test_file(self.test_name, 'all_processors_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) def test_custom_processors_on_creation(self): """Checks if system only uses specified processsors""" processors = {'panel', 'image'} - kordac = Kordac(processors=processors) + verto = Verto(processors=processors) test_string = self.read_test_file(self.test_name, 'all_processors.md') - converted_test_string = kordac.convert(test_string).html_string + converted_test_string = verto.convert(test_string).html_string expected_string = self.read_test_file(self.test_name, 'custom_processors_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) def test_custom_processors_after_creation(self): """Checks if extension correct changes processors""" - kordac = Kordac() - processors = Kordac.processor_defaults() + verto = Verto() + processors = Verto.processor_defaults() processors.add('example_processor') processors.remove('comment') - kordac.update_processors(processors) + verto.update_processors(processors) # Check example_processor is now stored in extension processors - self.assertEqual(kordac.kordac_extension.processors, processors) + self.assertEqual(verto.verto_extension.processors, processors) # Check comments are now skipped test_string = self.read_test_file(self.test_name, 'all_processors.md') - converted_test_string = kordac.convert(test_string).html_string + converted_test_string = verto.convert(test_string).html_string expected_string = self.read_test_file(self.test_name, 'all_processors_except_comment_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) def test_unique_custom_processors(self): """Checks if unique processors are stored when duplicates provided""" processors = ['comment', 'comment', 'comment'] - kordac = Kordac(processors=processors) - self.assertEqual(kordac.kordac_extension.processors, set(processors)) - processors = list(Kordac.processor_defaults()) + verto = Verto(processors=processors) + self.assertEqual(verto.verto_extension.processors, set(processors)) + processors = list(Verto.processor_defaults()) processors.append('example_processor') processors.append('example_processor') processors.append('example_processor') - kordac.update_processors(processors) - self.assertTrue(kordac.kordac_extension.processors, processors) + verto.update_processors(processors) + self.assertTrue(verto.verto_extension.processors, processors) def test_custom_templates_on_creation(self): """Checks custom templates are used when given on creation""" - kordac = Kordac(html_templates=self.custom_templates) + verto = Verto(html_templates=self.custom_templates) test_string = self.read_test_file(self.test_name, 'all_processors.md') - converted_test_string = kordac.convert(test_string).html_string + converted_test_string = verto.convert(test_string).html_string expected_string = self.read_test_file(self.test_name, 'all_processors_custom_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) def test_custom_templates_after_creation(self): """Checks custom templates are used when given after creation""" - kordac = Kordac() - kordac.update_templates(self.custom_templates) + verto = Verto() + verto.update_templates(self.custom_templates) test_string = self.read_test_file(self.test_name, 'all_processors.md') - converted_test_string = kordac.convert(test_string).html_string + converted_test_string = verto.convert(test_string).html_string expected_string = self.read_test_file(self.test_name, 'all_processors_custom_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) def test_reset_templates_after_custom(self): """Checks custom templates are reset when given at creation""" - kordac = Kordac(html_templates=self.custom_templates) - kordac.clear_templates() + verto = Verto(html_templates=self.custom_templates) + verto.clear_templates() test_string = self.read_test_file(self.test_name, 'all_processors.md') - converted_test_string = kordac.convert(test_string).html_string + converted_test_string = verto.convert(test_string).html_string expected_string = self.read_test_file(self.test_name, 'all_processors_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -209,8 +209,8 @@ def test_multiline_custom_templates(self): """ } - kordac = Kordac(html_templates=custom_templates) + verto = Verto(html_templates=custom_templates) test_string = self.read_test_file(self.test_name, 'all_processors.md') - converted_test_string = kordac.convert(test_string).html_string + converted_test_string = verto.convert(test_string).html_string expected_string = self.read_test_file(self.test_name, 'multiline_templates_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) diff --git a/kordac/tests/FrameTest.py b/verto/tests/FrameTest.py similarity index 80% rename from kordac/tests/FrameTest.py rename to verto/tests/FrameTest.py index e891f4dd..4331bd0c 100644 --- a/kordac/tests/FrameTest.py +++ b/verto/tests/FrameTest.py @@ -1,10 +1,10 @@ import markdown from unittest.mock import Mock -from kordac.KordacExtension import KordacExtension -from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor -from kordac.processors.errors.ArgumentMissingError import ArgumentMissingError -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.GenericTagBlockProcessor import GenericTagBlockProcessor +from verto.processors.errors.ArgumentMissingError import ArgumentMissingError +from verto.tests.ProcessorTest import ProcessorTest class FrameTest(ProcessorTest): @@ -23,7 +23,7 @@ def test_example_no_link(self): self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) with self.assertRaises(ArgumentMissingError): - markdown.markdown(test_string, extensions=[self.kordac_extension]) + markdown.markdown(test_string, extensions=[self.verto_extension]) #~ # Doc Tests @@ -35,7 +35,7 @@ def test_doc_example_basic(self): self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -46,8 +46,8 @@ def test_doc_example_override_html(self): self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) + verto_extension = VertoExtension([self.processor_name], html_templates={self.processor_name: html_template}) - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) diff --git a/kordac/tests/GlossaryLinkTest.py b/verto/tests/GlossaryLinkTest.py similarity index 86% rename from kordac/tests/GlossaryLinkTest.py rename to verto/tests/GlossaryLinkTest.py index e3f5775f..4916985e 100644 --- a/kordac/tests/GlossaryLinkTest.py +++ b/verto/tests/GlossaryLinkTest.py @@ -1,9 +1,9 @@ import markdown import re from unittest.mock import Mock -from kordac.KordacExtension import KordacExtension -from kordac.processors.GlossaryLinkPattern import GlossaryLinkPattern -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.GlossaryLinkPattern import GlossaryLinkPattern +from verto.tests.ProcessorTest import ProcessorTest class GlossaryLinkTest(ProcessorTest): @@ -22,11 +22,11 @@ def test_single_word_term(self): processor = GlossaryLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'single_word_term_expected.html', strip=True).strip() self.assertEqual(expected_string, converted_test_string) - glossary_terms = self.kordac_extension.glossary_terms + glossary_terms = self.verto_extension.glossary_terms expected_glossary_terms = dict() self.assertDictEqual(expected_glossary_terms, glossary_terms) @@ -36,11 +36,11 @@ def test_multiple_word_term(self): processor = GlossaryLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'multiple_word_term_expected.html', strip=True).strip() self.assertEqual(expected_string, converted_test_string) - glossary_terms = self.kordac_extension.glossary_terms + glossary_terms = self.verto_extension.glossary_terms expected_glossary_terms = dict() self.assertDictEqual(expected_glossary_terms, glossary_terms) @@ -50,11 +50,11 @@ def test_reference_text_given(self): processor = GlossaryLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'reference_text_given_expected.html', strip=True).strip() self.assertEqual(expected_string, converted_test_string) - glossary_terms = self.kordac_extension.glossary_terms + glossary_terms = self.verto_extension.glossary_terms expected_glossary_terms = { 'chomsky-hierarchy': [('Formal languages', 'glossary-chomsky-hierarchy')] @@ -67,11 +67,11 @@ def test_leading_inline_text(self): processor = GlossaryLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'leading_inline_text_expected.html', strip=True).strip() self.assertEqual(expected_string, converted_test_string) - glossary_terms = self.kordac_extension.glossary_terms + glossary_terms = self.verto_extension.glossary_terms expected_glossary_terms = dict() self.assertDictEqual(expected_glossary_terms, glossary_terms) @@ -81,11 +81,11 @@ def test_trailing_inline_text(self): processor = GlossaryLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'trailing_inline_text_expected.html', strip=True).strip() self.assertEqual(expected_string, converted_test_string) - glossary_terms = self.kordac_extension.glossary_terms + glossary_terms = self.verto_extension.glossary_terms expected_glossary_terms = dict() self.assertDictEqual(expected_glossary_terms, glossary_terms) @@ -95,11 +95,11 @@ def test_leading_and_trailing_inline_text(self): processor = GlossaryLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'leading_and_trailing_inline_text_expected.html', strip=True).strip() self.assertEqual(expected_string, converted_test_string) - glossary_terms = self.kordac_extension.glossary_terms + glossary_terms = self.verto_extension.glossary_terms expected_glossary_terms = dict() self.assertDictEqual(expected_glossary_terms, glossary_terms) @@ -109,11 +109,11 @@ def test_multiple_terms(self): processor = GlossaryLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'multiple_terms_expected.html', strip=True).strip() self.assertEqual(expected_string, converted_test_string) - glossary_terms = self.kordac_extension.glossary_terms + glossary_terms = self.verto_extension.glossary_terms expected_glossary_terms = { 'finite-state-automaton': [('Formal languages', 'glossary-finite-state-automaton')] @@ -126,11 +126,11 @@ def test_multiple_reference_text(self): processor = GlossaryLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'multiple_reference_text_expected.html', strip=True).strip() self.assertEqual(expected_string, converted_test_string) - glossary_terms = self.kordac_extension.glossary_terms + glossary_terms = self.verto_extension.glossary_terms expected_glossary_terms = { 'algorithm': [('computer program', 'glossary-algorithm'), @@ -150,11 +150,11 @@ def test_doc_example_basic(self): processor = GlossaryLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True).strip() self.assertEqual(expected_string, converted_test_string) - glossary_terms = self.kordac_extension.glossary_terms + glossary_terms = self.verto_extension.glossary_terms expected_glossary_terms = dict() self.assertDictEqual(expected_glossary_terms, glossary_terms) @@ -165,13 +165,13 @@ def test_doc_example_override_html(self): self.assertIsNotNone(re.search(processor.compiled_re, test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) + verto_extension = VertoExtension([self.processor_name], html_templates={self.processor_name: html_template}) - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True).strip() self.assertEqual(expected_string, converted_test_string) - glossary_terms = kordac_extension.glossary_terms + glossary_terms = verto_extension.glossary_terms expected_glossary_terms = { 'algorithm': [('Software Engineering', 'glossary-algorithm')] diff --git a/kordac/tests/HeadingTest.py b/verto/tests/HeadingTest.py similarity index 91% rename from kordac/tests/HeadingTest.py rename to verto/tests/HeadingTest.py index 89196f94..38913cc6 100644 --- a/kordac/tests/HeadingTest.py +++ b/verto/tests/HeadingTest.py @@ -2,10 +2,10 @@ import markdown from unittest.mock import Mock -from kordac.KordacExtension import KordacExtension -from kordac.processors.HeadingBlockProcessor import HeadingBlockProcessor -from kordac.tests.ProcessorTest import ProcessorTest -from kordac.utils.HeadingNode import HeadingNode +from verto.VertoExtension import VertoExtension +from verto.processors.HeadingBlockProcessor import HeadingBlockProcessor +from verto.tests.ProcessorTest import ProcessorTest +from verto.utils.HeadingNode import HeadingNode class HeadingTest(ProcessorTest): @@ -22,11 +22,11 @@ def test_example_blank(self): self.assertListEqual([False], [HeadingBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'example_blank_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - tree = self.kordac_extension.get_heading_tree() + tree = self.verto_extension.get_heading_tree() self.assertIsNone(tree) def test_single_heading(self): @@ -35,11 +35,11 @@ def test_single_heading(self): self.assertListEqual([True], [HeadingBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'example_single_heading_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - tree = self.kordac_extension.get_heading_tree() + tree = self.verto_extension.get_heading_tree() expected_tree = ( HeadingNode(title='Heading One', title_slug='heading-one', @@ -59,11 +59,11 @@ def test_doc_example_basic(self): self.assertListEqual([True, True, True], [HeadingBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - tree = self.kordac_extension.get_heading_tree() + tree = self.verto_extension.get_heading_tree() expected_tree = (HeadingNode(title='This is an H1', title_slug='this-is-an-h1', level=1, @@ -94,13 +94,13 @@ def test_doc_example_override_html(self): self.assertListEqual([True, True, True, True, True, True, True], [HeadingBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) + verto_extension = VertoExtension([self.processor_name], html_templates={self.processor_name: html_template}) - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - tree = kordac_extension.get_heading_tree() + tree = verto_extension.get_heading_tree() expected_tree = (HeadingNode(title='This is an H1', title_slug='this-is-an-h1', level=1, @@ -155,13 +155,13 @@ def test_multiple_roots_zero_level(self): self.assertListEqual([True, True, True, True, True, True, True], [HeadingBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) + verto_extension = VertoExtension([self.processor_name], html_templates={self.processor_name: html_template}) - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'multiple_roots_zero_level_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - tree = kordac_extension.get_heading_tree() + tree = verto_extension.get_heading_tree() expected_tree = (HeadingNode(title='This is an H4', title_slug='this-is-an-h4', level=4, diff --git a/kordac/tests/ImageTest.py b/verto/tests/ImageTest.py similarity index 86% rename from kordac/tests/ImageTest.py rename to verto/tests/ImageTest.py index 33d1be63..b88631a4 100644 --- a/kordac/tests/ImageTest.py +++ b/verto/tests/ImageTest.py @@ -2,9 +2,9 @@ from unittest.mock import Mock from collections import defaultdict -from kordac.KordacExtension import KordacExtension -from kordac.processors.ImageBlockProcessor import ImageBlockProcessor -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.ImageBlockProcessor import ImageBlockProcessor +from verto.tests.ProcessorTest import ProcessorTest class ImageTest(ProcessorTest): @@ -23,11 +23,11 @@ def test_internal_image(self): self.assertListEqual([False, True, False], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'internal_image_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = { 'pixel-diamond.png' } @@ -39,7 +39,7 @@ def test_external_image(self): self.assertListEqual([True, False], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'external_image_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -49,11 +49,11 @@ def test_default_image(self): self.assertListEqual([True, False], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'default_image_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = { 'computer-studying-turing-test.png' } @@ -65,11 +65,11 @@ def test_contains_multiple_images(self): self.assertListEqual([False, True, False, True, False, True, False], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_multiple_images_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = { 'finite-state-automata-no-trap-example.png', 'finite-state-automata-trap-added-example.png', @@ -83,11 +83,11 @@ def test_no_image(self): self.assertListEqual([False], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'no_image_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = set() self.assertSetEqual(expected_images, images) @@ -97,11 +97,11 @@ def test_text_contains_the_word_image(self): self.assertListEqual([False], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'text_contains_the_word_image_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = set() self.assertSetEqual(expected_images, images) @@ -111,11 +111,11 @@ def test_contains_image_and_text_contains_word_image(self): self.assertListEqual([False, True, False], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_image_and_text_contains_word_image_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = { 'pixel-diamond.png' } @@ -127,11 +127,11 @@ def test_contains_hover_text(self): self.assertListEqual([True], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_hover_text_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = { 'computer-studying-turing-test.png' } @@ -143,11 +143,11 @@ def test_contains_caption_link(self): self.assertListEqual([True], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_caption_link_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = { 'computer-studying-turing-test.png' } @@ -159,11 +159,11 @@ def test_contains_alt(self): self.assertListEqual([True], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_alt_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = { 'computer-studying-turing-test.png' } @@ -175,11 +175,11 @@ def test_contains_caption(self): self.assertListEqual([True], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_caption_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = { 'computer-studying-turing-test.png' } @@ -191,11 +191,11 @@ def test_contains_source(self): self.assertListEqual([True], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_source_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = { 'computer-studying-turing-test.png' } @@ -207,11 +207,11 @@ def test_align_left(self): self.assertListEqual([True], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'align_left_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = { 'computer-studying-turing-test.png' } @@ -223,11 +223,11 @@ def test_align_right(self): self.assertListEqual([True], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'align_right_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = { 'computer-studying-turing-test.png' } @@ -239,11 +239,11 @@ def test_align_center(self): self.assertListEqual([True], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'align_center_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = { 'computer-studying-turing-test.png' } @@ -259,9 +259,9 @@ def test_internal_image_required(self): self.assertListEqual([False, True, False], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = { 'pixel-diamond.png' } @@ -273,9 +273,9 @@ def test_multiple_internal_image_required(self): self.assertListEqual([False, True, True, True, False], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = { 'pixel-diamond.png', 'Lipsum.png' @@ -292,11 +292,11 @@ def test_doc_example_basic(self): self.assertListEqual([True], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = set() self.assertSetEqual(expected_images, images) @@ -307,13 +307,13 @@ def test_doc_example_override_html(self): self.assertListEqual([True], [ImageBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) + verto_extension = VertoExtension([self.processor_name], html_templates={self.processor_name: html_template}) - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = set() self.assertSetEqual(expected_images, images) @@ -325,12 +325,12 @@ def test_doc_example_2_override_html(self): html_template = self.read_test_file(self.processor_name, 'doc_example_2_override_html_template.html', strip=True) link_template = self.read_test_file(self.processor_name, 'doc_example_2_override_link_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template, 'relative-file-link': link_template}) + verto_extension = VertoExtension([self.processor_name], html_templates={self.processor_name: html_template, 'relative-file-link': link_template}) - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_2_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - images = self.kordac_extension.required_files['images'] + images = self.verto_extension.required_files['images'] expected_images = set() self.assertSetEqual(expected_images, images) diff --git a/kordac/tests/InteractiveTest.py b/verto/tests/InteractiveTest.py similarity index 87% rename from kordac/tests/InteractiveTest.py rename to verto/tests/InteractiveTest.py index dfeed2fa..84e71ba5 100644 --- a/kordac/tests/InteractiveTest.py +++ b/verto/tests/InteractiveTest.py @@ -2,9 +2,9 @@ from unittest.mock import Mock from collections import defaultdict -from kordac.KordacExtension import KordacExtension -from kordac.processors.InteractiveBlockProcessor import InteractiveBlockProcessor -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.InteractiveBlockProcessor import InteractiveBlockProcessor +from verto.tests.ProcessorTest import ProcessorTest class InteractiveTest(ProcessorTest): @@ -23,7 +23,7 @@ def test_doc_example_in_page(self): self.assertListEqual([True], [InteractiveBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_in_page_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -33,7 +33,7 @@ def test_doc_example_whole_page(self): self.assertListEqual([True], [InteractiveBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_whole_page_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -43,7 +43,7 @@ def test_doc_example_iframe(self): self.assertListEqual([True], [InteractiveBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_iframe_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -54,8 +54,8 @@ def test_doc_example_override_html(self): self.assertListEqual([True], [InteractiveBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) + verto_extension = VertoExtension([self.processor_name], html_templates={self.processor_name: html_template}) - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) diff --git a/kordac/tests/PanelTest.py b/verto/tests/PanelTest.py similarity index 89% rename from kordac/tests/PanelTest.py rename to verto/tests/PanelTest.py index 4cadc0ac..bd74024c 100644 --- a/kordac/tests/PanelTest.py +++ b/verto/tests/PanelTest.py @@ -1,10 +1,10 @@ import markdown from unittest.mock import Mock -from kordac.KordacExtension import KordacExtension -from kordac.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor -from kordac.processors.errors.TagNotMatchedError import TagNotMatchedError -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor +from verto.processors.errors.TagNotMatchedError import TagNotMatchedError +from verto.tests.ProcessorTest import ProcessorTest class PanelTest(ProcessorTest): @@ -23,7 +23,7 @@ def test_parses_blank(self): self.assertListEqual([True, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'parses_blank_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -33,7 +33,7 @@ def test_parses_no_blank_lines_single_paragraph(self): self.assertListEqual([True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'parses_no_blank_lines_single_paragraph_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -43,7 +43,7 @@ def test_parses_expanded_panel(self): self.assertListEqual([True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'parses_expanded_panel_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -53,7 +53,7 @@ def test_parses_always_expanded_panel(self): self.assertListEqual([True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'parses_always_expanded_panel_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -63,7 +63,7 @@ def test_parses_blank_lines_multiple_paragraphs(self): self.assertListEqual([True, False, False, False, False, False, False, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'parses_blank_lines_multiple_paragraphs_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -73,7 +73,7 @@ def test_contains_multiple_panels(self): self.assertListEqual([True, False, False, True, True, False, True, True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_multiple_panels_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -83,7 +83,7 @@ def test_contains_inner_panel(self): self.assertListEqual([True, False, True, False, True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'contains_inner_panel_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -93,7 +93,7 @@ def test_missing_start_tag(self): self.assertListEqual([True, False, True, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - self.assertRaises(TagNotMatchedError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) + self.assertRaises(TagNotMatchedError, lambda x: markdown.markdown(x, extensions=[self.verto_extension]), test_string) def test_missing_end_tag(self): test_string = self.read_test_file(self.processor_name, 'missing_end_tag.md') @@ -101,7 +101,7 @@ def test_missing_end_tag(self): self.assertListEqual([True, False, True, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - self.assertRaises(TagNotMatchedError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) + self.assertRaises(TagNotMatchedError, lambda x: markdown.markdown(x, extensions=[self.verto_extension]), test_string) def test_missing_tag_inner(self): test_string = self.read_test_file(self.processor_name, 'missing_tag_inner.md') @@ -109,7 +109,7 @@ def test_missing_tag_inner(self): self.assertListEqual([True, True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - self.assertRaises(TagNotMatchedError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) + self.assertRaises(TagNotMatchedError, lambda x: markdown.markdown(x, extensions=[self.verto_extension]), test_string) #~ # Doc Tests @@ -121,7 +121,7 @@ def test_doc_example_basic(self): self.assertListEqual([True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -132,8 +132,8 @@ def test_doc_example_override_html(self): self.assertListEqual([True, False, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) + verto_extension = VertoExtension([self.processor_name], html_templates={self.processor_name: html_template}) - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) diff --git a/kordac/tests/ProcessorTest.py b/verto/tests/ProcessorTest.py similarity index 75% rename from kordac/tests/ProcessorTest.py rename to verto/tests/ProcessorTest.py index 901e5886..c01088a1 100644 --- a/kordac/tests/ProcessorTest.py +++ b/verto/tests/ProcessorTest.py @@ -1,10 +1,10 @@ import unittest import json import markdown -from kordac.KordacExtension import KordacExtension +from verto.VertoExtension import VertoExtension from markdown.extensions import Extension from jinja2 import Environment, PackageLoader, select_autoescape -from kordac.tests.BaseTest import BaseTest +from verto.tests.BaseTest import BaseTest class ProcessorTest(BaseTest): """A base test class for individual test classes""" @@ -20,14 +20,14 @@ def __init__(self, *args, **kwargs): def loadJinjaTemplate(self, template): env = Environment( - loader=PackageLoader('kordac', 'html-templates'), + loader=PackageLoader('verto', 'html-templates'), autoescape=select_autoescape(['html']) ) jinja_template = env.get_template(template + '.html') return jinja_template def loadProcessorInfo(self): - pattern_data = open('kordac/processor-info.json').read() + pattern_data = open('verto/processor-info.json').read() return json.loads(pattern_data) def to_blocks(self, string): @@ -38,8 +38,8 @@ def to_blocks(self, string): return string.split('\n\n') def setUp(self): - self.kordac_extension = KordacExtension([self.processor_name], {}) - self.md = markdown.Markdown(extensions=[self.kordac_extension]) + self.verto_extension = VertoExtension([self.processor_name], {}) + self.md = markdown.Markdown(extensions=[self.verto_extension]) def tearDown(self): self.md = None diff --git a/kordac/tests/RelativeLinkTest.py b/verto/tests/RelativeLinkTest.py similarity index 92% rename from kordac/tests/RelativeLinkTest.py rename to verto/tests/RelativeLinkTest.py index 24b38397..4f0778ac 100644 --- a/kordac/tests/RelativeLinkTest.py +++ b/verto/tests/RelativeLinkTest.py @@ -1,9 +1,9 @@ import markdown import re from unittest.mock import Mock -from kordac.KordacExtension import KordacExtension -from kordac.processors.RelativeLinkPattern import RelativeLinkPattern -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.RelativeLinkPattern import RelativeLinkPattern +from verto.tests.ProcessorTest import ProcessorTest class RelativeLinkTest(ProcessorTest): """Tests to check the 'relative-link' pattern works as intended.""" @@ -22,7 +22,7 @@ def test_basic_usage(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True).strip() self.assertEqual(expected_string, converted_test_string) @@ -32,7 +32,7 @@ def test_long_path(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + 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) @@ -42,7 +42,7 @@ def test_multiple_links(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + 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) @@ -52,7 +52,7 @@ def test_ignore_http_schema(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + 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) @@ -62,7 +62,7 @@ def test_http_text(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + 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) @@ -72,7 +72,7 @@ def test_ignore_https_schema(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + 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) @@ -82,7 +82,7 @@ def test_https_text(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + 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) @@ -92,7 +92,7 @@ def test_ignore_ftp_schema(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + 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) @@ -102,7 +102,7 @@ def test_ftp_text(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + 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) @@ -112,7 +112,7 @@ def test_ignore_ftps_schema(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + 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) @@ -122,7 +122,7 @@ def test_ftps_text(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + 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) @@ -132,7 +132,7 @@ def test_ignore_mailto_schema(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + 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) @@ -142,7 +142,7 @@ def test_mailto_text(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + 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) @@ -153,7 +153,7 @@ def test_ignore_news_schema(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + 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) @@ -163,7 +163,7 @@ def test_news_text(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + 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) @@ -173,6 +173,6 @@ def test_www_text(self): processor = RelativeLinkPattern(self.ext, self.md.parser) self.assertIsNotNone(re.search(processor.compiled_re, test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + 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) diff --git a/kordac/tests/RemoveTitleTest.py b/verto/tests/RemoveTitleTest.py similarity index 88% rename from kordac/tests/RemoveTitleTest.py rename to verto/tests/RemoveTitleTest.py index 33b3eb57..29244b9d 100644 --- a/kordac/tests/RemoveTitleTest.py +++ b/verto/tests/RemoveTitleTest.py @@ -1,8 +1,8 @@ import markdown from unittest.mock import Mock -from kordac.KordacExtension import KordacExtension -from kordac.processors.RemoveTitlePreprocessor import RemoveTitlePreprocessor -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.RemoveTitlePreprocessor import RemoveTitlePreprocessor +from verto.tests.ProcessorTest import ProcessorTest class RemoveTitleTest(ProcessorTest): """Tests to check the 'remove-title' preprocesser works as intended.""" @@ -20,7 +20,7 @@ def test_basic_usage(self): processor = RemoveTitlePreprocessor(self.ext, self.md.parser) self.assertTrue(processor.test(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -30,7 +30,7 @@ def test_multiple_headings(self): processor = RemoveTitlePreprocessor(self.ext, self.md.parser) self.assertTrue(processor.test(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'multiple_headings_expected.html', strip=True).strip() self.assertEqual(expected_string, converted_test_string) @@ -40,7 +40,7 @@ def test_multiple_level_one_headings(self): processor = RemoveTitlePreprocessor(self.ext, self.md.parser) self.assertTrue(processor.test(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'multiple_level_one_headings_expected.html', strip=True).strip() self.assertEqual(expected_string, converted_test_string) @@ -50,7 +50,7 @@ def test_no_headings(self): processor = RemoveTitlePreprocessor(self.ext, self.md.parser) self.assertFalse(processor.test(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'no_headings_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -60,7 +60,7 @@ def test_level_two_heading(self): processor = RemoveTitlePreprocessor(self.ext, self.md.parser) self.assertTrue(processor.test(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'level_two_heading_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -70,7 +70,7 @@ def test_no_heading_permalink(self): processor = RemoveTitlePreprocessor(self.ext, self.md.parser) self.assertFalse(processor.test(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'no_heading_permalink_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -80,7 +80,7 @@ def test_no_space_title(self): processor = RemoveTitlePreprocessor(self.ext, self.md.parser) self.assertTrue(processor.test(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'no_space_title_expected.html', strip=True).strip() self.assertEqual(expected_string, converted_test_string) @@ -88,10 +88,10 @@ def test_no_space_title(self): # SYSTEM TESTS def test_processor_off(self): - # Create Kordac extension without processor enabled (off by default) - kordac_extension = KordacExtension() + # Create Verto extension without processor enabled (off by default) + verto_extension = VertoExtension() test_string = self.read_test_file(self.processor_name, 'processor_off.md') - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'processor_off_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) diff --git a/kordac/tests/SaveTitleTest.py b/verto/tests/SaveTitleTest.py similarity index 76% rename from kordac/tests/SaveTitleTest.py rename to verto/tests/SaveTitleTest.py index d9d21fa8..a05a567d 100644 --- a/kordac/tests/SaveTitleTest.py +++ b/verto/tests/SaveTitleTest.py @@ -1,8 +1,8 @@ import markdown from unittest.mock import Mock -from kordac.KordacExtension import KordacExtension -from kordac.processors.SaveTitlePreprocessor import SaveTitlePreprocessor -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.SaveTitlePreprocessor import SaveTitlePreprocessor +from verto.tests.ProcessorTest import ProcessorTest class SaveTitleTest(ProcessorTest): """Tests to check the 'save-title' preprocesser works as intended.""" @@ -20,9 +20,9 @@ def test_basic_usage(self): processor = SaveTitlePreprocessor(self.ext, self.md.parser) self.assertTrue(processor.test(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True).strip() - self.assertEqual(expected_string, self.kordac_extension.title) + self.assertEqual(expected_string, self.verto_extension.title) def test_multiple_headings(self): test_string = self.read_test_file(self.processor_name, 'multiple_headings.md') @@ -30,9 +30,9 @@ def test_multiple_headings(self): processor = SaveTitlePreprocessor(self.ext, self.md.parser) self.assertTrue(processor.test(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'multiple_headings_expected.html', strip=True).strip() - self.assertEqual(expected_string, self.kordac_extension.title) + self.assertEqual(expected_string, self.verto_extension.title) def test_multiple_level_one_headings(self): test_string = self.read_test_file(self.processor_name, 'multiple_level_one_headings.md') @@ -40,9 +40,9 @@ def test_multiple_level_one_headings(self): processor = SaveTitlePreprocessor(self.ext, self.md.parser) self.assertTrue(processor.test(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'multiple_level_one_headings_expected.html', strip=True).strip() - self.assertEqual(expected_string, self.kordac_extension.title) + self.assertEqual(expected_string, self.verto_extension.title) def test_no_headings(self): test_string = self.read_test_file(self.processor_name, 'no_headings.md') @@ -50,8 +50,8 @@ def test_no_headings(self): processor = SaveTitlePreprocessor(self.ext, self.md.parser) self.assertFalse(processor.test(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) - self.assertIsNone(self.kordac_extension.title) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + self.assertIsNone(self.verto_extension.title) def test_level_two_heading(self): test_string = self.read_test_file(self.processor_name, 'level_two_heading.md') @@ -59,9 +59,9 @@ def test_level_two_heading(self): processor = SaveTitlePreprocessor(self.ext, self.md.parser) self.assertTrue(processor.test(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'level_two_heading_expected.html', strip=True).strip() - self.assertEqual(expected_string, self.kordac_extension.title) + self.assertEqual(expected_string, self.verto_extension.title) def test_no_heading_permalink(self): test_string = self.read_test_file(self.processor_name, 'no_heading_permalink.md') @@ -69,8 +69,8 @@ def test_no_heading_permalink(self): processor = SaveTitlePreprocessor(self.ext, self.md.parser) self.assertFalse(processor.test(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) - self.assertIsNone(self.kordac_extension.title) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) + self.assertIsNone(self.verto_extension.title) def test_no_space_title(self): test_string = self.read_test_file(self.processor_name, 'no_space_title.md') @@ -78,16 +78,16 @@ def test_no_space_title(self): processor = SaveTitlePreprocessor(self.ext, self.md.parser) self.assertTrue(processor.test(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'no_space_title_expected.html', strip=True).strip() - self.assertEqual(expected_string, self.kordac_extension.title) + self.assertEqual(expected_string, self.verto_extension.title) # SYSTEM TESTS def test_no_result_processor_off(self): - # Create Kordac extension without processor enabled - kordac_extension = KordacExtension() + # Create Verto extension without processor enabled + verto_extension = VertoExtension() test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) - self.assertIsNone(kordac_extension.title) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) + self.assertIsNone(verto_extension.title) diff --git a/kordac/tests/ScratchTest.py b/verto/tests/ScratchTest.py similarity index 83% rename from kordac/tests/ScratchTest.py rename to verto/tests/ScratchTest.py index e1a196fd..149a7a37 100644 --- a/kordac/tests/ScratchTest.py +++ b/verto/tests/ScratchTest.py @@ -2,9 +2,9 @@ from unittest.mock import Mock from collections import defaultdict -from kordac.KordacExtension import KordacExtension -from kordac.processors.ScratchTreeprocessor import ScratchTreeprocessor, ScratchImageMetaData -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.ScratchTreeprocessor import ScratchTreeprocessor, ScratchImageMetaData +from verto.tests.ProcessorTest import ProcessorTest class ScratchTest(ProcessorTest): def __init__(self, *args, **kwargs): @@ -12,19 +12,19 @@ def __init__(self, *args, **kwargs): self.processor_name = 'scratch' def setUp(self): - self.kordac_extension = KordacExtension([self.processor_name], {}, ['markdown.extensions.fenced_code']) + self.verto_extension = VertoExtension([self.processor_name], {}, ['markdown.extensions.fenced_code']) #~ # Doc Tests #~ def test_doc_example_basic(self): test_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage.md') - converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) # Should really test result a better way - actual = self.kordac_extension.required_files['scratch_images'] + actual = self.verto_extension.required_files['scratch_images'] expected = { ScratchImageMetaData( hash='a0f8fcad796864abfacac8bda6e0719813833fd1fca348700abbd040557c1576', @@ -37,13 +37,13 @@ def test_doc_example_override_html(self): test_string = self.read_test_file(self.processor_name, 'doc_example_override_html.md') html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}, extensions=['markdown.extensions.fenced_code']) + verto_extension = VertoExtension([self.processor_name], html_templates={self.processor_name: html_template}, extensions=['markdown.extensions.fenced_code']) - converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', verto_extension]) 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 = kordac_extension.required_files['scratch_images'] + actual = verto_extension.required_files['scratch_images'] expected = { ScratchImageMetaData( hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', @@ -56,15 +56,15 @@ def test_doc_example_override_html(self): # Other Tests #~ def test_example_standard_markdown_block(self): - kordac_extension = KordacExtension([self.processor_name], {}, []) + verto_extension = VertoExtension([self.processor_name], {}, []) test_string = self.read_test_file(self.processor_name, 'example_standard_markdown_block.md') - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'example_standard_markdown_block_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) # Should really test result a better way - actual = kordac_extension.required_files['scratch_images'] + actual = verto_extension.required_files['scratch_images'] expected = { ScratchImageMetaData( hash='a0f8fcad796864abfacac8bda6e0719813833fd1fca348700abbd040557c1576', @@ -76,12 +76,12 @@ def test_example_standard_markdown_block(self): def test_example_separate_blocks(self): test_string = self.read_test_file(self.processor_name, 'example_separate_blocks.md') - converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.kordac_extension]) + 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_separate_blocks_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) # Should really test result a better way - actual = self.kordac_extension.required_files['scratch_images'] + actual = self.verto_extension.required_files['scratch_images'] expected = { ScratchImageMetaData( hash='8e8a2129c3cecf32101248439961735fc1d45793fadc56e2575673f63d42b9fb', @@ -94,12 +94,12 @@ def test_example_separate_blocks(self): def test_example_multiple_codeblocks(self): test_string = self.read_test_file(self.processor_name, 'example_multiple_codeblocks.md') - converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.kordac_extension]) + 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_multiple_codeblocks_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) # Should really test result a better way - actual = self.kordac_extension.required_files['scratch_images'] + actual = self.verto_extension.required_files['scratch_images'] expected = { ScratchImageMetaData( hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', @@ -118,15 +118,15 @@ def test_example_multiple_codeblocks(self): def test_example_multiple_codeblocks_2(self): extensions = ['markdown.extensions.codehilite', 'markdown.extensions.fenced_code'] - kordac_extension = KordacExtension([self.processor_name], {}, extensions) + verto_extension = VertoExtension([self.processor_name], {}, extensions) test_string = self.read_test_file(self.processor_name, 'example_multiple_codeblocks_2.md') - converted_test_string = markdown.markdown(test_string, extensions=extensions + [kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=extensions + [verto_extension]) expected_string = self.read_test_file(self.processor_name, 'example_multiple_codeblocks_expected_2.html', strip=True) self.assertEqual(expected_string, converted_test_string) # Should really test result a better way - actual = kordac_extension.required_files['scratch_images'] + actual = verto_extension.required_files['scratch_images'] expected = { ScratchImageMetaData( hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', @@ -146,12 +146,12 @@ def test_example_multiple_codeblocks_2(self): def test_example_other_code(self): test_string = self.read_test_file(self.processor_name, 'example_other_code.md') - converted_test_string = markdown.markdown(test_string, extensions=['markdown.extensions.fenced_code', self.kordac_extension]) + 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) # Should really test result a better way - actual = self.kordac_extension.required_files['scratch_images'] + actual = self.verto_extension.required_files['scratch_images'] expected = { ScratchImageMetaData( hash='a0f8fcad796864abfacac8bda6e0719813833fd1fca348700abbd040557c1576', diff --git a/kordac/tests/SmokeTests.py b/verto/tests/SmokeTests.py similarity index 86% rename from kordac/tests/SmokeTests.py rename to verto/tests/SmokeTests.py index c73d4421..9768de1e 100644 --- a/kordac/tests/SmokeTests.py +++ b/verto/tests/SmokeTests.py @@ -1,5 +1,5 @@ import unittest, os, subprocess -from kordac import Kordac +from verto import Verto class SmokeDocsTest(unittest.TestCase): """Tests that docs build if they are found.""" @@ -39,25 +39,25 @@ def test_compile_docs(self): self.assertEqual(p.returncode, 0) # Success returncode class SmokeFileTest(unittest.TestCase): - """Tests opening of files and that kordac generates some output.""" + """Tests opening of files and that verto generates some output.""" def __init__(self, *args, **kwargs): unittest.TestCase.__init__(self, *args, **kwargs) self.maxDiff = None - self.kordac = None - self.assets_template = 'kordac/tests/assets/smoke/{}' + self.verto = None + self.assets_template = 'verto/tests/assets/smoke/{}' def setUp(self): - self.kordac = Kordac() + self.verto = Verto() def tearDown(self): - self.kordac = None + self.verto = None def test_compile_files(self): for chapter in ['algorithms.md', 'introduction.md']: with open(self.assets_template.format(chapter), 'r') as f: text = f.read() - result = self.kordac.convert(text) + result = self.verto.convert(text) self.assertIsNot(result, None) self.assertIsNot(result.title, None) @@ -70,11 +70,11 @@ def test_compile_files_custom(self): 'boxed-text': '
    ' } - kordac = Kordac(html_templates=custom_templates) + verto = Verto(html_templates=custom_templates) for chapter in ['algorithms.md', 'introduction.md']: with open(self.assets_template.format(chapter), 'r') as f: text = f.read() - result = kordac.convert(text) + result = verto.convert(text) self.assertIsNot(result, None) self.assertIsNot(result.title, None) diff --git a/kordac/tests/TableOfContentsTest.py b/verto/tests/TableOfContentsTest.py similarity index 83% rename from kordac/tests/TableOfContentsTest.py rename to verto/tests/TableOfContentsTest.py index 5d3dd5f4..80682b2e 100644 --- a/kordac/tests/TableOfContentsTest.py +++ b/verto/tests/TableOfContentsTest.py @@ -1,9 +1,9 @@ import markdown from unittest.mock import Mock -from kordac.KordacExtension import KordacExtension -from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.GenericTagBlockProcessor import GenericTagBlockProcessor +from verto.tests.ProcessorTest import ProcessorTest class TableOfContentsTest(ProcessorTest): @@ -24,7 +24,7 @@ def test_doc_example_basic(self): self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -35,8 +35,8 @@ def test_doc_example_override_html(self): self.assertListEqual([True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) + verto_extension = VertoExtension([self.processor_name], html_templates={self.processor_name: html_template}) - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) diff --git a/kordac/tests/VideoTest.py b/verto/tests/VideoTest.py similarity index 88% rename from kordac/tests/VideoTest.py rename to verto/tests/VideoTest.py index 87c0583c..2f7896e6 100644 --- a/kordac/tests/VideoTest.py +++ b/verto/tests/VideoTest.py @@ -1,12 +1,12 @@ import markdown from unittest.mock import Mock -from kordac.KordacExtension import KordacExtension -from kordac.processors.VideoBlockProcessor import VideoBlockProcessor -from kordac.processors.errors.NoSourceLinkError import NoSourceLinkError -from kordac.processors.errors.NoVideoIdentifierError import NoVideoIdentifierError -from kordac.processors.errors.UnsupportedVideoPlayerError import UnsupportedVideoPlayerError -from kordac.tests.ProcessorTest import ProcessorTest +from verto.VertoExtension import VertoExtension +from verto.processors.VideoBlockProcessor import VideoBlockProcessor +from verto.processors.errors.NoSourceLinkError import NoSourceLinkError +from verto.processors.errors.NoVideoIdentifierError import NoVideoIdentifierError +from verto.processors.errors.UnsupportedVideoPlayerError import UnsupportedVideoPlayerError +from verto.tests.ProcessorTest import ProcessorTest class VideoTest(ProcessorTest): @@ -29,7 +29,7 @@ def test_contains_no_video(self): self.assertFalse(all(VideoBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks), msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_file_string = self.read_test_file(self.processor_name, 'contains_no_video_expected.html', strip=True) self.assertEqual(converted_test_string, expected_file_string) @@ -39,7 +39,7 @@ def test_youtube_embed_link(self): self.assertListEqual([False, True, False, False, False, False], [VideoBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_file_string = self.read_test_file(self.processor_name, 'youtube_embed_link_expected.html', strip=True) self.assertEqual(converted_test_string, expected_file_string) @@ -50,7 +50,7 @@ def test_youtube_watch_link(self): self.assertListEqual([False, False, False, False, False, True, False], [VideoBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_file_string = self.read_test_file(self.processor_name, 'youtube_watch_link_expected.html', strip=True) self.assertEqual(converted_test_string, expected_file_string) @@ -60,7 +60,7 @@ def test_youtube_be_link(self): self.assertListEqual([False, True, False], [VideoBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_file_string = self.read_test_file(self.processor_name, 'youtube_be_link_expected.html', strip=True) self.assertEqual(converted_test_string, expected_file_string) @@ -70,7 +70,7 @@ def test_vimeo_link(self): self.assertListEqual([False, False, True, False, False, False], [VideoBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_file_string = self.read_test_file(self.processor_name, 'vimeo_link_expected.html', strip=True) self.assertEqual(converted_test_string, expected_file_string) @@ -80,7 +80,7 @@ def test_vimeo_player_link(self): self.assertListEqual([False, False, True, False, False, False], [VideoBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_file_string = self.read_test_file(self.processor_name, 'vimeo_player_link_expected.html', strip=True) self.assertEqual(converted_test_string, expected_file_string) @@ -90,7 +90,7 @@ def test_multiple_youtube_links(self): self.assertListEqual([False, False, True, False, True, False, True, False, True, False, True], [VideoBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_file_string = self.read_test_file(self.processor_name, 'multiple_youtube_links_expected.html', strip=True) self.assertEqual(converted_test_string, expected_file_string) @@ -100,7 +100,7 @@ def test_multiple_vimeo_links(self): self.assertListEqual([True, True, True], [VideoBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_file_string = self.read_test_file(self.processor_name, 'multiple_vimeo_links_expected.html', strip=True) self.assertEqual(converted_test_string, expected_file_string) @@ -110,7 +110,7 @@ def test_youtube_and_vimeo_links(self): self.assertListEqual([False, False, True, True, False, True, False, True, False, True, True, False, True, True], [VideoBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_file_string = self.read_test_file(self.processor_name, 'youtube_and_vimeo_links_expected.html', strip=True) self.assertEqual(converted_test_string, expected_file_string) @@ -120,7 +120,7 @@ def test_unsupported_video_type(self): self.assertListEqual([False, False, True], [VideoBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - self.assertRaises(UnsupportedVideoPlayerError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) + self.assertRaises(UnsupportedVideoPlayerError, lambda x: markdown.markdown(x, extensions=[self.verto_extension]), test_string) def test_missing_identifier(self): test_string = self.read_test_file(self.processor_name, 'missing_identifier.md') @@ -128,7 +128,7 @@ def test_missing_identifier(self): self.assertListEqual([False, True, False], [VideoBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - self.assertRaises(NoVideoIdentifierError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]), test_string) + self.assertRaises(NoVideoIdentifierError, lambda x: markdown.markdown(x, extensions=[self.verto_extension]), test_string) #~ @@ -141,7 +141,7 @@ def test_doc_example_basic(self): self.assertListEqual([True], [VideoBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[self.verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_basic_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) @@ -152,9 +152,9 @@ def test_doc_example_override_html(self): self.assertListEqual([True], [VideoBlockProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) html_template = self.read_test_file(self.processor_name, 'doc_example_override_html_template.html', strip=True) - kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) + verto_extension = VertoExtension([self.processor_name], html_templates={self.processor_name: html_template}) - converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) + converted_test_string = markdown.markdown(test_string, extensions=[verto_extension]) expected_string = self.read_test_file(self.processor_name, 'doc_example_override_html_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) diff --git a/kordac/tests/__init__.py b/verto/tests/__init__.py similarity index 100% rename from kordac/tests/__init__.py rename to verto/tests/__init__.py diff --git a/kordac/tests/assets/beautify/example_inline_code.md b/verto/tests/assets/beautify/example_inline_code.md similarity index 100% rename from kordac/tests/assets/beautify/example_inline_code.md rename to verto/tests/assets/beautify/example_inline_code.md diff --git a/kordac/tests/assets/beautify/example_inline_code_expected.html b/verto/tests/assets/beautify/example_inline_code_expected.html similarity index 100% rename from kordac/tests/assets/beautify/example_inline_code_expected.html rename to verto/tests/assets/beautify/example_inline_code_expected.html diff --git a/kordac/tests/assets/beautify/example_mixed_code_types.md b/verto/tests/assets/beautify/example_mixed_code_types.md similarity index 100% rename from kordac/tests/assets/beautify/example_mixed_code_types.md rename to verto/tests/assets/beautify/example_mixed_code_types.md diff --git a/kordac/tests/assets/beautify/example_mixed_code_types_expected.html b/verto/tests/assets/beautify/example_mixed_code_types_expected.html similarity index 100% rename from kordac/tests/assets/beautify/example_mixed_code_types_expected.html rename to verto/tests/assets/beautify/example_mixed_code_types_expected.html diff --git a/kordac/tests/assets/beautify/example_preformatted_code.md b/verto/tests/assets/beautify/example_preformatted_code.md similarity index 100% rename from kordac/tests/assets/beautify/example_preformatted_code.md rename to verto/tests/assets/beautify/example_preformatted_code.md diff --git a/kordac/tests/assets/beautify/example_preformatted_code_expected.html b/verto/tests/assets/beautify/example_preformatted_code_expected.html similarity index 100% rename from kordac/tests/assets/beautify/example_preformatted_code_expected.html rename to verto/tests/assets/beautify/example_preformatted_code_expected.html diff --git a/kordac/tests/assets/beautify/example_preformatted_code_with_extension.md b/verto/tests/assets/beautify/example_preformatted_code_with_extension.md similarity index 100% rename from kordac/tests/assets/beautify/example_preformatted_code_with_extension.md rename to verto/tests/assets/beautify/example_preformatted_code_with_extension.md diff --git a/kordac/tests/assets/beautify/example_preformatted_code_with_extension_expected.html b/verto/tests/assets/beautify/example_preformatted_code_with_extension_expected.html similarity index 100% rename from kordac/tests/assets/beautify/example_preformatted_code_with_extension_expected.html rename to verto/tests/assets/beautify/example_preformatted_code_with_extension_expected.html diff --git a/kordac/tests/assets/boxed-text/doc_example_basic_usage.md b/verto/tests/assets/boxed-text/doc_example_basic_usage.md similarity index 100% rename from kordac/tests/assets/boxed-text/doc_example_basic_usage.md rename to verto/tests/assets/boxed-text/doc_example_basic_usage.md diff --git a/kordac/tests/assets/boxed-text/doc_example_basic_usage_expected.html b/verto/tests/assets/boxed-text/doc_example_basic_usage_expected.html similarity index 100% rename from kordac/tests/assets/boxed-text/doc_example_basic_usage_expected.html rename to verto/tests/assets/boxed-text/doc_example_basic_usage_expected.html diff --git a/kordac/tests/assets/boxed-text/doc_example_override_html.md b/verto/tests/assets/boxed-text/doc_example_override_html.md similarity index 100% rename from kordac/tests/assets/boxed-text/doc_example_override_html.md rename to verto/tests/assets/boxed-text/doc_example_override_html.md diff --git a/kordac/tests/assets/boxed-text/doc_example_override_html_expected.html b/verto/tests/assets/boxed-text/doc_example_override_html_expected.html similarity index 100% rename from kordac/tests/assets/boxed-text/doc_example_override_html_expected.html rename to verto/tests/assets/boxed-text/doc_example_override_html_expected.html diff --git a/kordac/tests/assets/boxed-text/doc_example_override_html_template.html b/verto/tests/assets/boxed-text/doc_example_override_html_template.html similarity index 100% rename from kordac/tests/assets/boxed-text/doc_example_override_html_template.html rename to verto/tests/assets/boxed-text/doc_example_override_html_template.html diff --git a/kordac/tests/assets/boxed-text/indented_boxed_text.md b/verto/tests/assets/boxed-text/indented_boxed_text.md similarity index 100% rename from kordac/tests/assets/boxed-text/indented_boxed_text.md rename to verto/tests/assets/boxed-text/indented_boxed_text.md diff --git a/kordac/tests/assets/boxed-text/indented_boxed_text_expected.html b/verto/tests/assets/boxed-text/indented_boxed_text_expected.html similarity index 100% rename from kordac/tests/assets/boxed-text/indented_boxed_text_expected.html rename to verto/tests/assets/boxed-text/indented_boxed_text_expected.html diff --git a/kordac/tests/assets/boxed-text/multiple_boxed_text.md b/verto/tests/assets/boxed-text/multiple_boxed_text.md similarity index 100% rename from kordac/tests/assets/boxed-text/multiple_boxed_text.md rename to verto/tests/assets/boxed-text/multiple_boxed_text.md diff --git a/kordac/tests/assets/boxed-text/multiple_boxed_text_expected.html b/verto/tests/assets/boxed-text/multiple_boxed_text_expected.html similarity index 100% rename from kordac/tests/assets/boxed-text/multiple_boxed_text_expected.html rename to verto/tests/assets/boxed-text/multiple_boxed_text_expected.html diff --git a/kordac/tests/assets/boxed-text/no_boxed_text.md b/verto/tests/assets/boxed-text/no_boxed_text.md similarity index 100% rename from kordac/tests/assets/boxed-text/no_boxed_text.md rename to verto/tests/assets/boxed-text/no_boxed_text.md diff --git a/kordac/tests/assets/boxed-text/no_boxed_text_expected.html b/verto/tests/assets/boxed-text/no_boxed_text_expected.html similarity index 100% rename from kordac/tests/assets/boxed-text/no_boxed_text_expected.html rename to verto/tests/assets/boxed-text/no_boxed_text_expected.html diff --git a/kordac/tests/assets/boxed-text/recursive_boxed_text.md b/verto/tests/assets/boxed-text/recursive_boxed_text.md similarity index 100% rename from kordac/tests/assets/boxed-text/recursive_boxed_text.md rename to verto/tests/assets/boxed-text/recursive_boxed_text.md diff --git a/kordac/tests/assets/boxed-text/recursive_boxed_text_expected.html b/verto/tests/assets/boxed-text/recursive_boxed_text_expected.html similarity index 100% rename from kordac/tests/assets/boxed-text/recursive_boxed_text_expected.html rename to verto/tests/assets/boxed-text/recursive_boxed_text_expected.html diff --git a/kordac/tests/assets/boxed-text/single_boxed_text.md b/verto/tests/assets/boxed-text/single_boxed_text.md similarity index 100% rename from kordac/tests/assets/boxed-text/single_boxed_text.md rename to verto/tests/assets/boxed-text/single_boxed_text.md diff --git a/kordac/tests/assets/boxed-text/single_boxed_text_expected.html b/verto/tests/assets/boxed-text/single_boxed_text_expected.html similarity index 100% rename from kordac/tests/assets/boxed-text/single_boxed_text_expected.html rename to verto/tests/assets/boxed-text/single_boxed_text_expected.html diff --git a/kordac/tests/assets/button-link/contains_button.md b/verto/tests/assets/button-link/contains_button.md similarity index 100% rename from kordac/tests/assets/button-link/contains_button.md rename to verto/tests/assets/button-link/contains_button.md diff --git a/kordac/tests/assets/button-link/contains_button_expected.html b/verto/tests/assets/button-link/contains_button_expected.html similarity index 100% rename from kordac/tests/assets/button-link/contains_button_expected.html rename to verto/tests/assets/button-link/contains_button_expected.html diff --git a/kordac/tests/assets/button-link/contains_file_link_button.md b/verto/tests/assets/button-link/contains_file_link_button.md similarity index 100% rename from kordac/tests/assets/button-link/contains_file_link_button.md rename to verto/tests/assets/button-link/contains_file_link_button.md diff --git a/kordac/tests/assets/button-link/contains_file_link_button_expected.html b/verto/tests/assets/button-link/contains_file_link_button_expected.html similarity index 100% rename from kordac/tests/assets/button-link/contains_file_link_button_expected.html rename to verto/tests/assets/button-link/contains_file_link_button_expected.html diff --git a/kordac/tests/assets/button-link/contains_multiple_buttons.md b/verto/tests/assets/button-link/contains_multiple_buttons.md similarity index 100% rename from kordac/tests/assets/button-link/contains_multiple_buttons.md rename to verto/tests/assets/button-link/contains_multiple_buttons.md diff --git a/kordac/tests/assets/button-link/contains_multiple_buttons_expected.html b/verto/tests/assets/button-link/contains_multiple_buttons_expected.html similarity index 100% rename from kordac/tests/assets/button-link/contains_multiple_buttons_expected.html rename to verto/tests/assets/button-link/contains_multiple_buttons_expected.html diff --git a/kordac/tests/assets/button-link/doc_example_basic_usage.md b/verto/tests/assets/button-link/doc_example_basic_usage.md similarity index 100% rename from kordac/tests/assets/button-link/doc_example_basic_usage.md rename to verto/tests/assets/button-link/doc_example_basic_usage.md diff --git a/kordac/tests/assets/button-link/doc_example_basic_usage_expected.html b/verto/tests/assets/button-link/doc_example_basic_usage_expected.html similarity index 100% rename from kordac/tests/assets/button-link/doc_example_basic_usage_expected.html rename to verto/tests/assets/button-link/doc_example_basic_usage_expected.html diff --git a/kordac/tests/assets/button-link/doc_example_file_usage.md b/verto/tests/assets/button-link/doc_example_file_usage.md similarity index 100% rename from kordac/tests/assets/button-link/doc_example_file_usage.md rename to verto/tests/assets/button-link/doc_example_file_usage.md diff --git a/kordac/tests/assets/button-link/doc_example_file_usage_expected.html b/verto/tests/assets/button-link/doc_example_file_usage_expected.html similarity index 100% rename from kordac/tests/assets/button-link/doc_example_file_usage_expected.html rename to verto/tests/assets/button-link/doc_example_file_usage_expected.html diff --git a/verto/tests/assets/button-link/doc_example_override_html.md b/verto/tests/assets/button-link/doc_example_override_html.md new file mode 100644 index 00000000..c585e663 --- /dev/null +++ b/verto/tests/assets/button-link/doc_example_override_html.md @@ -0,0 +1 @@ +{button-link link="https://github.com/uccser/verto" text="Verto on GitHub"} diff --git a/verto/tests/assets/button-link/doc_example_override_html_expected.html b/verto/tests/assets/button-link/doc_example_override_html_expected.html new file mode 100644 index 00000000..677abcd3 --- /dev/null +++ b/verto/tests/assets/button-link/doc_example_override_html_expected.html @@ -0,0 +1,3 @@ + + Verto on GitHub + diff --git a/kordac/tests/assets/button-link/doc_example_override_html_template.html b/verto/tests/assets/button-link/doc_example_override_html_template.html similarity index 100% rename from kordac/tests/assets/button-link/doc_example_override_html_template.html rename to verto/tests/assets/button-link/doc_example_override_html_template.html diff --git a/kordac/tests/assets/button-link/missing_end_brace.md b/verto/tests/assets/button-link/missing_end_brace.md similarity index 100% rename from kordac/tests/assets/button-link/missing_end_brace.md rename to verto/tests/assets/button-link/missing_end_brace.md diff --git a/kordac/tests/assets/button-link/missing_end_brace_expected.html b/verto/tests/assets/button-link/missing_end_brace_expected.html similarity index 100% rename from kordac/tests/assets/button-link/missing_end_brace_expected.html rename to verto/tests/assets/button-link/missing_end_brace_expected.html diff --git a/kordac/tests/assets/button-link/no_button.md b/verto/tests/assets/button-link/no_button.md similarity index 100% rename from kordac/tests/assets/button-link/no_button.md rename to verto/tests/assets/button-link/no_button.md diff --git a/kordac/tests/assets/button-link/no_button_expected.html b/verto/tests/assets/button-link/no_button_expected.html similarity index 100% rename from kordac/tests/assets/button-link/no_button_expected.html rename to verto/tests/assets/button-link/no_button_expected.html diff --git a/kordac/tests/assets/comment/comment_contains_comment.md b/verto/tests/assets/comment/comment_contains_comment.md similarity index 100% rename from kordac/tests/assets/comment/comment_contains_comment.md rename to verto/tests/assets/comment/comment_contains_comment.md diff --git a/kordac/tests/assets/comment/comment_contains_comment_expected.html b/verto/tests/assets/comment/comment_contains_comment_expected.html similarity index 100% rename from kordac/tests/assets/comment/comment_contains_comment_expected.html rename to verto/tests/assets/comment/comment_contains_comment_expected.html diff --git a/kordac/tests/assets/comment/contains_inline_comment.md b/verto/tests/assets/comment/contains_inline_comment.md similarity index 100% rename from kordac/tests/assets/comment/contains_inline_comment.md rename to verto/tests/assets/comment/contains_inline_comment.md diff --git a/kordac/tests/assets/comment/contains_inline_comment_expected.html b/verto/tests/assets/comment/contains_inline_comment_expected.html similarity index 100% rename from kordac/tests/assets/comment/contains_inline_comment_expected.html rename to verto/tests/assets/comment/contains_inline_comment_expected.html diff --git a/kordac/tests/assets/comment/contains_multiple_inline_comments.md b/verto/tests/assets/comment/contains_multiple_inline_comments.md similarity index 100% rename from kordac/tests/assets/comment/contains_multiple_inline_comments.md rename to verto/tests/assets/comment/contains_multiple_inline_comments.md diff --git a/kordac/tests/assets/comment/contains_multiple_inline_comments_expected.html b/verto/tests/assets/comment/contains_multiple_inline_comments_expected.html similarity index 100% rename from kordac/tests/assets/comment/contains_multiple_inline_comments_expected.html rename to verto/tests/assets/comment/contains_multiple_inline_comments_expected.html diff --git a/kordac/tests/assets/comment/doc_example_basic_usage.md b/verto/tests/assets/comment/doc_example_basic_usage.md similarity index 100% rename from kordac/tests/assets/comment/doc_example_basic_usage.md rename to verto/tests/assets/comment/doc_example_basic_usage.md diff --git a/kordac/tests/assets/comment/doc_example_basic_usage_expected.html b/verto/tests/assets/comment/doc_example_basic_usage_expected.html similarity index 100% rename from kordac/tests/assets/comment/doc_example_basic_usage_expected.html rename to verto/tests/assets/comment/doc_example_basic_usage_expected.html diff --git a/kordac/tests/assets/comment/doc_example_multiple_usage.md b/verto/tests/assets/comment/doc_example_multiple_usage.md similarity index 100% rename from kordac/tests/assets/comment/doc_example_multiple_usage.md rename to verto/tests/assets/comment/doc_example_multiple_usage.md diff --git a/kordac/tests/assets/comment/doc_example_multiple_usage_expected.html b/verto/tests/assets/comment/doc_example_multiple_usage_expected.html similarity index 100% rename from kordac/tests/assets/comment/doc_example_multiple_usage_expected.html rename to verto/tests/assets/comment/doc_example_multiple_usage_expected.html diff --git a/kordac/tests/assets/comment/no_inline_comment.md b/verto/tests/assets/comment/no_inline_comment.md similarity index 100% rename from kordac/tests/assets/comment/no_inline_comment.md rename to verto/tests/assets/comment/no_inline_comment.md diff --git a/kordac/tests/assets/comment/no_inline_comment_expected.html b/verto/tests/assets/comment/no_inline_comment_expected.html similarity index 100% rename from kordac/tests/assets/comment/no_inline_comment_expected.html rename to verto/tests/assets/comment/no_inline_comment_expected.html diff --git a/kordac/tests/assets/comment/text_contains_the_word_comment.md b/verto/tests/assets/comment/text_contains_the_word_comment.md similarity index 100% rename from kordac/tests/assets/comment/text_contains_the_word_comment.md rename to verto/tests/assets/comment/text_contains_the_word_comment.md diff --git a/kordac/tests/assets/comment/text_contains_the_word_comment_expected.html b/verto/tests/assets/comment/text_contains_the_word_comment_expected.html similarity index 100% rename from kordac/tests/assets/comment/text_contains_the_word_comment_expected.html rename to verto/tests/assets/comment/text_contains_the_word_comment_expected.html diff --git a/kordac/tests/assets/conditional/doc_example2_override_html.md b/verto/tests/assets/conditional/doc_example2_override_html.md similarity index 100% rename from kordac/tests/assets/conditional/doc_example2_override_html.md rename to verto/tests/assets/conditional/doc_example2_override_html.md diff --git a/kordac/tests/assets/conditional/doc_example2_override_html_expected.html b/verto/tests/assets/conditional/doc_example2_override_html_expected.html similarity index 100% rename from kordac/tests/assets/conditional/doc_example2_override_html_expected.html rename to verto/tests/assets/conditional/doc_example2_override_html_expected.html diff --git a/kordac/tests/assets/conditional/doc_example2_override_html_template.html b/verto/tests/assets/conditional/doc_example2_override_html_template.html similarity index 100% rename from kordac/tests/assets/conditional/doc_example2_override_html_template.html rename to verto/tests/assets/conditional/doc_example2_override_html_template.html diff --git a/kordac/tests/assets/conditional/doc_example_basic_usage.md b/verto/tests/assets/conditional/doc_example_basic_usage.md similarity index 100% rename from kordac/tests/assets/conditional/doc_example_basic_usage.md rename to verto/tests/assets/conditional/doc_example_basic_usage.md diff --git a/kordac/tests/assets/conditional/doc_example_basic_usage_expected.html b/verto/tests/assets/conditional/doc_example_basic_usage_expected.html similarity index 100% rename from kordac/tests/assets/conditional/doc_example_basic_usage_expected.html rename to verto/tests/assets/conditional/doc_example_basic_usage_expected.html diff --git a/kordac/tests/assets/conditional/doc_example_complex_usage.md b/verto/tests/assets/conditional/doc_example_complex_usage.md similarity index 100% rename from kordac/tests/assets/conditional/doc_example_complex_usage.md rename to verto/tests/assets/conditional/doc_example_complex_usage.md diff --git a/kordac/tests/assets/conditional/doc_example_complex_usage_expected.html b/verto/tests/assets/conditional/doc_example_complex_usage_expected.html similarity index 100% rename from kordac/tests/assets/conditional/doc_example_complex_usage_expected.html rename to verto/tests/assets/conditional/doc_example_complex_usage_expected.html diff --git a/kordac/tests/assets/conditional/doc_example_override_html.md b/verto/tests/assets/conditional/doc_example_override_html.md similarity index 100% rename from kordac/tests/assets/conditional/doc_example_override_html.md rename to verto/tests/assets/conditional/doc_example_override_html.md diff --git a/kordac/tests/assets/conditional/doc_example_override_html_expected.html b/verto/tests/assets/conditional/doc_example_override_html_expected.html similarity index 100% rename from kordac/tests/assets/conditional/doc_example_override_html_expected.html rename to verto/tests/assets/conditional/doc_example_override_html_expected.html diff --git a/kordac/tests/assets/conditional/doc_example_override_html_template.html b/verto/tests/assets/conditional/doc_example_override_html_template.html similarity index 100% rename from kordac/tests/assets/conditional/doc_example_override_html_template.html rename to verto/tests/assets/conditional/doc_example_override_html_template.html diff --git a/kordac/tests/assets/conditional/example_basic_else_usage.md b/verto/tests/assets/conditional/example_basic_else_usage.md similarity index 100% rename from kordac/tests/assets/conditional/example_basic_else_usage.md rename to verto/tests/assets/conditional/example_basic_else_usage.md diff --git a/kordac/tests/assets/conditional/example_basic_else_usage_expected.html b/verto/tests/assets/conditional/example_basic_else_usage_expected.html similarity index 100% rename from kordac/tests/assets/conditional/example_basic_else_usage_expected.html rename to verto/tests/assets/conditional/example_basic_else_usage_expected.html diff --git a/kordac/tests/assets/configuration/all_processors.md b/verto/tests/assets/configuration/all_processors.md similarity index 100% rename from kordac/tests/assets/configuration/all_processors.md rename to verto/tests/assets/configuration/all_processors.md diff --git a/kordac/tests/assets/configuration/all_processors_custom_expected.html b/verto/tests/assets/configuration/all_processors_custom_expected.html similarity index 100% rename from kordac/tests/assets/configuration/all_processors_custom_expected.html rename to verto/tests/assets/configuration/all_processors_custom_expected.html diff --git a/kordac/tests/assets/configuration/all_processors_custom_html_expected.html b/verto/tests/assets/configuration/all_processors_custom_html_expected.html similarity index 100% rename from kordac/tests/assets/configuration/all_processors_custom_html_expected.html rename to verto/tests/assets/configuration/all_processors_custom_html_expected.html diff --git a/kordac/tests/assets/configuration/all_processors_except_comment_expected.html b/verto/tests/assets/configuration/all_processors_except_comment_expected.html similarity index 100% rename from kordac/tests/assets/configuration/all_processors_except_comment_expected.html rename to verto/tests/assets/configuration/all_processors_except_comment_expected.html diff --git a/kordac/tests/assets/configuration/all_processors_expected.html b/verto/tests/assets/configuration/all_processors_expected.html similarity index 100% rename from kordac/tests/assets/configuration/all_processors_expected.html rename to verto/tests/assets/configuration/all_processors_expected.html diff --git a/kordac/tests/assets/configuration/custom_processors_expected.html b/verto/tests/assets/configuration/custom_processors_expected.html similarity index 100% rename from kordac/tests/assets/configuration/custom_processors_expected.html rename to verto/tests/assets/configuration/custom_processors_expected.html diff --git a/kordac/tests/assets/configuration/multiline_templates_expected.html b/verto/tests/assets/configuration/multiline_templates_expected.html similarity index 100% rename from kordac/tests/assets/configuration/multiline_templates_expected.html rename to verto/tests/assets/configuration/multiline_templates_expected.html diff --git a/kordac/tests/assets/configuration/some_processors.md b/verto/tests/assets/configuration/some_processors.md similarity index 100% rename from kordac/tests/assets/configuration/some_processors.md rename to verto/tests/assets/configuration/some_processors.md diff --git a/kordac/tests/assets/configuration/some_processors_2.md b/verto/tests/assets/configuration/some_processors_2.md similarity index 100% rename from kordac/tests/assets/configuration/some_processors_2.md rename to verto/tests/assets/configuration/some_processors_2.md diff --git a/kordac/tests/assets/configuration/some_processors_2_expected.html b/verto/tests/assets/configuration/some_processors_2_expected.html similarity index 100% rename from kordac/tests/assets/configuration/some_processors_2_expected.html rename to verto/tests/assets/configuration/some_processors_2_expected.html diff --git a/kordac/tests/assets/configuration/some_processors_expected.html b/verto/tests/assets/configuration/some_processors_expected.html similarity index 100% rename from kordac/tests/assets/configuration/some_processors_expected.html rename to verto/tests/assets/configuration/some_processors_expected.html diff --git a/kordac/tests/assets/glossary-link/doc_example_basic_usage.md b/verto/tests/assets/glossary-link/doc_example_basic_usage.md similarity index 100% rename from kordac/tests/assets/glossary-link/doc_example_basic_usage.md rename to verto/tests/assets/glossary-link/doc_example_basic_usage.md diff --git a/kordac/tests/assets/glossary-link/doc_example_basic_usage_expected.html b/verto/tests/assets/glossary-link/doc_example_basic_usage_expected.html similarity index 100% rename from kordac/tests/assets/glossary-link/doc_example_basic_usage_expected.html rename to verto/tests/assets/glossary-link/doc_example_basic_usage_expected.html diff --git a/kordac/tests/assets/glossary-link/doc_example_override_html.md b/verto/tests/assets/glossary-link/doc_example_override_html.md similarity index 100% rename from kordac/tests/assets/glossary-link/doc_example_override_html.md rename to verto/tests/assets/glossary-link/doc_example_override_html.md diff --git a/kordac/tests/assets/glossary-link/doc_example_override_html_expected.html b/verto/tests/assets/glossary-link/doc_example_override_html_expected.html similarity index 100% rename from kordac/tests/assets/glossary-link/doc_example_override_html_expected.html rename to verto/tests/assets/glossary-link/doc_example_override_html_expected.html diff --git a/kordac/tests/assets/glossary-link/doc_example_override_html_template.html b/verto/tests/assets/glossary-link/doc_example_override_html_template.html similarity index 100% rename from kordac/tests/assets/glossary-link/doc_example_override_html_template.html rename to verto/tests/assets/glossary-link/doc_example_override_html_template.html diff --git a/kordac/tests/assets/glossary-link/leading_and_trailing_inline_text.md b/verto/tests/assets/glossary-link/leading_and_trailing_inline_text.md similarity index 100% rename from kordac/tests/assets/glossary-link/leading_and_trailing_inline_text.md rename to verto/tests/assets/glossary-link/leading_and_trailing_inline_text.md diff --git a/kordac/tests/assets/glossary-link/leading_and_trailing_inline_text_expected.html b/verto/tests/assets/glossary-link/leading_and_trailing_inline_text_expected.html similarity index 100% rename from kordac/tests/assets/glossary-link/leading_and_trailing_inline_text_expected.html rename to verto/tests/assets/glossary-link/leading_and_trailing_inline_text_expected.html diff --git a/kordac/tests/assets/glossary-link/leading_inline_text.md b/verto/tests/assets/glossary-link/leading_inline_text.md similarity index 100% rename from kordac/tests/assets/glossary-link/leading_inline_text.md rename to verto/tests/assets/glossary-link/leading_inline_text.md diff --git a/kordac/tests/assets/glossary-link/leading_inline_text_expected.html b/verto/tests/assets/glossary-link/leading_inline_text_expected.html similarity index 100% rename from kordac/tests/assets/glossary-link/leading_inline_text_expected.html rename to verto/tests/assets/glossary-link/leading_inline_text_expected.html diff --git a/kordac/tests/assets/glossary-link/multiple_reference_text.md b/verto/tests/assets/glossary-link/multiple_reference_text.md similarity index 100% rename from kordac/tests/assets/glossary-link/multiple_reference_text.md rename to verto/tests/assets/glossary-link/multiple_reference_text.md diff --git a/kordac/tests/assets/glossary-link/multiple_reference_text_expected.html b/verto/tests/assets/glossary-link/multiple_reference_text_expected.html similarity index 100% rename from kordac/tests/assets/glossary-link/multiple_reference_text_expected.html rename to verto/tests/assets/glossary-link/multiple_reference_text_expected.html diff --git a/kordac/tests/assets/glossary-link/multiple_terms.md b/verto/tests/assets/glossary-link/multiple_terms.md similarity index 100% rename from kordac/tests/assets/glossary-link/multiple_terms.md rename to verto/tests/assets/glossary-link/multiple_terms.md diff --git a/kordac/tests/assets/glossary-link/multiple_terms_expected.html b/verto/tests/assets/glossary-link/multiple_terms_expected.html similarity index 100% rename from kordac/tests/assets/glossary-link/multiple_terms_expected.html rename to verto/tests/assets/glossary-link/multiple_terms_expected.html diff --git a/kordac/tests/assets/glossary-link/multiple_word_term.md b/verto/tests/assets/glossary-link/multiple_word_term.md similarity index 100% rename from kordac/tests/assets/glossary-link/multiple_word_term.md rename to verto/tests/assets/glossary-link/multiple_word_term.md diff --git a/kordac/tests/assets/glossary-link/multiple_word_term_expected.html b/verto/tests/assets/glossary-link/multiple_word_term_expected.html similarity index 100% rename from kordac/tests/assets/glossary-link/multiple_word_term_expected.html rename to verto/tests/assets/glossary-link/multiple_word_term_expected.html diff --git a/kordac/tests/assets/glossary-link/reference_text_given.md b/verto/tests/assets/glossary-link/reference_text_given.md similarity index 100% rename from kordac/tests/assets/glossary-link/reference_text_given.md rename to verto/tests/assets/glossary-link/reference_text_given.md diff --git a/kordac/tests/assets/glossary-link/reference_text_given_expected.html b/verto/tests/assets/glossary-link/reference_text_given_expected.html similarity index 100% rename from kordac/tests/assets/glossary-link/reference_text_given_expected.html rename to verto/tests/assets/glossary-link/reference_text_given_expected.html diff --git a/kordac/tests/assets/glossary-link/single_word_term.md b/verto/tests/assets/glossary-link/single_word_term.md similarity index 100% rename from kordac/tests/assets/glossary-link/single_word_term.md rename to verto/tests/assets/glossary-link/single_word_term.md diff --git a/kordac/tests/assets/glossary-link/single_word_term_expected.html b/verto/tests/assets/glossary-link/single_word_term_expected.html similarity index 100% rename from kordac/tests/assets/glossary-link/single_word_term_expected.html rename to verto/tests/assets/glossary-link/single_word_term_expected.html diff --git a/kordac/tests/assets/glossary-link/trailing_inline_text.md b/verto/tests/assets/glossary-link/trailing_inline_text.md similarity index 100% rename from kordac/tests/assets/glossary-link/trailing_inline_text.md rename to verto/tests/assets/glossary-link/trailing_inline_text.md diff --git a/kordac/tests/assets/glossary-link/trailing_inline_text_expected.html b/verto/tests/assets/glossary-link/trailing_inline_text_expected.html similarity index 100% rename from kordac/tests/assets/glossary-link/trailing_inline_text_expected.html rename to verto/tests/assets/glossary-link/trailing_inline_text_expected.html diff --git a/kordac/tests/assets/heading/doc_example_basic_usage.md b/verto/tests/assets/heading/doc_example_basic_usage.md similarity index 100% rename from kordac/tests/assets/heading/doc_example_basic_usage.md rename to verto/tests/assets/heading/doc_example_basic_usage.md diff --git a/kordac/tests/assets/heading/doc_example_basic_usage_expected.html b/verto/tests/assets/heading/doc_example_basic_usage_expected.html similarity index 100% rename from kordac/tests/assets/heading/doc_example_basic_usage_expected.html rename to verto/tests/assets/heading/doc_example_basic_usage_expected.html diff --git a/kordac/tests/assets/heading/doc_example_override_html.md b/verto/tests/assets/heading/doc_example_override_html.md similarity index 100% rename from kordac/tests/assets/heading/doc_example_override_html.md rename to verto/tests/assets/heading/doc_example_override_html.md diff --git a/kordac/tests/assets/heading/doc_example_override_html_expected.html b/verto/tests/assets/heading/doc_example_override_html_expected.html similarity index 100% rename from kordac/tests/assets/heading/doc_example_override_html_expected.html rename to verto/tests/assets/heading/doc_example_override_html_expected.html diff --git a/kordac/tests/assets/heading/doc_example_override_html_template.html b/verto/tests/assets/heading/doc_example_override_html_template.html similarity index 100% rename from kordac/tests/assets/heading/doc_example_override_html_template.html rename to verto/tests/assets/heading/doc_example_override_html_template.html diff --git a/kordac/tests/assets/heading/example_blank.md b/verto/tests/assets/heading/example_blank.md similarity index 100% rename from kordac/tests/assets/heading/example_blank.md rename to verto/tests/assets/heading/example_blank.md diff --git a/kordac/tests/assets/heading/example_blank_expected.html b/verto/tests/assets/heading/example_blank_expected.html similarity index 100% rename from kordac/tests/assets/heading/example_blank_expected.html rename to verto/tests/assets/heading/example_blank_expected.html diff --git a/kordac/tests/assets/heading/example_single_heading.md b/verto/tests/assets/heading/example_single_heading.md similarity index 100% rename from kordac/tests/assets/heading/example_single_heading.md rename to verto/tests/assets/heading/example_single_heading.md diff --git a/kordac/tests/assets/heading/example_single_heading_expected.html b/verto/tests/assets/heading/example_single_heading_expected.html similarity index 100% rename from kordac/tests/assets/heading/example_single_heading_expected.html rename to verto/tests/assets/heading/example_single_heading_expected.html diff --git a/kordac/tests/assets/heading/multiple_roots_zero_level.md b/verto/tests/assets/heading/multiple_roots_zero_level.md similarity index 100% rename from kordac/tests/assets/heading/multiple_roots_zero_level.md rename to verto/tests/assets/heading/multiple_roots_zero_level.md diff --git a/kordac/tests/assets/heading/multiple_roots_zero_level_expected.html b/verto/tests/assets/heading/multiple_roots_zero_level_expected.html similarity index 100% rename from kordac/tests/assets/heading/multiple_roots_zero_level_expected.html rename to verto/tests/assets/heading/multiple_roots_zero_level_expected.html diff --git a/kordac/tests/assets/iframe/doc_example_basic_usage.md b/verto/tests/assets/iframe/doc_example_basic_usage.md similarity index 100% rename from kordac/tests/assets/iframe/doc_example_basic_usage.md rename to verto/tests/assets/iframe/doc_example_basic_usage.md diff --git a/kordac/tests/assets/iframe/doc_example_basic_usage_expected.html b/verto/tests/assets/iframe/doc_example_basic_usage_expected.html similarity index 100% rename from kordac/tests/assets/iframe/doc_example_basic_usage_expected.html rename to verto/tests/assets/iframe/doc_example_basic_usage_expected.html diff --git a/kordac/tests/assets/iframe/doc_example_override_html.md b/verto/tests/assets/iframe/doc_example_override_html.md similarity index 100% rename from kordac/tests/assets/iframe/doc_example_override_html.md rename to verto/tests/assets/iframe/doc_example_override_html.md diff --git a/kordac/tests/assets/iframe/doc_example_override_html_expected.html b/verto/tests/assets/iframe/doc_example_override_html_expected.html similarity index 100% rename from kordac/tests/assets/iframe/doc_example_override_html_expected.html rename to verto/tests/assets/iframe/doc_example_override_html_expected.html diff --git a/kordac/tests/assets/iframe/doc_example_override_html_template.html b/verto/tests/assets/iframe/doc_example_override_html_template.html similarity index 100% rename from kordac/tests/assets/iframe/doc_example_override_html_template.html rename to verto/tests/assets/iframe/doc_example_override_html_template.html diff --git a/kordac/tests/assets/iframe/example_no_link.md b/verto/tests/assets/iframe/example_no_link.md similarity index 100% rename from kordac/tests/assets/iframe/example_no_link.md rename to verto/tests/assets/iframe/example_no_link.md diff --git a/kordac/tests/assets/image/align_center.md b/verto/tests/assets/image/align_center.md similarity index 100% rename from kordac/tests/assets/image/align_center.md rename to verto/tests/assets/image/align_center.md diff --git a/kordac/tests/assets/image/align_center_expected.html b/verto/tests/assets/image/align_center_expected.html similarity index 100% rename from kordac/tests/assets/image/align_center_expected.html rename to verto/tests/assets/image/align_center_expected.html diff --git a/kordac/tests/assets/image/align_left.md b/verto/tests/assets/image/align_left.md similarity index 100% rename from kordac/tests/assets/image/align_left.md rename to verto/tests/assets/image/align_left.md diff --git a/kordac/tests/assets/image/align_left_expected.html b/verto/tests/assets/image/align_left_expected.html similarity index 100% rename from kordac/tests/assets/image/align_left_expected.html rename to verto/tests/assets/image/align_left_expected.html diff --git a/kordac/tests/assets/image/align_right.md b/verto/tests/assets/image/align_right.md similarity index 100% rename from kordac/tests/assets/image/align_right.md rename to verto/tests/assets/image/align_right.md diff --git a/kordac/tests/assets/image/align_right_expected.html b/verto/tests/assets/image/align_right_expected.html similarity index 100% rename from kordac/tests/assets/image/align_right_expected.html rename to verto/tests/assets/image/align_right_expected.html diff --git a/kordac/tests/assets/image/contains_alt.md b/verto/tests/assets/image/contains_alt.md similarity index 100% rename from kordac/tests/assets/image/contains_alt.md rename to verto/tests/assets/image/contains_alt.md diff --git a/kordac/tests/assets/image/contains_alt_expected.html b/verto/tests/assets/image/contains_alt_expected.html similarity index 100% rename from kordac/tests/assets/image/contains_alt_expected.html rename to verto/tests/assets/image/contains_alt_expected.html diff --git a/kordac/tests/assets/image/contains_caption.md b/verto/tests/assets/image/contains_caption.md similarity index 100% rename from kordac/tests/assets/image/contains_caption.md rename to verto/tests/assets/image/contains_caption.md diff --git a/kordac/tests/assets/image/contains_caption_expected.html b/verto/tests/assets/image/contains_caption_expected.html similarity index 100% rename from kordac/tests/assets/image/contains_caption_expected.html rename to verto/tests/assets/image/contains_caption_expected.html diff --git a/kordac/tests/assets/image/contains_caption_link.md b/verto/tests/assets/image/contains_caption_link.md similarity index 100% rename from kordac/tests/assets/image/contains_caption_link.md rename to verto/tests/assets/image/contains_caption_link.md diff --git a/kordac/tests/assets/image/contains_caption_link_expected.html b/verto/tests/assets/image/contains_caption_link_expected.html similarity index 100% rename from kordac/tests/assets/image/contains_caption_link_expected.html rename to verto/tests/assets/image/contains_caption_link_expected.html diff --git a/kordac/tests/assets/image/contains_hover_text.md b/verto/tests/assets/image/contains_hover_text.md similarity index 100% rename from kordac/tests/assets/image/contains_hover_text.md rename to verto/tests/assets/image/contains_hover_text.md diff --git a/kordac/tests/assets/image/contains_hover_text_expected.html b/verto/tests/assets/image/contains_hover_text_expected.html similarity index 100% rename from kordac/tests/assets/image/contains_hover_text_expected.html rename to verto/tests/assets/image/contains_hover_text_expected.html diff --git a/kordac/tests/assets/image/contains_image.md b/verto/tests/assets/image/contains_image.md similarity index 100% rename from kordac/tests/assets/image/contains_image.md rename to verto/tests/assets/image/contains_image.md diff --git a/kordac/tests/assets/image/contains_image_and_text_contains_word_image.md b/verto/tests/assets/image/contains_image_and_text_contains_word_image.md similarity index 100% rename from kordac/tests/assets/image/contains_image_and_text_contains_word_image.md rename to verto/tests/assets/image/contains_image_and_text_contains_word_image.md diff --git a/kordac/tests/assets/image/contains_image_and_text_contains_word_image_expected.html b/verto/tests/assets/image/contains_image_and_text_contains_word_image_expected.html similarity index 100% rename from kordac/tests/assets/image/contains_image_and_text_contains_word_image_expected.html rename to verto/tests/assets/image/contains_image_and_text_contains_word_image_expected.html diff --git a/kordac/tests/assets/image/contains_image_expected.html b/verto/tests/assets/image/contains_image_expected.html similarity index 100% rename from kordac/tests/assets/image/contains_image_expected.html rename to verto/tests/assets/image/contains_image_expected.html diff --git a/kordac/tests/assets/image/contains_multiple_images.md b/verto/tests/assets/image/contains_multiple_images.md similarity index 100% rename from kordac/tests/assets/image/contains_multiple_images.md rename to verto/tests/assets/image/contains_multiple_images.md diff --git a/kordac/tests/assets/image/contains_multiple_images_expected.html b/verto/tests/assets/image/contains_multiple_images_expected.html similarity index 100% rename from kordac/tests/assets/image/contains_multiple_images_expected.html rename to verto/tests/assets/image/contains_multiple_images_expected.html diff --git a/kordac/tests/assets/image/contains_source.md b/verto/tests/assets/image/contains_source.md similarity index 100% rename from kordac/tests/assets/image/contains_source.md rename to verto/tests/assets/image/contains_source.md diff --git a/kordac/tests/assets/image/contains_source_expected.html b/verto/tests/assets/image/contains_source_expected.html similarity index 100% rename from kordac/tests/assets/image/contains_source_expected.html rename to verto/tests/assets/image/contains_source_expected.html diff --git a/kordac/tests/assets/image/default_image.md b/verto/tests/assets/image/default_image.md similarity index 100% rename from kordac/tests/assets/image/default_image.md rename to verto/tests/assets/image/default_image.md diff --git a/kordac/tests/assets/image/default_image_expected.html b/verto/tests/assets/image/default_image_expected.html similarity index 100% rename from kordac/tests/assets/image/default_image_expected.html rename to verto/tests/assets/image/default_image_expected.html diff --git a/kordac/tests/assets/image/doc_example_2_override_html.md b/verto/tests/assets/image/doc_example_2_override_html.md similarity index 100% rename from kordac/tests/assets/image/doc_example_2_override_html.md rename to verto/tests/assets/image/doc_example_2_override_html.md diff --git a/kordac/tests/assets/image/doc_example_2_override_html_expected.html b/verto/tests/assets/image/doc_example_2_override_html_expected.html similarity index 100% rename from kordac/tests/assets/image/doc_example_2_override_html_expected.html rename to verto/tests/assets/image/doc_example_2_override_html_expected.html diff --git a/kordac/tests/assets/image/doc_example_2_override_html_template.html b/verto/tests/assets/image/doc_example_2_override_html_template.html similarity index 100% rename from kordac/tests/assets/image/doc_example_2_override_html_template.html rename to verto/tests/assets/image/doc_example_2_override_html_template.html diff --git a/kordac/tests/assets/image/doc_example_2_override_link_html_template.html b/verto/tests/assets/image/doc_example_2_override_link_html_template.html similarity index 100% rename from kordac/tests/assets/image/doc_example_2_override_link_html_template.html rename to verto/tests/assets/image/doc_example_2_override_link_html_template.html diff --git a/kordac/tests/assets/image/doc_example_basic_usage.md b/verto/tests/assets/image/doc_example_basic_usage.md similarity index 100% rename from kordac/tests/assets/image/doc_example_basic_usage.md rename to verto/tests/assets/image/doc_example_basic_usage.md diff --git a/kordac/tests/assets/image/doc_example_basic_usage_expected.html b/verto/tests/assets/image/doc_example_basic_usage_expected.html similarity index 100% rename from kordac/tests/assets/image/doc_example_basic_usage_expected.html rename to verto/tests/assets/image/doc_example_basic_usage_expected.html diff --git a/kordac/tests/assets/image/doc_example_override_html.md b/verto/tests/assets/image/doc_example_override_html.md similarity index 100% rename from kordac/tests/assets/image/doc_example_override_html.md rename to verto/tests/assets/image/doc_example_override_html.md diff --git a/kordac/tests/assets/image/doc_example_override_html_expected.html b/verto/tests/assets/image/doc_example_override_html_expected.html similarity index 100% rename from kordac/tests/assets/image/doc_example_override_html_expected.html rename to verto/tests/assets/image/doc_example_override_html_expected.html diff --git a/kordac/tests/assets/image/doc_example_override_html_template.html b/verto/tests/assets/image/doc_example_override_html_template.html similarity index 100% rename from kordac/tests/assets/image/doc_example_override_html_template.html rename to verto/tests/assets/image/doc_example_override_html_template.html diff --git a/kordac/tests/assets/image/external_image.md b/verto/tests/assets/image/external_image.md similarity index 100% rename from kordac/tests/assets/image/external_image.md rename to verto/tests/assets/image/external_image.md diff --git a/kordac/tests/assets/image/external_image_expected.html b/verto/tests/assets/image/external_image_expected.html similarity index 100% rename from kordac/tests/assets/image/external_image_expected.html rename to verto/tests/assets/image/external_image_expected.html diff --git a/kordac/tests/assets/image/internal_image.md b/verto/tests/assets/image/internal_image.md similarity index 100% rename from kordac/tests/assets/image/internal_image.md rename to verto/tests/assets/image/internal_image.md diff --git a/kordac/tests/assets/image/internal_image_expected.html b/verto/tests/assets/image/internal_image_expected.html similarity index 100% rename from kordac/tests/assets/image/internal_image_expected.html rename to verto/tests/assets/image/internal_image_expected.html diff --git a/kordac/tests/assets/image/multiple_internal_image.md b/verto/tests/assets/image/multiple_internal_image.md similarity index 100% rename from kordac/tests/assets/image/multiple_internal_image.md rename to verto/tests/assets/image/multiple_internal_image.md diff --git a/kordac/tests/assets/image/no_image.md b/verto/tests/assets/image/no_image.md similarity index 100% rename from kordac/tests/assets/image/no_image.md rename to verto/tests/assets/image/no_image.md diff --git a/kordac/tests/assets/image/no_image_expected.html b/verto/tests/assets/image/no_image_expected.html similarity index 100% rename from kordac/tests/assets/image/no_image_expected.html rename to verto/tests/assets/image/no_image_expected.html diff --git a/kordac/tests/assets/image/text_contains_the_word_image.md b/verto/tests/assets/image/text_contains_the_word_image.md similarity index 100% rename from kordac/tests/assets/image/text_contains_the_word_image.md rename to verto/tests/assets/image/text_contains_the_word_image.md diff --git a/kordac/tests/assets/image/text_contains_the_word_image_expected.html b/verto/tests/assets/image/text_contains_the_word_image_expected.html similarity index 100% rename from kordac/tests/assets/image/text_contains_the_word_image_expected.html rename to verto/tests/assets/image/text_contains_the_word_image_expected.html diff --git a/kordac/tests/assets/interactive/doc_example_iframe_usage.md b/verto/tests/assets/interactive/doc_example_iframe_usage.md similarity index 100% rename from kordac/tests/assets/interactive/doc_example_iframe_usage.md rename to verto/tests/assets/interactive/doc_example_iframe_usage.md diff --git a/kordac/tests/assets/interactive/doc_example_iframe_usage_expected.html b/verto/tests/assets/interactive/doc_example_iframe_usage_expected.html similarity index 100% rename from kordac/tests/assets/interactive/doc_example_iframe_usage_expected.html rename to verto/tests/assets/interactive/doc_example_iframe_usage_expected.html diff --git a/kordac/tests/assets/interactive/doc_example_in_page_usage.md b/verto/tests/assets/interactive/doc_example_in_page_usage.md similarity index 100% rename from kordac/tests/assets/interactive/doc_example_in_page_usage.md rename to verto/tests/assets/interactive/doc_example_in_page_usage.md diff --git a/kordac/tests/assets/interactive/doc_example_in_page_usage_expected.html b/verto/tests/assets/interactive/doc_example_in_page_usage_expected.html similarity index 100% rename from kordac/tests/assets/interactive/doc_example_in_page_usage_expected.html rename to verto/tests/assets/interactive/doc_example_in_page_usage_expected.html diff --git a/kordac/tests/assets/interactive/doc_example_override_html.md b/verto/tests/assets/interactive/doc_example_override_html.md similarity index 100% rename from kordac/tests/assets/interactive/doc_example_override_html.md rename to verto/tests/assets/interactive/doc_example_override_html.md diff --git a/kordac/tests/assets/interactive/doc_example_override_html_expected.html b/verto/tests/assets/interactive/doc_example_override_html_expected.html similarity index 100% rename from kordac/tests/assets/interactive/doc_example_override_html_expected.html rename to verto/tests/assets/interactive/doc_example_override_html_expected.html diff --git a/kordac/tests/assets/interactive/doc_example_override_html_template.html b/verto/tests/assets/interactive/doc_example_override_html_template.html similarity index 100% rename from kordac/tests/assets/interactive/doc_example_override_html_template.html rename to verto/tests/assets/interactive/doc_example_override_html_template.html diff --git a/kordac/tests/assets/interactive/doc_example_whole_page_usage.md b/verto/tests/assets/interactive/doc_example_whole_page_usage.md similarity index 100% rename from kordac/tests/assets/interactive/doc_example_whole_page_usage.md rename to verto/tests/assets/interactive/doc_example_whole_page_usage.md diff --git a/kordac/tests/assets/interactive/doc_example_whole_page_usage_expected.html b/verto/tests/assets/interactive/doc_example_whole_page_usage_expected.html similarity index 100% rename from kordac/tests/assets/interactive/doc_example_whole_page_usage_expected.html rename to verto/tests/assets/interactive/doc_example_whole_page_usage_expected.html diff --git a/kordac/tests/assets/panel/contains_inner_panel.md b/verto/tests/assets/panel/contains_inner_panel.md similarity index 100% rename from kordac/tests/assets/panel/contains_inner_panel.md rename to verto/tests/assets/panel/contains_inner_panel.md diff --git a/kordac/tests/assets/panel/contains_inner_panel_expected.html b/verto/tests/assets/panel/contains_inner_panel_expected.html similarity index 100% rename from kordac/tests/assets/panel/contains_inner_panel_expected.html rename to verto/tests/assets/panel/contains_inner_panel_expected.html diff --git a/kordac/tests/assets/panel/contains_multiple_panels.md b/verto/tests/assets/panel/contains_multiple_panels.md similarity index 100% rename from kordac/tests/assets/panel/contains_multiple_panels.md rename to verto/tests/assets/panel/contains_multiple_panels.md diff --git a/kordac/tests/assets/panel/contains_multiple_panels_expected.html b/verto/tests/assets/panel/contains_multiple_panels_expected.html similarity index 100% rename from kordac/tests/assets/panel/contains_multiple_panels_expected.html rename to verto/tests/assets/panel/contains_multiple_panels_expected.html diff --git a/kordac/tests/assets/panel/doc_example_basic_usage.md b/verto/tests/assets/panel/doc_example_basic_usage.md similarity index 100% rename from kordac/tests/assets/panel/doc_example_basic_usage.md rename to verto/tests/assets/panel/doc_example_basic_usage.md diff --git a/kordac/tests/assets/panel/doc_example_basic_usage_expected.html b/verto/tests/assets/panel/doc_example_basic_usage_expected.html similarity index 100% rename from kordac/tests/assets/panel/doc_example_basic_usage_expected.html rename to verto/tests/assets/panel/doc_example_basic_usage_expected.html diff --git a/kordac/tests/assets/panel/doc_example_override_html.md b/verto/tests/assets/panel/doc_example_override_html.md similarity index 100% rename from kordac/tests/assets/panel/doc_example_override_html.md rename to verto/tests/assets/panel/doc_example_override_html.md diff --git a/kordac/tests/assets/panel/doc_example_override_html_expected.html b/verto/tests/assets/panel/doc_example_override_html_expected.html similarity index 100% rename from kordac/tests/assets/panel/doc_example_override_html_expected.html rename to verto/tests/assets/panel/doc_example_override_html_expected.html diff --git a/kordac/tests/assets/panel/doc_example_override_html_template.html b/verto/tests/assets/panel/doc_example_override_html_template.html similarity index 100% rename from kordac/tests/assets/panel/doc_example_override_html_template.html rename to verto/tests/assets/panel/doc_example_override_html_template.html diff --git a/kordac/tests/assets/panel/missing_end_tag.md b/verto/tests/assets/panel/missing_end_tag.md similarity index 100% rename from kordac/tests/assets/panel/missing_end_tag.md rename to verto/tests/assets/panel/missing_end_tag.md diff --git a/kordac/tests/assets/panel/missing_start_tag.md b/verto/tests/assets/panel/missing_start_tag.md similarity index 100% rename from kordac/tests/assets/panel/missing_start_tag.md rename to verto/tests/assets/panel/missing_start_tag.md diff --git a/kordac/tests/assets/panel/missing_tag_inner.md b/verto/tests/assets/panel/missing_tag_inner.md similarity index 100% rename from kordac/tests/assets/panel/missing_tag_inner.md rename to verto/tests/assets/panel/missing_tag_inner.md diff --git a/kordac/tests/assets/panel/parses_always_expanded_panel.md b/verto/tests/assets/panel/parses_always_expanded_panel.md similarity index 100% rename from kordac/tests/assets/panel/parses_always_expanded_panel.md rename to verto/tests/assets/panel/parses_always_expanded_panel.md diff --git a/kordac/tests/assets/panel/parses_always_expanded_panel_expected.html b/verto/tests/assets/panel/parses_always_expanded_panel_expected.html similarity index 100% rename from kordac/tests/assets/panel/parses_always_expanded_panel_expected.html rename to verto/tests/assets/panel/parses_always_expanded_panel_expected.html diff --git a/kordac/tests/assets/panel/parses_blank.md b/verto/tests/assets/panel/parses_blank.md similarity index 100% rename from kordac/tests/assets/panel/parses_blank.md rename to verto/tests/assets/panel/parses_blank.md diff --git a/kordac/tests/assets/panel/parses_blank_expected.html b/verto/tests/assets/panel/parses_blank_expected.html similarity index 100% rename from kordac/tests/assets/panel/parses_blank_expected.html rename to verto/tests/assets/panel/parses_blank_expected.html diff --git a/kordac/tests/assets/panel/parses_blank_lines_multiple_paragraphs.md b/verto/tests/assets/panel/parses_blank_lines_multiple_paragraphs.md similarity index 100% rename from kordac/tests/assets/panel/parses_blank_lines_multiple_paragraphs.md rename to verto/tests/assets/panel/parses_blank_lines_multiple_paragraphs.md diff --git a/kordac/tests/assets/panel/parses_blank_lines_multiple_paragraphs_expected.html b/verto/tests/assets/panel/parses_blank_lines_multiple_paragraphs_expected.html similarity index 100% rename from kordac/tests/assets/panel/parses_blank_lines_multiple_paragraphs_expected.html rename to verto/tests/assets/panel/parses_blank_lines_multiple_paragraphs_expected.html diff --git a/kordac/tests/assets/panel/parses_expanded_panel.md b/verto/tests/assets/panel/parses_expanded_panel.md similarity index 100% rename from kordac/tests/assets/panel/parses_expanded_panel.md rename to verto/tests/assets/panel/parses_expanded_panel.md diff --git a/kordac/tests/assets/panel/parses_expanded_panel_expected.html b/verto/tests/assets/panel/parses_expanded_panel_expected.html similarity index 100% rename from kordac/tests/assets/panel/parses_expanded_panel_expected.html rename to verto/tests/assets/panel/parses_expanded_panel_expected.html diff --git a/kordac/tests/assets/panel/parses_no_blank_lines_single_paragraph.md b/verto/tests/assets/panel/parses_no_blank_lines_single_paragraph.md similarity index 100% rename from kordac/tests/assets/panel/parses_no_blank_lines_single_paragraph.md rename to verto/tests/assets/panel/parses_no_blank_lines_single_paragraph.md diff --git a/kordac/tests/assets/panel/parses_no_blank_lines_single_paragraph_expected.html b/verto/tests/assets/panel/parses_no_blank_lines_single_paragraph_expected.html similarity index 100% rename from kordac/tests/assets/panel/parses_no_blank_lines_single_paragraph_expected.html rename to verto/tests/assets/panel/parses_no_blank_lines_single_paragraph_expected.html diff --git a/kordac/tests/assets/relative-link/doc_example_basic_usage.md b/verto/tests/assets/relative-link/doc_example_basic_usage.md similarity index 100% rename from kordac/tests/assets/relative-link/doc_example_basic_usage.md rename to verto/tests/assets/relative-link/doc_example_basic_usage.md diff --git a/kordac/tests/assets/relative-link/doc_example_basic_usage_expected.html b/verto/tests/assets/relative-link/doc_example_basic_usage_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/doc_example_basic_usage_expected.html rename to verto/tests/assets/relative-link/doc_example_basic_usage_expected.html diff --git a/kordac/tests/assets/relative-link/doc_example_override_html.md b/verto/tests/assets/relative-link/doc_example_override_html.md similarity index 100% rename from kordac/tests/assets/relative-link/doc_example_override_html.md rename to verto/tests/assets/relative-link/doc_example_override_html.md diff --git a/kordac/tests/assets/relative-link/doc_example_override_html_expected.html b/verto/tests/assets/relative-link/doc_example_override_html_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/doc_example_override_html_expected.html rename to verto/tests/assets/relative-link/doc_example_override_html_expected.html diff --git a/kordac/tests/assets/relative-link/doc_example_override_html_template.html b/verto/tests/assets/relative-link/doc_example_override_html_template.html similarity index 100% rename from kordac/tests/assets/relative-link/doc_example_override_html_template.html rename to verto/tests/assets/relative-link/doc_example_override_html_template.html diff --git a/kordac/tests/assets/relative-link/ftp_schema.md b/verto/tests/assets/relative-link/ftp_schema.md similarity index 100% rename from kordac/tests/assets/relative-link/ftp_schema.md rename to verto/tests/assets/relative-link/ftp_schema.md diff --git a/kordac/tests/assets/relative-link/ftp_schema_expected.html b/verto/tests/assets/relative-link/ftp_schema_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/ftp_schema_expected.html rename to verto/tests/assets/relative-link/ftp_schema_expected.html diff --git a/kordac/tests/assets/relative-link/ftp_text.md b/verto/tests/assets/relative-link/ftp_text.md similarity index 100% rename from kordac/tests/assets/relative-link/ftp_text.md rename to verto/tests/assets/relative-link/ftp_text.md diff --git a/kordac/tests/assets/relative-link/ftp_text_expected.html b/verto/tests/assets/relative-link/ftp_text_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/ftp_text_expected.html rename to verto/tests/assets/relative-link/ftp_text_expected.html diff --git a/kordac/tests/assets/relative-link/ftps_schema.md b/verto/tests/assets/relative-link/ftps_schema.md similarity index 100% rename from kordac/tests/assets/relative-link/ftps_schema.md rename to verto/tests/assets/relative-link/ftps_schema.md diff --git a/kordac/tests/assets/relative-link/ftps_schema_expected.html b/verto/tests/assets/relative-link/ftps_schema_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/ftps_schema_expected.html rename to verto/tests/assets/relative-link/ftps_schema_expected.html diff --git a/kordac/tests/assets/relative-link/ftps_text.md b/verto/tests/assets/relative-link/ftps_text.md similarity index 100% rename from kordac/tests/assets/relative-link/ftps_text.md rename to verto/tests/assets/relative-link/ftps_text.md diff --git a/kordac/tests/assets/relative-link/ftps_text_expected.html b/verto/tests/assets/relative-link/ftps_text_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/ftps_text_expected.html rename to verto/tests/assets/relative-link/ftps_text_expected.html diff --git a/kordac/tests/assets/relative-link/http_schema.md b/verto/tests/assets/relative-link/http_schema.md similarity index 100% rename from kordac/tests/assets/relative-link/http_schema.md rename to verto/tests/assets/relative-link/http_schema.md diff --git a/kordac/tests/assets/relative-link/http_schema_expected.html b/verto/tests/assets/relative-link/http_schema_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/http_schema_expected.html rename to verto/tests/assets/relative-link/http_schema_expected.html diff --git a/kordac/tests/assets/relative-link/http_text.md b/verto/tests/assets/relative-link/http_text.md similarity index 100% rename from kordac/tests/assets/relative-link/http_text.md rename to verto/tests/assets/relative-link/http_text.md diff --git a/kordac/tests/assets/relative-link/http_text_expected.html b/verto/tests/assets/relative-link/http_text_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/http_text_expected.html rename to verto/tests/assets/relative-link/http_text_expected.html diff --git a/kordac/tests/assets/relative-link/https_schema.md b/verto/tests/assets/relative-link/https_schema.md similarity index 100% rename from kordac/tests/assets/relative-link/https_schema.md rename to verto/tests/assets/relative-link/https_schema.md diff --git a/kordac/tests/assets/relative-link/https_schema_expected.html b/verto/tests/assets/relative-link/https_schema_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/https_schema_expected.html rename to verto/tests/assets/relative-link/https_schema_expected.html diff --git a/kordac/tests/assets/relative-link/https_text.md b/verto/tests/assets/relative-link/https_text.md similarity index 100% rename from kordac/tests/assets/relative-link/https_text.md rename to verto/tests/assets/relative-link/https_text.md diff --git a/kordac/tests/assets/relative-link/https_text_expected.html b/verto/tests/assets/relative-link/https_text_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/https_text_expected.html rename to verto/tests/assets/relative-link/https_text_expected.html diff --git a/kordac/tests/assets/relative-link/long_path.md b/verto/tests/assets/relative-link/long_path.md similarity index 100% rename from kordac/tests/assets/relative-link/long_path.md rename to verto/tests/assets/relative-link/long_path.md diff --git a/kordac/tests/assets/relative-link/long_path_expected.html b/verto/tests/assets/relative-link/long_path_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/long_path_expected.html rename to verto/tests/assets/relative-link/long_path_expected.html diff --git a/kordac/tests/assets/relative-link/mailto_schema.md b/verto/tests/assets/relative-link/mailto_schema.md similarity index 100% rename from kordac/tests/assets/relative-link/mailto_schema.md rename to verto/tests/assets/relative-link/mailto_schema.md diff --git a/kordac/tests/assets/relative-link/mailto_schema_expected.html b/verto/tests/assets/relative-link/mailto_schema_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/mailto_schema_expected.html rename to verto/tests/assets/relative-link/mailto_schema_expected.html diff --git a/kordac/tests/assets/relative-link/mailto_text.md b/verto/tests/assets/relative-link/mailto_text.md similarity index 100% rename from kordac/tests/assets/relative-link/mailto_text.md rename to verto/tests/assets/relative-link/mailto_text.md diff --git a/kordac/tests/assets/relative-link/mailto_text_expected.html b/verto/tests/assets/relative-link/mailto_text_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/mailto_text_expected.html rename to verto/tests/assets/relative-link/mailto_text_expected.html diff --git a/kordac/tests/assets/relative-link/multiple_links.md b/verto/tests/assets/relative-link/multiple_links.md similarity index 100% rename from kordac/tests/assets/relative-link/multiple_links.md rename to verto/tests/assets/relative-link/multiple_links.md diff --git a/kordac/tests/assets/relative-link/multiple_links_expected.html b/verto/tests/assets/relative-link/multiple_links_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/multiple_links_expected.html rename to verto/tests/assets/relative-link/multiple_links_expected.html diff --git a/kordac/tests/assets/relative-link/news_schema.md b/verto/tests/assets/relative-link/news_schema.md similarity index 100% rename from kordac/tests/assets/relative-link/news_schema.md rename to verto/tests/assets/relative-link/news_schema.md diff --git a/kordac/tests/assets/relative-link/news_schema_expected.html b/verto/tests/assets/relative-link/news_schema_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/news_schema_expected.html rename to verto/tests/assets/relative-link/news_schema_expected.html diff --git a/kordac/tests/assets/relative-link/news_text.md b/verto/tests/assets/relative-link/news_text.md similarity index 100% rename from kordac/tests/assets/relative-link/news_text.md rename to verto/tests/assets/relative-link/news_text.md diff --git a/kordac/tests/assets/relative-link/news_text_expected.html b/verto/tests/assets/relative-link/news_text_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/news_text_expected.html rename to verto/tests/assets/relative-link/news_text_expected.html diff --git a/kordac/tests/assets/relative-link/www_text.md b/verto/tests/assets/relative-link/www_text.md similarity index 100% rename from kordac/tests/assets/relative-link/www_text.md rename to verto/tests/assets/relative-link/www_text.md diff --git a/kordac/tests/assets/relative-link/www_text_expected.html b/verto/tests/assets/relative-link/www_text_expected.html similarity index 100% rename from kordac/tests/assets/relative-link/www_text_expected.html rename to verto/tests/assets/relative-link/www_text_expected.html diff --git a/kordac/tests/assets/remove-title/doc_example_basic_usage.md b/verto/tests/assets/remove-title/doc_example_basic_usage.md similarity index 100% rename from kordac/tests/assets/remove-title/doc_example_basic_usage.md rename to verto/tests/assets/remove-title/doc_example_basic_usage.md diff --git a/kordac/tests/assets/remove-title/doc_example_basic_usage_expected.html b/verto/tests/assets/remove-title/doc_example_basic_usage_expected.html similarity index 100% rename from kordac/tests/assets/remove-title/doc_example_basic_usage_expected.html rename to verto/tests/assets/remove-title/doc_example_basic_usage_expected.html diff --git a/kordac/tests/assets/remove-title/level_two_heading.md b/verto/tests/assets/remove-title/level_two_heading.md similarity index 100% rename from kordac/tests/assets/remove-title/level_two_heading.md rename to verto/tests/assets/remove-title/level_two_heading.md diff --git a/kordac/tests/assets/remove-title/level_two_heading_expected.html b/verto/tests/assets/remove-title/level_two_heading_expected.html similarity index 100% rename from kordac/tests/assets/remove-title/level_two_heading_expected.html rename to verto/tests/assets/remove-title/level_two_heading_expected.html diff --git a/kordac/tests/assets/remove-title/multiple_headings.md b/verto/tests/assets/remove-title/multiple_headings.md similarity index 100% rename from kordac/tests/assets/remove-title/multiple_headings.md rename to verto/tests/assets/remove-title/multiple_headings.md diff --git a/kordac/tests/assets/remove-title/multiple_headings_expected.html b/verto/tests/assets/remove-title/multiple_headings_expected.html similarity index 100% rename from kordac/tests/assets/remove-title/multiple_headings_expected.html rename to verto/tests/assets/remove-title/multiple_headings_expected.html diff --git a/kordac/tests/assets/remove-title/multiple_level_one_headings.md b/verto/tests/assets/remove-title/multiple_level_one_headings.md similarity index 100% rename from kordac/tests/assets/remove-title/multiple_level_one_headings.md rename to verto/tests/assets/remove-title/multiple_level_one_headings.md diff --git a/kordac/tests/assets/remove-title/multiple_level_one_headings_expected.html b/verto/tests/assets/remove-title/multiple_level_one_headings_expected.html similarity index 100% rename from kordac/tests/assets/remove-title/multiple_level_one_headings_expected.html rename to verto/tests/assets/remove-title/multiple_level_one_headings_expected.html diff --git a/kordac/tests/assets/remove-title/no_heading_permalink.md b/verto/tests/assets/remove-title/no_heading_permalink.md similarity index 100% rename from kordac/tests/assets/remove-title/no_heading_permalink.md rename to verto/tests/assets/remove-title/no_heading_permalink.md diff --git a/kordac/tests/assets/remove-title/no_heading_permalink_expected.html b/verto/tests/assets/remove-title/no_heading_permalink_expected.html similarity index 100% rename from kordac/tests/assets/remove-title/no_heading_permalink_expected.html rename to verto/tests/assets/remove-title/no_heading_permalink_expected.html diff --git a/kordac/tests/assets/remove-title/no_headings.md b/verto/tests/assets/remove-title/no_headings.md similarity index 100% rename from kordac/tests/assets/remove-title/no_headings.md rename to verto/tests/assets/remove-title/no_headings.md diff --git a/kordac/tests/assets/remove-title/no_headings_expected.html b/verto/tests/assets/remove-title/no_headings_expected.html similarity index 100% rename from kordac/tests/assets/remove-title/no_headings_expected.html rename to verto/tests/assets/remove-title/no_headings_expected.html diff --git a/kordac/tests/assets/remove-title/no_space_title.md b/verto/tests/assets/remove-title/no_space_title.md similarity index 100% rename from kordac/tests/assets/remove-title/no_space_title.md rename to verto/tests/assets/remove-title/no_space_title.md diff --git a/kordac/tests/assets/remove-title/no_space_title_expected.html b/verto/tests/assets/remove-title/no_space_title_expected.html similarity index 100% rename from kordac/tests/assets/remove-title/no_space_title_expected.html rename to verto/tests/assets/remove-title/no_space_title_expected.html diff --git a/kordac/tests/assets/remove-title/processor_off.md b/verto/tests/assets/remove-title/processor_off.md similarity index 100% rename from kordac/tests/assets/remove-title/processor_off.md rename to verto/tests/assets/remove-title/processor_off.md diff --git a/kordac/tests/assets/remove-title/processor_off_expected.html b/verto/tests/assets/remove-title/processor_off_expected.html similarity index 100% rename from kordac/tests/assets/remove-title/processor_off_expected.html rename to verto/tests/assets/remove-title/processor_off_expected.html diff --git a/kordac/tests/assets/save-title/doc_example_basic_usage.md b/verto/tests/assets/save-title/doc_example_basic_usage.md similarity index 100% rename from kordac/tests/assets/save-title/doc_example_basic_usage.md rename to verto/tests/assets/save-title/doc_example_basic_usage.md diff --git a/kordac/tests/assets/save-title/doc_example_basic_usage_expected.html b/verto/tests/assets/save-title/doc_example_basic_usage_expected.html similarity index 100% rename from kordac/tests/assets/save-title/doc_example_basic_usage_expected.html rename to verto/tests/assets/save-title/doc_example_basic_usage_expected.html diff --git a/kordac/tests/assets/save-title/level_two_heading.md b/verto/tests/assets/save-title/level_two_heading.md similarity index 100% rename from kordac/tests/assets/save-title/level_two_heading.md rename to verto/tests/assets/save-title/level_two_heading.md diff --git a/kordac/tests/assets/save-title/level_two_heading_expected.html b/verto/tests/assets/save-title/level_two_heading_expected.html similarity index 100% rename from kordac/tests/assets/save-title/level_two_heading_expected.html rename to verto/tests/assets/save-title/level_two_heading_expected.html diff --git a/kordac/tests/assets/save-title/multiple_headings.md b/verto/tests/assets/save-title/multiple_headings.md similarity index 100% rename from kordac/tests/assets/save-title/multiple_headings.md rename to verto/tests/assets/save-title/multiple_headings.md diff --git a/kordac/tests/assets/save-title/multiple_headings_expected.html b/verto/tests/assets/save-title/multiple_headings_expected.html similarity index 100% rename from kordac/tests/assets/save-title/multiple_headings_expected.html rename to verto/tests/assets/save-title/multiple_headings_expected.html diff --git a/kordac/tests/assets/save-title/multiple_level_one_headings.md b/verto/tests/assets/save-title/multiple_level_one_headings.md similarity index 100% rename from kordac/tests/assets/save-title/multiple_level_one_headings.md rename to verto/tests/assets/save-title/multiple_level_one_headings.md diff --git a/kordac/tests/assets/save-title/multiple_level_one_headings_expected.html b/verto/tests/assets/save-title/multiple_level_one_headings_expected.html similarity index 100% rename from kordac/tests/assets/save-title/multiple_level_one_headings_expected.html rename to verto/tests/assets/save-title/multiple_level_one_headings_expected.html diff --git a/kordac/tests/assets/save-title/no_heading_permalink.md b/verto/tests/assets/save-title/no_heading_permalink.md similarity index 100% rename from kordac/tests/assets/save-title/no_heading_permalink.md rename to verto/tests/assets/save-title/no_heading_permalink.md diff --git a/kordac/tests/assets/save-title/no_headings.md b/verto/tests/assets/save-title/no_headings.md similarity index 100% rename from kordac/tests/assets/save-title/no_headings.md rename to verto/tests/assets/save-title/no_headings.md diff --git a/kordac/tests/assets/save-title/no_space_title.md b/verto/tests/assets/save-title/no_space_title.md similarity index 100% rename from kordac/tests/assets/save-title/no_space_title.md rename to verto/tests/assets/save-title/no_space_title.md diff --git a/kordac/tests/assets/save-title/no_space_title_expected.html b/verto/tests/assets/save-title/no_space_title_expected.html similarity index 100% rename from kordac/tests/assets/save-title/no_space_title_expected.html rename to verto/tests/assets/save-title/no_space_title_expected.html diff --git a/kordac/tests/assets/scratch/doc_example_basic_usage.md b/verto/tests/assets/scratch/doc_example_basic_usage.md similarity index 100% rename from kordac/tests/assets/scratch/doc_example_basic_usage.md rename to verto/tests/assets/scratch/doc_example_basic_usage.md diff --git a/kordac/tests/assets/scratch/doc_example_basic_usage_expected.html b/verto/tests/assets/scratch/doc_example_basic_usage_expected.html similarity index 100% rename from kordac/tests/assets/scratch/doc_example_basic_usage_expected.html rename to verto/tests/assets/scratch/doc_example_basic_usage_expected.html diff --git a/kordac/tests/assets/scratch/doc_example_override_html.md b/verto/tests/assets/scratch/doc_example_override_html.md similarity index 100% rename from kordac/tests/assets/scratch/doc_example_override_html.md rename to verto/tests/assets/scratch/doc_example_override_html.md diff --git a/kordac/tests/assets/scratch/doc_example_override_html_expected.html b/verto/tests/assets/scratch/doc_example_override_html_expected.html similarity index 100% rename from kordac/tests/assets/scratch/doc_example_override_html_expected.html rename to verto/tests/assets/scratch/doc_example_override_html_expected.html diff --git a/kordac/tests/assets/scratch/doc_example_override_html_template.html b/verto/tests/assets/scratch/doc_example_override_html_template.html similarity index 100% rename from kordac/tests/assets/scratch/doc_example_override_html_template.html rename to verto/tests/assets/scratch/doc_example_override_html_template.html diff --git a/kordac/tests/assets/scratch/example_multiple_codeblocks.md b/verto/tests/assets/scratch/example_multiple_codeblocks.md similarity index 100% rename from kordac/tests/assets/scratch/example_multiple_codeblocks.md rename to verto/tests/assets/scratch/example_multiple_codeblocks.md diff --git a/kordac/tests/assets/scratch/example_multiple_codeblocks_2.md b/verto/tests/assets/scratch/example_multiple_codeblocks_2.md similarity index 100% rename from kordac/tests/assets/scratch/example_multiple_codeblocks_2.md rename to verto/tests/assets/scratch/example_multiple_codeblocks_2.md diff --git a/kordac/tests/assets/scratch/example_multiple_codeblocks_expected.html b/verto/tests/assets/scratch/example_multiple_codeblocks_expected.html similarity index 100% rename from kordac/tests/assets/scratch/example_multiple_codeblocks_expected.html rename to verto/tests/assets/scratch/example_multiple_codeblocks_expected.html diff --git a/kordac/tests/assets/scratch/example_multiple_codeblocks_expected_2.html b/verto/tests/assets/scratch/example_multiple_codeblocks_expected_2.html similarity index 100% rename from kordac/tests/assets/scratch/example_multiple_codeblocks_expected_2.html rename to verto/tests/assets/scratch/example_multiple_codeblocks_expected_2.html diff --git a/kordac/tests/assets/scratch/example_other_code.md b/verto/tests/assets/scratch/example_other_code.md similarity index 100% rename from kordac/tests/assets/scratch/example_other_code.md rename to verto/tests/assets/scratch/example_other_code.md diff --git a/kordac/tests/assets/scratch/example_other_code_expected.html b/verto/tests/assets/scratch/example_other_code_expected.html similarity index 100% rename from kordac/tests/assets/scratch/example_other_code_expected.html rename to verto/tests/assets/scratch/example_other_code_expected.html diff --git a/kordac/tests/assets/scratch/example_separate_blocks.md b/verto/tests/assets/scratch/example_separate_blocks.md similarity index 100% rename from kordac/tests/assets/scratch/example_separate_blocks.md rename to verto/tests/assets/scratch/example_separate_blocks.md diff --git a/kordac/tests/assets/scratch/example_separate_blocks_expected.html b/verto/tests/assets/scratch/example_separate_blocks_expected.html similarity index 100% rename from kordac/tests/assets/scratch/example_separate_blocks_expected.html rename to verto/tests/assets/scratch/example_separate_blocks_expected.html diff --git a/kordac/tests/assets/scratch/example_standard_markdown_block.md b/verto/tests/assets/scratch/example_standard_markdown_block.md similarity index 100% rename from kordac/tests/assets/scratch/example_standard_markdown_block.md rename to verto/tests/assets/scratch/example_standard_markdown_block.md diff --git a/kordac/tests/assets/scratch/example_standard_markdown_block_expected.html b/verto/tests/assets/scratch/example_standard_markdown_block_expected.html similarity index 100% rename from kordac/tests/assets/scratch/example_standard_markdown_block_expected.html rename to verto/tests/assets/scratch/example_standard_markdown_block_expected.html diff --git a/kordac/tests/assets/smoke/algorithms.md b/verto/tests/assets/smoke/algorithms.md similarity index 100% rename from kordac/tests/assets/smoke/algorithms.md rename to verto/tests/assets/smoke/algorithms.md diff --git a/kordac/tests/assets/smoke/introduction.md b/verto/tests/assets/smoke/introduction.md similarity index 100% rename from kordac/tests/assets/smoke/introduction.md rename to verto/tests/assets/smoke/introduction.md diff --git a/kordac/tests/assets/table-of-contents/doc_example_basic_usage.md b/verto/tests/assets/table-of-contents/doc_example_basic_usage.md similarity index 100% rename from kordac/tests/assets/table-of-contents/doc_example_basic_usage.md rename to verto/tests/assets/table-of-contents/doc_example_basic_usage.md diff --git a/kordac/tests/assets/table-of-contents/doc_example_basic_usage_expected.html b/verto/tests/assets/table-of-contents/doc_example_basic_usage_expected.html similarity index 100% rename from kordac/tests/assets/table-of-contents/doc_example_basic_usage_expected.html rename to verto/tests/assets/table-of-contents/doc_example_basic_usage_expected.html diff --git a/kordac/tests/assets/table-of-contents/doc_example_override_html.md b/verto/tests/assets/table-of-contents/doc_example_override_html.md similarity index 100% rename from kordac/tests/assets/table-of-contents/doc_example_override_html.md rename to verto/tests/assets/table-of-contents/doc_example_override_html.md diff --git a/kordac/tests/assets/table-of-contents/doc_example_override_html_expected.html b/verto/tests/assets/table-of-contents/doc_example_override_html_expected.html similarity index 100% rename from kordac/tests/assets/table-of-contents/doc_example_override_html_expected.html rename to verto/tests/assets/table-of-contents/doc_example_override_html_expected.html diff --git a/kordac/tests/assets/table-of-contents/doc_example_override_html_template.html b/verto/tests/assets/table-of-contents/doc_example_override_html_template.html similarity index 100% rename from kordac/tests/assets/table-of-contents/doc_example_override_html_template.html rename to verto/tests/assets/table-of-contents/doc_example_override_html_template.html diff --git a/kordac/tests/assets/video/contains_multiple_videos.md b/verto/tests/assets/video/contains_multiple_videos.md similarity index 100% rename from kordac/tests/assets/video/contains_multiple_videos.md rename to verto/tests/assets/video/contains_multiple_videos.md diff --git a/kordac/tests/assets/video/contains_multiple_videos_expected.html b/verto/tests/assets/video/contains_multiple_videos_expected.html similarity index 100% rename from kordac/tests/assets/video/contains_multiple_videos_expected.html rename to verto/tests/assets/video/contains_multiple_videos_expected.html diff --git a/kordac/tests/assets/video/contains_no_video.md b/verto/tests/assets/video/contains_no_video.md similarity index 100% rename from kordac/tests/assets/video/contains_no_video.md rename to verto/tests/assets/video/contains_no_video.md diff --git a/kordac/tests/assets/video/contains_no_video_expected.html b/verto/tests/assets/video/contains_no_video_expected.html similarity index 100% rename from kordac/tests/assets/video/contains_no_video_expected.html rename to verto/tests/assets/video/contains_no_video_expected.html diff --git a/kordac/tests/assets/video/contains_vimeo_video.md b/verto/tests/assets/video/contains_vimeo_video.md similarity index 100% rename from kordac/tests/assets/video/contains_vimeo_video.md rename to verto/tests/assets/video/contains_vimeo_video.md diff --git a/kordac/tests/assets/video/contains_vimeo_video_expected.html b/verto/tests/assets/video/contains_vimeo_video_expected.html similarity index 100% rename from kordac/tests/assets/video/contains_vimeo_video_expected.html rename to verto/tests/assets/video/contains_vimeo_video_expected.html diff --git a/kordac/tests/assets/video/doc_example_basic_usage.md b/verto/tests/assets/video/doc_example_basic_usage.md similarity index 100% rename from kordac/tests/assets/video/doc_example_basic_usage.md rename to verto/tests/assets/video/doc_example_basic_usage.md diff --git a/kordac/tests/assets/video/doc_example_basic_usage_expected.html b/verto/tests/assets/video/doc_example_basic_usage_expected.html similarity index 100% rename from kordac/tests/assets/video/doc_example_basic_usage_expected.html rename to verto/tests/assets/video/doc_example_basic_usage_expected.html diff --git a/kordac/tests/assets/video/doc_example_override_html.md b/verto/tests/assets/video/doc_example_override_html.md similarity index 100% rename from kordac/tests/assets/video/doc_example_override_html.md rename to verto/tests/assets/video/doc_example_override_html.md diff --git a/kordac/tests/assets/video/doc_example_override_html_expected.html b/verto/tests/assets/video/doc_example_override_html_expected.html similarity index 100% rename from kordac/tests/assets/video/doc_example_override_html_expected.html rename to verto/tests/assets/video/doc_example_override_html_expected.html diff --git a/kordac/tests/assets/video/doc_example_override_html_template.html b/verto/tests/assets/video/doc_example_override_html_template.html similarity index 100% rename from kordac/tests/assets/video/doc_example_override_html_template.html rename to verto/tests/assets/video/doc_example_override_html_template.html diff --git a/kordac/tests/assets/video/doc_example_override_html_youtube_template.html b/verto/tests/assets/video/doc_example_override_html_youtube_template.html similarity index 100% rename from kordac/tests/assets/video/doc_example_override_html_youtube_template.html rename to verto/tests/assets/video/doc_example_override_html_youtube_template.html diff --git a/kordac/tests/assets/video/missing_identifier.md b/verto/tests/assets/video/missing_identifier.md similarity index 100% rename from kordac/tests/assets/video/missing_identifier.md rename to verto/tests/assets/video/missing_identifier.md diff --git a/kordac/tests/assets/video/multiple_vimeo_links.md b/verto/tests/assets/video/multiple_vimeo_links.md similarity index 100% rename from kordac/tests/assets/video/multiple_vimeo_links.md rename to verto/tests/assets/video/multiple_vimeo_links.md diff --git a/kordac/tests/assets/video/multiple_vimeo_links_expected.html b/verto/tests/assets/video/multiple_vimeo_links_expected.html similarity index 100% rename from kordac/tests/assets/video/multiple_vimeo_links_expected.html rename to verto/tests/assets/video/multiple_vimeo_links_expected.html diff --git a/kordac/tests/assets/video/multiple_youtube_links.md b/verto/tests/assets/video/multiple_youtube_links.md similarity index 100% rename from kordac/tests/assets/video/multiple_youtube_links.md rename to verto/tests/assets/video/multiple_youtube_links.md diff --git a/kordac/tests/assets/video/multiple_youtube_links_expected.html b/verto/tests/assets/video/multiple_youtube_links_expected.html similarity index 100% rename from kordac/tests/assets/video/multiple_youtube_links_expected.html rename to verto/tests/assets/video/multiple_youtube_links_expected.html diff --git a/kordac/tests/assets/video/unsupported_video_type.md b/verto/tests/assets/video/unsupported_video_type.md similarity index 100% rename from kordac/tests/assets/video/unsupported_video_type.md rename to verto/tests/assets/video/unsupported_video_type.md diff --git a/kordac/tests/assets/video/vimeo_link.md b/verto/tests/assets/video/vimeo_link.md similarity index 100% rename from kordac/tests/assets/video/vimeo_link.md rename to verto/tests/assets/video/vimeo_link.md diff --git a/kordac/tests/assets/video/vimeo_link_expected.html b/verto/tests/assets/video/vimeo_link_expected.html similarity index 100% rename from kordac/tests/assets/video/vimeo_link_expected.html rename to verto/tests/assets/video/vimeo_link_expected.html diff --git a/kordac/tests/assets/video/vimeo_player_link.md b/verto/tests/assets/video/vimeo_player_link.md similarity index 100% rename from kordac/tests/assets/video/vimeo_player_link.md rename to verto/tests/assets/video/vimeo_player_link.md diff --git a/kordac/tests/assets/video/vimeo_player_link_expected.html b/verto/tests/assets/video/vimeo_player_link_expected.html similarity index 100% rename from kordac/tests/assets/video/vimeo_player_link_expected.html rename to verto/tests/assets/video/vimeo_player_link_expected.html diff --git a/kordac/tests/assets/video/youtube_and_vimeo_links.md b/verto/tests/assets/video/youtube_and_vimeo_links.md similarity index 100% rename from kordac/tests/assets/video/youtube_and_vimeo_links.md rename to verto/tests/assets/video/youtube_and_vimeo_links.md diff --git a/kordac/tests/assets/video/youtube_and_vimeo_links_expected.html b/verto/tests/assets/video/youtube_and_vimeo_links_expected.html similarity index 100% rename from kordac/tests/assets/video/youtube_and_vimeo_links_expected.html rename to verto/tests/assets/video/youtube_and_vimeo_links_expected.html diff --git a/kordac/tests/assets/video/youtube_be_link.md b/verto/tests/assets/video/youtube_be_link.md similarity index 100% rename from kordac/tests/assets/video/youtube_be_link.md rename to verto/tests/assets/video/youtube_be_link.md diff --git a/kordac/tests/assets/video/youtube_be_link_expected.html b/verto/tests/assets/video/youtube_be_link_expected.html similarity index 100% rename from kordac/tests/assets/video/youtube_be_link_expected.html rename to verto/tests/assets/video/youtube_be_link_expected.html diff --git a/kordac/tests/assets/video/youtube_embed_link.md b/verto/tests/assets/video/youtube_embed_link.md similarity index 100% rename from kordac/tests/assets/video/youtube_embed_link.md rename to verto/tests/assets/video/youtube_embed_link.md diff --git a/kordac/tests/assets/video/youtube_embed_link_expected.html b/verto/tests/assets/video/youtube_embed_link_expected.html similarity index 100% rename from kordac/tests/assets/video/youtube_embed_link_expected.html rename to verto/tests/assets/video/youtube_embed_link_expected.html diff --git a/kordac/tests/assets/video/youtube_watch_link.md b/verto/tests/assets/video/youtube_watch_link.md similarity index 100% rename from kordac/tests/assets/video/youtube_watch_link.md rename to verto/tests/assets/video/youtube_watch_link.md diff --git a/kordac/tests/assets/video/youtube_watch_link_expected.html b/verto/tests/assets/video/youtube_watch_link_expected.html similarity index 100% rename from kordac/tests/assets/video/youtube_watch_link_expected.html rename to verto/tests/assets/video/youtube_watch_link_expected.html diff --git a/kordac/tests/start_tests.py b/verto/tests/start_tests.py similarity index 69% rename from kordac/tests/start_tests.py rename to verto/tests/start_tests.py index 79895e86..0834b34f 100644 --- a/kordac/tests/start_tests.py +++ b/verto/tests/start_tests.py @@ -1,29 +1,29 @@ import sys, unittest, optparse from collections import defaultdict -from kordac.tests.SmokeTests import SmokeFileTest, SmokeDocsTest -from kordac.tests.ConfigurationTest import ConfigurationTest -from kordac.tests.GlossaryLinkTest import GlossaryLinkTest -from kordac.tests.PanelTest import PanelTest -from kordac.tests.CommentTest import CommentTest -from kordac.tests.HeadingTest import HeadingTest -from kordac.tests.ImageTest import ImageTest -from kordac.tests.VideoTest import VideoTest -from kordac.tests.InteractiveTest import InteractiveTest -from kordac.tests.ButtonLinkTest import ButtonLinkTest -from kordac.tests.BoxedTextTest import BoxedTextTest -from kordac.tests.SaveTitleTest import SaveTitleTest -from kordac.tests.RemoveTitleTest import RemoveTitleTest -from kordac.tests.RelativeLinkTest import RelativeLinkTest -from kordac.tests.ConditionalTest import ConditionalTest -from kordac.tests.FrameTest import FrameTest -from kordac.tests.TableOfContentsTest import TableOfContentsTest -from kordac.tests.ScratchTest import ScratchTest -from kordac.tests.BeautifyTest import BeautifyTest +from verto.tests.SmokeTests import SmokeFileTest, SmokeDocsTest +from verto.tests.ConfigurationTest import ConfigurationTest +from verto.tests.GlossaryLinkTest import GlossaryLinkTest +from verto.tests.PanelTest import PanelTest +from verto.tests.CommentTest import CommentTest +from verto.tests.HeadingTest import HeadingTest +from verto.tests.ImageTest import ImageTest +from verto.tests.VideoTest import VideoTest +from verto.tests.InteractiveTest import InteractiveTest +from verto.tests.ButtonLinkTest import ButtonLinkTest +from verto.tests.BoxedTextTest import BoxedTextTest +from verto.tests.SaveTitleTest import SaveTitleTest +from verto.tests.RemoveTitleTest import RemoveTitleTest +from verto.tests.RelativeLinkTest import RelativeLinkTest +from verto.tests.ConditionalTest import ConditionalTest +from verto.tests.FrameTest import FrameTest +from verto.tests.TableOfContentsTest import TableOfContentsTest +from verto.tests.ScratchTest import ScratchTest +from verto.tests.BeautifyTest import BeautifyTest def parse_args(): opts = optparse.OptionParser( - usage='Run the command `python -m kordac.tests.start_tests` from the level above the kordac directory.', description="Verifies that Kordac is functional compared to the testing suite.") + usage='Run the command `python -m verto.tests.start_tests` from the level above the verto directory.', description="Verifies that Verto is functional compared to the testing suite.") opts.add_option('--travis', action='store_true', help='Enables skipping suites on failure. To be used by continuous integration system.', default=False) opts.add_option('--no_smoke', diff --git a/kordac/utils/HeadingNode.py b/verto/utils/HeadingNode.py similarity index 100% rename from kordac/utils/HeadingNode.py rename to verto/utils/HeadingNode.py diff --git a/kordac/utils/UniqueSlugify.py b/verto/utils/UniqueSlugify.py similarity index 100% rename from kordac/utils/UniqueSlugify.py rename to verto/utils/UniqueSlugify.py diff --git a/kordac/utils/__init__.py b/verto/utils/__init__.py similarity index 100% rename from kordac/utils/__init__.py rename to verto/utils/__init__.py diff --git a/kordac/utils/overrides.py b/verto/utils/overrides.py similarity index 100% rename from kordac/utils/overrides.py rename to verto/utils/overrides.py From 1c867b6bf197e1d9a0e01f3c7cef408fb16c1b28 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Fri, 31 Mar 2017 11:40:42 +1300 Subject: [PATCH 77/86] Update logo. --- verto/images/verto-logo.png | Bin 6535 -> 33749 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/verto/images/verto-logo.png b/verto/images/verto-logo.png index 8c19916d7d597da680495b3fc6928655d26f3c4d..6bf7a2be80de2a55eccbd7b942484f729689648c 100644 GIT binary patch literal 33749 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 Date: Fri, 31 Mar 2017 15:53:07 +1300 Subject: [PATCH 78/86] PR updates --- .../GenericContainerBlockProcessor.py | 7 +- .../processors/InteractiveBlockProcessor.py | 4 - .../processors/errors/ArgumentValueError.py | 1 - .../errors/InvalidParameterError.py | 18 -- kordac/processors/utils.py | 24 +- kordac/tests/ConditionalTest.py | 8 +- kordac/tests/HeadingTest.py | 3 +- kordac/tests/ImageTest.py | 5 +- kordac/tests/InteractiveTest.py | 10 +- kordac/tests/PanelTest.py | 5 +- kordac/tests/RelativeLinkTest.py | 4 +- kordac/tests/ScratchTest.py | 45 ++-- .../comment/comment_within_block_container.md | 1 + ...mment_within_block_container_expected.html | 4 +- ...elif_noelse.md => example_elif_no_else.md} | 0 ...tml => example_elif_no_else_expected.html} | 0 ...tml => example_elif_no_else_template.html} | 0 .../assets/panel/parses_blank_expected.html | 11 - verto/VertoExtension.py | 224 ++++++++++++++++++ 19 files changed, 289 insertions(+), 85 deletions(-) delete mode 100644 kordac/processors/errors/InvalidParameterError.py rename kordac/tests/assets/conditional/{example_elif_noelse.md => example_elif_no_else.md} (100%) rename kordac/tests/assets/conditional/{example_elif_noelse_expected.html => example_elif_no_else_expected.html} (100%) rename kordac/tests/assets/conditional/{example_elif_noelse_template.html => example_elif_no_else_template.html} (100%) delete mode 100644 kordac/tests/assets/panel/parses_blank_expected.html create mode 100644 verto/VertoExtension.py diff --git a/kordac/processors/GenericContainerBlockProcessor.py b/kordac/processors/GenericContainerBlockProcessor.py index f3f0f1b5..026bf772 100644 --- a/kordac/processors/GenericContainerBlockProcessor.py +++ b/kordac/processors/GenericContainerBlockProcessor.py @@ -1,5 +1,6 @@ from markdown.blockprocessors import BlockProcessor from kordac.processors.errors.TagNotMatchedError import TagNotMatchedError +from kordac.processors.errors.ArgumentValueError import ArgumentValueError from kordac.processors.utils import etree, parse_arguments, process_parameters, blocks_to_string import re @@ -96,7 +97,11 @@ def run(self, parent, blocks): content = '' for child in content_tree: - content += etree.tostring(child, encoding="unicode", method="html") + '\n' + content += etree.tostring(child, encoding='unicode', method='html') + '\n' + + if content.strip() == '': + message = 'content cannot be blank.' + raise ArgumentValueError(self.processor, 'content', content, message) argument_values['content'] = content context = self.process_parameters(self.processor, self.template_parameters, argument_values) diff --git a/kordac/processors/InteractiveBlockProcessor.py b/kordac/processors/InteractiveBlockProcessor.py index 6b3b7340..2ac79ae6 100644 --- a/kordac/processors/InteractiveBlockProcessor.py +++ b/kordac/processors/InteractiveBlockProcessor.py @@ -1,5 +1,4 @@ from kordac.processors.GenericTagBlockProcessor import GenericTagBlockProcessor -from kordac.processors.errors.InvalidParameterError import InvalidParameterError from kordac.processors.utils import etree, parse_arguments import re @@ -62,9 +61,6 @@ def run(self, parent, blocks): text = argument_values.get('text', None) parameters = argument_values.get('parameters', None) - if name is not None and name is '': - raise InvalidParameterError(self.processor, "name", "Name parameter must not be an empty string.") - if interactive_type == 'in-page': self.scripts.add('interactive/{}/scripts.html'.format(name)) if interactive_type != 'whole-page': diff --git a/kordac/processors/errors/ArgumentValueError.py b/kordac/processors/errors/ArgumentValueError.py index 918a15dc..0eee6994 100644 --- a/kordac/processors/errors/ArgumentValueError.py +++ b/kordac/processors/errors/ArgumentValueError.py @@ -7,7 +7,6 @@ class ArgumentValueError(Error): Attributes: tag: tag which was not matched - block: block where tag was not matched argument: the argument that was not found value: the value that was not matched message: explanation of why error was thrown diff --git a/kordac/processors/errors/InvalidParameterError.py b/kordac/processors/errors/InvalidParameterError.py deleted file mode 100644 index 692d0b23..00000000 --- a/kordac/processors/errors/InvalidParameterError.py +++ /dev/null @@ -1,18 +0,0 @@ -from kordac.processors.errors.Error import Error - - -class InvalidParameterError(Error): - '''Exception raised when an invalid parameter value is found. - - Attributes: - tag: tag which was not matched - block: block where tag was not matched - parameter: the parameter that was not found - message: explanation of why error was thrown - ''' - - def __init__(self, tag, parameter, message): - super().__init__(message) - self.tag = tag - self.parameter = parameter - self.message = message diff --git a/kordac/processors/utils.py b/kordac/processors/utils.py index 5d369f08..623957fd 100644 --- a/kordac/processors/utils.py +++ b/kordac/processors/utils.py @@ -6,7 +6,7 @@ def parse_argument(argument_key, arguments, default=None): - ''' Search for the given argument in a string of all arguments + '''Search for the given argument in a string of all arguments Args: argument_key: The name of the argument. @@ -24,7 +24,7 @@ def parse_argument(argument_key, arguments, default=None): def parse_flag(argument_key, arguments, default=False): - ''' Search for the given argument in a string of all arguments, + '''Search for the given argument in a string of all arguments, treating the argument as a flag only. Args: @@ -43,7 +43,7 @@ def parse_flag(argument_key, arguments, default=False): def parse_arguments(processor, inputs, arguments): - ''' Parses the arguments of a given input and ensures + '''Parses the arguments of a given input and ensures they meet the defined requirements. Args: @@ -63,29 +63,31 @@ def parse_arguments(processor, inputs, arguments): is_flag = parse_flag(argument, inputs) if is_required and not (is_arg or is_flag): - raise ArgumentMissingError(processor, argument, "{} is a required argument.".format(argument)) + raise ArgumentMissingError(processor, argument, '{} is a required argument.'.format(argument)) elif not is_required and (is_arg or is_flag): dependencies = argument_info.get('dependencies', []) 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) + message = '{} is a required argument because {} exists.'.format(other_argument, argument) raise ArgumentMissingError(processor, argument, message) if is_flag: argument_values[argument] = True elif is_arg: value = parse_argument(argument, inputs, None) + if value and value.strip() == '': + message = '{} cannot be blank.'.format(argument) + raise ArgumentValueError(processor, argument, value, message) if argument_info.get('values', None) and value not in argument_info['values']: - message = "{} is not one of {}".format(value, argument_info['values']) + message = '{} is not one of {}.'.format(value, argument_info['values']) raise ArgumentValueError(processor, argument, value, message) argument_values[argument] = value return argument_values def process_parameters(ext, processor, parameters, argument_values): - ''' - Processes a given set of arguments by the parameter definitions. + '''Processes a given set of arguments by the parameter definitions. Args: processor: The processor of the given arguments. @@ -121,8 +123,7 @@ def process_parameters(ext, processor, parameters, argument_values): def find_transformation(ext, option): - ''' - Returns a transformation for a given string. + '''Returns a transformation for a given string. TODO: In future should be able to combine piped transformations into a single function. @@ -140,7 +141,8 @@ def find_transformation(ext, option): def blocks_to_string(blocks): - ''' Returns a string after the blocks have been joined back together. + '''Returns a string after the blocks have been joined back + together. Args: blocks: A list of strings of the document blocks. diff --git a/kordac/tests/ConditionalTest.py b/kordac/tests/ConditionalTest.py index c334dcbb..b0829c47 100644 --- a/kordac/tests/ConditionalTest.py +++ b/kordac/tests/ConditionalTest.py @@ -33,20 +33,20 @@ def test_example_basic_else(self): expected_string = self.read_test_file(self.processor_name, 'example_basic_else_usage_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - def test_example_elif_noelse(self): + def test_example_elif_no_else(self): '''Complex example showing multiple elif statements with no else statement. ''' - test_string = self.read_test_file(self.processor_name, 'example_elif_noelse.md') + test_string = self.read_test_file(self.processor_name, 'example_elif_no_else.md') blocks = self.to_blocks(test_string) self.assertListEqual([True, False, True, False, True, False, True], [ConditionalProcessor(self.ext, self.md.parser).test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - html_template = self.read_test_file(self.processor_name, 'example_elif_noelse_template.html', strip=True) + html_template = self.read_test_file(self.processor_name, 'example_elif_no_else_template.html', strip=True) kordac_extension = KordacExtension([self.processor_name], html_templates={self.processor_name: html_template}) converted_test_string = markdown.markdown(test_string, extensions=[kordac_extension]) - expected_string = self.read_test_file(self.processor_name, 'example_elif_noelse_expected.html', strip=True) + expected_string = self.read_test_file(self.processor_name, 'example_elif_no_else_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) def test_example_single_elif(self): diff --git a/kordac/tests/HeadingTest.py b/kordac/tests/HeadingTest.py index b4aa6104..96c13985 100644 --- a/kordac/tests/HeadingTest.py +++ b/kordac/tests/HeadingTest.py @@ -12,7 +12,7 @@ class HeadingTest(ProcessorTest): functionality of the default markdown (#) heading. We allow for an html override and the final result also outputs a tree representing the layout of the headings. A consideration when - testing is that slugs of headings should all be unique. + creating tests is that slugs of headings are unique. ''' def __init__(self, *args, **kwargs): @@ -65,7 +65,6 @@ def test_single_heading(self): def test_multiple_roots_zero_level(self): '''Test complex usage of heading where root level nodes may be of varying levels until an H1 is used. - environment. ''' test_string = self.read_test_file(self.processor_name, 'multiple_roots_zero_level.md') blocks = self.to_blocks(test_string) diff --git a/kordac/tests/ImageTest.py b/kordac/tests/ImageTest.py index dd5c1e80..48ccdf1b 100644 --- a/kordac/tests/ImageTest.py +++ b/kordac/tests/ImageTest.py @@ -22,7 +22,10 @@ def __init__(self, *args, **kwargs): ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'image' self.ext = Mock() - self.ext.jinja_templates = {self.processor_name: ProcessorTest.loadJinjaTemplate(self, self.processor_name), 'relative-file-link': ProcessorTest.loadJinjaTemplate(self, 'relative-file-link')} + self.ext.jinja_templates = { + self.processor_name: ProcessorTest.loadJinjaTemplate(self, self.processor_name), + 'relative-file-link': ProcessorTest.loadJinjaTemplate(self, 'relative-file-link') + } self.ext.processor_info = ProcessorTest.loadProcessorInfo(self) self.ext.required_files = defaultdict(set) diff --git a/kordac/tests/InteractiveTest.py b/kordac/tests/InteractiveTest.py index ac5e731b..40209bed 100644 --- a/kordac/tests/InteractiveTest.py +++ b/kordac/tests/InteractiveTest.py @@ -9,13 +9,15 @@ class InteractiveTest(ProcessorTest): '''The interactive processor is a simple tag with a complex output that relies on external systems. - Internally linked file features need to be considered - when testing images, such that required files are modified - and need to be checked to see if updated correctly. + When writing tests whether or not the thumbnail is externally + or internally linked will changed output. If the thumbnail is + internal then the required files must be modified to include + this image. ''' def __init__(self, *args, **kwargs): - '''Set processor name in class for file names.''' + '''Set processor name in class for file names. + ''' ProcessorTest.__init__(self, *args, **kwargs) self.processor_name = 'interactive' self.ext = Mock() diff --git a/kordac/tests/PanelTest.py b/kordac/tests/PanelTest.py index 524610ff..667a0b05 100644 --- a/kordac/tests/PanelTest.py +++ b/kordac/tests/PanelTest.py @@ -4,6 +4,7 @@ from kordac.KordacExtension import KordacExtension from kordac.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor from kordac.processors.errors.TagNotMatchedError import TagNotMatchedError +from kordac.processors.errors.ArgumentValueError import ArgumentValueError from kordac.tests.ProcessorTest import ProcessorTest class PanelTest(ProcessorTest): @@ -31,9 +32,7 @@ def test_parses_blank(self): self.assertListEqual([True, True], [self.block_processor.test(blocks, block) for block in blocks], msg='"{}"'.format(test_string)) - converted_test_string = markdown.markdown(test_string, extensions=[self.kordac_extension]) - expected_string = self.read_test_file(self.processor_name, 'parses_blank_expected.html', strip=True) - self.assertEqual(expected_string, converted_test_string) + self.assertRaises(ArgumentValueError, lambda x: markdown.markdown(x, extensions=[self.kordac_extension]),test_string) def test_parses_no_blank_lines_single_paragraph(self): '''Tests that a block of text as content is added to the panel. diff --git a/kordac/tests/RelativeLinkTest.py b/kordac/tests/RelativeLinkTest.py index 3b273816..9cd38153 100644 --- a/kordac/tests/RelativeLinkTest.py +++ b/kordac/tests/RelativeLinkTest.py @@ -32,7 +32,7 @@ def test_basic_usage(self): self.assertEqual(expected_string, converted_test_string) def test_long_path(self): - '''Tests that long paths less than 31 characters work. + '''Tests that long paths with less than 31 characters work. ''' test_string = self.read_test_file(self.processor_name, 'long_path.md') @@ -44,7 +44,7 @@ def test_long_path(self): 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') diff --git a/kordac/tests/ScratchTest.py b/kordac/tests/ScratchTest.py index 14292f55..2a80fc81 100644 --- a/kordac/tests/ScratchTest.py +++ b/kordac/tests/ScratchTest.py @@ -22,9 +22,11 @@ def setUp(self): extension by default (as this is the desired usecase). ''' self.kordac_extension = KordacExtension([self.processor_name], {}, ['markdown.extensions.fenced_code']) + #~ # Doc Tests #~ + def test_doc_example_basic(self): '''An example of common useage. ''' @@ -34,15 +36,14 @@ 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) - # Should really test result a better way - actual = self.kordac_extension.required_files['scratch_images'] - expected = { + actual_scratch_images = self.kordac_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, expected) + 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,14 +57,14 @@ 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 = kordac_extension.required_files['scratch_images'] - expected = { + actual_scratch_images = kordac_extension.required_files['scratch_images'] + expected_scratch_images = { ScratchImageMetaData( hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', text='when flag clicked\nsay [Hi]' ), } - self.assertSetEqual(actual, expected) + self.assertSetEqual(actual_scratch_images, expected_scratch_images) #~ # Other Tests @@ -79,14 +80,14 @@ def test_example_standard_markdown_block(self): self.assertEqual(expected_string, converted_test_string) # Should really test result a better way - actual = kordac_extension.required_files['scratch_images'] - expected = { + actual_scratch_images = kordac_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, expected) + self.assertSetEqual(actual_scratch_images, expected_scratch_images) def test_example_separate_blocks(self): '''Tests that code separated by whitespace is still processed. @@ -98,14 +99,14 @@ def test_example_separate_blocks(self): self.assertEqual(expected_string, converted_test_string) # Should really test result a better way - actual = self.kordac_extension.required_files['scratch_images'] - expected = { + actual_scratch_images = self.kordac_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, expected) + self.assertSetEqual(actual_scratch_images, expected_scratch_images) def test_example_multiple_codeblocks(self): @@ -118,8 +119,8 @@ def test_example_multiple_codeblocks(self): self.assertEqual(expected_string, converted_test_string) # Should really test result a better way - actual = self.kordac_extension.required_files['scratch_images'] - expected = { + actual_scratch_images = self.kordac_extension.required_files['scratch_images'] + expected_scratch_images = { ScratchImageMetaData( hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', text='when flag clicked\nsay [Hi]' @@ -133,7 +134,7 @@ def test_example_multiple_codeblocks(self): 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, expected) + self.assertSetEqual(actual_scratch_images, expected_scratch_images) def test_example_multiple_codeblocks_2(self): '''Tests that enabling the codehilite extension does not effect @@ -148,8 +149,8 @@ def test_example_multiple_codeblocks_2(self): self.assertEqual(expected_string, converted_test_string) # Should really test result a better way - actual = kordac_extension.required_files['scratch_images'] - expected = { + actual_scratch_images = kordac_extension.required_files['scratch_images'] + expected_scratch_images = { ScratchImageMetaData( hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', text='when flag clicked\nsay [Hi]' @@ -163,7 +164,7 @@ def test_example_multiple_codeblocks_2(self): 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, expected) + self.assertSetEqual(actual_scratch_images, expected_scratch_images) def test_example_other_code(self): '''Tests that other codeblocks that are not scratch codeblocks @@ -176,11 +177,11 @@ def test_example_other_code(self): self.assertEqual(expected_string, converted_test_string) # Should really test result a better way - actual = self.kordac_extension.required_files['scratch_images'] - expected = { + actual_scratch_images = self.kordac_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, expected) + self.assertSetEqual(actual_scratch_images, expected_scratch_images) diff --git a/kordac/tests/assets/comment/comment_within_block_container.md b/kordac/tests/assets/comment/comment_within_block_container.md index 89a0bd6c..846345ac 100644 --- a/kordac/tests/assets/comment/comment_within_block_container.md +++ b/kordac/tests/assets/comment/comment_within_block_container.md @@ -1,5 +1,6 @@ {panel type="lipsum" title="Lipsum Lorem"} {comment This is a comment for other authors to read} +Should be the only text left. {panel end} diff --git a/kordac/tests/assets/comment/comment_within_block_container_expected.html b/kordac/tests/assets/comment/comment_within_block_container_expected.html index af6d002b..4fc569d0 100644 --- a/kordac/tests/assets/comment/comment_within_block_container_expected.html +++ b/kordac/tests/assets/comment/comment_within_block_container_expected.html @@ -5,6 +5,8 @@
    -
    +

    + Should be the only text left. +

    diff --git a/kordac/tests/assets/conditional/example_elif_noelse.md b/kordac/tests/assets/conditional/example_elif_no_else.md similarity index 100% rename from kordac/tests/assets/conditional/example_elif_noelse.md rename to kordac/tests/assets/conditional/example_elif_no_else.md diff --git a/kordac/tests/assets/conditional/example_elif_noelse_expected.html b/kordac/tests/assets/conditional/example_elif_no_else_expected.html similarity index 100% rename from kordac/tests/assets/conditional/example_elif_noelse_expected.html rename to kordac/tests/assets/conditional/example_elif_no_else_expected.html diff --git a/kordac/tests/assets/conditional/example_elif_noelse_template.html b/kordac/tests/assets/conditional/example_elif_no_else_template.html similarity index 100% rename from kordac/tests/assets/conditional/example_elif_noelse_template.html rename to kordac/tests/assets/conditional/example_elif_no_else_template.html diff --git a/kordac/tests/assets/panel/parses_blank_expected.html b/kordac/tests/assets/panel/parses_blank_expected.html deleted file mode 100644 index 3e1c35b4..00000000 --- a/kordac/tests/assets/panel/parses_blank_expected.html +++ /dev/null @@ -1,11 +0,0 @@ -
    -
    - - Extra For Experts: - - Something About Love -
    -
    -
    -
    -
    diff --git a/verto/VertoExtension.py b/verto/VertoExtension.py new file mode 100644 index 00000000..658b9b0d --- /dev/null +++ b/verto/VertoExtension.py @@ -0,0 +1,224 @@ +from markdown.extensions import Extension +import markdown.util as utils + +from verto.processors.CommentPreprocessor import CommentPreprocessor +from verto.processors.VideoBlockProcessor import VideoBlockProcessor +from verto.processors.ImageBlockProcessor import ImageBlockProcessor +from verto.processors.InteractiveBlockProcessor import InteractiveBlockProcessor +from verto.processors.RelativeLinkPattern import RelativeLinkPattern +from verto.processors.RemoveTitlePreprocessor import RemoveTitlePreprocessor +from verto.processors.SaveTitlePreprocessor import SaveTitlePreprocessor +from verto.processors.GlossaryLinkPattern import GlossaryLinkPattern +from verto.processors.BeautifyPostprocessor import BeautifyPostprocessor +from verto.processors.ConditionalProcessor import ConditionalProcessor +from verto.processors.StylePreprocessor import StylePreprocessor +from verto.processors.RemovePostprocessor import RemovePostprocessor +from verto.processors.JinjaPostprocessor import JinjaPostprocessor +from verto.processors.HeadingBlockProcessor import HeadingBlockProcessor +from verto.processors.ScratchTreeprocessor import ScratchTreeprocessor +from verto.processors.ScratchCompatibilityPreprocessor import ScratchCompatibilityPreprocessor +from verto.processors.GenericTagBlockProcessor import GenericTagBlockProcessor +from verto.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor + +from verto.utils.UniqueSlugify import UniqueSlugify +from verto.utils.HeadingNode import HeadingNode +from verto.utils.overrides import is_block_level, BLOCK_LEVEL_ELEMENTS + +from collections import defaultdict, OrderedDict +from os import listdir +import os.path +import re +import json + +from jinja2 import Environment, PackageLoader, select_autoescape + + +class VertoExtension(Extension): + '''The Verto markdown extension which enables all the processors, + and extracts all the important information to expose externally to + the Verto converter. + ''' + + def __init__(self, processors=[], html_templates={}, extensions=[], *args, **kwargs): + ''' + Args: + processors: A set of processor names given as strings for which + their processors are enabled. If given, all other + processors are skipped. + html_templates: A dictionary of HTML templates to override + existing HTML templates for processors. Dictionary contains + processor names given as a string as keys mapping HTML strings + as values. + eg: {'image': ''} + extensions: A list of extra extensions for compatibility. + ''' + super().__init__(*args, **kwargs) + self.required_files = defaultdict(set) + self.title = None + self.jinja_templates = self.loadJinjaTemplates(html_templates) + self.processor_info = self.loadProcessorInfo() + self.processors = processors + self.custom_slugify = UniqueSlugify() + self.glossary_terms = defaultdict(list) + self.heading_tree = None + + self.compatibility = [] + for extension in extensions: + if isinstance(extension, utils.string_type): + if extension.endswith('codehilite'): + self.compatibility.append('hilite') + if extension.endswith('fenced_code'): + self.compatibility.append('fenced_code_block') + + def extendMarkdown(self, md, md_globals): + '''Inherited from the markdown.Extension class. Extends + markdown with custom processors. + ['style', StylePreprocessor(self, md), '_begin'] + + Args: + md: An instance of the markdown object to extend. + md_globals: Global variables in the markdown module namespace. + ''' + self.buildProcessors(md, md_globals) + + def update_processors(processors, markdown_processors): + for processor_data in processors: + if processor_data[0] in self.processors: + markdown_processors.add(processor_data[0], processor_data[1], processor_data[2]) + + update_processors(self.preprocessors, md.preprocessors) + update_processors(self.blockprocessors, md.parser.blockprocessors) + update_processors(self.inlinepatterns, md.inlinePatterns) + update_processors(self.treeprocessors, md.treeprocessors) + update_processors(self.postprocessors, md.postprocessors) + + md.preprocessors.add('style', StylePreprocessor(self, md), '_begin') + md.postprocessors.add('remove', RemovePostprocessor(md), '_end') + md.postprocessors.add('beautify', BeautifyPostprocessor(md), '_end') + md.postprocessors.add('jinja', JinjaPostprocessor(md), '_end') + + # Compatibility modules + md.postprocessors['raw_html'].isblocklevel = lambda html: is_block_level(html, BLOCK_LEVEL_ELEMENTS) + + if ('hilite' in self.compatibility + and 'fenced_code_block' in self.compatibility + and 'scratch' in self.processors): + processor = ScratchCompatibilityPreprocessor(self, md) + md.preprocessors.add('scratch-compatibility', processor, ' Date: Fri, 31 Mar 2017 15:59:48 +1300 Subject: [PATCH 79/86] Fixes from merge with develop. --- kordac/tests/assets/comment/comment_within_block_container.md | 1 + .../configuration/all_processors_custom_html_expected.html | 2 +- .../configuration/all_processors_except_comment_expected.html | 2 +- kordac/tests/assets/configuration/all_processors_expected.html | 2 +- .../assets/configuration/multiline_templates_expected.html | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/kordac/tests/assets/comment/comment_within_block_container.md b/kordac/tests/assets/comment/comment_within_block_container.md index 846345ac..80b64a2b 100644 --- a/kordac/tests/assets/comment/comment_within_block_container.md +++ b/kordac/tests/assets/comment/comment_within_block_container.md @@ -1,6 +1,7 @@ {panel type="lipsum" title="Lipsum Lorem"} {comment This is a comment for other authors to read} + Should be the only text left. {panel end} diff --git a/kordac/tests/assets/configuration/all_processors_custom_html_expected.html b/kordac/tests/assets/configuration/all_processors_custom_html_expected.html index 68a8e410..e92cf049 100644 --- a/kordac/tests/assets/configuration/all_processors_custom_html_expected.html +++ b/kordac/tests/assets/configuration/all_processors_custom_html_expected.html @@ -69,7 +69,7 @@

    Your browser does not support iframes.

    -
    +
    diff --git a/kordac/tests/assets/configuration/all_processors_except_comment_expected.html b/kordac/tests/assets/configuration/all_processors_except_comment_expected.html index ddac6ed5..c786864b 100644 --- a/kordac/tests/assets/configuration/all_processors_except_comment_expected.html +++ b/kordac/tests/assets/configuration/all_processors_except_comment_expected.html @@ -82,7 +82,7 @@

    Your browser does not support iframes.

    -
    +
    diff --git a/kordac/tests/assets/configuration/all_processors_expected.html b/kordac/tests/assets/configuration/all_processors_expected.html index 283046a3..b747d267 100644 --- a/kordac/tests/assets/configuration/all_processors_expected.html +++ b/kordac/tests/assets/configuration/all_processors_expected.html @@ -79,7 +79,7 @@

    Your browser does not support iframes.

    -
    +
    diff --git a/kordac/tests/assets/configuration/multiline_templates_expected.html b/kordac/tests/assets/configuration/multiline_templates_expected.html index b3ba5d68..03895b19 100644 --- a/kordac/tests/assets/configuration/multiline_templates_expected.html +++ b/kordac/tests/assets/configuration/multiline_templates_expected.html @@ -73,7 +73,7 @@

    Your browser does not support iframes.

    -
    +
    From 34f1a669bf40770a4168cd9f9994994e2d5bbaab Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Fri, 31 Mar 2017 16:06:28 +1300 Subject: [PATCH 80/86] Tidy new test code, remove old comments. --- kordac/tests/ScratchTest.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/kordac/tests/ScratchTest.py b/kordac/tests/ScratchTest.py index d78399fc..9c490b86 100644 --- a/kordac/tests/ScratchTest.py +++ b/kordac/tests/ScratchTest.py @@ -26,7 +26,6 @@ def setUp(self): #~ # Doc Tests #~ - def test_doc_example_basic(self): '''An example of common useage. ''' @@ -79,7 +78,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) - # Should really test result a better way actual_scratch_images = kordac_extension.required_files['scratch_images'] expected_scratch_images = { ScratchImageMetaData( @@ -98,7 +96,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) - # Should really test result a better way actual_scratch_images = self.kordac_extension.required_files['scratch_images'] expected_scratch_images = { ScratchImageMetaData( @@ -117,7 +114,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) - # Should really test result a better way actual_scratch_images = self.kordac_extension.required_files['scratch_images'] expected_scratch_images = { ScratchImageMetaData( @@ -147,7 +143,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) - # Should really test result a better way actual_scratch_images = kordac_extension.required_files['scratch_images'] expected_scratch_images = { ScratchImageMetaData( @@ -175,7 +170,6 @@ def test_example_split_codeblocks(self): expected_string = self.read_test_file(self.processor_name, 'example_split_codeblocks_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - # Should really test result a better way actual = self.kordac_extension.required_files['scratch_images'] expected = { ScratchImageMetaData( @@ -204,7 +198,6 @@ def test_example_split_codeblocks_default(self): expected_string = self.read_test_file(self.processor_name, 'example_split_codeblocks_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - # Should really test result a better way actual = kordac_extension.required_files['scratch_images'] expected = { ScratchImageMetaData( @@ -223,6 +216,8 @@ def test_example_split_codeblocks_default(self): self.assertSetEqual(actual, expected) def test_example_split_codeblocks_compatibility(self): + '''Tests that options are compatible with codehilite. + ''' extensions = ['markdown.extensions.codehilite', 'markdown.extensions.fenced_code'] kordac_extension = KordacExtension([self.processor_name], {}, extensions) test_string = self.read_test_file(self.processor_name, 'example_split_codeblocks.md') @@ -231,7 +226,6 @@ def test_example_split_codeblocks_compatibility(self): expected_string = self.read_test_file(self.processor_name, 'example_split_codeblocks_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - # Should really test result a better way actual = kordac_extension.required_files['scratch_images'] expected = { ScratchImageMetaData( @@ -287,7 +281,6 @@ def test_example_other_code(self): expected_string = self.read_test_file(self.processor_name, 'example_other_code_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - # Should really test result a better way actual_scratch_images = self.kordac_extension.required_files['scratch_images'] expected_scratch_images = { ScratchImageMetaData( From e2457bf6ef763d983c2ec70d08aff0c81a8b98af Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Fri, 31 Mar 2017 16:08:32 +1300 Subject: [PATCH 81/86] update missed variable names from last commit. --- kordac/tests/ScratchTest.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/kordac/tests/ScratchTest.py b/kordac/tests/ScratchTest.py index 9c490b86..ed712ec5 100644 --- a/kordac/tests/ScratchTest.py +++ b/kordac/tests/ScratchTest.py @@ -170,8 +170,8 @@ def test_example_split_codeblocks(self): expected_string = self.read_test_file(self.processor_name, 'example_split_codeblocks_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - actual = self.kordac_extension.required_files['scratch_images'] - expected = { + actual_scratch_images = self.kordac_extension.required_files['scratch_images'] + expected_scratch_images = { ScratchImageMetaData( hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', text='when flag clicked\nsay [Hi]' @@ -185,7 +185,7 @@ def test_example_split_codeblocks(self): 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, expected) + 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 @@ -198,8 +198,8 @@ def test_example_split_codeblocks_default(self): expected_string = self.read_test_file(self.processor_name, 'example_split_codeblocks_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - actual = kordac_extension.required_files['scratch_images'] - expected = { + actual_scratch_images = kordac_extension.required_files['scratch_images'] + expected_scratch_images = { ScratchImageMetaData( hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', text='when flag clicked\nsay [Hi]' @@ -213,7 +213,7 @@ def test_example_split_codeblocks_default(self): 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, expected) + self.assertSetEqual(actual_scratch_images, expected_scratch_images) def test_example_split_codeblocks_compatibility(self): '''Tests that options are compatible with codehilite. @@ -226,8 +226,8 @@ def test_example_split_codeblocks_compatibility(self): expected_string = self.read_test_file(self.processor_name, 'example_split_codeblocks_expected.html', strip=True) self.assertEqual(expected_string, converted_test_string) - actual = kordac_extension.required_files['scratch_images'] - expected = { + actual_scratch_images = kordac_extension.required_files['scratch_images'] + expected_scratch_images = { ScratchImageMetaData( hash='a3b77ed3c3fa57e43c830e338dc39d292c7def676e0e8f7545972b7da20275da', text='when flag clicked\nsay [Hi]' @@ -241,7 +241,7 @@ def test_example_split_codeblocks_compatibility(self): 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, expected) + self.assertSetEqual(actual_scratch_images, expected_scratch_images) def test_example_random_codeblocks(self): '''Tests that scratch images are arranged randomly given From 45bb95cbf088b8d6dec2a88aa23547f52c95bd62 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Mon, 3 Apr 2017 09:44:23 +1200 Subject: [PATCH 82/86] Added tests for combined custom processors and custom templates. --- kordac/tests/ConfigurationTest.py | 51 ++++++++---- ..._processors_custom_templates_expected.html | 79 +++++++++++++++++++ 2 files changed, 116 insertions(+), 14 deletions(-) create mode 100644 kordac/tests/assets/configuration/custom_processors_custom_templates_expected.html diff --git a/kordac/tests/ConfigurationTest.py b/kordac/tests/ConfigurationTest.py index 026981b2..47e4accb 100644 --- a/kordac/tests/ConfigurationTest.py +++ b/kordac/tests/ConfigurationTest.py @@ -136,6 +136,29 @@ def test_multiple_calls(self): self.assertTupleEqual(kordac_result.heading_tree, test[1].heading_tree) self.assertDictEqual(kordac_result.required_glossary_terms, test[1].required_glossary_terms) + def test_custom_processors_and_custom_templates_on_creation(self): + '''Checks if custom processors and custom templates work + together on creation of kordac. + ''' + processors = {'image', 'boxed-text'} + kordac = Kordac(processors=processors, html_templates=self.custom_templates) + test_string = self.read_test_file(self.test_name, 'all_processors.md') + converted_test_string = kordac.convert(test_string).html_string + expected_string = self.read_test_file(self.test_name, 'custom_processors_custom_templates_expected.html', strip=True) + self.assertEqual(expected_string, converted_test_string) + + def test_custom_processors_and_custom_templates_after_creation(self): + '''Checks if custom processors and custom templates work + together after creation of kordac. + ''' + processors = {'image', 'boxed-text'} + kordac = Kordac() + kordac.update_processors(processors) + kordac.update_templates(self.custom_templates) + test_string = self.read_test_file(self.test_name, 'all_processors.md') + converted_test_string = kordac.convert(test_string).html_string + expected_string = self.read_test_file(self.test_name, 'custom_processors_custom_templates_expected.html', strip=True) + self.assertEqual(expected_string, converted_test_string) def test_default_processors_on_creation(self): '''Checks if all expected default processors work on default @@ -148,8 +171,8 @@ def test_default_processors_on_creation(self): self.assertEqual(expected_string, converted_test_string) def test_custom_processors_on_creation(self): - """Checks if system only uses specified processors. - """ + '''Checks if system only uses specified processors. + ''' processors = {'panel', 'image'} kordac = Kordac(processors=processors) test_string = self.read_test_file(self.test_name, 'all_processors.md') @@ -158,8 +181,8 @@ def test_custom_processors_on_creation(self): self.assertEqual(expected_string, converted_test_string) def test_custom_processors_after_creation(self): - """Checks if extension correct changes processors. - """ + '''Checks if extension correct changes processors. + ''' kordac = Kordac() processors = Kordac.processor_defaults() processors.add('example_processor') @@ -174,9 +197,9 @@ def test_custom_processors_after_creation(self): self.assertEqual(expected_string, converted_test_string) def test_unique_custom_processors(self): - """Checks if unique processors are stored when duplicates + '''Checks if unique processors are stored when duplicates provided. - """ + ''' processors = ['comment', 'comment', 'comment'] kordac = Kordac(processors=processors) self.assertEqual(kordac.kordac_extension.processors, set(processors)) @@ -188,8 +211,8 @@ def test_unique_custom_processors(self): self.assertTrue(kordac.kordac_extension.processors, processors) def test_custom_templates_on_creation(self): - """Checks custom templates are used when given on creation. - """ + '''Checks custom templates are used when given on creation. + ''' kordac = Kordac(html_templates=self.custom_templates) test_string = self.read_test_file(self.test_name, 'all_processors.md') converted_test_string = kordac.convert(test_string).html_string @@ -197,8 +220,8 @@ def test_custom_templates_on_creation(self): self.assertEqual(expected_string, converted_test_string) def test_custom_templates_after_creation(self): - """Checks custom templates are used when given after creation. - """ + '''Checks custom templates are used when given after creation. + ''' kordac = Kordac() kordac.update_templates(self.custom_templates) test_string = self.read_test_file(self.test_name, 'all_processors.md') @@ -207,8 +230,8 @@ def test_custom_templates_after_creation(self): self.assertEqual(expected_string, converted_test_string) def test_reset_templates_after_custom(self): - """Checks custom templates are reset when given at creation. - """ + '''Checks custom templates are reset when given at creation. + ''' kordac = Kordac(html_templates=self.custom_templates) kordac.clear_templates() test_string = self.read_test_file(self.test_name, 'all_processors.md') @@ -217,9 +240,9 @@ def test_reset_templates_after_custom(self): self.assertEqual(expected_string, converted_test_string) def test_multiline_custom_templates(self): - """Checks that multiple multiline custom templates are loaded + '''Checks that multiple multiline custom templates are loaded and used correctly. - """ + ''' custom_templates = { "image": """
    diff --git a/kordac/tests/assets/configuration/custom_processors_custom_templates_expected.html b/kordac/tests/assets/configuration/custom_processors_custom_templates_expected.html new file mode 100644 index 00000000..1c8eee76 --- /dev/null +++ b/kordac/tests/assets/configuration/custom_processors_custom_templates_expected.html @@ -0,0 +1,79 @@ +

    + Example Title +

    +

    + This is a sentence. +

    +

    + Example Title 2 +

    +

    + {comment This is a comment for other authors to read} +

    +

    + Check out this + + resource + + . +

    +

    + {panel type="teacher-note" title="Teacher Note" subtitle="Guides for Algorithms"} +

    +

    + This text is the panel's contents. +

    +

    + {panel end} +

    + +
    +

    + + Computer Science Report for 2.44 + +

    +

    + Put your introduction to what bits are here. +

    +
    +

    + {button-link link="http://www.google.com" text="Visit Google"} +

    +

    + {conditional if condition="version == 'teacher'"} +

    +

    + This is text that only teachers should see. +

    +

    + {conditional end} +

    +

    + It's worth considering which {glossary-link term="algorithm"}algorithms{glossary-link end} should be used. +

    +

    + {iframe link="https://github.com/"} +

    +

    + {interactive name="binary-cards" type="iframe" parameters="digits=5&start=BBBBB"} +

    +
    scratch
    +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} +

    +

    + {video url="https://www.youtube.com/watch?v=dQw4w9WgXcQ"} +

    From e559f65f57982d32415e25a5df156a1e62fec660 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Mon, 3 Apr 2017 11:37:42 +1200 Subject: [PATCH 83/86] Remove accidental commit of rename. --- verto/VertoExtension.py | 224 ---------------------------------------- 1 file changed, 224 deletions(-) delete mode 100644 verto/VertoExtension.py diff --git a/verto/VertoExtension.py b/verto/VertoExtension.py deleted file mode 100644 index 658b9b0d..00000000 --- a/verto/VertoExtension.py +++ /dev/null @@ -1,224 +0,0 @@ -from markdown.extensions import Extension -import markdown.util as utils - -from verto.processors.CommentPreprocessor import CommentPreprocessor -from verto.processors.VideoBlockProcessor import VideoBlockProcessor -from verto.processors.ImageBlockProcessor import ImageBlockProcessor -from verto.processors.InteractiveBlockProcessor import InteractiveBlockProcessor -from verto.processors.RelativeLinkPattern import RelativeLinkPattern -from verto.processors.RemoveTitlePreprocessor import RemoveTitlePreprocessor -from verto.processors.SaveTitlePreprocessor import SaveTitlePreprocessor -from verto.processors.GlossaryLinkPattern import GlossaryLinkPattern -from verto.processors.BeautifyPostprocessor import BeautifyPostprocessor -from verto.processors.ConditionalProcessor import ConditionalProcessor -from verto.processors.StylePreprocessor import StylePreprocessor -from verto.processors.RemovePostprocessor import RemovePostprocessor -from verto.processors.JinjaPostprocessor import JinjaPostprocessor -from verto.processors.HeadingBlockProcessor import HeadingBlockProcessor -from verto.processors.ScratchTreeprocessor import ScratchTreeprocessor -from verto.processors.ScratchCompatibilityPreprocessor import ScratchCompatibilityPreprocessor -from verto.processors.GenericTagBlockProcessor import GenericTagBlockProcessor -from verto.processors.GenericContainerBlockProcessor import GenericContainerBlockProcessor - -from verto.utils.UniqueSlugify import UniqueSlugify -from verto.utils.HeadingNode import HeadingNode -from verto.utils.overrides import is_block_level, BLOCK_LEVEL_ELEMENTS - -from collections import defaultdict, OrderedDict -from os import listdir -import os.path -import re -import json - -from jinja2 import Environment, PackageLoader, select_autoescape - - -class VertoExtension(Extension): - '''The Verto markdown extension which enables all the processors, - and extracts all the important information to expose externally to - the Verto converter. - ''' - - def __init__(self, processors=[], html_templates={}, extensions=[], *args, **kwargs): - ''' - Args: - processors: A set of processor names given as strings for which - their processors are enabled. If given, all other - processors are skipped. - html_templates: A dictionary of HTML templates to override - existing HTML templates for processors. Dictionary contains - processor names given as a string as keys mapping HTML strings - as values. - eg: {'image': ''} - extensions: A list of extra extensions for compatibility. - ''' - super().__init__(*args, **kwargs) - self.required_files = defaultdict(set) - self.title = None - self.jinja_templates = self.loadJinjaTemplates(html_templates) - self.processor_info = self.loadProcessorInfo() - self.processors = processors - self.custom_slugify = UniqueSlugify() - self.glossary_terms = defaultdict(list) - self.heading_tree = None - - self.compatibility = [] - for extension in extensions: - if isinstance(extension, utils.string_type): - if extension.endswith('codehilite'): - self.compatibility.append('hilite') - if extension.endswith('fenced_code'): - self.compatibility.append('fenced_code_block') - - def extendMarkdown(self, md, md_globals): - '''Inherited from the markdown.Extension class. Extends - markdown with custom processors. - ['style', StylePreprocessor(self, md), '_begin'] - - Args: - md: An instance of the markdown object to extend. - md_globals: Global variables in the markdown module namespace. - ''' - self.buildProcessors(md, md_globals) - - def update_processors(processors, markdown_processors): - for processor_data in processors: - if processor_data[0] in self.processors: - markdown_processors.add(processor_data[0], processor_data[1], processor_data[2]) - - update_processors(self.preprocessors, md.preprocessors) - update_processors(self.blockprocessors, md.parser.blockprocessors) - update_processors(self.inlinepatterns, md.inlinePatterns) - update_processors(self.treeprocessors, md.treeprocessors) - update_processors(self.postprocessors, md.postprocessors) - - md.preprocessors.add('style', StylePreprocessor(self, md), '_begin') - md.postprocessors.add('remove', RemovePostprocessor(md), '_end') - md.postprocessors.add('beautify', BeautifyPostprocessor(md), '_end') - md.postprocessors.add('jinja', JinjaPostprocessor(md), '_end') - - # Compatibility modules - md.postprocessors['raw_html'].isblocklevel = lambda html: is_block_level(html, BLOCK_LEVEL_ELEMENTS) - - if ('hilite' in self.compatibility - and 'fenced_code_block' in self.compatibility - and 'scratch' in self.processors): - processor = ScratchCompatibilityPreprocessor(self, md) - md.preprocessors.add('scratch-compatibility', processor, ' Date: Mon, 3 Apr 2017 12:31:38 +1200 Subject: [PATCH 84/86] double qoute to single qoutes to keep consistency. --- kordac/processors/BeautifyPostprocessor.py | 4 ++-- kordac/processors/ConditionalProcessor.py | 2 +- kordac/processors/HeadingBlockProcessor.py | 4 ++-- kordac/processors/InteractiveBlockProcessor.py | 8 ++++---- .../ScratchCompatibilityPreprocessor.py | 4 ++-- kordac/processors/ScratchTreeprocessor.py | 6 +++--- kordac/processors/StylePreprocessor.py | 4 ++-- kordac/processors/errors/StyleError.py | 4 ++-- kordac/tests/BaseTest.py | 2 +- kordac/tests/ConfigurationTest.py | 16 ++++++++-------- kordac/tests/SmokeTests.py | 2 +- kordac/tests/start_tests.py | 10 +++++----- kordac/utils/UniqueSlugify.py | 2 +- kordac/utils/overrides.py | 2 +- setup.py | 2 +- 15 files changed, 36 insertions(+), 36 deletions(-) diff --git a/kordac/processors/BeautifyPostprocessor.py b/kordac/processors/BeautifyPostprocessor.py index 6d5fda22..d0aa9b48 100644 --- a/kordac/processors/BeautifyPostprocessor.py +++ b/kordac/processors/BeautifyPostprocessor.py @@ -27,7 +27,7 @@ def run(self, text): A string of the converted document. ''' text = self.store_non_pre_code_tags(text) - text = BeautifulSoup(text, 'html.parser').prettify(formatter="html") + text = BeautifulSoup(text, 'html.parser').prettify(formatter='html') text = self.restore_non_pre_code_tags(text) return text @@ -80,7 +80,7 @@ def restore_non_pre_code_tags(self, text): replacements[self.html_stash.get_placeholder(i)] = html if len(replacements) > 0: - pattern = re.compile("|".join(re.escape(k) for k in replacements)) + pattern = re.compile('|'.join(re.escape(k) for k in replacements)) text = pattern.sub(lambda m: replacements[m.group(0)], text) return text diff --git a/kordac/processors/ConditionalProcessor.py b/kordac/processors/ConditionalProcessor.py index d658c6d2..caef9c46 100644 --- a/kordac/processors/ConditionalProcessor.py +++ b/kordac/processors/ConditionalProcessor.py @@ -185,5 +185,5 @@ def parse_blocks(self, blocks): # Convert parsed element tree back into html text for rendering content = '' for child in content_tree: - content += etree.tostring(child, encoding="unicode", method="html") + content += etree.tostring(child, encoding='unicode', method='html') return content diff --git a/kordac/processors/HeadingBlockProcessor.py b/kordac/processors/HeadingBlockProcessor.py index 67c22dac..fa09f8a3 100644 --- a/kordac/processors/HeadingBlockProcessor.py +++ b/kordac/processors/HeadingBlockProcessor.py @@ -69,11 +69,11 @@ def run(self, parent, blocks): context = dict() context['heading_level'] = level - context['heading_type'] = "h{0}".format(level) + context['heading_type'] = 'h{0}'.format(level) context['title'] = heading context['title_slug'] = heading_slug for i, level_val in enumerate(level_trail): - context["level_{0}".format(i + 1)] = level_val + context['level_{0}'.format(i + 1)] = level_val html_string = self.template.render(context) node = etree.fromstring(html_string) diff --git a/kordac/processors/InteractiveBlockProcessor.py b/kordac/processors/InteractiveBlockProcessor.py index 2ac79ae6..6cc4d682 100644 --- a/kordac/processors/InteractiveBlockProcessor.py +++ b/kordac/processors/InteractiveBlockProcessor.py @@ -16,9 +16,9 @@ def __init__(self, ext, *args, **kwargs): ''' super().__init__('interactive', ext, *args, **kwargs) self.relative_file_template = ext.jinja_templates['relative-file-link'] - self.scripts = ext.required_files["page_scripts"] - self.required = ext.required_files["interactives"] - self.required_images = ext.required_files["images"] + self.scripts = ext.required_files['page_scripts'] + self.required = ext.required_files['interactives'] + self.required_images = ext.required_files['images'] def test(self, parent, block): ''' Tests a block to see if the run method should be applied. @@ -75,7 +75,7 @@ def run(self, parent, blocks): if interactive_type == 'whole-page': file_path = argument_values.get('thumbnail', None) if file_path is None: - file_path = "{}/thumbnail.png".format(name) + file_path = '{}/thumbnail.png'.format(name) external_path_match = re.search(r'^http', file_path) if external_path_match is None: # internal image diff --git a/kordac/processors/ScratchCompatibilityPreprocessor.py b/kordac/processors/ScratchCompatibilityPreprocessor.py index 8a18bb10..597946f2 100644 --- a/kordac/processors/ScratchCompatibilityPreprocessor.py +++ b/kordac/processors/ScratchCompatibilityPreprocessor.py @@ -41,14 +41,14 @@ def run(self, lines): Returns: Markdown document with scratch codeblocks removed. ''' - text = "\n".join(lines) + text = '\n'.join(lines) match = self.pattern.search(text) while match is not None: code = self.CODE_FORMAT.format(self._escape(match.group('code')), match.group('options')) placeholder = self.markdown.htmlStash.store(code, safe=True) text = text[:match.start()] + '\n' + placeholder + '\n' + text[match.end():] match = self.pattern.search(text) - return text.split("\n") + return text.split('\n') def _escape(self, text): ''' basic html escaping, as per fenced_code. diff --git a/kordac/processors/ScratchTreeprocessor.py b/kordac/processors/ScratchTreeprocessor.py index ee4dfbc1..63a98c2c 100644 --- a/kordac/processors/ScratchTreeprocessor.py +++ b/kordac/processors/ScratchTreeprocessor.py @@ -57,7 +57,7 @@ def run(self, root): if node is None: continue self.process_html(node) - html_string = etree.tostring(node, encoding="unicode", method="html") + html_string = etree.tostring(node, encoding='unicode', method='html') self.markdown.htmlStash.rawHtmlBlocks[i] = html_string, safe def process_html(self, node): @@ -94,8 +94,8 @@ def process_html(self, node): html_string = self.template.render({'images': images}) new_node = etree.fromstring(html_string) - node.tag = "remove" - node.text = "" + node.tag = 'remove' + node.text = '' node.append(new_node) node.remove(children[0]) diff --git a/kordac/processors/StylePreprocessor.py b/kordac/processors/StylePreprocessor.py index 94f80ae5..ed9c505d 100644 --- a/kordac/processors/StylePreprocessor.py +++ b/kordac/processors/StylePreprocessor.py @@ -43,12 +43,12 @@ def run(self, lines): # Remove all empty lines Should only be one line left if len([line for line in error_lines if line != '']) != 1: - raise StyleError(line_nums, error_lines, "Blocks must be separated by whitespace.") + raise StyleError(line_nums, error_lines, 'Blocks must be separated by whitespace.') start_index, end_index = block_match.span() rest = line[:start_index] + line[end_index+1:] for char in rest: if not char.isspace(): - 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/kordac/processors/errors/StyleError.py b/kordac/processors/errors/StyleError.py index 9a33e2d8..ca0443ed 100644 --- a/kordac/processors/errors/StyleError.py +++ b/kordac/processors/errors/StyleError.py @@ -2,13 +2,13 @@ class StyleError(Error): - """Exception raised when a Style rule is broken. + '''Exception raised when a Style rule is broken. Attributes: rule -- rule which was broken lines -- lines where the style rule was broken message -- explanation of why error was thrown - """ + ''' def __init__(self, line_nums, lines, message): super().__init__(message) diff --git a/kordac/tests/BaseTest.py b/kordac/tests/BaseTest.py index 259c0372..3b86c599 100644 --- a/kordac/tests/BaseTest.py +++ b/kordac/tests/BaseTest.py @@ -20,7 +20,7 @@ def read_test_file(self, test_type, filename, strip=False): This function reads a file from a given filename in UTF-8 encoding. ''' file_path = self.test_file_path.format(test_type=test_type, filename=filename) - file_object = open(file_path, encoding="utf-8") + file_object = open(file_path, encoding='utf-8') text = file_object.read() if strip: text = text.rstrip('\r\n') diff --git a/kordac/tests/ConfigurationTest.py b/kordac/tests/ConfigurationTest.py index 47e4accb..6b4cb4a5 100644 --- a/kordac/tests/ConfigurationTest.py +++ b/kordac/tests/ConfigurationTest.py @@ -25,8 +25,8 @@ def __init__(self, *args, **kwargs): self.test_name = 'configuration' self.maxDiff = None self.custom_templates = { - "image": "", - "boxed-text": "
    {% autoescape false %}{{ text }}{% endautoescape %}
    " + 'image': '', + 'boxed-text': '
    {% autoescape false %}{{ text }}{% endautoescape %}
    ' } def test_multiple_calls(self): @@ -244,20 +244,20 @@ def test_multiline_custom_templates(self): and used correctly. ''' custom_templates = { - "image": """
    + 'image': '''
    -
    """, - "boxed-text": """
    +
    ''', + 'boxed-text': '''
    {{ text }}
    -
    """, - "heading": """<{{ heading_type }} id="{{ title_slug }}"> +
    ''', + 'heading': '''<{{ heading_type }} id="{{ title_slug }}"> {{ level_1 }}.{{ level_2 }}.{{ level_3 }}.{{ level_4 }}.{{ level_5 }}.{{ level_6 }}. {{ title }} - """ + ''' } kordac = Kordac(html_templates=custom_templates) diff --git a/kordac/tests/SmokeTests.py b/kordac/tests/SmokeTests.py index 66422076..9a576a57 100644 --- a/kordac/tests/SmokeTests.py +++ b/kordac/tests/SmokeTests.py @@ -7,7 +7,7 @@ class SmokeDocsTest(unittest.TestCase): def __init__(self, *args, **kwargs): unittest.TestCase.__init__(self, *args, **kwargs) self.maxDiff = None - self.build_path = "docs/build" + self.build_path = 'docs/build' @unittest.skipIf(not os.path.isdir('docs') and os.name not in ['nt', 'posix'], 'Docs are not present') def test_compile_docs(self): diff --git a/kordac/tests/start_tests.py b/kordac/tests/start_tests.py index c9e398f7..79241b64 100644 --- a/kordac/tests/start_tests.py +++ b/kordac/tests/start_tests.py @@ -27,7 +27,7 @@ def parse_args(): useful for developing when parts of verto are known to fail. ''' opts = optparse.OptionParser( - usage='Run the command `python -m kordac.tests.start_tests` from the level above the kordac directory.', description="Verifies that Kordac is functional compared to the testing suite.") + usage='Run the command `python -m kordac.tests.start_tests` from the level above the kordac directory.', description='Verifies that Kordac is functional compared to the testing suite.') opts.add_option('--travis', action='store_true', help='Enables skipping suites on failure. To be used by continuous integration system.', default=False) opts.add_option('--no_smoke', @@ -86,23 +86,23 @@ def unit_suite(): smoke_result = None if not options.no_smoke: - print("Running Smoke Tests") + print('Running Smoke Tests') smoke_result = runner.run(smoke_suite()) print() if options.travis and smoke_result and not smoke_result.wasSuccessful(): - print("Skipping other test-suites.") + print('Skipping other test-suites.') sys.exit(1) system_result = None if not options.no_system: - print("Running System Tests") + print('Running System Tests') system_result = runner.run(system_suite()) print() unit_result = None if not options.no_unit: - print("Running Unit Tests") + print('Running Unit Tests') unit_result = runner.run(unit_suite()) print() diff --git a/kordac/utils/UniqueSlugify.py b/kordac/utils/UniqueSlugify.py index dfb219a8..c6423466 100644 --- a/kordac/utils/UniqueSlugify.py +++ b/kordac/utils/UniqueSlugify.py @@ -51,7 +51,7 @@ def __call__(self, text): + len(self.occurance_separator) + floor(log10(count))) >= self.max_length: end_index = self.max_length - floor(log10(count)) - len(self.occurance_separator) - 1 - new_slug = "{0}{1}{2}".format(slug[:end_index], self.occurance_separator, count) + new_slug = '{0}{1}{2}'.format(slug[:end_index], self.occurance_separator, count) self.uids.add(new_slug) return new_slug diff --git a/kordac/utils/overrides.py b/kordac/utils/overrides.py index dd65c898..63268e60 100644 --- a/kordac/utils/overrides.py +++ b/kordac/utils/overrides.py @@ -27,7 +27,7 @@ def is_block_level(html, block_level_elements): return True if isinstance(tag, string_type): elements = '|'.join(block_level_elements) - block_elements_re = re.compile("^({})$".format(elements), + block_elements_re = re.compile('^({})$'.format(elements), re.IGNORECASE) return block_elements_re.match(tag) return False diff --git a/setup.py b/setup.py index 93ff5bbb..0a369d02 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ from kordac import __version__ if not sys.version_info[0] == 3: - sys.exit("Sorry, currently only Python 3 is supported.") + sys.exit('Sorry, currently only Python 3 is supported.') setup( name='kordac', From 648ecfdb06aacd68d5c276468d565c5ba21db528 Mon Sep 17 00:00:00 2001 From: ravenmaster001 Date: Mon, 3 Apr 2017 13:51:41 +1200 Subject: [PATCH 85/86] Resize image. --- verto/images/verto-logo.png | Bin 33749 -> 12833 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/verto/images/verto-logo.png b/verto/images/verto-logo.png index 6bf7a2be80de2a55eccbd7b942484f729689648c..a3eb20475a2a46974645fec9565ff2baec5d3a7a 100644 GIT binary patch literal 12833 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 NNsB9pm5Uhq{V#-SwpjoG literal 33749 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 Date: Mon, 3 Apr 2017 18:14:51 +1200 Subject: [PATCH 86/86] Bumped version to v0.4.0. --- docs/source/changelog.rst | 24 ++++++++++++++++++++++++ verto/__init__.py | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 8680c515..a9ea2c0a 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -1,6 +1,30 @@ Changelog ####################################### +0.4.0 +======================================= +Fourth prerelease of the Verto converter. +(The project was renamed to Verto from Kordac in release.) + +Adds support for the following processors: + + - :doc:`processors/iframe` + - :doc:`processors/interactive` + - :doc:`processors/heading` + - :doc:`processors/scratch` + - :doc:`processors/table-of-contents` + +Features: + + - The :doc:`processors/scratch` processor supports ``split`` and ``random`` options. + +Fixes: + + - Scratch blocks work with other extensions. + - Glossary slugs are now added to the output of Verto. + - Processors are now ordered correctly. + + 0.3.1 ======================================= Fixes: diff --git a/verto/__init__.py b/verto/__init__.py index 9adcccd2..eeffec8b 100644 --- a/verto/__init__.py +++ b/verto/__init__.py @@ -1,4 +1,4 @@ # flake8: noqa from .Verto import Verto -__version__ = '0.3.1' +__version__ = '0.4.0'