forked from ChelseaKR/ca-tariff-parse
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapplicability.py
More file actions
79 lines (65 loc) · 2.61 KB
/
Copy pathapplicability.py
File metadata and controls
79 lines (65 loc) · 2.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
"""Capture eligibility and exclusion statements verbatim.
Applicability language decides who a rate applies to, so it is carried across
word for word. The only interpretation is a coarse ``disposition`` label, and
that label never replaces the text it summarises.
"""
from __future__ import annotations
import re
from ..extract import squash
from ..segment import Section
from .base import Citer, Emission, paragraphs, strip_item_number
EXCLUDES = (
"are not eligible",
"is not eligible",
"not be eligible",
"are not available",
"shall not apply",
"does not apply",
"closed to new customers",
)
REQUIRES = (
"must ",
"is required for",
"are required to",
"is required to",
)
#: A section whose own heading is this states eligibility under another name.
#: A schedule that puts its conditions under "Conditions of Service" rather
#: than "Applicability" is saying the same kind of thing, and skipping it left
#: the parser answering "who is eligible" from half the document.
ELIGIBILITY_HEADINGS = frozenset({"eligibility", "eligibilityrequirements"})
def _disposition(text: str) -> str:
low = text.lower()
if any(token in low for token in EXCLUDES):
return "excluded"
if any(token in low for token in REQUIRES):
return "required"
return "included"
def claims(section: Section, headings: dict[str, str]) -> bool:
"""True for the Applicability part, its subsections, and any Eligibility part."""
root = section.section_id.split(".")[0]
if squash(headings.get(root, "")) == "applicability":
return True
return squash(section.heading) in ELIGIBILITY_HEADINGS
def parse(section: Section, citer: Citer) -> Emission:
emission = Emission()
for group in paragraphs(section):
text = strip_item_number(" ".join(line.text for line in group))
text = re.sub(r"\s+", " ", text).strip()
if not text:
continue
provenance = citer.cite_span(group, section.section_id)
from ..model import Applicability, Cited
emission.applicability.append(
Applicability(
text=Cited(value=text, provenance=provenance),
disposition=_disposition(text),
)
)
emission.take(*group)
# The heading itself is part of the section and is accounted for here.
# A heading set inline shares its line with the body, and that line is
# taken above as part of the paragraph it opens rather than for free.
if section.content_lines and section.level > 0 and not section.heading_inline:
emission.take(section.content_lines[0])
return emission