1# 2# Copyright (c) SAS Institute, Inc. 3# 4# Permission is hereby granted, free of charge, to any person obtaining a copy 5# of this software and associated documentation files (the "Software"), to deal 6# in the Software without restriction, including without limitation the rights 7# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8# copies of the Software, and to permit persons to whom the Software is 9# furnished to do so, subject to the following conditions: 10# 11# The above copyright notice and this permission notice shall be included in 12# all copies or substantial portions of the Software. 13# 14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20# THE SOFTWARE. 21# 22 23 24""" Tools for printing out extended information about frame variables """ 25from __future__ import unicode_literals 26from __future__ import print_function 27from __future__ import division 28from __future__ import absolute_import 29 30import inspect 31import smtplib 32import sys 33import string 34import tempfile 35import traceback 36from six.moves import xmlrpc_client 37 38from six.moves.reprlib import Repr 39_repr = Repr() 40_repr.maxstring = 3000 41_saferepr = _repr.repr 42 43 44def printTraceBack(tb=None, output=sys.stderr, exc_type=None, exc_msg=None): 45 if isinstance(output, str): 46 output = open(output, 'w') 47 48 exc_info = sys.exc_info() 49 if tb is None: 50 tb = exc_info[2] 51 52 if exc_type is None: 53 exc_type = exc_info[0] 54 55 if exc_msg is None: 56 exc_msg = exc_info[1] 57 58 if exc_type is not None: 59 output.write('Exception: ') 60 exc_info = '\n'.join(traceback.format_exception_only( 61 exc_type, exc_msg)) 62 output.write(exc_info) 63 output.write('\n\n') 64 65 lines = traceback.format_exception(exc_type, exc_msg, tb) 66 output.write(string.joinfields(lines, "")) 67 68 while tb: 69 _printFrame(tb.tb_frame, output=output) 70 tb = tb.tb_next 71 72 73def printFrame(frame=0, output=sys.stderr): 74 # if output is a path, assume it is a writable one 75 # otherwise, it must be an already opened file 76 if isinstance(output, str): 77 output = open(output, 'w') 78 # skip this frame because who cares about the printFrame func? 79 if isinstance(frame, int): 80 # stack was given in depth form 81 # (skip the current frame when counting depth) 82 frame = sys._getframe(frame + 1) 83 _printFrame(frame, output) 84 85 86def printStack(frame=0, output=sys.stderr): 87 if isinstance(output, str): 88 output = open(output, 'w') 89 if isinstance(frame, int): 90 # stack was given in depth form 91 # (skip the current frame when counting depth) 92 frame = sys._getframe(frame + 1) 93 while(frame): 94 output.write("*************************************\n") 95 _printFrame(frame, output) 96 frame = frame.f_back 97 98 99def mailStack(frame, recips, sender, subject, extracontent=None): 100 file = tempfile.TemporaryFile() 101 file.write('Subject: ' + subject + '\n\n') 102 if extracontent: 103 file.write(extracontent) 104 printStack(frame, file) 105 server = smtplib.SMTP('localhost') 106 file.seek(0) 107 server.sendmail(sender, 108 recips, 109 file.read()) 110 server.close() 111 file.close() 112 113 114def _printFrame(f, output=sys.stderr): 115 c = f.f_code 116 argcount = c.co_argcount 117 varnames = c.co_varnames 118 args = varnames[:argcount] 119 locals = f.f_locals 120 globals = f.f_globals 121 output.write(">> %s:%s: %s.%s(%s)\n" % ( 122 c.co_filename, f.f_lineno, globals['__name__'], c.co_name, 123 ', '.join(args))) 124 125 localkeys = [l for l in list(f.f_locals.keys()) 126 if not inspect.ismodule(locals[l])] 127 if argcount > 0: 128 output.write(" Params: \n") 129 for var in varnames[:argcount]: 130 if var in locals: 131 val = locals[var] 132 val = _getStringValue(val) 133 localkeys.remove(var) 134 else: 135 val = '<Unknown>' 136 137 output.write(" %s = %s\n" % (var, _saferepr(val))) 138 for hidden in ('__file__', '__name__', '__doc__'): 139 if hidden in localkeys: 140 localkeys.remove(hidden) 141 localkeys.sort() 142 if localkeys: 143 output.write(" Locals: \n") 144 for key in localkeys: 145 if key in locals: 146 val = locals[key] 147 val = _getStringValue(val) 148 else: 149 val = '<Unknown>' 150 output.write(" %s = %r\n" % (key, _saferepr(val))) 151 152 153def _getStringValue(val): 154 try: 155 if isinstance(val, xmlrpc_client.ServerProxy): 156 rval = "<Server Proxy>" 157 elif hasattr(val, 'asString'): 158 rval = val.asString() 159 elif inspect.isclass(val): 160 rval = '<Class %s.%s>' % (val.__module__, val.__name__) 161 elif not hasattr(val, '__str__'): 162 if hasattr(val, '__class__'): 163 rval = '<unprintable of class %s>' % val.__class__ 164 else: 165 rval = '<unprintable>' 166 else: 167 rval = val 168 return rval 169 except Exception as e: 170 try: 171 return '<Exception occured while converting %s to string: %s' % ( 172 repr(val), e) 173 except Exception as e: 174 return '<Exception occured while converting to repr: %s' % (e,) 175