~anitanayak/charms/trusty/ibm-mq/ibm-mq-trusty

« back to all changes in this revision

Viewing changes to .tox/py35/lib/python3.5/site-packages/py/_code/code.py

  • Committer: Anita Nayak
  • Date: 2016-10-24 07:10:08 UTC
  • Revision ID: anitanayak@in.ibm.com-20161024071008-tqk3cefak6nc1c69
checking in after fixing lint errors

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import py
 
2
import sys
 
3
from inspect import CO_VARARGS, CO_VARKEYWORDS
 
4
 
 
5
builtin_repr = repr
 
6
 
 
7
reprlib = py.builtin._tryimport('repr', 'reprlib')
 
8
 
 
9
if sys.version_info[0] >= 3:
 
10
    from traceback import format_exception_only
 
11
else:
 
12
    from py._code._py2traceback import format_exception_only
 
13
 
 
14
class Code(object):
 
15
    """ wrapper around Python code objects """
 
16
    def __init__(self, rawcode):
 
17
        if not hasattr(rawcode, "co_filename"):
 
18
            rawcode = py.code.getrawcode(rawcode)
 
19
        try:
 
20
            self.filename = rawcode.co_filename
 
21
            self.firstlineno = rawcode.co_firstlineno - 1
 
22
            self.name = rawcode.co_name
 
23
        except AttributeError:
 
24
            raise TypeError("not a code object: %r" %(rawcode,))
 
25
        self.raw = rawcode
 
26
 
 
27
    def __eq__(self, other):
 
28
        return self.raw == other.raw
 
29
 
 
30
    def __ne__(self, other):
 
31
        return not self == other
 
32
 
 
33
    @property
 
34
    def path(self):
 
35
        """ return a path object pointing to source code (note that it
 
36
        might not point to an actually existing file). """
 
37
        p = py.path.local(self.raw.co_filename)
 
38
        # maybe don't try this checking
 
39
        if not p.check():
 
40
            # XXX maybe try harder like the weird logic
 
41
            # in the standard lib [linecache.updatecache] does?
 
42
            p = self.raw.co_filename
 
43
        return p
 
44
 
 
45
    @property
 
46
    def fullsource(self):
 
47
        """ return a py.code.Source object for the full source file of the code
 
48
        """
 
49
        from py._code import source
 
50
        full, _ = source.findsource(self.raw)
 
51
        return full
 
52
 
 
53
    def source(self):
 
54
        """ return a py.code.Source object for the code object's source only
 
55
        """
 
56
        # return source only for that part of code
 
57
        return py.code.Source(self.raw)
 
58
 
 
59
    def getargs(self, var=False):
 
60
        """ return a tuple with the argument names for the code object
 
61
 
 
62
            if 'var' is set True also return the names of the variable and
 
63
            keyword arguments when present
 
64
        """
 
65
        # handfull shortcut for getting args
 
66
        raw = self.raw
 
67
        argcount = raw.co_argcount
 
68
        if var:
 
69
            argcount += raw.co_flags & CO_VARARGS
 
70
            argcount += raw.co_flags & CO_VARKEYWORDS
 
71
        return raw.co_varnames[:argcount]
 
72
 
 
73
class Frame(object):
 
74
    """Wrapper around a Python frame holding f_locals and f_globals
 
75
    in which expressions can be evaluated."""
 
76
 
 
77
    def __init__(self, frame):
 
78
        self.lineno = frame.f_lineno - 1
 
79
        self.f_globals = frame.f_globals
 
80
        self.f_locals = frame.f_locals
 
81
        self.raw = frame
 
82
        self.code = py.code.Code(frame.f_code)
 
83
 
 
84
    @property
 
85
    def statement(self):
 
86
        """ statement this frame is at """
 
87
        if self.code.fullsource is None:
 
88
            return py.code.Source("")
 
89
        return self.code.fullsource.getstatement(self.lineno)
 
90
 
 
91
    def eval(self, code, **vars):
 
92
        """ evaluate 'code' in the frame
 
93
 
 
94
            'vars' are optional additional local variables
 
95
 
 
96
            returns the result of the evaluation
 
97
        """
 
