Convert PEP index to ReST (#705)

Keeps Python 3.5 compatibility, as that's what
pythondotorg currently still uses.
This commit is contained in:
Nick Coghlan 2018-07-10 23:10:43 +10:00 committed by GitHub
parent 0630155b47
commit d18a264e4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 162 additions and 121 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
pep-0000.txt pep-0000.txt
pep-0000.rst
pep-????.html pep-????.html
__pycache__ __pycache__
*.pyc *.pyc

View File

@ -15,13 +15,13 @@ PYTHON=python3
.rst.html: .rst.html:
@$(PYTHON) $(PEP2HTML) $< @$(PYTHON) $(PEP2HTML) $<
TARGETS= $(patsubst %.rst,%.html,$(wildcard pep-????.rst)) $(patsubst %.txt,%.html,$(wildcard pep-????.txt)) pep-0000.html TARGETS= $(patsubst %.rst,%.html,$(wildcard pep-????.rst)) $(patsubst %.txt,%.html,$(wildcard pep-????.txt)) pep-0000.html
all: pep-0000.txt $(TARGETS) all: pep-0000.rst $(TARGETS)
$(TARGETS): pep2html.py $(TARGETS): pep2html.py
pep-0000.txt: $(wildcard pep-????.txt) $(wildcard pep-????.rst) $(wildcard pep0/*.py) pep-0000.rst: $(wildcard pep-????.txt) $(wildcard pep-????.rst) $(wildcard pep0/*.py) genpepindex.py
$(PYTHON) genpepindex.py . $(PYTHON) genpepindex.py .
rss: rss:
@ -31,6 +31,7 @@ install:
echo "Installing is not necessary anymore. It will be done in post-commit." echo "Installing is not necessary anymore. It will be done in post-commit."
clean: clean:
-rm pep-0000.rst
-rm pep-0000.txt -rm pep-0000.txt
-rm *.html -rm *.html

View File

@ -36,7 +36,7 @@ def main(argv):
peps = [] peps = []
if os.path.isdir(path): if os.path.isdir(path):
for file_path in os.listdir(path): for file_path in os.listdir(path):
if file_path == 'pep-0000.txt': if file_path.startswith('pep-0000.'):
continue continue
abs_file_path = os.path.join(path, file_path) abs_file_path = os.path.join(path, file_path)
if not os.path.isfile(abs_file_path): if not os.path.isfile(abs_file_path):
@ -61,7 +61,7 @@ def main(argv):
else: else:
raise ValueError("argument must be a directory or file path") raise ValueError("argument must be a directory or file path")
with codecs.open('pep-0000.txt', 'w', encoding='UTF-8') as pep0_file: with codecs.open('pep-0000.rst', 'w', encoding='UTF-8') as pep0_file:
write_pep0(peps, pep0_file) write_pep0(peps, pep0_file)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1,44 +1,43 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys text_type = str
if sys.version_info[0] > 2:
text_type = str
else:
text_type = unicode
title_length = 55 title_length = 55
column_format = (u' %(type)1s%(status)1s %(number)4s %(title)-' + author_length = 40
text_type(title_length) + u's %(authors)-s') table_separator = "== ==== " + "="*title_length + " " + "="*author_length
column_format = (
'%(type)1s%(status)1s %(number)4s %(title)-{title_length}s %(authors)-s'
).format(title_length=title_length)
header = u"""PEP: 0 header = """\
PEP: 0
Title: Index of Python Enhancement Proposals (PEPs) Title: Index of Python Enhancement Proposals (PEPs)
Version: N/A Version: N/A
Last-Modified: %s Last-Modified: %s
Author: David Goodger <goodger@python.org>, Author: python-dev <python-dev@python.org>
Barry Warsaw <barry@python.org>
Status: Active Status: Active
Type: Informational Type: Informational
Content-Type: text/x-rst
Created: 13-Jul-2000 Created: 13-Jul-2000
""" """
intro = u""" intro = """\
This PEP contains the index of all Python Enhancement Proposals, This PEP contains the index of all Python Enhancement Proposals,
known as PEPs. PEP numbers are assigned by the PEP editors, and known as PEPs. PEP numbers are assigned by the PEP editors, and
once assigned are never changed[1]. The version control history[2] of once assigned are never changed [1_]. The version control history [2_] of
the PEP texts represent their historical record. the PEP texts represent their historical record.
""" """
references = u""" references = """\
[1] PEP 1: PEP Purpose and Guidelines .. [1] PEP 1: PEP Purpose and Guidelines
[2] View PEP history online .. [2] View PEP history online: https://github.com/python/peps
https://github.com/python/peps
""" """
footer = u""" footer = """ \
Local Variables: ..
mode: indented-text Local Variables:
indent-tabs-mode: nil mode: indented-text
sentence-end-double-space: t indent-tabs-mode: nil
fill-column: 70 sentence-end-double-space: t
coding: utf-8 fill-column: 70
End:""" coding: utf-8
End:\
"""

View File

@ -26,15 +26,13 @@ RESERVED = [
indent = u' ' indent = u' '
def write_column_headers(output): def emit_column_headers(output):
"""Output the column headers for the PEP indices.""" """Output the column headers for the PEP indices."""
column_headers = {'status': u'', 'type': u'', 'number': u'num', column_headers = {'status': '.', 'type': '.', 'number': 'PEP',
'title': u'title', 'authors': u'owner'} 'title': 'PEP Title', 'authors': 'PEP Author(s)'}
print(constants.table_separator, file=output)
print(constants.column_format % column_headers, file=output) print(constants.column_format % column_headers, file=output)
underline_headers = {} print(constants.table_separator, file=output)
for key, value in column_headers.items():
underline_headers[key] = constants.text_type(len(value) * '-')
print(constants.column_format % underline_headers, file=output)
def sort_peps(peps): def sort_peps(peps):
@ -93,7 +91,7 @@ def verify_email_addresses(peps):
authors_dict = {} authors_dict = {}
for pep in peps: for pep in peps:
for author in pep.authors: for author in pep.authors:
# If this is the first time we have come across an author, add him. # If this is the first time we have come across an author, add them.
if author not in authors_dict: if author not in authors_dict:
authors_dict[author] = [author.email] authors_dict[author] = [author.email]
else: else:
@ -133,118 +131,160 @@ def sort_authors(authors_dict):
def normalized_last_first(name): def normalized_last_first(name):
return len(unicodedata.normalize('NFC', name.last_first)) return len(unicodedata.normalize('NFC', name.last_first))
def emit_title(text, anchor, output, *, symbol="="):
print(".. _{anchor}:\n".format(anchor=anchor), file=output)
print(text, file=output)
print(symbol*len(text), file=output)
print(file=output)
def emit_subtitle(text, anchor, output):
emit_title(text, anchor, output, symbol="-")
def emit_pep_category(output, category, anchor, peps):
emit_subtitle(category, anchor, output)
emit_column_headers(output)
for pep in peps:
print(pep, file=output)
print(constants.table_separator, file=output)
print(file=output)
def write_pep0(peps, output=sys.stdout): def write_pep0(peps, output=sys.stdout):
# PEP metadata
today = datetime.date.today().strftime("%Y-%m-%d") today = datetime.date.today().strftime("%Y-%m-%d")
print(constants.header % today, file=output) print(constants.header % today, file=output)
print(file=output) print(file=output)
print(u"Introduction", file=output) # Introduction
emit_title("Introduction", "intro", output)
print(constants.intro, file=output) print(constants.intro, file=output)
print(file=output) print(file=output)
print(u"Index by Category", file=output) # PEPs by category
print(file=output)
write_column_headers(output)
(meta, info, provisional, accepted, open_, (meta, info, provisional, accepted, open_,
finished, historical, deferred, dead) = sort_peps(peps) finished, historical, deferred, dead) = sort_peps(peps)
emit_title("Index by Category", "by-category", output)
emit_pep_category(
category="Meta-PEPs (PEPs about PEPs or Processes)",
anchor="by-category-meta",
peps=meta,
output=output,
)
emit_pep_category(
category="Other Informational PEPs",
anchor="by-category-other-info",
peps=info,
output=output,
)
emit_pep_category(
category="Provisional PEPs (provisionally accepted; interface may still change)",
anchor="by-category-provisional",
peps=provisional,
output=output,
)
emit_pep_category(
category="Accepted PEPs (accepted; may not be implemented yet)",
anchor="by-category-accepted",
peps=accepted,
output=output,
)
emit_pep_category(
category="Open PEPs (under consideration)",
anchor="by-category-open",
peps=open_,
output=output,
)
emit_pep_category(
category="Finished PEPs (done, with a stable interface)",
anchor="by-category-finished",
peps=finished,
output=output,
)
emit_pep_category(
category="Historical Meta-PEPs and Informational PEPs",
anchor="by-category-historical",
peps=historical,
output=output,
)
emit_pep_category(
category="Deferred PEPs (postponed pending further research or updates)",
anchor="by-category-deferred",
peps=deferred,
output=output,
)
emit_pep_category(
category="Abandoned, Withdrawn, and Rejected PEPs",
anchor="by-category-abandoned",
peps=dead,
output=output,
)
print(file=output) print(file=output)
print(u" Meta-PEPs (PEPs about PEPs or Processes)", file=output) # PEPs by number
print(file=output) emit_title("Numerical Index", "by-pep-number", output)
for pep in meta: emit_column_headers(output)
print(constants.text_type(pep), file=output)
print(file=output)
print(u" Other Informational PEPs", file=output)
print(file=output)
for pep in info:
print(constants.text_type(pep), file=output)
print(file=output)
print(u" Provisional PEPs (provisionally accepted; interface may still change)",
file=output)
print(file=output)
for pep in provisional:
print(constants.text_type(pep), file=output)
print(file=output)
print(u" Accepted PEPs (accepted; may not be implemented yet)", file=output)
print(file=output)
for pep in accepted:
print(constants.text_type(pep), file=output)
print(file=output)
print(u" Open PEPs (under consideration)", file=output)
print(file=output)
for pep in open_:
print(constants.text_type(pep), file=output)
print(file=output)
print(u" Finished PEPs (done, with a stable interface)", file=output)
print(file=output)
for pep in finished:
print(constants.text_type(pep), file=output)
print(file=output)
print(u" Historical Meta-PEPs and Informational PEPs", file=output)
print(file=output)
for pep in historical:
print(constants.text_type(pep), file=output)
print(file=output)
print(u" Deferred PEPs", file=output)
print(file=output)
for pep in deferred:
print(constants.text_type(pep), file=output)
print(file=output)
print(u" Abandoned, Withdrawn, and Rejected PEPs", file=output)
print(file=output)
for pep in dead:
print(constants.text_type(pep), file=output)
print(file=output)
print(file=output)
print(u"Numerical Index", file=output)
print(file=output)
write_column_headers(output)
prev_pep = 0 prev_pep = 0
for pep in peps: for pep in peps:
if pep.number - prev_pep > 1: if pep.number - prev_pep > 1:
print(file=output) print(file=output)
print(constants.text_type(pep), file=output) print(constants.text_type(pep), file=output)
prev_pep = pep.number prev_pep = pep.number
print(constants.table_separator, file=output)
print(file=output) print(file=output)
print(file=output) # Reserved PEP numbers
print(u'Reserved PEP Numbers', file=output) emit_title('Reserved PEP Numbers', "reserved", output)
print(file=output) emit_column_headers(output)
write_column_headers(output)
for number, claimants in sorted(RESERVED): for number, claimants in sorted(RESERVED):
print(constants.column_format % { print(constants.column_format % {
'type': '', 'type': '.',
'status': '', 'status': '.',
'number': number, 'number': number,
'title': 'RESERVED', 'title': 'RESERVED',
'authors': claimants, 'authors': claimants,
}, file=output) }, file=output)
print(constants.table_separator, file=output)
print(file=output) print(file=output)
print(file=output) # PEP types key
print(u"Key", file=output) emit_title("PEP Types Key", "type-key", output)
print(file=output) for type_ in sorted(PEP.type_values):
for type_ in PEP.type_values:
print(u" %s - %s PEP" % (type_[0], type_), file=output) print(u" %s - %s PEP" % (type_[0], type_), file=output)
print(file=output)
print(file=output) print(file=output)
for status in PEP.status_values: # PEP status key
print(u" %s - %s proposal" % (status[0], status), file=output) emit_title("PEP Status Key", "status-key", output)
for status in sorted(PEP.status_values):
# Draft PEPs have no status displayed, Active shares a key with Accepted
if status in ("Active", "Draft"):
continue
if status == "Accepted":
msg = " A - Accepted (Standards Track only) or Active proposal"
else:
msg = " {status[0]} - {status} proposal".format(status=status)
print(msg, file=output)
print(file=output)
print(file=output) print(file=output)
print(file=output) # PEP owners
print(u"Owners", file=output) emit_title("Authors/Owners", "authors", output)
print(file=output)
authors_dict = verify_email_addresses(peps) authors_dict = verify_email_addresses(peps)
max_name = max(authors_dict.keys(), key=normalized_last_first) max_name = max(authors_dict.keys(), key=normalized_last_first)
max_name_len = len(max_name.last_first) max_name_len = len(max_name.last_first)
print(u" %s %s" % ('name'.ljust(max_name_len), 'email address'), file=output) author_table_separator = "="*max_name_len + " " + "="*len("email address")
print(u" %s %s" % ((len('name')*'-').ljust(max_name_len), print(author_table_separator, file=output)
len('email address')*'-'), file=output) _author_header_fmt = "{name:{max_name_len}} Email Address"
print(_author_header_fmt.format(name="Name", max_name_len=max_name_len), file=output)
print(author_table_separator, file=output)
sorted_authors = sort_authors(authors_dict) sorted_authors = sort_authors(authors_dict)
_author_fmt = "{author.last_first:{max_name_len}} {author_email}"
for author in sorted_authors: for author in sorted_authors:
# Use the email from authors_dict instead of the one from 'author' as # Use the email from authors_dict instead of the one from 'author' as
# the author instance may have an empty email. # the author instance may have an empty email.
print((u" %s %s" % _entry = _author_fmt.format(
(author.last_first.ljust(max_name_len), authors_dict[author])), file=output) author=author,
author_email=authors_dict[author],
max_name_len=max_name_len,
)
print(_entry, file=output)
print(author_table_separator, file=output)
print(file=output) print(file=output)
print(file=output) print(file=output)
print(u"References", file=output) # References for introduction footnotes
print(file=output) emit_title("References", "references", output)
print(constants.references, file=output) print(constants.references, file=output)
print(constants.footer, file=output) print(constants.footer, file=output)

View File

@ -99,11 +99,11 @@ class Author(object):
name_parts = self.last.split() name_parts = self.last.split()
for index, part in enumerate(name_parts): for index, part in enumerate(name_parts):
if part[0].isupper(): if part[0].isupper():
base = u' '.join(name_parts[index:]).lower()
break break
else: else:
raise ValueError("last name missing a capital letter: %r" # If no capitals, use the whole string
% name_parts) base = self.last.lower()
base = u' '.join(name_parts[index:]).lower()
return unicodedata.normalize('NFKD', base).encode('ASCII', 'ignore') return unicodedata.normalize('NFKD', base).encode('ASCII', 'ignore')
def _last_name(self, full_name): def _last_name(self, full_name):