buildframework/helium/external/python/lib/common/docutils-0.5-py2.5.egg/docutils/transforms/peps.py
author wbernard
Wed, 23 Dec 2009 19:29:07 +0200
changeset 179 d8ac696cc51f
permissions -rw-r--r--
helium_7.0-r14027
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
179
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     1
# $Id: peps.py 4564 2006-05-21 20:44:42Z wiemann $
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     2
# Author: David Goodger <goodger@python.org>
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     3
# Copyright: This module has been placed in the public domain.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     4
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     5
"""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     6
Transforms for PEP processing.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     7
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     8
- `Headers`: Used to transform a PEP's initial RFC-2822 header.  It remains a
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     9
  field list, but some entries get processed.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    10
- `Contents`: Auto-inserts a table of contents.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    11
- `PEPZero`: Special processing for PEP 0.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    12
"""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    13
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    14
__docformat__ = 'reStructuredText'
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    15
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    16
import sys
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    17
import os
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    18
import re
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    19
import time
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    20
from docutils import nodes, utils, languages
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    21
from docutils import ApplicationError, DataError
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    22
from docutils.transforms import Transform, TransformError
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    23
from docutils.transforms import parts, references, misc
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    24
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    25
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    26
class Headers(Transform):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    27
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    28
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    29
    Process fields in a PEP's initial RFC-2822 header.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    30
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    31
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    32
    default_priority = 360
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    33
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    34
    pep_url = 'pep-%04d'
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    35
    pep_cvs_url = ('http://svn.python.org/view/*checkout*'
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    36
                   '/peps/trunk/pep-%04d.txt')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    37
    rcs_keyword_substitutions = (
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    38
          (re.compile(r'\$' r'RCSfile: (.+),v \$$', re.IGNORECASE), r'\1'),
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    39
          (re.compile(r'\$[a-zA-Z]+: (.+) \$$'), r'\1'),)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    40
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    41
    def apply(self):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    42
        if not len(self.document):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    43
            # @@@ replace these DataErrors with proper system messages
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    44
            raise DataError('Document tree is empty.')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    45
        header = self.document[0]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    46
        if not isinstance(header, nodes.field_list) or \
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    47
              'rfc2822' not in header['classes']:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    48
            raise DataError('Document does not begin with an RFC-2822 '
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    49
                            'header; it is not a PEP.')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    50
        pep = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    51
        for field in header:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    52
            if field[0].astext().lower() == 'pep': # should be the first field
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    53
                value = field[1].astext()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    54
                try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    55
                    pep = int(value)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    56
                    cvs_url = self.pep_cvs_url % pep
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    57
                except ValueError:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    58
                    pep = value
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    59
                    cvs_url = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    60
                    msg = self.document.reporter.warning(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    61
                        '"PEP" header must contain an integer; "%s" is an '
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    62
                        'invalid value.' % pep, base_node=field)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    63
                    msgid = self.document.set_id(msg)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    64
                    prb = nodes.problematic(value, value or '(none)',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    65
                                            refid=msgid)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    66
                    prbid = self.document.set_id(prb)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    67
                    msg.add_backref(prbid)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    68
                    if len(field[1]):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    69
                        field[1][0][:] = [prb]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    70
                    else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    71
                        field[1] += nodes.paragraph('', '', prb)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    72
                break
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    73
        if pep is None:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    74
            raise DataError('Document does not contain an RFC-2822 "PEP" '
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    75
                            'header.')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    76
        if pep == 0:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    77
            # Special processing for PEP 0.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    78
            pending = nodes.pending(PEPZero)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    79
            self.document.insert(1, pending)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    80
            self.document.note_pending(pending)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    81
        if len(header) < 2 or header[1][0].astext().lower() != 'title':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    82
            raise DataError('No title!')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    83
        for field in header:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    84
            name = field[0].astext().lower()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    85
            body = field[1]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    86
            if len(body) > 1:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    87
                raise DataError('PEP header field body contains multiple '
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    88
                                'elements:\n%s' % field.pformat(level=1))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    89
            elif len(body) == 1:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    90
                if not isinstance(body[0], nodes.paragraph):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    91
                    raise DataError('PEP header field body may only contain '
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    92
                                    'a single paragraph:\n%s'
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    93
                                    % field.pformat(level=1))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    94
            elif name == 'last-modified':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    95
                date = time.strftime(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    96
                      '%d-%b-%Y',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    97
                      time.localtime(os.stat(self.document['source'])[8]))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    98
                if cvs_url:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    99
                    body += nodes.paragraph(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   100
                        '', '', nodes.reference('', date, refuri=cvs_url))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   101
            else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   102
                # empty
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   103
                continue
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   104
            para = body[0]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   105
            if name == 'author':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   106
                for node in para:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   107
                    if isinstance(node, nodes.reference):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   108
                        node.replace_self(mask_email(node))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   109
            elif name == 'discussions-to':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   110
                for node in para:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   111
                    if isinstance(node, nodes.reference):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   112
                        node.replace_self(mask_email(node, pep))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   113
            elif name in ('replaces', 'replaced-by', 'requires'):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   114
                newbody = []
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   115
                space = nodes.Text(' ')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   116
                for refpep in re.split(',?\s+', body.astext()):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   117
                    pepno = int(refpep)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   118
                    newbody.append(nodes.reference(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   119
                        refpep, refpep,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   120
                        refuri=(self.document.settings.pep_base_url
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   121
                                + self.pep_url % pepno)))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   122
                    newbody.append(space)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   123
                para[:] = newbody[:-1] # drop trailing space
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   124
            elif name == 'last-modified':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   125
                utils.clean_rcs_keywords(para, self.rcs_keyword_substitutions)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   126
                if cvs_url:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   127
                    date = para.astext()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   128
                    para[:] = [nodes.reference('', date, refuri=cvs_url)]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   129
            elif name == 'content-type':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   130
                pep_type = para.astext()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   131
                uri = self.document.settings.pep_base_url + self.pep_url % 12
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   132
                para[:] = [nodes.reference('', pep_type, refuri=uri)]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   133
            elif name == 'version' and len(body):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   134
                utils.clean_rcs_keywords(para, self.rcs_keyword_substitutions)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   135
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   136
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   137
class Contents(Transform):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   138
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   139
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   140
    Insert an empty table of contents topic and a transform placeholder into
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   141
    the document after the RFC 2822 header.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   142
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   143
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   144
    default_priority = 380
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   145
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   146
    def apply(self):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   147
        language = languages.get_language(self.document.settings.language_code)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   148
        name = language.labels['contents']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   149
        title = nodes.title('', name)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   150
        topic = nodes.topic('', title, classes=['contents'])
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   151
        name = nodes.fully_normalize_name(name)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   152
        if not self.document.has_name(name):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   153
            topic['names'].append(name)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   154
        self.document.note_implicit_target(topic)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   155
        pending = nodes.pending(parts.Contents)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   156
        topic += pending
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   157
        self.document.insert(1, topic)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   158
        self.document.note_pending(pending)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   159
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   160
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   161
class TargetNotes(Transform):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   162
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   163
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   164
    Locate the "References" section, insert a placeholder for an external
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   165
    target footnote insertion transform at the end, and schedule the
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   166
    transform to run immediately.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   167
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   168
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   169
    default_priority = 520
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   170
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   171
    def apply(self):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   172
        doc = self.document
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   173
        i = len(doc) - 1
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   174
        refsect = copyright = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   175
        while i >= 0 and isinstance(doc[i], nodes.section):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   176
            title_words = doc[i][0].astext().lower().split()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   177
            if 'references' in title_words:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   178
                refsect = doc[i]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   179
                break
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   180
            elif 'copyright' in title_words:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   181
                copyright = i
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   182
            i -= 1
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   183
        if not refsect:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   184
            refsect = nodes.section()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   185
            refsect += nodes.title('', 'References')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   186
            doc.set_id(refsect)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   187
            if copyright:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   188
                # Put the new "References" section before "Copyright":
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   189
                doc.insert(copyright, refsect)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   190
            else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   191
                # Put the new "References" section at end of doc:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   192
                doc.append(refsect)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   193
        pending = nodes.pending(references.TargetNotes)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   194
        refsect.append(pending)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   195
        self.document.note_pending(pending, 0)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   196
        pending = nodes.pending(misc.CallBack,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   197
                                details={'callback': self.cleanup_callback})
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   198
        refsect.append(pending)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   199
        self.document.note_pending(pending, 1)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   200
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   201
    def cleanup_callback(self, pending):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   202
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   203
        Remove an empty "References" section.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   204
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   205
        Called after the `references.TargetNotes` transform is complete.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   206
        """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   207
        if len(pending.parent) == 2:    # <title> and <pending>
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   208
            pending.parent.parent.remove(pending.parent)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   209
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   210
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   211
class PEPZero(Transform):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   212
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   213
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   214
    Special processing for PEP 0.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   215
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   216
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   217
    default_priority =760
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   218
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   219
    def apply(self):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   220
        visitor = PEPZeroSpecial(self.document)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   221
        self.document.walk(visitor)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   222
        self.startnode.parent.remove(self.startnode)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   223
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   224
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   225
class PEPZeroSpecial(nodes.SparseNodeVisitor):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   226
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   227
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   228
    Perform the special processing needed by PEP 0:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   229
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   230
    - Mask email addresses.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   231
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   232
    - Link PEP numbers in the second column of 4-column tables to the PEPs
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   233
      themselves.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   234
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   235
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   236
    pep_url = Headers.pep_url
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   237
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   238
    def unknown_visit(self, node):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   239
        pass
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   240
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   241
    def visit_reference(self, node):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   242
        node.replace_self(mask_email(node))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   243
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   244
    def visit_field_list(self, node):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   245
        if 'rfc2822' in node['classes']:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   246
            raise nodes.SkipNode
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   247
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   248
    def visit_tgroup(self, node):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   249
        self.pep_table = node['cols'] == 4
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   250
        self.entry = 0
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   251
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   252
    def visit_colspec(self, node):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   253
        self.entry += 1
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   254
        if self.pep_table and self.entry == 2:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   255
            node['classes'].append('num')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   256
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   257
    def visit_row(self, node):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   258
        self.entry = 0
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   259
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   260
    def visit_entry(self, node):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   261
        self.entry += 1
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   262
        if self.pep_table and self.entry == 2 and len(node) == 1:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   263
            node['classes'].append('num')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   264
            p = node[0]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   265
            if isinstance(p, nodes.paragraph) and len(p) == 1:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   266
                text = p.astext()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   267
                try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   268
                    pep = int(text)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   269
                    ref = (self.document.settings.pep_base_url
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   270
                           + self.pep_url % pep)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   271
                    p[0] = nodes.reference(text, text, refuri=ref)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   272
                except ValueError:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   273
                    pass
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   274
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   275
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   276
non_masked_addresses = ('peps@python.org',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   277
                        'python-list@python.org',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   278
                        'python-dev@python.org')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   279
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   280
def mask_email(ref, pepno=None):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   281
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   282
    Mask the email address in `ref` and return a replacement node.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   283
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   284
    `ref` is returned unchanged if it contains no email address.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   285
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   286
    For email addresses such as "user@host", mask the address as "user at
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   287
    host" (text) to thwart simple email address harvesters (except for those
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   288
    listed in `non_masked_addresses`).  If a PEP number (`pepno`) is given,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   289
    return a reference including a default email subject.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   290
    """
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   291
    if ref.hasattr('refuri') and ref['refuri'].startswith('mailto:'):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   292
        if ref['refuri'][8:] in non_masked_addresses:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   293
            replacement = ref[0]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   294
        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   295
            replacement_text = ref.astext().replace('@', '&#32;&#97;t&#32;')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   296
            replacement = nodes.raw('', replacement_text, format='html')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   297
        if pepno is None:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   298
            return replacement
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   299
        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   300
            ref['refuri'] += '?subject=PEP%%20%s' % pepno
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   301
            ref[:] = [replacement]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   302
            return ref
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   303
    else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   304
        return ref