98
        f_locals = self.f_locals.copy()
 
99
        f_locals.update(vars)
 
100
        return eval(code, self.f_globals, f_locals)
 
101
 
 
102
    def exec_(self, code, **vars):
 
103
        """ exec 'code' in the frame
 
104
 
 
105
            'vars' are optiona; additional local variables
 
106
        """
 
107
        f_locals = self.f_locals.copy()
 
108
        f_locals.update(vars)
 
109
        py.builtin.exec_(code, self.f_globals, f_locals )
 
110
 
 
111
    def repr(self, object):
 
112
        """ return a 'safe' (non-recursive, one-line) string repr for 'object'
 
113
        """
 
114
        return py.io.saferepr(object)
 
115
 
 
116
    def is_true(self, object):
 
117
        return object
 
118
 
 
119
    def getargs(self, var=False):
 
120
        """ return a list of tuples (name, value) for all arguments
 
121
 
 
122
            if 'var' is set True also include the variable and keyword
 
123
            arguments when present
 
124
        """
 
125
        retval = []
 
126
        for arg in self.code.getargs(var):
 
127
            try:
 
128
                retval.append((arg, self.f_locals[arg]))
 
129
            except KeyError:
 
130
                pass     # this can occur when using Psyco
 
131
        return retval
 
132
 
 
133
class TracebackEntry(object):
 
134
    """ a single entry in a traceback """
 
135
 
 
136
    _repr_style = None
 
137
    exprinfo = None
 
138
 
 
139
    def __init__(self, rawentry):
 
140
        self._rawentry = rawentry
 
141
        self.lineno = rawentry.tb_lineno - 1
 
142
 
 
143
    def set_repr_style(self, mode):
 
144
        assert mode in ("short", "long")
 
145
        self._repr_style = mode
 
146
 
 
147
    @property
 
148
    def frame(self):
 
149
        return py.code.Frame(self._rawentry.tb_frame)
 
150
 
 
151
    @property
 
152
    def relline(self):
 
153
        return self.lineno - self.frame.code.firstlineno
 
154
 
 
155
    def __repr__(self):
 
156
        return "<TracebackEntry %s:%d>" %(self.frame.code.path, self.lineno+1)
 
157
 
 
158
    @property
 
159
    def statement(self):
 
160
        """ py.code.Source object for the current statement """
 
161
        source = self.frame.code.fullsource
 
162
        return source.getstatement(self.lineno)
 
163
 
 
164
    @property
 
165
    def path(self):
 
166
        """ path to the source code """
 
167
        return self.frame.code.path
 
168
 
 
169
    def getlocals(self):
 
170
        return self.frame.f_locals
 
171
    locals = property(getlocals, None, None, "locals of underlaying frame")
 
172
 
 
173
    def reinterpret(self):
 
174
        """Reinterpret the failing statement and returns a detailed information
 
175
           about what operations are performed."""
 
176
        if self.exprinfo is None:
 
177
            source = str(self.statement).strip()
 
178
            x = py.code._reinterpret(source, self.frame, should_fail=True)
 
179
            if not isinstance(x, str):
 
180
                raise TypeError("interpret returned non-string %r" % (x,))
 
181
            self.exprinfo = x
 
182
        return self.exprinfo
 
183
 
 
184
    def getfirstlinesource(self):
 
185
        # on Jython this firstlineno can be -1 apparently
 
186
        return max(self.frame.code.firstlineno, 0)
 
187
 
 
188
    def getsource(self, astcache=None):
 
189
        """ return failing source code. """
 
190
        # we use the passed in astcache to not reparse asttrees
 
191
        # within exception info printing
 
192
        from py._code.source import getstatementrange_ast
 
193
        source = self.frame.code.fullsource
 
194
        if source is None:
 
195
            return None
 
196
        key = astnode = None
 
197
        if astcache is not None:
 
198
            key = self.frame.code.path
 
199
            if key is not None:
 
200
                astnode = astcache.get(key, None)
 
201
        start = self.getfirstlinesource()
 
202
        try:
 
