def _get_sentry_stack_info( cls, frames: _traceback.StackSummary) -> Dict[str, Any]: """ Based on Raven's ``get_stack_info``. Because Raven is quite outdated, we need to convert the traceback to a format Sentry accepts. The original method cannot deal with ``FrameSummary`` objects used by Python 3.5+, it understands only the old frame objects, witg ``f_*`` attributes. """ from raven.utils.stacks import get_lines_from_file, slim_frame_data result = [] for frame in frames: lineno = frame.lineno filename = frame.filename function = frame.name line = frame.line frame_result: Dict[str, Union[int, str, Dict[str, str], None]] = { 'abs_path': filename, 'filename': os.path.relpath(filename, os.getcwd()), 'module': None, 'function': function or '<unknown>', 'lineno': lineno, } if line is not None: # Lines are indexed from 0, but human representation starts with 1: "1st line". # Hence the decrement. pre_context, context_line, post_context = get_lines_from_file( filename, lineno - 1, 5) frame_result.update({ 'pre_context': pre_context, 'context_line': context_line, 'post_context': post_context, }) if frame.locals: frame_result['vars'] = frame.locals result.append(frame_result) stackinfo = { 'frames': slim_frame_data(result), } return stackinfo
def convert_traceback(uwsgi_traceback): """ Convert uwsgi traceback string with following pattern to raven protocol traceback thread_id = %s filename = %s lineno = %s function = %s line = %s More info: http://sentry.readthedocs.org/en/latest/developer/client/#building-the-json-packet http://uwsgi-docs.readthedocs.org/en/latest/Tracebacker.html thread_id = MainThread filename = /home/belonika/.pythonz/pythons/CPython-2.6.8/lib/python2.6/socket.py lineno = 554 function = create_connection line = sock.connect(sa) """ variables = ('thread_id', 'filename', 'lineno', 'function', 'line') regexp = r' '.join(('%s = (?P<%s>.+?)' % (var, var) for var in variables)) traceback = [] for line in uwsgi_traceback.split('\n'): match = re.match(r'^%s$' % regexp, line) values = match.groupdict() if match else None if values: frame_result = { 'abs_path': values['filename'], 'context_line': values['line'], 'filename': (values['filename']), 'function': values['function'], 'lineno': int(values['lineno']), 'module': None, 'post_context': [], 'pre_context': [], 'vars': {} } pre_context, context_line, post_context = get_lines_from_file(frame_result['abs_path'], frame_result['lineno'], 5) if context_line is not None: frame_result.update({ 'pre_context': pre_context, 'post_context': post_context, }) traceback.append(frame_result) return traceback
def test_missing_zip_get_source(self): filename = 'does_not_exist.zip' module = 'not.zip.loadable' self.assertEqual( get_lines_from_file(filename, 3, 1, self.loader, module), (None, None, None))
def test_non_ascii_file(self): filename = os.path.join(os.path.dirname(__file__), 'utf8_file.txt') self.assertEqual(get_lines_from_file(filename, 3, 1), (['Some code here'], '', ['lorem ipsum']))
def test_non_ascii_file(self): import os.path filename = os.path.join(os.path.dirname(__file__), 'utf8_file.txt') self.assertEqual( get_lines_from_file(filename, 3, 1), (['Some code here'], '', ['lorem ipsum']))
def test_non_ascii_file(self): import os.path filename = os.path.join(os.path.dirname(__file__), "utf8_file.txt") self.assertEqual(get_lines_from_file(filename, 3, 1), (["Some code here"], "", ["lorem ipsum"]))