Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1import py 

2import sys 

3from inspect import CO_VARARGS, CO_VARKEYWORDS, isclass 

4 

5builtin_repr = repr 

6 

7reprlib = py.builtin._tryimport('repr', 'reprlib') 

8 

9if sys.version_info[0] >= 3: 

10 from traceback import format_exception_only 

11else: 

12 from py._code._py2traceback import format_exception_only 

13 

14import traceback 

15 

16 

17class Code(object): 

18 """ wrapper around Python code objects """ 

19 def __init__(self, rawcode): 

20 if not hasattr(rawcode, "co_filename"): 

21 rawcode = py.code.getrawcode(rawcode) 

22 try: 

23 self.filename = rawcode.co_filename 

24 self.firstlineno = rawcode.co_firstlineno - 1 

25 self.name = rawcode.co_name 

26 except AttributeError: 

27 raise TypeError("not a code object: %r" % (rawcode,)) 

28 self.raw = rawcode 

29 

30 def __eq__(self, other): 

31 return self.raw == other.raw 

32 

33 def __ne__(self, other): 

34 return not self == other 

35 

36 @property 

37 def path(self): 

38 """ return a path object pointing to source code (note that it 

39 might not point to an actually existing file). """ 

40 p = py.path.local(self.raw.co_filename) 

41 # maybe don't try this checking 

42 if not p.check(): 

43 # XXX maybe try harder like the weird logic 

44 # in the standard lib [linecache.updatecache] does? 

45 p = self.raw.co_filename 

46 return p 

47 

48 @property 

49 def fullsource(self): 

50 """ return a py.code.Source object for the full source file of the code 

51 """ 

52 from py._code import source 

53 full, _ = source.findsource(self.raw) 

54 return full 

55 

56 def source(self): 

57 """ return a py.code.Source object for the code object's source only 

58 """ 

59 # return source only for that part of code 

60 return py.code.Source(self.raw) 

61 

62 def getargs(self, var=False): 

63 """ return a tuple with the argument names for the code object 

64 

65 if 'var' is set True also return the names of the variable and 

66 keyword arguments when present 

67 """ 

68 # handfull shortcut for getting args 

69 raw = self.raw 

70 argcount = raw.co_argcount 

71 if var: 

72 argcount += raw.co_flags & CO_VARARGS 

73 argcount += raw.co_flags & CO_VARKEYWORDS 

74 return raw.co_varnames[:argcount] 

75 

76class Frame(object): 

77 """Wrapper around a Python frame holding f_locals and f_globals 

78 in which expressions can be evaluated.""" 

79 

80 def __init__(self, frame): 

81 self.lineno = frame.f_lineno - 1 

82 self.f_globals = frame.f_globals 

83 self.f_locals = frame.f_locals 

84 self.raw = frame 

85 self.code = py.code.Code(frame.f_code) 

86 

87 @property 

88 def statement(self): 

89 """ statement this frame is at """ 

90 if self.code.fullsource is None: 

91 return py.code.Source("") 

92 return self.code.fullsource.getstatement(self.lineno) 

93 

94 def eval(self, code, **vars): 

95 """ evaluate 'code' in the frame 

96 

97 'vars' are optional additional local variables 

98 

99 returns the result of the evaluation 

100 """ 

101 f_locals = self.f_locals.copy() 

102 f_locals.update(vars) 

103 return eval(code, self.f_globals, f_locals) 

104 

105 def exec_(self, code, **vars): 

106 """ exec 'code' in the frame 

107 

108 'vars' are optiona; additional local variables 

109 """ 

110 f_locals = self.f_locals.copy() 

111 f_locals.update(vars) 

112 py.builtin.exec_(code, self.f_globals, f_locals) 

113 

114 def repr(self, object): 

115 """ return a 'safe' (non-recursive, one-line) string repr for 'object' 

116 """ 

117 return py.io.saferepr(object) 

118 

119 def is_true(self, object): 

120 return object 

121 

122 def getargs(self, var=False): 