203
            astnode, _, end = getstatementrange_ast(self.lineno, source,
 
204
                                                    astnode=astnode)
 
205
        except SyntaxError:
 
206
            end = self.lineno + 1
 
207
        else:
 
208
            if key is not None:
 
209
                astcache[key] = astnode
 
210
        return source[start:end]
 
211
 
 
212
    source = property(getsource)
 
213
 
 
214
    def ishidden(self):
 
215
        """ return True if the current frame has a var __tracebackhide__
 
216
            resolving to True
 
217
 
 
218
            mostly for internal use
 
219
        """
 
220
        try:
 
221
            return self.frame.f_locals['__tracebackhide__']
 
222
        except KeyError:
 
223
            try:
 
224
                return self.frame.f_globals['__tracebackhide__']
 
225
            except KeyError:
 
226
                return False
 
227
 
 
228
    def __str__(self):
 
229
        try:
 
230
            fn = str(self.path)
 
231
        except py.error.Error:
 
232
            fn = '???'
 
233
        name = self.frame.code.name
 
234
        try:
 
235
            line = str(self.statement).lstrip()
 
236
        except KeyboardInterrupt:
 
237
            raise
 
238
        except:
 
239
            line = "???"
 
240
        return "  File %r:%d in %s\n  %s\n" %(fn, self.lineno+1, name, line)
 
241
 
 
242
    def name(self):
 
243
        return self.frame.code.raw.co_name
 
244
    name = property(name, None, None, "co_name of underlaying code")
 
245
 
 
246
class Traceback(list):
 
247
    """ Traceback objects encapsulate and offer higher level
 
248
        access to Traceback entries.
 
249
    """
 
250
    Entry = TracebackEntry
 
251
    def __init__(self, tb):
 
252
        """ initialize from given python traceback object. """
 
253
        if hasattr(tb, 'tb_next'):
 
254
            def f(cur):
 
255
                while cur is not None:
 
256
                    yield self.Entry(cur)
 
257
                    cur = cur.tb_next
 
258
            list.__init__(self, f(tb))
 
259
        else:
 
260
            list.__init__(self, tb)
 
261
 
 
262
    def cut(self, path=None, lineno=None, firstlineno=None, excludepath=None):
 
263
        """ return a Traceback instance wrapping part of this Traceback
 
264
 
 
265
            by provding any combination of path, lineno and firstlineno, the
 
266
            first frame to start the to-be-returned traceback is determined
 
267
 
 
268
            this allows cutting the first part of a Traceback instance e.g.
 
269
            for formatting reasons (removing some uninteresting bits that deal
 
270
            with handling of the exception/traceback)
 
271
        """
 
272
        for x in self:
 
273
            code = x.frame.code
 
274
            codepath = code.path
 
275
            if ((path is None or codepath == path) and
 
276
                (excludepath is None or not hasattr(codepath, 'relto') or
 
277
                 not codepath.relto(excludepath)) and
 
278
                (lineno is None or x.lineno == lineno) and
 
279
                (firstlineno is None or x.frame.code.firstlineno == firstlineno)):
 
280
                return Traceback(x._rawentry)
 
281
        return self
 
282
 
 
283
    def __getitem__(self, key):
 
284
        val = super(Traceback, self).__getitem__(key)
 
285
        if isinstance(key, type(slice(0))):
 
286
            val = self.__class__(val)
 
287
        return val
 
288
 
 
289
    def filter(self, fn=lambda x: not x.ishidden()):
 
290
        """ return a Traceback instance with certain items removed
 
291
 
 
292
            fn is a function that gets a single argument, a TracebackItem
 
293
            instance, and should return True when the item should be added
 
294
            to the Traceback, False when not
 
295
 
 
296
            by default this removes all the TracebackItems which are hidden
 
297
            (see ishidden() above)
 
298
        """
 
299
        return Traceback(filter(fn, self))
 
300
 
 
301
    def getcrashentry(self):
 
302
        """ return last non-hidden traceback entry that lead
 
303
        to the exception of a traceback.
 
304
        """
 
305
        for i in range(-1, -len(self)-1, -1):
 
