python-peps/pep0/output.py

213 lines
7.1 KiB
Python

"""Code to handle the output of PEP 0."""
import datetime
import sys
import unicodedata
from operator import attrgetter
from . import constants
from .pep import PEP, PEPError
indent = u' '
def write_column_headers(output):
"""Output the column headers for the PEP indices."""
column_headers = {'status': u'', 'type': u'', 'number': u'num',
'title': u'title', 'authors': u'owner'}
print>>output, constants.column_format % column_headers
underline_headers = {}
for key, value in column_headers.items():
underline_headers[key] = unicode(len(value) * '-')
print>>output, constants.column_format % underline_headers
def sort_peps(peps):
"""Sort PEPs into meta, informational, accepted, open, finished,
and essentially dead."""
meta = []
info = []
accepted = []
open_ = []
finished = []
historical = []
deferred = []
dead = []
for pep in peps:
# Order of 'if' statement important. Key Status values take precedence
# over Type value, and vice-versa.
if pep.status == 'Draft':
open_.append(pep)
elif pep.type_ == 'Process':
if pep.status == "Active":
meta.append(pep)
elif pep.status in ("Withdrawn", "Rejected"):
dead.append(pep)
else:
historical.append(pep)
elif pep.status == 'Deferred':
deferred.append(pep)
elif pep.status in ('Rejected', 'Withdrawn',
'Incomplete', 'Superseded'):
dead.append(pep)
elif pep.type_ == 'Informational':
# Hack until the conflict between the use of "Final"
# for both API definition PEPs and other (actually
# obsolete) PEPs is addressed
if (pep.status == "Active" or
"Release Schedule" not in pep.title):
info.append(pep)
else:
historical.append(pep)
elif pep.status in ('Accepted', 'Active'):
accepted.append(pep)
elif pep.status == 'Final':
finished.append(pep)
else:
raise PEPError("unsorted (%s/%s)" %
(pep.type_, pep.status),
pep.filename, pep.number)
return meta, info, accepted, open_, finished, historical, deferred, dead
def verify_email_addresses(peps):
authors_dict = {}
for pep in peps:
for author in pep.authors:
# If this is the first time we have come across an author, add him.
if author not in authors_dict:
authors_dict[author] = [author.email]
else:
found_emails = authors_dict[author]
# If no email exists for the author, use the new value.
if not found_emails[0]:
authors_dict[author] = [author.email]
# If the new email is an empty string, move on.
elif not author.email:
continue
# If the email has not been seen, add it to the list.
elif author.email not in found_emails:
authors_dict[author].append(author.email)
valid_authors_dict = {}
too_many_emails = []
for author, emails in authors_dict.items():
if len(emails) > 1:
too_many_emails.append((author.first_last, emails))
else:
valid_authors_dict[author] = emails[0]
if too_many_emails:
err_output = []
for author, emails in too_many_emails:
err_output.append(" %s: %r" % (author, emails))
raise ValueError("some authors have more than one email address "
"listed:\n" + '\n'.join(err_output))
return valid_authors_dict
def sort_authors(authors_dict):
authors_list = authors_dict.keys()
authors_list.sort(key=attrgetter('sort_by'))
return authors_list
def normalized_last_first(name):
return len(unicodedata.normalize('NFC', name.last_first))
def write_pep0(peps, output=sys.stdout):
today = datetime.date.today().strftime("%Y-%m-%d")
print>>output, constants.header % today
print>>output
print>>output, u"Introduction"
print>>output, constants.intro
print>>output
print>>output, u"Index by Category"
print>>output
write_column_headers(output)
(meta, info, accepted, open_, finished,
historical, deferred, dead) = sort_peps(peps)
print>>output
print>>output, u" Meta-PEPs (PEPs about PEPs or Processes)"
print>>output
for pep in meta:
print>>output, unicode(pep)
print>>output
print>>output, u" Other Informational PEPs"
print>>output
for pep in info:
print>>output, unicode(pep)
print>>output
print>>output, u" Accepted PEPs (accepted; may not be implemented yet)"
print>>output
for pep in accepted:
print>>output, unicode(pep)
print>>output
print>>output, u" Open PEPs (under consideration)"
print>>output
for pep in open_:
print>>output, unicode(pep)
print>>output
print>>output, u" Finished PEPs (done, implemented in code repository)"
print>>output
for pep in finished:
print>>output, unicode(pep)
print>>output
print>>output, u" Historical Meta-PEPs and Informational PEPs"
print>>output
for pep in historical:
print>>output, unicode(pep)
print>>output
print>>output, u" Deferred PEPs"
print>>output
for pep in deferred:
print>>output, unicode(pep)
print>>output
print>>output, u" Abandoned, Withdrawn, and Rejected PEPs"
print>>output
for pep in dead:
print>>output, unicode(pep)
print>>output
print>>output
print>>output, u"Numerical Index"
print>>output
write_column_headers(output)
prev_pep = 0
for pep in peps:
if pep.number - prev_pep > 1:
print>>output
print>>output, unicode(pep)
prev_pep = pep.number
print>>output
print>>output
print>>output, u"Key"
print>>output
for type_ in PEP.type_values:
print>>output, u" %s - %s PEP" % (type_[0], type_)
print>>output
for status in PEP.status_values:
print>>output, u" %s - %s proposal" % (status[0], status)
print>>output
print>>output
print>>output, u"Owners"
print>>output
authors_dict = verify_email_addresses(peps)
max_name = max(authors_dict.keys(), key=normalized_last_first)
max_name_len = len(max_name.last_first)
print>>output, u" %s %s" % ('name'.ljust(max_name_len), 'email address')
print>>output, u" %s %s" % ((len('name')*'-').ljust(max_name_len),
len('email address')*'-')
sorted_authors = sort_authors(authors_dict)
for author in sorted_authors:
# Use the email from authors_dict instead of the one from 'author' as
# the author instance may have an empty email.
print>>output, (u" %s %s" %
(author.last_first.ljust(max_name_len), authors_dict[author]))
print>>output
print>>output
print>>output, u"References"
print>>output
print>>output, constants.references
print>>output, constants.footer