-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
👌 IMPROVE: Bug fix, latex support and some refactoring #33
* proper enumeration * bug fixes and latex support * writing post-transforms and node output handling * edits * if not number for enumerable node * handling of refs * test file * handled nodes * test corrections * creating different transforms * readding test * some refactoring * created global variables, and moved code around
- Loading branch information
1 parent
78bf69b
commit ee0f065
Showing
20 changed files
with
417 additions
and
345 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
""" | ||
sphinx_exercise.nodes | ||
~~~~~~~~~~~~~~~~~~~~~ | ||
Enumerable and unenumerable nodes | ||
:copyright: Copyright 2020 by the QuantEcon team, see AUTHORS | ||
:licences: see LICENSE for details | ||
""" | ||
from docutils.nodes import Node | ||
from sphinx.util import logging | ||
from docutils import nodes as docutil_nodes | ||
from sphinx.writers.latex import LaTeXTranslator | ||
from .utils import get_node_number, find_parent | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
CR = "\n" | ||
latex_admonition_start = CR + "\\begin{sphinxadmonition}{note}" | ||
latex_admonition_end = "\\end{sphinxadmonition}" + CR | ||
|
||
|
||
class exercise_node(docutil_nodes.Admonition, docutil_nodes.Element): | ||
pass | ||
|
||
|
||
class solution_node(docutil_nodes.Admonition, docutil_nodes.Element): | ||
pass | ||
|
||
|
||
class exercise_unenumerable_node(docutil_nodes.Admonition, docutil_nodes.Element): | ||
pass | ||
|
||
|
||
def visit_enumerable_node(self, node: Node) -> None: | ||
if isinstance(self, LaTeXTranslator): | ||
docname = find_parent(self.builder.env, node, "section") | ||
self.body.append("\\label{" + f"{docname}:{node.attributes['label']}" + "}") | ||
self.body.append(latex_admonition_start) | ||
else: | ||
for title in node.traverse(docutil_nodes.title): | ||
if "Exercise" in title.astext(): | ||
title[0] = docutil_nodes.Text("") | ||
self.body.append(self.starttag(node, "div", CLASS="admonition")) | ||
|
||
|
||
def depart_enumerable_node(self, node: Node) -> None: | ||
typ = node.attributes.get("type", "") | ||
if isinstance(self, LaTeXTranslator): | ||
number = get_node_number(self, node, typ) | ||
idx = list_rindex(self.body, latex_admonition_start) + 2 | ||
self.body.insert(idx, f"{typ.title()} {number} ") | ||
self.body.append(latex_admonition_end) | ||
else: | ||
number = get_node_number(self, node, typ) | ||
if number: | ||
idx = self.body.index(f"{typ.title()} {number} ") | ||
self.body[idx] = f"{typ.title()} {number} " | ||
self.body.append("</div>") | ||
|
||
|
||
def visit_exercise_unenumerable_node(self, node: Node) -> None: | ||
if isinstance(self, LaTeXTranslator): | ||
docname = find_parent(self.builder.env, node, "section") | ||
self.body.append("\\label{" + f"{docname}:{node.attributes['label']}" + "}") | ||
self.body.append(latex_admonition_start) | ||
else: | ||
for title in node.traverse(docutil_nodes.title): | ||
if "Exercise" in title.astext(): | ||
title[0] = docutil_nodes.Text("") | ||
self.body.append(self.starttag(node, "div", CLASS="admonition")) | ||
|
||
|
||
def depart_exercise_unenumerable_node(self, node: Node) -> None: | ||
typ = node.attributes.get("type", "") | ||
if isinstance(self, LaTeXTranslator): | ||
idx = list_rindex(self.body, latex_admonition_start) + 2 | ||
self.body.insert(idx, f"{typ.title()} ") | ||
self.body.append(latex_admonition_end) | ||
else: | ||
idx = list_rindex(self.body, '<p class="admonition-title">') + 1 | ||
element = f"<span>{typ.title()} </span>" | ||
self.body.insert(idx, element) | ||
self.body.append("</div>") | ||
|
||
|
||
def visit_solution_node(self, node: Node) -> None: | ||
if isinstance(self, LaTeXTranslator): | ||
docname = find_parent(self.builder.env, node, "section") | ||
self.body.append("\\label{" + f"{docname}:{node.attributes['label']}" + "}") | ||
self.body.append(latex_admonition_start) | ||
else: | ||
self.body.append(self.starttag(node, "div", CLASS="admonition")) | ||
|
||
|
||
def depart_solution_node(self, node: Node) -> None: | ||
typ = node.attributes.get("type", "") | ||
if isinstance(self, LaTeXTranslator): | ||
idx = list_rindex(self.body, latex_admonition_start) + 2 | ||
self.body.pop(idx) | ||
self.body.insert(idx, f"{typ.title()} ") | ||
self.body.append(latex_admonition_end) | ||
else: | ||
number = get_node_number(self, node, typ) | ||
idx = self.body.index(f"{typ.title()} {number} ") | ||
self.body.pop(idx) | ||
self.body.append("</div>") | ||
|
||
|
||
def is_exercise_node(node): | ||
return isinstance(node, exercise_node) | ||
|
||
|
||
def is_unenumerable_node(node): | ||
return isinstance(node, exercise_unenumerable_node) | ||
|
||
|
||
def is_solution_node(node): | ||
return isinstance(node, solution_node) | ||
|
||
|
||
def is_extension_node(node): | ||
return ( | ||
is_exercise_node(node) or is_unenumerable_node(node) or is_solution_node(node) | ||
) | ||
|
||
|
||
def rreplace(s, old, new, occurrence): | ||
# taken from https://stackoverflow.com/a/2556252 | ||
li = s.rsplit(old, occurrence) | ||
return new.join(li) | ||
|
||
|
||
def list_rindex(li, x) -> int: | ||
"""Getting the last occurence of an item in a list.""" | ||
for i in reversed(range(len(li))): | ||
if li[i] == x: | ||
return i | ||
raise ValueError("{} is not in list".format(x)) | ||
|
||
|
||
NODE_TYPES = { | ||
"exercise": {"node": exercise_node, "type": "exercise"}, | ||
"solution": {"node": solution_node, "type": "solution"}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
from sphinx.writers.latex import LaTeXTranslator | ||
from docutils import nodes as docutil_nodes | ||
|
||
|
||
def find_parent(env, node, parent_tag): | ||
"""Find the nearest parent node with the given tagname.""" | ||
while True: | ||
node = node.parent | ||
if node is None: | ||
return None | ||
# parent should be a document in toc | ||
if ( | ||
"docname" in node.attributes | ||
and env.titles[node.attributes["docname"]].astext().lower() | ||
in node.attributes["names"] | ||
): | ||
return node.attributes["docname"] | ||
|
||
if node.tagname == parent_tag: | ||
return node.attributes["docname"] | ||
|
||
return None | ||
|
||
|
||
def get_node_number(self, node, typ) -> str: | ||
"""Get the number for the directive node for HTML.""" | ||
ids = node.attributes.get("ids", [])[0] | ||
if isinstance(self, LaTeXTranslator): | ||
docname = find_parent(self.builder.env, node, "section") | ||
else: | ||
docname = node.attributes.get("docname", "") | ||
# Latex does not have builder.fignumbers | ||
fignumbers = self.builder.env.toc_fignumbers.get(docname, {}) | ||
number = fignumbers.get(typ, {}).get(ids, ()) | ||
return ".".join(map(str, number)) | ||
|
||
|
||
def has_math_child(node): | ||
""" Check if a parent node as a math child node. """ | ||
for item in node: | ||
if isinstance(item, docutil_nodes.math): | ||
return True | ||
return False | ||
|
||
|
||
def get_refuri(node): | ||
""" Check both refuri and refid, to see which one is available. """ | ||
id_ = "" | ||
if node.get("refuri", ""): | ||
id_ = node.get("refuri", "") | ||
|
||
if node.get("refid", ""): | ||
id_ = node.get("refid", "") | ||
|
||
return id_.split("#")[-1] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.