First implementation (#1)
Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
1 parent
34c0abb26a
commit
4fa326dc76
534 files changed
+28280
-37
No files matched your search
@@ -0,0 +1,69 @@
|
||||
"""The target set of targeted F3: the nodes a team's claims, data and quotations rest on.
|
||||
|
||||
Non-normative; see spec/08-fidelity.md §8.10.
|
||||
"""
|
||||
|
||||
from .model import LEAVES, MATH_KINDS
|
||||
from .text import is_digit
|
||||
|
||||
DIGIT_RULES = ("all", "anchored-sections", "none")
|
||||
# The kinds that count as the section a node sits in: a section, or the front or back matter outside any.
|
||||
SECTION_KINDS = frozenset(["section", "front", "back"])
|
||||
DIGIT_KINDS = frozenset(["sentence", "cell"])
|
||||
DIGIT_RUNS = frozenset(["text", "math"])
|
||||
|
||||
|
||||
def has_digit_run(node):
|
||||
"""Whether a `text` or `math` run of the node holds a digit (General Category Nd)."""
|
||||
for r in node.get("content") or []:
|
||||
if not isinstance(r, dict) or r.get("kind") not in DIGIT_RUNS:
|
||||
continue
|
||||
s = r.get("text") if r["kind"] == "text" else r.get("source")
|
||||
if any(is_digit(ch) for ch in s or ""):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def enclosing_section(doc, nid):
|
||||
"""The nearest ancestor-or-self that is a section, or the front or back matter, else the root."""
|
||||
if doc.nodes[nid]["kind"] in SECTION_KINDS:
|
||||
return nid
|
||||
for a in reversed(doc.ancestors(nid)):
|
||||
if doc.nodes[a]["kind"] in SECTION_KINDS:
|
||||
return a
|
||||
return doc.root
|
||||
|
||||
|
||||
def target_set(doc, anchored, digit_rule="all"):
|
||||
"""The target set as `[[node, reason], …]` in document order, with `reason` the first that applies of
|
||||
`anchored`, `equation` and `digits`.
|
||||
|
||||
`anchored` lists the live nodes that extracts, dataset values, confirmed claim links, draft quotations or
|
||||
pinned citations anchor; a container among them contributes its leaves. Every equation and equation line
|
||||
is a target. Under `all`, so is every sentence or cell with a digit in a text or math run; under
|
||||
`anchored-sections`, only those in a section that holds an anchored node; under `none`, none.
|
||||
"""
|
||||
if digit_rule not in DIGIT_RULES:
|
||||
raise ValueError("digit rule must be one of %s" % ", ".join(DIGIT_RULES))
|
||||
anchored = set(anchored)
|
||||
unknown = sorted(a for a in anchored if a not in doc.nodes)
|
||||
if unknown:
|
||||
raise ValueError("anchored nodes are not live: %s" % ", ".join(unknown))
|
||||
reasons = {}
|
||||
for nid in sorted(anchored):
|
||||
if doc.nodes[nid]["kind"] in LEAVES:
|
||||
reasons[nid] = "anchored"
|
||||
else:
|
||||
for leaf in doc.leaves(nid):
|
||||
reasons.setdefault(leaf, "anchored")
|
||||
for nid in doc.preorder():
|
||||
if doc.nodes[nid]["kind"] in MATH_KINDS:
|
||||
reasons.setdefault(nid, "equation")
|
||||
if digit_rule != "none":
|
||||
sections = {enclosing_section(doc, a) for a in anchored}
|
||||
for nid in doc.preorder():
|
||||
n = doc.nodes[nid]
|
||||
if n["kind"] in DIGIT_KINDS and has_digit_run(n):
|
||||
if digit_rule == "all" or enclosing_section(doc, nid) in sections:
|
||||
reasons.setdefault(nid, "digits")
|
||||
return [[nid, reasons[nid]] for nid in doc.preorder() if nid in reasons]
|
||||
Reference in new issue
Block a user