|
| 1 | +"""Code to handle the output of PEP 0.""" |
| 2 | +import sys |
| 3 | +import unicodedata |
| 4 | + |
| 5 | +from operator import attrgetter |
| 6 | + |
| 7 | +from . import constants |
| 8 | +from .pep import PEP, PEPError |
| 9 | + |
| 10 | + |
| 11 | +indent = u' ' |
| 12 | + |
| 13 | +def write_column_headers(output): |
| 14 | + """Output the column headers for the PEP indices.""" |
| 15 | + column_headers = {'status': u'', 'type': u'', 'number': u'num', |
| 16 | + 'title': u'title', 'authors': u'owner'} |
| 17 | + print>>output, constants.column_format % column_headers |
| 18 | + underline_headers = {} |
| 19 | + for key, value in column_headers.items(): |
| 20 | + underline_headers[key] = unicode(len(value) * '-') |
| 21 | + print>>output, constants.column_format % underline_headers |
| 22 | + |
| 23 | + |
| 24 | +def sort_peps(peps): |
| 25 | + """Sort PEPs into meta, informational, accepted, open, finished, |
| 26 | + and essentially dead.""" |
| 27 | + meta = [] |
| 28 | + info = [] |
| 29 | + accepted = [] |
| 30 | + open_ = [] |
| 31 | + finished = [] |
| 32 | + dead = [] |
| 33 | + for pep in peps: |
| 34 | + # Order of 'if' statement important. Key Status values take precedence |
| 35 | + # over Type value, and vice-versa. |
| 36 | + if pep.type_ == 'Process': |
| 37 | + meta.append(pep) |
| 38 | + elif pep.status == 'Draft': |
| 39 | + open_.append(pep) |
| 40 | + elif pep.status in ('Rejected', 'Withdrawn', 'Deferred', |
| 41 | + 'Incomplete', 'Replaced'): |
| 42 | + dead.append(pep) |
| 43 | + elif pep.type_ == 'Informational': |
| 44 | + info.append(pep) |
| 45 | + elif pep.status in ('Accepted', 'Active'): |
| 46 | + accepted.append(pep) |
| 47 | + elif pep.status == 'Final': |
| 48 | + finished.append(pep) |
| 49 | + else: |
| 50 | + raise PEPError("unsorted (%s/%s)" % |
| 51 | + (pep.type_, pep.status), |
| 52 | + pep.filename, pep.number) |
| 53 | + return meta, info, accepted, open_, finished, dead |
| 54 | + |
| 55 | + |
| 56 | +def verify_email_addresses(peps): |
| 57 | + authors_dict = {} |
| 58 | + for pep in peps: |
| 59 | + for author in pep.authors: |
| 60 | + # If this is the first time we have come across an author, add him. |
| 61 | + if author not in authors_dict: |
| 62 | + authors_dict[author] = [author.email] |
| 63 | + else: |
| 64 | + found_emails = authors_dict[author] |
| 65 | + # If no email exists for the author, use the new value. |
| 66 | + if not found_emails[0]: |
| 67 | + authors_dict[author] = [author.email] |
| 68 | + # If the new email is an empty string, move on. |
| 69 | + elif not author.email: |
| 70 | + continue |
| 71 | + # If the email has not been seen, add it to the list. |
| 72 | + elif author.email not in found_emails: |
| 73 | + authors_dict[author].append(author.email) |
| 74 | + |
| 75 | + valid_authors_dict = {} |
| 76 | + too_many_emails = [] |
| 77 | + for author, emails in authors_dict.items(): |
| 78 | + if len(emails) > 1: |
| 79 | + too_many_emails.append((author.first_last, emails)) |
| 80 | + else: |
| 81 | + valid_authors_dict[author] = emails[0] |
| 82 | + if too_many_emails: |
| 83 | + err_output = [] |
| 84 | + for author, emails in too_many_emails: |
| 85 | + err_output.append(" %s: %r" % (author, emails)) |
| 86 | + raise ValueError("some authors have more than one email address " |
| 87 | + "listed:\n" + '\n'.join(err_output)) |
| 88 | + |
| 89 | + return valid_authors_dict |
| 90 | + |
| 91 | + |
| 92 | +def sort_authors(authors_dict): |
| 93 | + authors_list = authors_dict.keys() |
| 94 | + authors_list.sort(key=attrgetter('sort_by')) |
| 95 | + return authors_list |
| 96 | + |
| 97 | +def normalized_last_first(name): |
| 98 | + return len(unicodedata.normalize('NFC', name.last_first)) |
| 99 | + |
| 100 | + |
| 101 | +def write_pep0(peps, output=sys.stdout): |
| 102 | + print>>output, constants.header |
| 103 | + print>>output |
| 104 | + print>>output, u"Introduction" |
| 105 | + print>>output, constants.intro |
| 106 | + print>>output |
| 107 | + print>>output, u"Index by Category" |
| 108 | + print>>output |
| 109 | + write_column_headers(output) |
| 110 | + meta, info, accepted, open_, finished, dead = sort_peps(peps) |
| 111 | + print>>output |
| 112 | + print>>output, u" Meta-PEPs (PEPs about PEPs or Processs)" |
| 113 | + print>>output |
| 114 | + for pep in meta: |
| 115 | + print>>output, unicode(pep) |
| 116 | + print>>output |
| 117 | + print>>output, u" Other Informational PEPs" |
| 118 | + print>>output |
| 119 | + for pep in info: |
| 120 | + print>>output, unicode(pep) |
| 121 | + print>>output |
| 122 | + print>>output, u" Accepted PEPs (accepted; may not be implemented yet)" |
| 123 | + print>>output |
| 124 | + for pep in accepted: |
| 125 | + print>>output, unicode(pep) |
| 126 | + print>>output |
| 127 | + print>>output, u" Open PEPs (under consideration)" |
| 128 | + print>>output |
| 129 | + for pep in open_: |
| 130 | + print>>output, unicode(pep) |
| 131 | + print>>output |
| 132 | + print>>output, u" Finished PEPs (done, implemented in code repository)" |
| 133 | + print>>output |
| 134 | + for pep in finished: |
| 135 | + print>>output, unicode(pep) |
| 136 | + print>>output |
| 137 | + print>>output, u" Deferred, Abandoned, Withdrawn, and Rejected PEPs" |
| 138 | + print>>output |
| 139 | + for pep in dead: |
| 140 | + print>>output, unicode(pep) |
| 141 | + print>>output |
| 142 | + print>>output |
| 143 | + print>>output, u" Numerical Index" |
| 144 | + print>>output |
| 145 | + write_column_headers(output) |
| 146 | + prev_pep = 0 |
| 147 | + for pep in peps: |
| 148 | + if pep.number - prev_pep > 1: |
| 149 | + print>>output |
| 150 | + print>>output, unicode(pep) |
| 151 | + prev_pep = pep.number |
| 152 | + print>>output |
| 153 | + print>>output |
| 154 | + print>>output, u"Key" |
| 155 | + print>>output |
| 156 | + for type_ in PEP.type_values: |
| 157 | + print>>output, u" %s - %s PEP" % (type_[0], type_) |
| 158 | + print>>output |
| 159 | + for status in PEP.status_values: |
| 160 | + print>>output, u" %s - %s proposal" % (status[0], status) |
| 161 | + |
| 162 | + print>>output |
| 163 | + print>>output |
| 164 | + print>>output, u"Owners" |
| 165 | + print>>output |
| 166 | + authors_dict = verify_email_addresses(peps) |
| 167 | + max_name = max(authors_dict.keys(), key=normalized_last_first) |
| 168 | + max_name_len = len(max_name.last_first) |
| 169 | + print>>output, u" %s %s" % ('name'.ljust(max_name_len), 'email address') |
| 170 | + print>>output, u" %s %s" % ((len('name')*'-').ljust(max_name_len), |
| 171 | + len('email address')*'-') |
| 172 | + sorted_authors = sort_authors(authors_dict) |
| 173 | + for author in sorted_authors: |
| 174 | + # Use the email from authors_dict instead of the one from 'author' as |
| 175 | + # the author instance may have an empty email. |
| 176 | + print>>output, (u" %s %s" % |
| 177 | + (author.last_first.ljust(max_name_len), authors_dict[author])) |
| 178 | + print>>output |
| 179 | + print>>output |
| 180 | + print>>output, u"References" |
| 181 | + print>>output |
| 182 | + print>>output, constants.references |
| 183 | + print>>output, constants.footer |
0 commit comments