From 1b28e246b773dee65ffd957f058299a50ae13b3c Mon Sep 17 00:00:00 2001
From: ravenmaster001
+ Here is a fragment of code that is important:
+ Here is a fragment of code that is important:
+ Here is another fragment of code that is important:
+
+ Here is a fragment of code that is important:
+
+ Here is a fragment of code that is important:
+
Here is a fragment of code that is important:
.*?
', 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 string = "Hello World"
and the formatting is unchanged.
+string = "Hello World"
and the formatting is unchanged.
+
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 @@
+string = "Hello Jack!"
+
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 @@
+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 string = "Hello World!"
+
string = "Hello World!"
+
From 6d17ab27f68e130b28e421ba01b69e1186b6f2ae Mon Sep 17 00:00:00 2001
From: ravenmaster001 string = "Hello World!"
string = "Hello Jack!"
++ I really hope he sees this. +
From 5c88b58655620f08814eb6d2adf414c37f8348ac Mon Sep 17 00:00:00 2001 From: ravenmaster001- 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.
- 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+
- -
+Scratch is great for kids you can great simple code like:
-+
Which then easily builds into:
-+
Finally they can create complex code like so:
-+
+
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 @@
-+
Codeblock follows:
- ++ Scratch is great for kids you can great simple code like: +
+.*?)(?<=\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}}
-
-
-