306
            entry = self[i]
 
307
            if not entry.ishidden():
 
308
                return entry
 
309
        return self[-1]
 
310
 
 
311
    def recursionindex(self):
 
312
        """ return the index of the frame/TracebackItem where recursion
 
313
            originates if appropriate, None if no recursion occurred
 
314
        """
 
315
        cache = {}
 
316
        for i, entry in enumerate(self):
 
317
            # id for the code.raw is needed to work around
 
318
            # the strange metaprogramming in the decorator lib from pypi
 
319
            # which generates code objects that have hash/value equality
 
320
            #XXX needs a test
 
321
            key = entry.frame.code.path, id(entry.frame.code.raw), entry.lineno
 
322
            #print "checking for recursion at", key
 
323
            l = cache.setdefault(key, [])
 
324
            if l:
 
325
                f = entry.frame
 
326
                loc = f.f_locals
 
327
                for otherloc in l:
 
328
                    if f.is_true(f.eval(co_equal,
 
329
                        __recursioncache_locals_1=loc,
 
330
                        __recursioncache_locals_2=otherloc)):
 
331
                        return i
 
332
            l.append(entry.frame.f_locals)
 
333
        return None
 
334
 
 
335
co_equal = compile('__recursioncache_locals_1 == __recursioncache_locals_2',
 
336
                   '?', 'eval')
 
337
 
 
338
class ExceptionInfo(object):
 
339
    """ wraps sys.exc_info() objects and offers
 
340
        help for navigating the traceback.
 
341
    """
 
342
    _striptext = ''
 
343
    def __init__(self, tup=None, exprinfo=None):
 
344
        if tup is None:
 
345
            tup = sys.exc_info()
 
346
            if exprinfo is None and isinstance(tup[1], AssertionError):
 
347
                exprinfo = getattr(tup[1], 'msg', None)
 
348
                if exprinfo is None:
 
349
                    exprinfo = str(tup[1])
 
350
                if exprinfo and exprinfo.startswith('assert '):
 
351
                    self._striptext = 'AssertionError: '
 
352
        self._excinfo = tup
 
353
        #: the exception class
 
354
        self.type = tup[0]
 
355
        #: the exception instance
 
356
        self.value = tup[1]
 
357
        #: the exception raw traceback
 
358
        self.tb = tup[2]
 
359
        #: the exception type name
 
360
        self.typename = self.type.__name__
 
361
        #: the exception traceback (py.code.Traceback instance)
 
362
        self.traceback = py.code.Traceback(self.tb)
 
363
 
 
364
    def __repr__(self):
 
365
        return "<ExceptionInfo %s tblen=%d>" % (self.typename, len(self.traceback))
 
366
 
 
367
    def exconly(self, tryshort=False):
 
368
        """ return the exception as a string
 
369
 
 
370
            when 'tryshort' resolves to True, and the exception is a
 
371
            py.code._AssertionError, only the actual exception part of
 
372
            the exception representation is returned (so 'AssertionError: ' is
 
373
            removed from the beginning)
 
374
        """
 
375
        lines = format_exception_only(self.type, self.value)
 
376
        text = ''.join(lines)
 
377
        text = text.rstrip()
 
378
        if tryshort:
 
379
            if text.startswith(self._striptext):
 
380
                text = text[len(self._striptext):]
 
381
        return text
 
382
 
 
383
    def errisinstance(self, exc):
 
384
        """ return True if the exception is an instance of exc """
 
385
        return isinstance(self.value, exc)
 
386
 
 
387
    def _getreprcrash(self):
 
388
        exconly = self.exconly(tryshort=True)
 
389
        entry = self.traceback.getcrashentry()
 
390
        path, lineno = entry.frame.code.raw.co_filename, entry.lineno
 
391
        return ReprFileLocation(path, lineno+1, exconly)
 
392
 
 
393
    def getrepr(self, showlocals=False, style="long",
 
394
            abspath=False, tbfilter=True, funcargs=False):
 