123 """ return a list of tuples (name, value) for all arguments 

124 

125 if 'var' is set True also include the variable and keyword 

126 arguments when present 

127 """ 

128 retval = [] 

129 for arg in self.code.getargs(var): 

130 try: 

131 retval.append((arg, self.f_locals[arg])) 

132 except KeyError: 

133 pass # this can occur when using Psyco 

134 return retval 

135 

136 

137class TracebackEntry(object): 

138 """ a single entry in a traceback """ 

139 

140 _repr_style = None 

141 exprinfo = None 

142 

143 def __init__(self, rawentry): 

144 self._rawentry = rawentry 

145 self.lineno = rawentry.tb_lineno - 1 

146 

147 def set_repr_style(self, mode): 

148 assert mode in ("short", "long") 

149 self._repr_style = mode 

150 

151 @property 

152 def frame(self): 

153 return py.code.Frame(self._rawentry.tb_frame) 

154 

155 @property 

156 def relline(self): 

157 return self.lineno - self.frame.code.firstlineno 

158 

159 def __repr__(self): 

160 return "<TracebackEntry %s:%d>" % (self.frame.code.path, self.lineno+1) 

161 

162 @property 

163 def statement(self): 

164 """ py.code.Source object for the current statement """ 

165 source = self.frame.code.fullsource 

166 return source.getstatement(self.lineno) 

167 

168 @property 

169 def path(self): 

170 """ path to the source code """ 

171 return self.frame.code.path 

172 

173 def getlocals(self): 

174 return self.frame.f_locals 

175 locals = property(getlocals, None, None, "locals of underlaying frame") 

176 

177 def reinterpret(self): 

178 """Reinterpret the failing statement and returns a detailed information 

179 about what operations are performed.""" 

180 if self.exprinfo is None: 

181 source = str(self.statement).strip() 

182 x = py.code._reinterpret(source, self.frame, should_fail=True) 

183 if not isinstance(x, str): 

184 raise TypeError("interpret returned non-string %r" % (x,)) 

185 self.exprinfo = x 

186 return self.exprinfo 

187 

188 def getfirstlinesource(self): 

189 # on Jython this firstlineno can be -1 apparently 

190 return max(self.frame.code.firstlineno, 0) 

191 

192 def getsource(self, astcache=None): 

193 """ return failing source code. """ 

194 # we use the passed in astcache to not reparse asttrees 

195 # within exception info printing 

196 from py._code.source import getstatementrange_ast 

197 source = self.frame.code.fullsource 

198 if source is None: 

199 return None 

200 key = astnode = None 

201 if astcache is not None: 

202 key = self.frame.code.path 

203 if key is not None: 

204 astnode = astcache.get(key, None) 

205 start = self.getfirstlinesource() 

206 try: 

207 astnode, _, end = getstatementrange_ast(self.lineno, source, 

208 astnode=astnode) 

209 except SyntaxError: 

210 end = self.lineno + 1 

211 else: 

212 if key is not None: 

213 astcache[key] = astnode 

214 return source[start:end] 

215 

216 source = property(getsource) 

217 

218 def ishidden(self): 

219 """ return True if the current frame has a var __tracebackhide__ 

220 resolving to True 

221 

222 mostly for internal use 

223 """ 

224 try: 

225 return self.frame.f_locals['__tracebackhide__'] 

226 except KeyError: 

227 try: 

228 return self.frame.f_globals['__tracebackhide__'] 

229 except KeyError: 

230 return False 

231 

232 def __str__(self): 

233 try: 

234 fn = str(self.path) 

235 except py.error.Error: 

236 fn = '???' 

237 name = self.frame.code.name 

238 try: 

239 line = str(self.statement).lstrip() 

240 except KeyboardInterrupt: 

241 raise 

242 except: 

243 line = "???" 

244 return " File %r:%d in %s\n %s\n" % (fn, self.lineno+1, name, line) 

245 

246 def name(self): 

247 return self.frame.code.raw.co_name 

248 name = property(name, None, None, "co_name of underlaying code") 

249 

250 

251class Traceback(list): 

