Skip to content

Commit ffbea31

Browse files
committed
Implement abstract parsing in draft utils. See ietf-tools#587.
- Legacy-Id: 2840
1 parent 2f68029 commit ffbea31

1 file changed

Lines changed: 75 additions & 0 deletions

File tree

ietf/utils/draft.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ def __init__(self, text):
125125
self.filename, self.revision = self._parse_draftname()
126126

127127
self._authors = None
128+
self._abstract = None
128129
self._pagecount = None
129130
self._status = None
130131
self._creation_date = None
@@ -274,6 +275,77 @@ def get_creation_date(self):
274275
return self._creation_date
275276

276277

278+
# ------------------------------------------------------------------
279+
def get_abstract(self):
280+
"""Extract abstract from draft text.
281+
based on: http://wiki.tools.ietf.org/tools/ietfdb/browser/branch/legacy/idst/validate.cgi
282+
"""
283+
if self._abstract:
284+
return self._abstract
285+
draft_text = "\n".join(self.lines[:len(self.lines)/2])
286+
287+
abstract_patterns = [
288+
r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Status of this Memo\s{0,2}\n)',
289+
r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Editorial Note\s{0,2}\n)',
290+
r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Sub-IP ID Summary\s{0,2}\n)',
291+
r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Table of Contents?\s{0,2}\n)',
292+
r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Conventions used in this document\s{0,2}\n)',
293+
r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Introduction\s{0,2}\n)',
294+
r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Terminology\s{0,2}\n)',
295+
r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Definitions\s\s{0,2}\n)',
296+
r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Background( and Intended Usage)?\s{0,2}\n)',
297+
r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Conventions\s{0,2}\n)',
298+
r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Requirements\s{0,2}\n)',
299+
r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*motivation\s{0,2}\n)',
300+
r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*translation\s{0,2}\n)',
301+
r'((Abstract|Summary):?\n+)([\s|\S]+?)(\n\s*Contents?)',
302+
r'((Abstract|Summary):?\n+)([\s|\S]+?)(\n\s*0. meta information on this)',
303+
r'((Abstract|Summary):?\n+)([\s|\S]+?)(\n\s*0. introduction)',
304+
r'((Abstract|Summary):?\s*\n+)(( {3,}.+\n+)+)',
305+
r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\n{4,})',
306+
r'((Abstract|Summary):?\s*\n+)([\s|\S]+)((\d\.?)[^\n]{10,50}\n{0,2})',
307+
]
308+
309+
abstract = None
310+
for ap in abstract_patterns:
311+
match = re.search(ap, draft_text, re.IGNORECASE)
312+
if match:
313+
abstract = match.group(3)
314+
break
315+
316+
# Remove possible missed sections
317+
match = re.search(r'([\s|\S]+?)(\n+\s{0,10}(\d\.?)\s{0,10}[^\n]{10,50}\s{0,2}\n)', abstract or '')
318+
if match:
319+
abstract = match.group(1)
320+
321+
if abstract:
322+
cleanup_patterns = [
323+
(r"\n{3,}", "\n\n"), (r"\f[\n ]*[^\n]*\n", ""),
324+
(r"(?s)(\d{1,3}\.\s*)?(Conventions used in this document|Requirements language).*", ""),
325+
(r"(?sm)[\n ]*The key words [\'\"]MUST[\'\"], [\'\"]MUST NOT[\'\"],\n.*$", ""),
326+
(r"(?s)\nStatus of [tT]his Memo\n\s{1,2}\n.*$", ""),
327+
(r"(?s)(\d{1,3}\.?\s*)?Table of Contents\s{0,2}.*$", ""),
328+
(r"(?s)(\d{1,3}\.?\s*)?Status of this memo\s{1,2}\n.*$", ""),
329+
(r"(?s)(\d{1,3}\.?\s*)?Editorial note.\n*$", ""),
330+
(r"(?s)(\d{1,3}\.?\s*)?Terminology\s{1,2}\n.*$", ""),
331+
(r"(?s)(\d{1,3}\.?\s*)?Specification of Requirements\s{1,2}\n.*$", ""),
332+
(r"(?s)\s*\d\.?(Abstract|Introduction)?\.{15,}", ""),
333+
(r"\n\s*\d\.?\s*[\s|\S]+?\n.*", ""),
334+
(r"(?sm)(\(|\[)?to be (deleted|removed) (by|when).*", ""),
335+
(r"(?s)\n.$", ""), (r"(?m)^[^\n]+\.{10,}\d{1,3}", "")
336+
]
337+
for cp, sub in cleanup_patterns:
338+
e = re.compile(cp, re.IGNORECASE)
339+
abstract = e.sub(sub, abstract)
340+
341+
# wrap long lines without messing up formatting
342+
while re.match("([^\n]{72,}?) +", abstract):
343+
abstract = re.sub("([^\n]{72,}?) +([^\n ]*)(\n|$)", "\\1\n\\2 ", abstract)
344+
345+
return abstract.strip()
346+
return None
347+
348+
277349
# ------------------------------------------------------------------
278350
def get_authors(self):
279351
"""Extract author information from draft text.
@@ -581,6 +653,9 @@ def _printmeta(timestamp, fn):
581653
deststatus = draft.get_status()
582654
if deststatus:
583655
fields["docdeststatus"] = deststatus
656+
abstract = draft.get_abstract()
657+
if abstract:
658+
fields["docabstract"] = abstract
584659

585660
_output(fields)
586661

0 commit comments

Comments
 (0)