395
        """ return str()able representation of this exception info.
 
396
            showlocals: show locals per traceback entry
 
397
            style: long|short|no|native traceback style
 
398
            tbfilter: hide entries (where __tracebackhide__ is true)
 
399
 
 
400
            in case of style==native, tbfilter and showlocals is ignored.
 
401
        """
 
402
        if style == 'native':
 
403
            return ReprExceptionInfo(ReprTracebackNative(
 
404
                py.std.traceback.format_exception(
 
405
                    self.type,
 
406
                    self.value,
 
407
                    self.traceback[0]._rawentry,
 
408
                )), self._getreprcrash())
 
409
 
 
410
        fmt = FormattedExcinfo(showlocals=showlocals, style=style,
 
411
            abspath=abspath, tbfilter=tbfilter, funcargs=funcargs)
 
412
        return fmt.repr_excinfo(self)
 
413
 
 
414
    def __str__(self):
 
415
        entry = self.traceback[-1]
 
416
        loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly())
 
417
        return str(loc)
 
418
 
 
419
    def __unicode__(self):
 
420
        entry = self.traceback[-1]
 
421
        loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly())
 
422
        return unicode(loc)
 
423
 
 
424
 
 
425
class FormattedExcinfo(object):
 
426
    """ presenting information about failing Functions and Generators. """
 
427
    # for traceback entries
 
428
    flow_marker = ">"
 
429
    fail_marker = "E"
 
430
 
 
431
    def __init__(self, showlocals=False, style="long", abspath=True, tbfilter=True, funcargs=False):
 
432
        self.showlocals = showlocals
 
433
        self.style = style
 
434
        self.tbfilter = tbfilter
 
435
        self.funcargs = funcargs
 
436
        self.abspath = abspath
 
437
        self.astcache = {}
 
438
 
 
439
    def _getindent(self, source):
 
440
        # figure out indent for given source
 
441
        try:
 
442
            s = str(source.getstatement(len(source)-1))
 
443
        except KeyboardInterrupt:
 
444
            raise
 
445
        except:
 
446
            try:
 
447
                s = str(source[-1])
 
448
            except KeyboardInterrupt:
 
449
                raise
 
450
            except:
 
451
                return 0
 
452
        return 4 + (len(s) - len(s.lstrip()))
 
453
 
 
454
    def _getentrysource(self, entry):
 
455
        source = entry.getsource(self.astcache)
 
456
        if source is not None:
 
457
            source = source.deindent()
 
458
        return source
 
459
 
 
460
    def _saferepr(self, obj):
 
461
        return py.io.saferepr(obj)
 
462
 
 
463
    def repr_args(self, entry):
 
464
        if self.funcargs:
 
465
            args = []
 
466
            for argname, argvalue in entry.frame.getargs(var=True):
 
467
                args.append((argname, self._saferepr(argvalue)))
 
468
            return ReprFuncArgs(args)
 
469
 
 
470
    def get_source(self, source, line_index=-1, excinfo=None, short=False):
 
471
        """ return formatted and marked up source lines. """
 
472
        lines = []
 
473
        if source is None or line_index >= len(source.lines):
 
474
            source = py.code.Source("???")
 
475
            line_index = 0
 
476
        if line_index < 0:
 
477
            line_index += len(source)
 
478
        space_prefix = "    "
 
479
        if short:
 
480
            lines.append(space_prefix + source.lines[line_index].strip())
 
481
        else:
 
482
            for line in source.lines[:line_index]:
 
483
                lines.append(space_prefix + line)
 
484
            lines.append(self.flow_marker + "   " + source.lines[line_index])
 
485
            for line in source.lines[line_index+1:]:
 
486
                lines.append(space_prefix + line)
 
487
        if excinfo is not None:
 
488
            indent = 4 if short else self._getindent(source)
 
489
            lines.extend(self.get_exconly(excinfo, indent=indent, markall=True))
 
490
        return lines
 
491
 
 
492
    def get_exconly(self, excinfo, indent=4, markall=False):
 
493
        lines = []
 
494
        indent = " " * indent
 
495
        # get the real exception information out
 
496
        exlines = excinfo.exconly(tryshort=True).split('\n')
 
497
        failindent = self.fail_marker + indent[1:]
 
