-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Sphinx support: add PEP 0 generation extension (1932)
* Add PEP 0 parser * Add PEP 0 writer * Add PEP 0 generator and authors override * Add/update build and run * Simplify `create_index_file` * Special status handling * Add constants for PEP related magic strings * Prefer checking on class * Add PEP.hide_status, use constants * Remove comment from 2008 (current method works fine) * Clarify intent of for-else loop * Hook in to Sphinx (oops, missed when splitting out this PR) * Rename AUTHORS.csv for clarity * Sort and strip spaces * Prefer `authors_overrides` name * Add pep_0_errors.py * Move author_sort_by to writer * PEP init misc * Split out Author * Drop pep_0 prefix * Pass title length as an argument * Add constants.py to hold global type / status values * Capitalise constants * Capitalise constants * Update PEP classification algorithm * Extract static methods to module level * Add emit_text, emit_pep_row * Use constants in writer.py * Sort imports * Sort constants * Fix sorting in historical and dead PEPs * Extract static methods to module level * Extract static methods to module level (parser.py * Make Author a NamedTuple * Fix author duplication bug with NamedTuples * Revert to old PEP classification algorithm * Define PEP equality
- Loading branch information
Showing
12 changed files
with
717 additions
and
6 deletions.
There are no files selected for viewing
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,11 @@ | ||
Overridden Name,Surname First,Name Reference | ||
The Python core team and community,The Python core team and community,python-dev | ||
Ernest W. Durbin III,"Durbin, Ernest W., III",Durbin | ||
Greg Ewing,"Ewing, Gregory",Ewing | ||
Guido van Rossum,"van Rossum, Guido (GvR)",GvR | ||
Inada Naoki,"Inada, Naoki",Inada | ||
Jim Jewett,"Jewett, Jim J.",Jewett | ||
Just van Rossum,"van Rossum, Just (JvR)",JvR | ||
Martin v. Löwis,"von Löwis, Martin",von Löwis | ||
Nathaniel Smith,"Smith, Nathaniel J.",Smith | ||
P.J. Eby,"Eby, Phillip J.",Eby |
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 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 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 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
4 changes: 2 additions & 2 deletions
4
pep_sphinx_extensions/pep_processor/transforms/pep_headers.py
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 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,93 @@ | ||
from __future__ import annotations | ||
|
||
from typing import NamedTuple | ||
|
||
|
||
class _Name(NamedTuple): | ||
mononym: str = None | ||
forename: str = None | ||
surname: str = None | ||
suffix: str = None | ||
|
||
|
||
class Author(NamedTuple): | ||
"""Represent PEP authors.""" | ||
last_first: str # The author's name in Surname, Forename, Suffix order. | ||
nick: str # Author's nickname for PEP tables. Defaults to surname. | ||
email: str # The author's email address. | ||
|
||
|
||
def parse_author_email(author_email_tuple: tuple[str, str], authors_overrides: dict[str, dict[str, str]]) -> Author: | ||
"""Parse the name and email address of an author.""" | ||
name, email = author_email_tuple | ||
_first_last = name.strip() | ||
email = email.lower() | ||
|
||
if _first_last in authors_overrides: | ||
name_dict = authors_overrides[_first_last] | ||
last_first = name_dict["Surname First"] | ||
nick = name_dict["Name Reference"] | ||
return Author(last_first, nick, email) | ||
|
||
name_parts = _parse_name(_first_last) | ||
if name_parts.mononym is not None: | ||
return Author(name_parts.mononym, name_parts.mononym, email) | ||
|
||
if name_parts.surname[1] == ".": | ||
# Add an escape to avoid docutils turning `v.` into `22.`. | ||
name_parts.surname = f"\\{name_parts.surname}" | ||
|
||
if name_parts.suffix: | ||
last_first = f"{name_parts.surname}, {name_parts.forename}, {name_parts.suffix}" | ||
return Author(last_first, name_parts.surname, email) | ||
|
||
last_first = f"{name_parts.surname}, {name_parts.forename}" | ||
return Author(last_first, name_parts.surname, email) | ||
|
||
|
||
def _parse_name(full_name: str) -> _Name: | ||
"""Decompose a full name into parts. | ||
If a mononym (e.g, 'Aahz') then return the full name. If there are | ||
suffixes in the name (e.g. ', Jr.' or 'II'), then find and extract | ||
them. If there is a middle initial followed by a full stop, then | ||
combine the following words into a surname (e.g. N. Vander Weele). If | ||
there is a leading, lowercase portion to the last name (e.g. 'van' or | ||
'von') then include it in the surname. | ||
""" | ||
possible_suffixes = {"Jr", "Jr.", "II", "III"} | ||
|
||
pre_suffix, _, raw_suffix = full_name.partition(",") | ||
name_parts = pre_suffix.strip().split(" ") | ||
num_parts = len(name_parts) | ||
suffix = raw_suffix.strip() | ||
|
||
if num_parts == 0: | ||
raise ValueError("Name is empty!") | ||
elif num_parts == 1: | ||
return _Name(mononym=name_parts[0], suffix=suffix) | ||
elif num_parts == 2: | ||
return _Name(forename=name_parts[0].strip(), surname=name_parts[1], suffix=suffix) | ||
|
||
# handles rogue uncaught suffixes | ||
if name_parts[-1] in possible_suffixes: | ||
suffix = f"{name_parts.pop(-1)} {suffix}".strip() | ||
|
||
# handles von, van, v. etc. | ||
if name_parts[-2].islower(): | ||
forename = " ".join(name_parts[:-2]).strip() | ||
surname = " ".join(name_parts[-2:]) | ||
return _Name(forename=forename, surname=surname, suffix=suffix) | ||
|
||
# handles double surnames after a middle initial (e.g. N. Vander Weele) | ||
elif any(s.endswith(".") for s in name_parts): | ||
split_position = [i for i, x in enumerate(name_parts) if x.endswith(".")][-1] + 1 | ||
forename = " ".join(name_parts[:split_position]).strip() | ||
surname = " ".join(name_parts[split_position:]) | ||
return _Name(forename=forename, surname=surname, suffix=suffix) | ||
|
||
# default to using the last item as the surname | ||
else: | ||
forename = " ".join(name_parts[:-1]).strip() | ||
return _Name(forename=forename, surname=name_parts[-1], suffix=suffix) |
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,34 @@ | ||
"""Holds type and status constants for PEP 0 generation.""" | ||
|
||
STATUS_ACCEPTED = "Accepted" | ||
STATUS_ACTIVE = "Active" | ||
STATUS_DEFERRED = "Deferred" | ||
STATUS_DRAFT = "Draft" | ||
STATUS_FINAL = "Final" | ||
STATUS_PROVISIONAL = "Provisional" | ||
STATUS_REJECTED = "Rejected" | ||
STATUS_SUPERSEDED = "Superseded" | ||
STATUS_WITHDRAWN = "Withdrawn" | ||
|
||
# Valid values for the Status header. | ||
STATUS_VALUES = { | ||
STATUS_ACCEPTED, STATUS_PROVISIONAL, STATUS_REJECTED, STATUS_WITHDRAWN, | ||
STATUS_DEFERRED, STATUS_FINAL, STATUS_ACTIVE, STATUS_DRAFT, STATUS_SUPERSEDED, | ||
} | ||
# Map of invalid/special statuses to their valid counterparts | ||
SPECIAL_STATUSES = { | ||
"April Fool!": STATUS_REJECTED, # See PEP 401 :) | ||
} | ||
# Draft PEPs have no status displayed, Active shares a key with Accepted | ||
HIDE_STATUS = {STATUS_DRAFT, STATUS_ACTIVE} | ||
# Dead PEP statuses | ||
DEAD_STATUSES = {STATUS_REJECTED, STATUS_WITHDRAWN, STATUS_SUPERSEDED} | ||
|
||
TYPE_INFO = "Informational" | ||
TYPE_PROCESS = "Process" | ||
TYPE_STANDARDS = "Standards Track" | ||
|
||
# Valid values for the Type header. | ||
TYPE_VALUES = {TYPE_STANDARDS, TYPE_INFO, TYPE_PROCESS} | ||
# Active PEPs can only be for Informational or Process PEPs. | ||
ACTIVE_ALLOWED = {TYPE_PROCESS, TYPE_INFO} |
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,16 @@ | ||
from __future__ import annotations | ||
|
||
from pathlib import Path | ||
|
||
|
||
class PEPError(Exception): | ||
def __init__(self, error: str, pep_file: Path, pep_number: int | None = None): | ||
super().__init__(error) | ||
self.filename = pep_file | ||
self.number = pep_number | ||
|
||
def __str__(self): | ||
error_msg = super(PEPError, self).__str__() | ||
error_msg = f"({self.filename}): {error_msg}" | ||
pep_str = f"PEP {self.number}" | ||
return f"{pep_str} {error_msg}" if self.number is not None else error_msg |
Oops, something went wrong.