This file is indexed.

/usr/share/pyshared/nisext/py3builder.py is in python-nibabel 1.2.2-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
""" distutils utilities for porting to python 3 within 2-compatible tree """

from __future__ import with_statement

import sys
import re

try:
    from distutils.command.build_py import build_py_2to3
except ImportError:
    # 2.x - no parsing of code
    from distutils.command.build_py import build_py
else: # Python 3
    # Command to also apply 2to3 to doctests
    from distutils import log
    class build_py(build_py_2to3):
        def run_2to3(self, files):
            # Add doctest parsing; this stuff copied from distutils.utils in
            # python 3.2 source
            if not files:
                return
            fixer_names, options, explicit = (self.fixer_names,
                                              self.options,
                                              self.explicit)
            # Make this class local, to delay import of 2to3
            from lib2to3.refactor import RefactoringTool, get_fixers_from_package
            class DistutilsRefactoringTool(RefactoringTool):
                def log_error(self, msg, *args, **kw):
                    log.error(msg, *args)

                def log_message(self, msg, *args):
                    log.info(msg, *args)

                def log_debug(self, msg, *args):
                    log.debug(msg, *args)

            if fixer_names is None:
                fixer_names = get_fixers_from_package('lib2to3.fixes')
            r = DistutilsRefactoringTool(fixer_names, options=options)
            r.refactor(files, write=True)
            # Then doctests
            r.refactor(files, write=True, doctests_only=True)
            # Then custom doctests markup
            doctest_markup_files(files)


def doctest_markup_files(fnames):
    """ Process simple doctest comment markup on sequence of filenames

    Parameters
    ----------
    fnames : seq
        sequence of filenames

    Returns
    -------
    None
    """
    for fname in fnames:
        with open(fname, 'rt') as fobj:
            res = list(fobj)
        out, errs = doctest_markup(res)
        for err_tuple in errs:
            print('Marked line %s unchanged because "%s"' % err_tuple)
        with open(fname, 'wt') as fobj:
            fobj.write(''.join(out))


MARK_COMMENT = re.compile('(\s*>>>\s+)(.*?)(\s*#23dt\s+)(.*?\s*)$', re.DOTALL)
PLACE_LINE_EXPRS = re.compile('\s*([\w+\- ]*):\s*(.*)$')
INDENT_SPLITTER = re.compile('(\s*)(.*?)(\s*)$', re.DOTALL)