498
        for line in exlines:
 
499
            lines.append(failindent + line)
 
500
            if not markall:
 
501
                failindent = indent
 
502
        return lines
 
503
 
 
504
    def repr_locals(self, locals):
 
505
        if self.showlocals:
 
506
            lines = []
 
507
            keys = [loc for loc in locals if loc[0] != "@"]
 
508
            keys.sort()
 
509
            for name in keys:
 
510
                value = locals[name]
 
511
                if name == '__builtins__':
 
512
                    lines.append("__builtins__ = <builtins>")
 
513
                else:
 
514
                    # This formatting could all be handled by the
 
515
                    # _repr() function, which is only reprlib.Repr in
 
516
                    # disguise, so is very configurable.
 
517
                    str_repr = self._saferepr(value)
 
518
                    #if len(str_repr) < 70 or not isinstance(value,
 
519
                    #                            (list, tuple, dict)):
 
520
                    lines.append("%-10s = %s" %(name, str_repr))
 
521
                    #else:
 
522
                    #    self._line("%-10s =\\" % (name,))
 
523
                    #    # XXX
 
524
                    #    py.std.pprint.pprint(value, stream=self.excinfowriter)
 
525
            return ReprLocals(lines)
 
526
 
 
527
    def repr_traceback_entry(self, entry, excinfo=None):
 
528
        source = self._getentrysource(entry)
 
529
        if source is None:
 
530
            source = py.code.Source("???")
 
531
            line_index = 0
 
532
        else:
 
533
            # entry.getfirstlinesource() can be -1, should be 0 on jython
 
534
            line_index = entry.lineno - max(entry.getfirstlinesource(), 0)
 
535
 
 
536
        lines = []
 
537
        style = entry._repr_style
 
538
        if style is None:
 
539
            style = self.style
 
540
        if style in ("short", "long"):
 
541
            short = style == "short"
 
542
            reprargs = self.repr_args(entry) if not short else None
 
543
            s = self.get_source(source, line_index, excinfo, short=short)
 
544
            lines.extend(s)
 
545
            if short:
 
546
                message = "in %s" %(entry.name)
 
547
            else:
 
548
                message = excinfo and excinfo.typename or ""
 
549
            path = self._makepath(entry.path)
 
550
            filelocrepr = ReprFileLocation(path, entry.lineno+1, message)
 
551
            localsrepr = None
 
552
            if not short:
 
553
                localsrepr =  self.repr_locals(entry.locals)
 
554
            return ReprEntry(lines, reprargs, localsrepr, filelocrepr, style)
 
555
        if excinfo:
 
556
            lines.extend(self.get_exconly(excinfo, indent=4))
 
557
        return ReprEntry(lines, None, None, None, style)
 
558
 
 
559
    def _makepath(self, path):
 
560
        if not self.abspath:
 
561
            try:
 
562
                np = py.path.local().bestrelpath(path)
 
563
            except OSError:
 
564
                return path
 
565
            if len(np) < len(str(path)):
 
566
                path = np
 
567
        return path
 
568
 
 
569
    def repr_traceback(self, excinfo):
 
570
        traceback = excinfo.traceback
 
571
        if self.tbfilter:
 
572
            traceback = traceback.filter()
 
573
        recursionindex = None
 
574
        if excinfo.errisinstance(RuntimeError):
 
575
            if "maximum recursion depth exceeded" in str(excinfo.value):
 
576
                recursionindex = traceback.recursionindex()
 
577
        last = traceback[-1]
 
578
        entries = []
 
579
        extraline = None
 
580
        for index, entry in enumerate(traceback):
 
581
            einfo = (last == entry) and excinfo or None
 
582
            reprentry = self.repr_traceback_entry(entry, einfo)
 
583
            entries.append(reprentry)
 
584
            if index == recursionindex:
 
585
                extraline = "!!! Recursion detected (same locals & position)"
 
586
                break
 
587
        return ReprTraceback(entries, extraline, style=self.style)
 
588
 
 
589
    def repr_excinfo(self, excinfo):
 