252 """ Traceback objects encapsulate and offer higher level 

253 access to Traceback entries. 

254 """ 

255 Entry = TracebackEntry 

256 

257 def __init__(self, tb): 

258 """ initialize from given python traceback object. """ 

259 if hasattr(tb, 'tb_next'): 

260 def f(cur): 

261 while cur is not None: 

262 yield self.Entry(cur) 

263 cur = cur.tb_next 

264 list.__init__(self, f(tb)) 

265 else: 

266 list.__init__(self, tb) 

267 

268 def cut(self, path=None, lineno=None, firstlineno=None, excludepath=None): 

269 """ return a Traceback instance wrapping part of this Traceback 

270 

271 by provding any combination of path, lineno and firstlineno, the 

272 first frame to start the to-be-returned traceback is determined 

273 

274 this allows cutting the first part of a Traceback instance e.g. 

275 for formatting reasons (removing some uninteresting bits that deal 

276 with handling of the exception/traceback) 

277 """ 

278 for x in self: 

279 code = x.frame.code 

280 codepath = code.path 

281 if ((path is None or codepath == path) and 

282 (excludepath is None or not hasattr(codepath, 'relto') or 

283 not codepath.relto(excludepath)) and 

284 (lineno is None or x.lineno == lineno) and 

285 (firstlineno is None or x.frame.code.firstlineno == firstlineno)): 

286 return Traceback(x._rawentry) 

287 return self 

288 

289 def __getitem__(self, key): 

290 val = super(Traceback, self).__getitem__(key) 

291 if isinstance(key, type(slice(0))): 

292 val = self.__class__(val) 

293 return val 

294 

295 def filter(self, fn=lambda x: not x.ishidden()): 

296 """ return a Traceback instance with certain items removed 

297 

298 fn is a function that gets a single argument, a TracebackItem 

299 instance, and should return True when the item should be added 

300 to the Traceback, False when not 

301 

302 by default this removes all the TracebackItems which are hidden 

303 (see ishidden() above) 

304 """ 

305 return Traceback(filter(fn, self)) 

306 

307 def getcrashentry(self): 

308 """ return last non-hidden traceback entry that lead 

309 to the exception of a traceback. 

310 """ 

311 for i in range(-1, -len(self)-1, -1): 

312 entry = self[i] 

313 if not entry.ishidden(): 

314 return entry 

315 return self[-1] 

316 

317 def recursionindex(self): 

318 """ return the index of the frame/TracebackItem where recursion 

319 originates if appropriate, None if no recursion occurred 

320 """ 

321 cache = {} 

322 for i, entry in enumerate(self): 

323 # id for the code.raw is needed to work around 

324 # the strange metaprogramming in the decorator lib from pypi 

325 # which generates code objects that have hash/value equality 

326 #XXX needs a test 

327 key = entry.frame.code.path, id(entry.frame.code.raw), entry.lineno 

328 #print "checking for recursion at", key 

329 l = cache.setdefault(key, []) 

330 if l: 

331 f = entry.frame 

332 loc = f.f_locals 

333 for otherloc in l: 

334 if f.is_true(f.eval(co_equal, 

335 __recursioncache_locals_1=loc, 

336 __recursioncache_locals_2=otherloc)): 

337 return i 

338 l.append(entry.frame.f_locals) 

339 return None 

340 

341co_equal = compile('__recursioncache_locals_1 == __recursioncache_locals_2', 

342 '?', 'eval') 

343 

344class ExceptionInfo(object): 

345 """ wraps sys.exc_info() objects and offers 

346 help for navigating the traceback. 

347 """ 

348 _striptext = '' 

349 def __init__(self, tup=None, exprinfo=None): 

350 if tup is None: 

351 tup = sys.exc_info() 

352 if exprinfo is None and isinstance(tup[1], AssertionError): 

353 exprinfo = getattr(tup[1], 'msg', None) 

354 if exprinfo is None: 

355 exprinfo = str(tup[1]) 

356 if exprinfo and exprinfo.startswith('assert '): 

