def test_parse_fragment_fail(self): """if given broken document parse_fragment() raises RuntimeError and prints errors""" with captured_output() as out: with self.assertRaises(RuntimeError): parse_fragment(r"\begin{fooenv}bla", "en") err_out = out[1].getvalue() self.assertTrue("ERROR" in err_out)
def test_parse_fragment(self): """parse_fragment() returns valid output if given test document""" doc = parse_fragment(CONTENT, "en") h_1 = doc[0] para_1 = doc[1] h_2 = doc[2] para_2 = doc[3] # test types type_tests = ( (h_1, pf.Header), (h_1, pf.Header), (h_1.content[0], pf.Str), (h_1.content[1], pf.Space), (h_1.content[2], pf.Str), (para_1, pf.Para), (h_2, pf.Header), (para_1, pf.Para), ) for elem in type_tests: with self.subTest(_type=type(elem[0])): self.assertIsInstance(elem[0], elem[1]) # test content content_tests = ( (h_1.content[0].text, "Test"), (h_1.content[2].text, "heading"), (len(para_1.content), 121), (h_2.content[0].text, "Another"), (h_2.content[2].text, "heading"), (len(para_2.content), 149), ) for elem in content_tests: with self.subTest(value=elem[0]): self.assertEqual(elem[0], elem[1])
def create_header( title_str, doc, level=0, parse_text=False, identifier="", short_title=None ): """ Create a header element. Because headers need to be referenced by later elements, references to the last found header is remembered. """ if not isinstance(doc, pf.Doc): raise ValueError("create_header without Doc element") attributes = {} if short_title == title_str: short_title = None if short_title is not None: # Attach short title as attribute to be picked up later on by generate_innodoc attributes["short_title"] = short_title if parse_text: title = parse_fragment(title_str, doc.metadata["lang"].text)[0].content else: title = destringify(title_str) header = pf.Header( *title, level=level, identifier=identifier, attributes=attributes ) remember(doc, "label", header) return header
def create_content_box(elem_content, elem_classes, lang): """ Create a content box. Convenience function for creating content boxes that only differ by having diffent content and classes. """ if not elem_classes or elem_classes == []: msg = "create_content_box without element classes: {}".format(elem_classes) raise ValueError(msg) if not elem_content or elem_content == "": msg = "create_content_box without element content: {}".format(elem_content) raise ValueError(msg) div = pf.Div(classes=elem_classes) content = parse_fragment(elem_content, lang) # Check if environment had an \MLabel/SiteUXID identifier identifier = extract_identifier(content) if identifier: div.identifier = identifier div.content.extend(content) return div
def handle_input(self, cmd_args, elem): r"""Handle ``\input`` command.""" filepath = join(getcwd(), cmd_args[0]) with open(filepath, "r") as input_file: input_content = input_file.read() environ["INNOCONV_MINTMOD_CURRENT_DIR"] = dirname(filepath) return parse_fragment(input_content, elem.doc.metadata["lang"].text)
def _replace_mexerciseitems(self, elem): r"""Helper function to replace `MExerciseItems` with enumerate in elem text and return the pandoc output of the parsed altered element.""" elem.text = elem.text.replace("\\begin{MExerciseItems}", "\\begin{enumerate}") elem.text = elem.text.replace("\\end{MExerciseItems}", "\\end{enumerate}") return parse_fragment(elem.text, elem.doc.metadata["lang"].text)
def handle_minputhint(self, cmd_args, elem): r"""Handle ``\MInputHint`` command.""" content = parse_fragment(cmd_args[0], elem.doc.metadata["lang"].text) if isinstance(elem, pf.Block): div = pf.Div(classes=ELEMENT_CLASSES["MINPUTHINT"]) div.content.extend(content) return div span = pf.Span(classes=ELEMENT_CLASSES["MINPUTHINT"]) if content and isinstance(content[0], pf.Para): span.content.extend(content[0].content) return span
def handle_mdirectrouletteexercises(self, cmd_args, elem): r"""Handle ``\MDirectRouletteExercises`` command. Remember points for next question. """ filepath = join(environ["INNOCONV_MINTMOD_CURRENT_DIR"], cmd_args[0]) with open(filepath, "r") as input_file: input_content = input_file.read() content = parse_fragment(input_content, elem.doc.metadata["lang"].text) div = pf.Div(classes=ELEMENT_CLASSES["MDIRECTROULETTEEXERCISES"]) div.content.extend(content) return div
def handle_highlight(self, cmd_args, elem): r"""Handle \highlight command. This seems to be some sort of formatting command. There's no documentation and it does nothing in the mintmod code. We just keep the information here. """ return pf.Span( *parse_fragment(cmd_args[0], elem.doc.metadata["lang"].text)[0].content, classes=ELEMENT_CLASSES["HIGHLIGHT"], )
def handle_mequationitem(self, cmd_args, elem): r"""Handle ``\MEquationItem`` command.""" if len(cmd_args) != 2: raise ValueError( r"\MEquationItem needs 2 arguments. Received: {}".format( cmd_args)) content_left = parse_fragment(cmd_args[0], elem.doc.metadata["lang"].text) content_right = parse_fragment(cmd_args[1], elem.doc.metadata["lang"].text) content = to_inline([ content_left, pf.Math(r"\;\;=\;", format="InlineMath"), content_right ]) if isinstance(elem, pf.Block): return pf.Plain(content) return content
def handle_mexercises(self, elem_content, env_args, elem): r"""Handle ``\MExercises`` environment.""" content = parse_fragment(elem_content, elem.doc.metadata["lang"].text) lang = elem.doc.metadata["lang"].text header = create_header(TRANSLATIONS["exercises"][lang], elem.doc, level=3) identifier = extract_identifier(content) if identifier: header.identifier = identifier # pylint: disable=no-member header.classes.extend(ELEMENT_CLASSES["MEXERCISES"]) content.insert(0, header) return content
def handle_mcontent(self, elem_content, env_args, elem): r"""Handle ``\MContent`` environment.""" content = parse_fragment(elem_content, elem.doc.metadata["lang"].text) lang = elem.doc.metadata["lang"].text header = create_header( TRANSLATIONS["content"][lang], elem.doc, level=3, identifier="content", ) identifier = extract_identifier(content) if identifier: header.identifier = identifier content.insert(0, header) return content
def handle_mxcontent(self, elem_content, env_args, elem): r"""Handle ``\MXContent`` environment.""" content = parse_fragment(elem_content, elem.doc.metadata["lang"].text) # special case: Skip header creation for some weird (meta?) caption in # entrance test. if env_args[0] != "Restart" and env_args[0] != "Neustart": header = create_header(env_args[0], elem.doc, level=3, short_title=env_args[1]) identifier = extract_identifier(content) if identifier: header.identifier = identifier content.insert(0, header) return content
def handle_mintro(self, elem_content, env_args, elem): r"""Handle ``\MIntro`` environment.""" content = parse_fragment(elem_content, elem.doc.metadata["lang"].text) lang = elem.doc.metadata["lang"].text header = create_header( TRANSLATIONS["introduction"][lang], elem.doc, level=3, identifier="introduction", ) identifier = extract_identifier(content) if identifier: header.identifier = identifier # pylint: disable=no-member header.classes.extend(ELEMENT_CLASSES["MINTRO"]) content.insert(0, header) return content
def handle_mentry(self, cmd_args, elem): r"""Handle ``\MEntry`` command. This command creates an entry for the index. """ if isinstance(elem, pf.Block): log("Warning: Expected Inline for MEntry: {}".format(cmd_args)) text = cmd_args[0] concept = cmd_args[1] for repl in MATH_SUBSTITUTIONS: # can contain LaTeX! concept = re.sub(repl[0], repl[1], concept) strong = pf.Strong() strong.content.extend( parse_fragment(text, elem.doc.metadata["lang"].text)[0].content) span = pf.Span() span.attributes = {INDEX_ATTRIBUTE: concept} span.content = [strong] return block_wrap(span, elem)
def create_image(filename, descr, elem, add_descr=True, block=True): """Create an image element.""" img = pf.Image(url=filename, classes=ELEMENT_CLASSES["IMAGE"]) if add_descr: descr = parse_fragment(descr, elem.doc.metadata["lang"].text, as_doc=True) img.title = shorten( pf.stringify(*descr.content).strip(), width=125, placeholder="..." ) else: img.title = descr if block: ret = pf.Div(pf.Plain(img), classes=ELEMENT_CLASSES["FIGURE"]) remember(elem.doc, "label", ret) if add_descr: ret.content.append(descr.content[0]) else: remember(elem.doc, "label", img) ret = img return ret
def handle_mtest(self, elem_content, env_args, elem): r"""Handle ``\MTest`` environment.""" content = parse_fragment(elem_content, elem.doc.metadata["lang"].text) title = env_args[0] # Normalize various forms of inconsistent titles if "Abschlusstest" in title: # Final test title = "Abschlusstest" elif "Final Test" in title: title = "Final Test" elif "Eingangstest" in title: # Entrance test title = "Test 1: Abzugebender Teil" elif "Graded Test" in title: title = "Test 1: Graded Part To Be Submitted" header = create_header(title, elem.doc, level=2) identifier = extract_identifier(content) if identifier: header.identifier = identifier # pylint: disable=no-member header.classes.extend(ELEMENT_CLASSES["MTEST"]) content.insert(0, header) return content
def handle_msectionstart(self, elem_content, env_args, elem): r"""Handle ``\MSectionStart`` environment.""" return parse_fragment(elem_content, elem.doc.metadata["lang"].text)
def handle_modsemph(self, cmd_args, elem): r"""Handle \modsemph command.""" return pf.Emph(*parse_fragment( cmd_args[0], elem.doc.metadata["lang"].text)[0].content)
def handle_mexercisecollection(self, elem_content, env_args, elem): r"""Handle ``\MExerciseCollection`` environment.""" return parse_fragment(elem_content, elem.doc.metadata["lang"].text)
def test_parse_fragment_quiet(self): """parse_fragment() prints debug messages""" with captured_output() as out: parse_fragment(r"\section{foo} \unknownfoobar", "en") err_out = out[1].getvalue() self.assertTrue("Could not handle command unknownfoobar" in err_out)
def handle_mquestiongroup(self, elem_content, env_args, elem): r"""Handle ``\MQuestionGroup`` environments. In mintmod used to group checkboxes together. We just return the content as questions are grouped by exercises anyway.""" return parse_fragment(elem_content, elem.doc.metadata["lang"].text)
def test_parse_fragment_not_in_path(self, mock_func): # pylint: disable=unused-argument """parse_fragment() raises OSError if panzer not in PATH""" with self.assertRaises(OSError): parse_fragment("foo bar", "en")
def test_parse_fragment_empty(self): """parse_fragment() returns empty list if given empty document""" ret = parse_fragment("", "en") self.assertEqual(len(ret), 0)
def test_parse_fragment_log_is_called(self, log_mock): """parse_fragment() calls log function on warning""" parse_fragment(r"\unknowncommandfoobar", "en") self.assertTrue(log_mock.called)
def handle_html(self, elem_content, env_args, elem): r"""Handle ``\html`` environment.""" return parse_fragment(elem_content, elem.doc.metadata["lang"].text, from_format="html")