590
        reprtraceback = self.repr_traceback(excinfo)
 
591
        reprcrash = excinfo._getreprcrash()
 
592
        return ReprExceptionInfo(reprtraceback, reprcrash)
 
593
 
 
594
class TerminalRepr:
 
595
    def __str__(self):
 
596
        s = self.__unicode__()
 
597
        if sys.version_info[0] < 3:
 
598
            s = s.encode('utf-8')
 
599
        return s
 
600
 
 
601
    def __unicode__(self):
 
602
        # FYI this is called from pytest-xdist's serialization of exception
 
603
        # information.
 
604
        io = py.io.TextIO()
 
605
        tw = py.io.TerminalWriter(file=io)
 
606
        self.toterminal(tw)
 
607
        return io.getvalue().strip()
 
608
 
 
609
    def __repr__(self):
 
610
        return "<%s instance at %0x>" %(self.__class__, id(self))
 
611
 
 
612
 
 
613
class ReprExceptionInfo(TerminalRepr):
 
614
    def __init__(self, reprtraceback, reprcrash):
 
615
        self.reprtraceback = reprtraceback
 
616
        self.reprcrash = reprcrash
 
617
        self.sections = []
 
618
 
 
619
    def addsection(self, name, content, sep="-"):
 
620
        self.sections.append((name, content, sep))
 
621
 
 
622
    def toterminal(self, tw):
 
623
        self.reprtraceback.toterminal(tw)
 
624
        for name, content, sep in self.sections:
 
625
            tw.sep(sep, name)
 
626
            tw.line(content)
 
627
 
 
628
class ReprTraceback(TerminalRepr):
 
629
    entrysep = "_ "
 
630
 
 
631
    def __init__(self, reprentries, extraline, style):
 
632
        self.reprentries = reprentries
 
633
        self.extraline = extraline
 
634
        self.style = style
 
635
 
 
636
    def toterminal(self, tw):
 
637
        # the entries might have different styles
 
638
        last_style = None
 
639
        for i, entry in enumerate(self.reprentries):
 
640
            if entry.style == "long":
 
641
                tw.line("")
 
642
            entry.toterminal(tw)
 
643
            if i < len(self.reprentries) - 1:
 
644
                next_entry = self.reprentries[i+1]
 
645
                if entry.style == "long" or \
 
646
                   entry.style == "short" and next_entry.style == "long":
 
647
                    tw.sep(self.entrysep)
 
648
 
 
649
        if self.extraline:
 
650
            tw.line(self.extraline)
 
651
 
 
652
class ReprTracebackNative(ReprTraceback):
 
653
    def __init__(self, tblines):
 
654
        self.style = "native"
 
655
        self.reprentries = [ReprEntryNative(tblines)]
 
656
        self.extraline = None
 
657
 
 
658
class ReprEntryNative(TerminalRepr):
 
659
    style = "native"
 
660
 
 
661
    def __init__(self, tblines):
 
662
        self.lines = tblines
 
663
 
 
664
    def toterminal(self, tw):
 
665
        tw.write("".join(self.lines))
 
666
 
 
667
class ReprEntry(TerminalRepr):
 
668
    localssep = "_ "
 
669
 
 
670
    def __init__(self, lines, reprfuncargs, reprlocals, filelocrepr, style):
 
671
        self.lines = lines
 
672
        self.reprfuncargs = reprfuncargs
 
673
        self.reprlocals = reprlocals
 
674
        self.reprfileloc = filelocrepr
 
675
        self.style = style
 
676
 
 
677
    def toterminal(self, tw):
 
678
        if self.style == "short":
 
679
            self.reprfileloc.toterminal(tw)
 
680
            for line in self.lines:
 
681
                red = line.startswith("E   ")
 
682
                tw.line(line, bold=True, red=red)
 
683
            #tw.line("")
 
684
            return
 
685
        if self.reprfuncargs:
 
686
            self.reprfuncargs.toterminal(tw)
 
687
        for line in self.lines:
 
688
            red = line.startswith("E   ")
 
689
            tw.line(line, bold=True, red=red)
 
690
        if self.reprlocals:
 