357 self._striptext = 'AssertionError: ' 

358 self._excinfo = tup 

359 #: the exception class 

360 self.type = tup[0] 

361 #: the exception instance 

362 self.value = tup[1] 

363 #: the exception raw traceback 

364 self.tb = tup[2] 

365 #: the exception type name 

366 self.typename = self.type.__name__ 

367 #: the exception traceback (py.code.Traceback instance) 

368 self.traceback = py.code.Traceback(self.tb) 

369 

370 def __repr__(self): 

371 return "<ExceptionInfo %s tblen=%d>" % ( 

372 self.typename, len(self.traceback)) 

373 

374 def exconly(self, tryshort=False): 

375 """ return the exception as a string 

376 

377 when 'tryshort' resolves to True, and the exception is a 

378 py.code._AssertionError, only the actual exception part of 

379 the exception representation is returned (so 'AssertionError: ' is 

380 removed from the beginning) 

381 """ 

382 lines = format_exception_only(self.type, self.value) 

383 text = ''.join(lines) 

384 text = text.rstrip() 

385 if tryshort: 

386 if text.startswith(self._striptext): 

387 text = text[len(self._striptext):] 

388 return text 

389 

390 def errisinstance(self, exc): 

391 """ return True if the exception is an instance of exc """ 

392 return isinstance(self.value, exc) 

393 

394 def _getreprcrash(self): 

395 exconly = self.exconly(tryshort=True) 

396 entry = self.traceback.getcrashentry() 

397 path, lineno = entry.frame.code.raw.co_filename, entry.lineno 

398 return ReprFileLocation(path, lineno+1, exconly) 

399 

400 def getrepr(self, showlocals=False, style="long", 

401 abspath=False, tbfilter=True, funcargs=False): 

402 """ return str()able representation of this exception info. 

403 showlocals: show locals per traceback entry 

404 style: long|short|no|native traceback style 

405 tbfilter: hide entries (where __tracebackhide__ is true) 

406 

407 in case of style==native, tbfilter and showlocals is ignored. 

408 """ 

409 if style == 'native': 

410 return ReprExceptionInfo(ReprTracebackNative( 

411 traceback.format_exception( 

412 self.type, 

413 self.value, 

414 self.traceback[0]._rawentry, 

415 )), self._getreprcrash()) 

416 

417 fmt = FormattedExcinfo( 

418 showlocals=showlocals, style=style, 

419 abspath=abspath, tbfilter=tbfilter, funcargs=funcargs) 

420 return fmt.repr_excinfo(self) 

421 

422 def __str__(self): 

423 entry = self.traceback[-1] 

424 loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly()) 

425 return str(loc) 

426 

427 def __unicode__(self): 

428 entry = self.traceback[-1] 

429 loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly()) 

430 return loc.__unicode__() 

431 

432 

433class FormattedExcinfo(object): 

434 """ presenting information about failing Functions and Generators. """ 

435 # for traceback entries 

436 flow_marker = ">" 

437 fail_marker = "E" 

438 

439 def __init__(self, showlocals=False, style="long", 

440 abspath=True, tbfilter=True, funcargs=False): 

441 self.showlocals = showlocals 

442 self.style = style 

443 self.tbfilter = tbfilter 

444 self.funcargs = funcargs 

445 self.abspath = abspath 

446 self.astcache = {} 

447 

448 def _getindent(self, source): 

449 # figure out indent for given source 

450 try: 

451 s = str(source.getstatement(len(source)-1)) 

452 except KeyboardInterrupt: 

453 raise 

454 except: 

455 try: 

456 s = str(source[-1]) 

457 except KeyboardInterrupt: 

458 raise 

459 except: 

460 return 0 

461 return 4 + (len(s) - len(s.lstrip())) 

462 

463 def _getentrysource(self, entry): 

464 source = entry.getsource(self.astcache) 

465 if source is not None: 

466 source = source.deindent() 

467 return source 

468 

469 def _saferepr(self, obj): 

470 return py.io.saferepr(obj) 

471 

