def prepare(doc: Doc) -> None: assert hasattr(doc, "config"), "Need to read config first." assert hasattr(doc, "code_map"), "Need to tangle first." doc.suites = get_doc_tests(doc.code_map) for name, suite in doc.suites.items(): run_suite(doc.config, suite) doc.code_counter = defaultdict(lambda: 0)
def prepare(doc: pf.Doc): """ Instantiate file objects for each file specified by the document's metadata. """ doc.files = [] class_map = doc.get_metadata('tangle-files', {}) for name, classes in class_map.items(): doc.files.append(OutputFile(name, wrap_list(classes)))
def prepare(doc: Doc) -> Doc: from datetime import date from itertools import islice, chain, repeat def intersperse(delimiter, seq): return islice(chain.from_iterable(zip(repeat(delimiter), seq)), 1, None) annotate.prepare(doc) if "footer" in doc.metadata: content = [[Str(str(date.today()))]] try: old_footer = list(doc.metadata["footer"].content) except AttributeError: old_footer = [Str("")] try: version = doc.metadata["version"].content[0] content.append([Str("version:"), Space, version]) except (AttributeError, KeyError): pass try: license = doc.metadata["license"].content[0] content.append([Str("license:"), Space, license]) except (AttributeError, KeyError): pass content = sum(intersperse([Space, Str("—"), Space], content), []) doc.metadata["footer"] = MetaInlines(*old_footer, LineBreak, *content)
def finalize(doc: Doc) -> None: """Writes all file references found in `doc.code_map` to disk. This only overwrites a file if the content is different.""" file_map = get_file_map(doc.code_map) for filename, codename in file_map.items(): write_file(filename, get_code(doc.code_map, codename)) doc.content = []
def _get_load_manual_references_kwargs(doc: pf.Doc) -> Dict[str, Any]: """ Return keyword arguments for Citations.load_manual_references. """ manual_refs = doc.get_metadata("references", default=[]) bibliography_paths = doc.get_metadata("bibliography", default=[]) if not isinstance(bibliography_paths, list): bibliography_paths = [bibliography_paths] bibliography_cache_path = doc.manubot["bibliography_cache"] if (bibliography_cache_path and bibliography_cache_path not in bibliography_paths and os.path.exists(bibliography_cache_path)): bibliography_paths.append(bibliography_cache_path) return dict( paths=bibliography_paths, extra_csl_items=manual_refs, )
def test_headers(self): markdown = r""" # Title 1 ## Subtitle1 # Title 2 ## Subtitle 2 # Title 3 {.unnumbered} """ doc = Doc(*convert_text(markdown)) pandoc_numbering.main(doc) self.assertEqual(doc.headers, [2, 1, 0, 0, 0, 0])
def prepare(doc: panflute.Doc) -> None: """Prepare the document If ``acronyms`` map is in the metadata, generate the LaTeX definitions of the acronyms and count the number of uses of the acronyms in the document. These details are to be used by the writer or the main filter. """ if "acronyms" not in doc.metadata: return # Store the acronym information as an attribute of the document doc.acronyms = PandocAcro(doc.get_metadata("acronyms")) # Prepare the LaTeX details. header = doc.metadata["header-includes"] \ if "header-includes" in doc.metadata else [] LaTeX = lambda l: panflute.MetaInlines( # noqa E731 I just want a short name panflute.RawInline(l, format="latex")) header.append(LaTeX(r"\usepackage{acro}")) if doc.acronyms.options: header.append(LaTeX(options.acsetup(doc.acronyms.options))) for key, values in doc.acronyms.items(): header.append(LaTeX(fr"\DeclareAcronym{{{key}}}{{")) # The short key *must be first*! header.append(LaTeX(f"short = {values['short']},\n")) header.append( LaTeX(",\n".join(f"{k} = {v}" for k, v in sorted(values.items()) if k != "short"))) header.append(LaTeX("}")) doc.acronyms[key]["count"] = 0 doc.acronyms[key]["total"] = 0 doc.acronyms[key]["list"] = False doc.metadata["header-includes"] = header # For other outputs, we'll need to tally use of the acronyms doc.walk(keys.count) return
def test_div(self): doc = Doc( Div(classes=["tip", "listing"]), Div(classes=["tip"]), Div(classes=["warning"]), Div( attributes={ "latex-tip-icon": "warning", "latex-tip-position": "right", "latex-tip-size": 24, }), metadata=self.metadata(), format="latex", api_version=(1, 17, 2), ) pandoc_latex_tip.main(doc) self.assertEqual(doc.content[0].format, "tex") self.assertEqual(doc.content[2].format, "tex") self.assertEqual(doc.content[4].format, "tex") self.assertEqual(doc.content[6].format, "tex")
def test_codeblock(self): doc = Doc( CodeBlock("", classes=["tip", "listing"]), CodeBlock("", classes=["tip"]), CodeBlock("", classes=["warning"]), CodeBlock( "", attributes={ "latex-tip-icon": "warning", "latex-tip-position": "right", "latex-tip-size": 24, }, ), metadata=self.metadata(), format="latex", ) pandoc_latex_tip.main(doc) self.assertEqual(doc.content[0].format, "tex") self.assertEqual(doc.content[2].format, "tex") self.assertEqual(doc.content[5].format, "tex") self.assertEqual(doc.content[8].format, "tex")
def test_span(self): doc = Doc( Para( Span(classes=["tip", "listing"]), Span(classes=["tip"]), Span(classes=["warning"]), Span(classes=["v5.0"]), Span( attributes={ "latex-tip-icon": "warning", "latex-tip-position": "right", "latex-tip-size": 24, }), ), metadata=self.metadata(), format="latex", ) pandoc_latex_tip.main(doc) self.assertEqual(doc.content[0].content[1].format, "tex") self.assertEqual(doc.content[0].content[3].format, "tex") self.assertEqual(doc.content[0].content[5].format, "tex") self.assertEqual(doc.content[0].content[7].format, "tex") self.assertEqual(doc.content[0].content[9].format, "tex")
def test_code(self): doc = Doc( Para( Code("", classes=["tip", "listing"]), Code("", classes=["tip"]), Code("", classes=["warning"]), Code( "", attributes={ "latex-tip-icon": "warning", "latex-tip-position": "right", "latex-tip-size": 24, }, ), ), metadata=self.metadata(), format="latex", api_version=(1, 17, 2), ) pandoc_latex_tip.main(doc) self.assertEqual(doc.content[0].content[1].format, "tex") self.assertEqual(doc.content[0].content[3].format, "tex") self.assertEqual(doc.content[0].content[5].format, "tex") self.assertEqual(doc.content[0].content[7].format, "tex")
def process_citations(doc: pf.Doc) -> None: """ Apply citation-by-identifier to a Python object representation of Pandoc's Abstract Syntax Tree. """ # process metadata.manubot-bibliography-cache bib_cache = doc.get_metadata(key="manubot-bibliography-cache") if not (bib_cache is None or isinstance(bib_cache, str)): logging.warning( f"Expected metadata.manubot-bibliography-cache to be a string or null (None), " f"but received a {bib_cache.__class__.__name__}. Setting to None.") bib_cache = None doc.manubot["bibliography_cache"] = bib_cache # process metadata.citekey-aliases citekey_aliases = doc.get_metadata("citekey-aliases", default={}) if not isinstance(citekey_aliases, dict): logging.warning( f"Expected metadata.citekey-aliases to be a dict, " f"but received a {citekey_aliases.__class__.__name__}. Disregarding." ) citekey_aliases = dict() doc.manubot["citekey_aliases"] = citekey_aliases doc.walk(_get_reference_link_citekey_aliases) doc.walk(_get_citekeys_action) manuscript_citekeys = doc.manubot["manuscript_citekeys"] citations = Citations(input_ids=manuscript_citekeys, aliases=citekey_aliases) citations.csl_item_failure_log_level = "ERROR" requests_cache_path = doc.get_metadata("manubot-requests-cache-path") if requests_cache_path: from manubot.process.requests_cache import RequestsCache req_cache = RequestsCache(requests_cache_path) req_cache.mkdir() req_cache.install() if doc.get_metadata("manubot-clear-requests-cache", default=False): req_cache.clear() citations.filter_pandoc_xnos() citations.load_manual_references(**_get_load_manual_references_kwargs(doc)) citations.inspect(log_level="WARNING") citations.get_csl_items() doc.manubot["citekey_shortener"] = citations.input_to_csl_id doc.walk(_citation_to_id_action) if requests_cache_path: req_cache.close() citations.write_citekeys_tsv( path=doc.get_metadata("manubot-output-citekeys")) citations.write_csl_items( path=doc.get_metadata("manubot-output-bibliography")) citations.write_csl_items(path=doc.manubot["bibliography_cache"]) # Update pandoc metadata with fields that this filter # has either consumed, created, or modified. doc.metadata["bibliography"] = [] doc.metadata["references"] = citations.csl_items doc.metadata["citekey_aliases"] = citekey_aliases
def test_sharp_sharp(self): definition = r"Example ##" doc = Doc(*convert_text(definition)) pandoc_numbering.main(doc) self.assertEqual(doc.content[0].content[-1].text, "#")
def format_image(image, doc): # type: (Image, Doc) -> Element """ originally adapted from: `pandoc-fignos <https://github.com/tomduck/pandoc-fignos/>`_ """ if not isinstance(image, pf.Image): return None span = None if (isinstance(image.parent, pf.Span) and LABELLED_IMAGE_CLASS in image.parent.classes): span = image.parent if span is not None: identifier = span.identifier attributes = span.attributes # classes = span.classes else: identifier = image.identifier attributes = image.attributes # classes = image.classes if doc.format in ("tex", "latex"): new_doc = Doc(pf.Para(*image.content)) new_doc.api_version = doc.api_version if image.content: caption = pf.run_pandoc(json.dumps(new_doc.to_json()), args=["-f", "json", "-t", "latex"]).strip() else: caption = "" options = attributes.get("placement", "") size = "" # max width set as 0.9\linewidth if "width" in attributes: width = convert_units(attributes["width"], "fraction") size = "width={0}\\linewidth".format(width) elif "height" in attributes: height = convert_units(attributes["height"], "fraction") size = "height={0}\\paperheight".format(height) if identifier: latex = LATEX_FIG_LABELLED.format( label=identifier, options=options, path=image.url, caption=caption, size=size, ) else: latex = LATEX_FIG_UNLABELLED.format(options=options, path=image.url, caption=caption, size=size) return pf.RawInline(latex, format="tex") elif doc.format in ("rst", ): if not image.content.list: # If the container is empty, then pandoc will assign an iterative # reference identifier to it (image0, image1). # However, this iterator restarts for each markdown cell, # which can lead to reference clashes. # Therefore we specifically assign the identifier here, as its url # TODO does this identifier need to be sanitized? # (it works fine in the tests) identifier = image.url image.content = pf.ListContainer(pf.Str(str(identifier))) return image # TODO formatting and span identifier (convert width/height to %) elif doc.format in ("html", "html5"): if identifier: return _wrap_in_anchor(image, identifier) else: return image # TODO formatting, name by count else: return None
def format_image(image, doc): # type: (Image, Doc) -> Element """ originally adapted from: `pandoc-fignos <https://github.com/tomduck/pandoc-fignos/>`_ """ if not isinstance(image, pf.Image): return None span = None if (isinstance(image.parent, pf.Span) and LABELLED_IMAGE_CLASS in image.parent.classes): span = image.parent if span is not None: identifier = span.identifier attributes = span.attributes # classes = span.classes else: identifier = image.identifier attributes = image.attributes # classes = image.classes if doc.format in ("tex", "latex"): new_doc = Doc(pf.Para(*image.content)) new_doc.api_version = doc.api_version if image.content: caption = pf.run_pandoc(json.dumps(new_doc.to_json()), args=["-f", "json", "-t", "latex"]).strip() else: caption = "" options = attributes.get("placement", "") size = '' # max width set as 0.9\linewidth if "width" in attributes: width = convert_units(attributes['width'], "fraction") size = 'width={0}\\linewidth'.format(width) elif "height" in attributes: height = convert_units(attributes['height'], "fraction") size = 'height={0}\\paperheight'.format(height) if identifier: latex = LATEX_FIG_LABELLED.format(label=identifier, options=options, path=image.url, caption=caption, size=size) else: latex = LATEX_FIG_UNLABELLED.format(options=options, path=image.url, caption=caption, size=size) return pf.RawInline(latex, format="tex") elif doc.format in ("rst", ): return image # TODO formatting and span identifier (convert width/height to %) elif doc.format in ("html", "html5"): if identifier: return _wrap_in_anchor(image, identifier) else: return image # TODO formatting, name by count else: return None
def prepare(doc: Doc) -> None: doc.code_map = defaultdict(list)