691
            #tw.sep(self.localssep, "Locals")
 
692
            tw.line("")
 
693
            self.reprlocals.toterminal(tw)
 
694
        if self.reprfileloc:
 
695
            if self.lines:
 
696
                tw.line("")
 
697
            self.reprfileloc.toterminal(tw)
 
698
 
 
699
    def __str__(self):
 
700
        return "%s\n%s\n%s" % ("\n".join(self.lines),
 
701
                               self.reprlocals,
 
702
                               self.reprfileloc)
 
703
 
 
704
class ReprFileLocation(TerminalRepr):
 
705
    def __init__(self, path, lineno, message):
 
706
        self.path = str(path)
 
707
        self.lineno = lineno
 
708
        self.message = message
 
709
 
 
710
    def toterminal(self, tw):
 
711
        # filename and lineno output for each entry,
 
712
        # using an output format that most editors unterstand
 
713
        msg = self.message
 
714
        i = msg.find("\n")
 
715
        if i != -1:
 
716
            msg = msg[:i]
 
717
        tw.line("%s:%s: %s" %(self.path, self.lineno, msg))
 
718
 
 
719
class ReprLocals(TerminalRepr):
 
720
    def __init__(self, lines):
 
721
        self.lines = lines
 
722
 
 
723
    def toterminal(self, tw):
 
724
        for line in self.lines:
 
725
            tw.line(line)
 
726
 
 
727
class ReprFuncArgs(TerminalRepr):
 
728
    def __init__(self, args):
 
729
        self.args = args
 
730
 
 
731
    def toterminal(self, tw):
 
732
        if self.args:
 
733
            linesofar = ""
 
734
            for name, value in self.args:
 
735
                ns = "%s = %s" %(name, value)
 
736
                if len(ns) + len(linesofar) + 2 > tw.fullwidth:
 
737
                    if linesofar:
 
738
                        tw.line(linesofar)
 
739
                    linesofar =  ns
 
740
                else:
 
741
                    if linesofar:
 
742
                        linesofar += ", " + ns
 
743
                    else:
 
744
                        linesofar = ns
 
745
            if linesofar:
 
746
                tw.line(linesofar)
 
747
            tw.line("")
 
748
 
 
749
 
 
750
 
 
751
oldbuiltins = {}
 
752
 
 
753
def patch_builtins(assertion=True, compile=True):
 
754
    """ put compile and AssertionError builtins to Python's builtins. """
 
755
    if assertion:
 
756
        from py._code import assertion
 
757
        l = oldbuiltins.setdefault('AssertionError', [])
 
758
        l.append(py.builtin.builtins.AssertionError)
 
759
        py.builtin.builtins.AssertionError = assertion.AssertionError
 
760
    if compile:
 
761
        l = oldbuiltins.setdefault('compile', [])
 
762
        l.append(py.builtin.builtins.compile)
 
763
        py.builtin.builtins.compile = py.code.compile
 
764
 
 
765
def unpatch_builtins(assertion=True, compile=True):
 
766
    """ remove compile and AssertionError builtins from Python builtins. """
 
767
    if assertion:
 
768
        py.builtin.builtins.AssertionError = oldbuiltins['AssertionError'].pop()
 
769
    if compile:
 
770
        py.builtin.builtins.compile = oldbuiltins['compile'].pop()
 
771
 
 
772
def getrawcode(obj, trycall=True):
 
773
    """ return code object for given function. """
 
774
    try:
 
775
        return obj.__code__
 
776
    except AttributeError:
 
777
        obj = getattr(obj, 'im_func', obj)
 
778
        obj = getattr(obj, 'func_code', obj)
 
779
        obj = getattr(obj, 'f_code', obj)
 
780
        obj = getattr(obj, '__code__', obj)
 
781
        if trycall and not hasattr(obj, 'co_firstlineno'):
 
782
            if hasattr(obj, '__call__') and not py.std.inspect.isclass(obj):
 
783
                x = getrawcode(obj.__call__, trycall=False)
 
784
                if hasattr(x, 'co_firstlineno'):
 
785
                    return x
 
786
        return obj
 
787