472 def repr_args(self, entry): 

473 if self.funcargs: 

474 args = [] 

475 for argname, argvalue in entry.frame.getargs(var=True): 

476 args.append((argname, self._saferepr(argvalue))) 

477 return ReprFuncArgs(args) 

478 

479 def get_source(self, source, line_index=-1, excinfo=None, short=False): 

480 """ return formatted and marked up source lines. """ 

481 lines = [] 

482 if source is None or line_index >= len(source.lines): 

483 source = py.code.Source("???") 

484 line_index = 0 

485 if line_index < 0: 

486 line_index += len(source) 

487 space_prefix = " " 

488 if short: 

489 lines.append(space_prefix + source.lines[line_index].strip()) 

490 else: 

491 for line in source.lines[:line_index]: 

492 lines.append(space_prefix + line) 

493 lines.append(self.flow_marker + " " + source.lines[line_index]) 

494 for line in source.lines[line_index+1:]: 

495 lines.append(space_prefix + line) 

496 if excinfo is not None: 

497 indent = 4 if short else self._getindent(source) 

498 lines.extend(self.get_exconly(excinfo, indent=indent, markall=True)) 

499 return lines 

500 

501 def get_exconly(self, excinfo, indent=4, markall=False): 

502 lines = [] 

503 indent = " " * indent 

504 # get the real exception information out 

505 exlines = excinfo.exconly(tryshort=True).split('\n') 

506 failindent = self.fail_marker + indent[1:] 

507 for line in exlines: 

508 lines.append(failindent + line) 

509 if not markall: 

510 failindent = indent 

511 return lines 

512 

513 def repr_locals(self, locals): 

514 if self.showlocals: 

515 lines = [] 

516 keys = [loc for loc in locals if loc[0] != "@"] 

517 keys.sort() 

518 for name in keys: 

519 value = locals[name] 

520 if name == '__builtins__': 

521 lines.append("__builtins__ = <builtins>") 

522 else: 

523 # This formatting could all be handled by the 

524 # _repr() function, which is only reprlib.Repr in 

525 # disguise, so is very configurable. 

526 str_repr = self._saferepr(value) 

527 #if len(str_repr) < 70 or not isinstance(value, 

528 # (list, tuple, dict)): 

529 lines.append("%-10s = %s" %(name, str_repr)) 

530 #else: 

531 # self._line("%-10s =\\" % (name,)) 

532 # # XXX 

533 # pprint.pprint(value, stream=self.excinfowriter) 

534 return ReprLocals(lines) 

535 

536 def repr_traceback_entry(self, entry, excinfo=None): 

537 source = self._getentrysource(entry) 

538 if source is None: 

539 source = py.code.Source("???") 

540 line_index = 0 

541 else: 

542 # entry.getfirstlinesource() can be -1, should be 0 on jython 

543 line_index = entry.lineno - max(entry.getfirstlinesource(), 0) 

544 

545 lines = [] 

546 style = entry._repr_style 

547 if style is None: 

548 style = self.style 

549 if style in ("short", "long"): 

550 short = style == "short" 

551 reprargs = self.repr_args(entry) if not short else None 

552 s = self.get_source(source, line_index, excinfo, short=short) 

553 lines.extend(s) 

554 if short: 

555 message = "in %s" %(entry.name) 

556 else: 

557 message = excinfo and excinfo.typename or "" 

558 path = self._makepath(entry.path) 

559 filelocrepr = ReprFileLocation(path, entry.lineno+1, message) 

560 localsrepr = None 

561 if not short: 

562 localsrepr = self.repr_locals(entry.locals) 

563 return ReprEntry(lines, reprargs, localsrepr, filelocrepr, style) 

564 if excinfo: 

565 lines.extend(self.get_exconly(excinfo, indent=4)) 

566 return ReprEntry(lines, None, None, None, style) 

567 

568 def _makepath(self, path): 

569 if not self.abspath: 

570 try: 

571 np = py.path.local().bestrelpath(path) 

572 except OSError: 

573 return path 

574 if len(np) < len(str(path)): 

