Skip to content

Commit 1ec8438

Browse files
committed
Extract static methods to module level (parser.py
1 parent a4a4f50 commit 1ec8438

File tree

2 files changed

+67
-62
lines changed

2 files changed

+67
-62
lines changed

pep_sphinx_extensions/pep_zero_generator/parser.py

+65-60
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,6 @@ class PEP:
3434
# The required RFC 822 headers for all PEPs.
3535
required_headers = {"PEP", "Title", "Author", "Status", "Type", "Created"}
3636

37-
def raise_pep_error(self, msg: str, pep_num: bool = False) -> None:
38-
pep_number = self.number if pep_num else None
39-
raise PEPError(msg, self.filename, pep_number=pep_number)
40-
4137
def __init__(self, filename: Path, authors_overrides: dict):
4238
"""Init object from an open PEP file object.
4339
@@ -51,106 +47,115 @@ def __init__(self, filename: Path, authors_overrides: dict):
5147
metadata = HeaderParser().parsestr(pep_text)
5248
required_header_misses = PEP.required_headers - set(metadata.keys())
5349
if required_header_misses:
54-
self.raise_pep_error(f"PEP is missing required headers {required_header_misses}")
50+
_raise_pep_error(self, f"PEP is missing required headers {required_header_misses}")
5551

5652
try:
5753
self.number = int(metadata["PEP"])
5854
except ValueError:
59-
self.raise_pep_error("PEP number isn't an integer")
55+
_raise_pep_error(self, "PEP number isn't an integer")
6056

6157
# Check PEP number matches filename
6258
if self.number != int(filename.stem[4:]):
63-
self.raise_pep_error(f"PEP number does not match file name ({filename})", pep_num=True)
59+
_raise_pep_error(self, f"PEP number does not match file name ({filename})", pep_num=True)
6460

6561
# Title
6662
self.title: str = metadata["Title"]
6763

6864
# Type
6965
self.pep_type: str = metadata["Type"]
7066
if self.pep_type not in TYPE_VALUES:
71-
self.raise_pep_error(f"{self.pep_type} is not a valid Type value", pep_num=True)
67+
_raise_pep_error(self, f"{self.pep_type} is not a valid Type value", pep_num=True)
7268

7369
# Status
7470
status = metadata["Status"]
7571
if status in SPECIAL_STATUSES:
7672
status = SPECIAL_STATUSES[status]
7773
if status not in STATUS_VALUES:
78-
self.raise_pep_error(f"{status} is not a valid Status value", pep_num=True)
74+
_raise_pep_error(self, f"{status} is not a valid Status value", pep_num=True)
7975

8076
# Special case for Active PEPs.
8177
if status == STATUS_ACTIVE and self.pep_type not in ACTIVE_ALLOWED:
8278
msg = "Only Process and Informational PEPs may have an Active status"
83-
self.raise_pep_error(msg, pep_num=True)
79+
_raise_pep_error(self, msg, pep_num=True)
8480

8581
# Special case for Provisional PEPs.
8682
if status == STATUS_PROVISIONAL and self.pep_type != TYPE_STANDARDS:
8783
msg = "Only Standards Track PEPs may have a Provisional status"
88-
self.raise_pep_error(msg, pep_num=True)
84+
_raise_pep_error(self, msg, pep_num=True)
8985
self.status: str = status
9086

9187
# Parse PEP authors
92-
self.authors: list[Author] = self.parse_authors(metadata["Author"], authors_overrides)
88+
self.authors: list[Author] = _parse_authors(self, metadata["Author"], authors_overrides)
9389

9490
def __repr__(self) -> str:
9591
return f"<PEP {self.number:0>4} - {self.title}>"
9692

9793
def __lt__(self, other: PEP) -> bool:
9894
return self.number < other.number
9995

100-
def parse_authors(self, author_header: str, authors_overrides: dict) -> list[Author]:
101-
"""Parse Author header line"""
102-
authors_and_emails = self._parse_author(author_header)
103-
if not authors_and_emails:
104-
raise self.raise_pep_error("no authors found", pep_num=True)
105-
return [Author(author_tuple, authors_overrides) for author_tuple in authors_and_emails]
106-
107-
angled = re.compile(r"(?P<author>.+?) <(?P<email>.+?)>(,\s*)?")
108-
paren = re.compile(r"(?P<email>.+?) \((?P<author>.+?)\)(,\s*)?")
109-
simple = re.compile(r"(?P<author>[^,]+)(,\s*)?")
110-
111-
@staticmethod
112-
def _parse_author(data: str) -> list[tuple[str, str]]:
113-
"""Return a list of author names and emails."""
114-
115-
author_list = []
116-
for regex in (PEP.angled, PEP.paren, PEP.simple):
117-
for match in regex.finditer(data):
118-
# Watch out for suffixes like 'Jr.' when they are comma-separated
119-
# from the name and thus cause issues when *all* names are only
120-
# separated by commas.
121-
match_dict = match.groupdict()
122-
author = match_dict["author"]
123-
if not author.partition(" ")[1] and author.endswith("."):
124-
prev_author = author_list.pop()
125-
author = ", ".join([prev_author, author])
126-
if "email" not in match_dict:
127-
email = ""
128-
else:
129-
email = match_dict["email"]
130-
author_list.append((author, email))
131-
132-
# If authors were found then stop searching as only expect one
133-
# style of author citation.
134-
if author_list:
135-
break
136-
return author_list
137-
138-
def title_abbr(self, title_length) -> str:
139-
"""Shorten the title to be no longer than the max title length."""
140-
if len(self.title) <= title_length:
141-
return self.title
142-
wrapped_title, *_excess = textwrap.wrap(self.title, title_length - 4)
143-
return f"{wrapped_title} ..."
144-
145-
def pep(self, *, title_length) -> dict[str, str | int]:
96+
def details(self, *, title_length) -> dict[str, str | int]:
14697
"""Return the line entry for the PEP."""
14798
return {
14899
# how the type is to be represented in the index
149100
"type": self.pep_type[0].upper(),
150101
"number": self.number,
151-
"title": self.title_abbr(title_length),
102+
"title": _title_abbr(self.title, title_length),
152103
# how the status should be represented in the index
153-
"status": self.status[0].upper() if self.status not in HIDE_STATUS else " ",
104+
"status": " " if self.status in HIDE_STATUS else self.status[0].upper(),
154105
# the author list as a comma-separated with only last names
155106
"authors": ", ".join(x.nick for x in self.authors),
156107
}
108+
109+
110+
def _raise_pep_error(pep: PEP, msg: str, pep_num: bool = False) -> None:
111+
if pep_num:
112+
raise PEPError(msg, pep.filename, pep_number=pep.number)
113+
raise PEPError(msg, pep.filename)
114+
115+
116+
def _parse_authors(pep: PEP, author_header: str, authors_overrides: dict) -> list[Author]:
117+
"""Parse Author header line"""
118+
authors_and_emails = _parse_author(author_header)
119+
if not authors_and_emails:
120+
raise _raise_pep_error(pep, "no authors found", pep_num=True)
121+
return [Author(author_tuple, authors_overrides) for author_tuple in authors_and_emails]
122+
123+
124+
author_angled = re.compile(r"(?P<author>.+?) <(?P<email>.+?)>(,\s*)?")
125+
author_paren = re.compile(r"(?P<email>.+?) \((?P<author>.+?)\)(,\s*)?")
126+
author_simple = re.compile(r"(?P<author>[^,]+)(,\s*)?")
127+
128+
129+
def _parse_author(data: str) -> list[tuple[str, str]]:
130+
"""Return a list of author names and emails."""
131+
132+
author_list = []
133+
for regex in (author_angled, author_paren, author_simple):
134+
for match in regex.finditer(data):
135+
# Watch out for suffixes like 'Jr.' when they are comma-separated
136+
# from the name and thus cause issues when *all* names are only
137+
# separated by commas.
138+
match_dict = match.groupdict()
139+
author = match_dict["author"]
140+
if not author.partition(" ")[1] and author.endswith("."):
141+
prev_author = author_list.pop()
142+
author = ", ".join([prev_author, author])
143+
if "email" not in match_dict:
144+
email = ""
145+
else:
146+
email = match_dict["email"]
147+
author_list.append((author, email))
148+
149+
# If authors were found then stop searching as only expect one
150+
# style of author citation.
151+
if author_list:
152+
break
153+
return author_list
154+
155+
156+
def _title_abbr(title, title_length) -> str:
157+
"""Shorten the title to be no longer than the max title length."""
158+
if len(title) <= title_length:
159+
return title
160+
wrapped_title, *_excess = textwrap.wrap(title, title_length - 4)
161+
return f"{wrapped_title} ..."

pep_sphinx_extensions/pep_zero_generator/writer.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def emit_pep_category(self, category: str, anchor: str, peps: list[PEP]) -> None
114114
self.emit_subtitle(category, anchor)
115115
self.emit_column_headers()
116116
for pep in peps:
117-
self.output.append(column_format(**pep.pep(title_length=title_length)))
117+
self.output.append(column_format(**pep.details(title_length=title_length)))
118118
self.emit_table_separator()
119119
self.emit_newline()
120120

@@ -155,7 +155,7 @@ def write_pep0(self, peps: list[PEP]):
155155
for pep in peps:
156156
if pep.number - prev_pep > 1:
157157
self.emit_newline()
158-
self.emit_pep_row(pep.pep(title_length=title_length))
158+
self.emit_pep_row(pep.details(title_length=title_length))
159159
prev_pep = pep.number
160160

161161
self.emit_table_separator()

0 commit comments

Comments
 (0)