def doctest_markup(in_lines):
    """ Process doctest comment markup on sequence of strings

    The algorithm looks for lines that start with optional whitespace followed
    by ``>>>`` and ending with a comment starting with ``#23dt``.  The stuff
    after the ``#23dt`` marker is the *markup* and gives instructions for
    modifying the corresponding line or some other line.

    The *markup* is of form <place-expr> : <line-expr>.  Let's say the output
    lines are in a variable ``out_lines``.

    * <place-expr> is an expression giving a line number.  In this expression,
      the two variables defined are ``here`` (giving the current line number),
      and ``next == here+1``.  Let's call the result of <place-expr> ``place``.
      If <place-expr> is empty (only whitespace before the colon) then ``place
      == here``. The result of <line-expr> will replace ``lines[place]``.
    * <line-expr> is a special value (see below) or a python3 expression
      returning a processed value, where ``line`` contains the line referred to
      by line number ``place``, and ``lines`` is a list of all lines.  If
      ``place != here``, then ``line == lines[place]``.  If ``place == here``
      then ``line`` will be the source line, minus the comment and markup.

    A <line-expr> beginning with "replace(" we take to be short for
    "line.replace(".

    Special values; if <line-expr> ==:

    * 'bytes': make all the strings in the selected line be byte strings. This
      algormithm uses the ``ast`` module, so the text in which it works must be
      valid python 3 syntax.
    * 'BytesIO': shorthand for ``replace('StringIO', 'BytesIO')``

    There is also a special non-doctest comment markup - '#23dt skip rest'.  If
    we find that comment (with whitespace before or after) as a line in the
    file, we just pass the rest of the file unchanged.  This is a hack to stop
    23dt processing its own tests.

    Parameters
    ----------
    in_lines : sequence of str

    Returns
    -------
    out_lines : sequence of str
        lines with processing applied
    error_tuples : sequence of (str, str)
        sequence of 2 element tuples, where the first entry in the tuple is one
        line that generated an error during processing, and the second is the
        explanatory message for the error.  These lines remain unchanged in
        `out_lines`.

    Examples
    --------
    The next three lines all do the same thing:

    >> a = '1234567890' #23dt here: line.replace("'12", "b'12")
    >> a = '1234567890' #23dt here: replace("'12", "b'12")
    >> a = '1234567890' #23dt here: bytes

    and that is to result in the part before the comment changing to:

    >> a = b'1234567890'

    The part after the comment (including markup) stays the same.

    You might want to process the line after the comment - such as test output.
    The next test replaces "'a string'" with "b'a string'"

    >> 'a string'.encode('ascii') #23dt next: bytes
    'a string'

    This might work too, to do the same thing:

    >> 'a string'.encode('ascii') #23dt here+1: bytes
    'a string'
    """
    out_lines = list(in_lines)[:]
    err_tuples = []
    for pos, this in enumerate(out_lines):
        # Check for 'leave the rest' markup
        if this.strip() == '#23dt skip rest':
            break
        # Check for docest line with markup
        mark_match = MARK_COMMENT.search(this)
        if mark_match is None:
            continue
        docbits, marked_line, marker, markup = mark_match.groups()
        place_line_match = PLACE_LINE_EXPRS.match(markup)
        if place_line_match is None:
            msg = ('Found markup "%s" in line "%s" but wrong syntax' %
                   (markup, this))
            err_tuples.append((this, msg))
            continue
        place_expr, line_expr = place_line_match.groups()
        exec_globals = {'here': pos, 'next': pos+1}
        if place_expr.strip() == '':
            place = pos
        else:
            try:
                place = eval(place_expr, exec_globals)
            except:
                msg = ('Error finding place with "%s" in line "%s"' %
                    (place_expr, this))
                err_tuples.append((this, msg))
                continue
        # Prevent processing operating on 23dt comment part of line
        if place == pos:
            line = marked_line
        else:
            line = out_lines[place]
        # Shorthand
        if line_expr == 'bytes':
            # Any strings on the given line are byte strings
            pre, mid, post = INDENT_SPLITTER.match(line).groups()
            try:
                res = byter(mid)
            except:
                err = sys.exc_info()[1]
                msg = ('Error "%s" parsing "%s"' % (err, err))
                err_tuples.append((this, msg))
                continue
            res = pre + res + post
        else:
            exec_globals.update({'line': line, 'lines': out_lines})
            # If line_expr starts with 'replace', implies "line.replace"
            if line_expr.startswith('replace('):
                line_expr = 'line.' + line_expr
            elif line_expr == 'BytesIO':
                line_expr = "line.replace('StringIO', 'BytesIO')"
            try:
                res = eval(line_expr, exec_globals)
            except:
                err = sys.exc_info()[1]
                msg = ('Error "%s" working on "%s" at line %d with "%s"' %
                       (err, line, place, line_expr))
                err_tuples.append((this, msg))
                continue
        # Put back comment if removed
        if place == pos:
            res = docbits + res + marker + markup
        if res != line:
            out_lines[place] = res
    return out_lines, err_tuples


def byter(src):
    """ Convert strings in `src` to byte string literals

    Parameters
    ----------
    src : str
        source string.  Must be valid python 3 source

    Returns
    -------
    p_src : str
        string with ``str`` literals replace by ``byte`` literals
    """
    import ast
    from . import codegen
    class RewriteStr(ast.NodeTransformer):
        def visit_Str(self, node):
            return ast.Bytes(node.s.encode('ascii'))
    tree = ast.parse(src)
    tree = RewriteStr().visit(tree)
    return codegen.to_source(tree)