575 path = np 

576 return path 

577 

578 def repr_traceback(self, excinfo): 

579 traceback = excinfo.traceback 

580 if self.tbfilter: 

581 traceback = traceback.filter() 

582 recursionindex = None 

583 if excinfo.errisinstance(RuntimeError): 

584 if "maximum recursion depth exceeded" in str(excinfo.value): 

585 recursionindex = traceback.recursionindex() 

586 last = traceback[-1] 

587 entries = [] 

588 extraline = None 

589 for index, entry in enumerate(traceback): 

590 einfo = (last == entry) and excinfo or None 

591 reprentry = self.repr_traceback_entry(entry, einfo) 

592 entries.append(reprentry) 

593 if index == recursionindex: 

594 extraline = "!!! Recursion detected (same locals & position)" 

595 break 

596 return ReprTraceback(entries, extraline, style=self.style) 

597 

598 def repr_excinfo(self, excinfo): 

599 reprtraceback = self.repr_traceback(excinfo) 

600 reprcrash = excinfo._getreprcrash() 

601 return ReprExceptionInfo(reprtraceback, reprcrash) 

602 

603class TerminalRepr: 

604 def __str__(self): 

605 s = self.__unicode__() 

606 if sys.version_info[0] < 3: 

607 s = s.encode('utf-8') 

608 return s 

609 

610 def __unicode__(self): 

611 # FYI this is called from pytest-xdist's serialization of exception 

612 # information. 

613 io = py.io.TextIO() 

614 tw = py.io.TerminalWriter(file=io) 

615 self.toterminal(tw) 

616 return io.getvalue().strip() 

617 

618 def __repr__(self): 

619 return "<%s instance at %0x>" %(self.__class__, id(self)) 

620 

621 

622class ReprExceptionInfo(TerminalRepr): 

623 def __init__(self, reprtraceback, reprcrash): 

624 self.reprtraceback = reprtraceback 

625 self.reprcrash = reprcrash 

626 self.sections = [] 

627 

628 def addsection(self, name, content, sep="-"): 

629 self.sections.append((name, content, sep)) 

630 

631 def toterminal(self, tw): 

632 self.reprtraceback.toterminal(tw) 

633 for name, content, sep in self.sections: 

634 tw.sep(sep, name) 

635 tw.line(content) 

636 

637class ReprTraceback(TerminalRepr): 

638 entrysep = "_ " 

639 

640 def __init__(self, reprentries, extraline, style): 

641 self.reprentries = reprentries 

642 self.extraline = extraline 

643 self.style = style 

644 

645 def toterminal(self, tw): 

646 # the entries might have different styles 

647 last_style = None 

648 for i, entry in enumerate(self.reprentries): 

649 if entry.style == "long": 

650 tw.line("") 

651 entry.toterminal(tw) 

652 if i < len(self.reprentries) - 1: 

653 next_entry = self.reprentries[i+1] 

654 if entry.style == "long" or \ 

655 entry.style == "short" and next_entry.style == "long": 

656 tw.sep(self.entrysep) 

657 

658 if self.extraline: 

659 tw.line(self.extraline) 

660 

661class ReprTracebackNative(ReprTraceback): 

662 def __init__(self, tblines): 

663 self.style = "native" 

664 self.reprentries = [ReprEntryNative(tblines)] 

665 self.extraline = None 

666 

667class ReprEntryNative(TerminalRepr): 

668 style = "native" 

669 

670 def __init__(self, tblines): 

671 self.lines = tblines 

672 

673 def toterminal(self, tw): 

674 tw.write("".join(self.lines)) 

675 

676class ReprEntry(TerminalRepr): 

677 localssep = "_ " 

678 

679 def __init__(self, lines, reprfuncargs, reprlocals, filelocrepr, style): 

680 self.lines = lines 

681 self.reprfuncargs = reprfuncargs 

682 self.reprlocals = reprlocals 

683 self.reprfileloc = filelocrepr 

684 self.style = style 

685 

686 def toterminal(self, tw): 

687 if self.style == "short": 

688 self.reprfileloc.toterminal(tw) 

689 for line in self.lines: 

690 red = line.startswith("E ") 

691 tw.line(line, bold=True, red=red) 

692 #tw.line("") 

693 return 

694 if self.reprfuncargs: 

695 self.reprfuncargs.toterminal(tw) 

696 for line in self.lines: 

697 red = line.startswith("E ") 

698 tw.line(line, bold=True, red=red) 

699 if self.reprlocals: 

700 #tw.sep(self.localssep, "Locals") 

701 tw.line("") 

702 self.reprlocals.toterminal(tw) 

703 if self.reprfileloc: 

704 if self.lines: 

705 tw.line("") 

706 self.reprfileloc.toterminal(tw) 

707 

708 def __str__(self): 

709 return "%s\n%s\n%s" % ("\n".join(self.lines), 

710 self.reprlocals, 

711 self.reprfileloc) 

712 

713class ReprFileLocation(TerminalRepr): 

714 def __init__(self, path, lineno, message): 

715 self.path = str(path) 

716 self.lineno = lineno 

717 self.message = message 

718 

719 def toterminal(self, tw): 

720 # filename and lineno output for each entry, 

721 # using an output format that most editors unterstand 

722 msg = self.message 

723 i = msg.find("\n") 

724 if i != -1: 

725 msg = msg[:i] 

726 tw.line("%s:%s: %s" %(self.path, self.lineno, msg)) 

727 

728class ReprLocals(TerminalRepr): 

729 def __init__(self, lines): 

730 self.lines = lines 

731 

732 def toterminal(self, tw): 

733 for line in self.lines: 

734 tw.line(line) 

735 

736class ReprFuncArgs(TerminalRepr): 

737 def __init__(self, args): 

738 self.args = args 

739 

740 def toterminal(self, tw): 

741 if self.args: 

742 linesofar = "" 

743 for name, value in self.args: 

744 ns = "%s = %s" %(name, value) 

745 if len(ns) + len(linesofar) + 2 > tw.fullwidth: 

746 if linesofar: 

747 tw.line(linesofar) 

748 linesofar = ns 

749 else: 

750 if linesofar: 

751 linesofar += ", " + ns 

752 else: 

753 linesofar = ns 

754 if linesofar: 

755 tw.line(linesofar) 

756 tw.line("") 

757 

758 

759 

760oldbuiltins = {} 

761 

762def patch_builtins(assertion=True, compile=True): 

763 """ put compile and AssertionError builtins to Python's builtins. """ 

764 if assertion: 

765 from py._code import assertion 

766 l = oldbuiltins.setdefault('AssertionError', []) 

767 l.append(py.builtin.builtins.AssertionError) 

768 py.builtin.builtins.AssertionError = assertion.AssertionError 

769 if compile: 

770 l = oldbuiltins.setdefault('compile', []) 

771 l.append(py.builtin.builtins.compile) 

772 py.builtin.builtins.compile = py.code.compile 

773 

774def unpatch_builtins(assertion=True, compile=True): 

775 """ remove compile and AssertionError builtins from Python builtins. """ 

776 if assertion: 

777 py.builtin.builtins.AssertionError = oldbuiltins['AssertionError'].pop() 

778 if compile: 

779 py.builtin.builtins.compile = oldbuiltins['compile'].pop() 

780 

781def getrawcode(obj, trycall=True): 

782 """ return code object for given function. """ 

783 try: 

784 return obj.__code__ 

785 except AttributeError: 

786 obj = getattr(obj, 'im_func', obj) 

787 obj = getattr(obj, 'func_code', obj) 

788 obj = getattr(obj, 'f_code', obj) 

789 obj = getattr(obj, '__code__', obj) 

790 if trycall and not hasattr(obj, 'co_firstlineno'): 

791 if hasattr(obj, '__call__') and not isclass(obj): 

792 x = getrawcode(obj.__call__, trycall=False) 

793 if hasattr(x, 'co_firstlineno'): 

794 return x 

795 return obj 

796