Robot Framework Integrated Development Environment (RIDE)
error.py
Go to the documentation of this file.
1 # Copyright 2008-2015 Nokia Networks
2 # Copyright 2016- Robot Framework Foundation
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 import os
17 import re
18 import sys
19 import traceback
20 
21 from robotide.lib.robot.errors import RobotError
22 
23 from .platform import JYTHON, RERAISED_EXCEPTIONS
24 from .unic import unic
25 
26 
27 EXCLUDE_ROBOT_TRACES = not os.getenv('ROBOT_INTERNAL_TRACES')
28 if JYTHON:
29  from java.io import StringWriter, PrintWriter
30  from java.lang import Throwable, OutOfMemoryError
31 else:
32  Throwable = ()
33 
34 
35 
42  return ErrorDetails().message
43 
44 
45 
46 def get_error_details(exclude_robot_traces=EXCLUDE_ROBOT_TRACES):
47  details = ErrorDetails(exclude_robot_traces=exclude_robot_traces)
48  return details.message, details.traceback
49 
50 
51 
57 def ErrorDetails(exc_info=None, exclude_robot_traces=EXCLUDE_ROBOT_TRACES):
58  exc_type, exc_value, exc_traceback = exc_info or sys.exc_info()
59  if exc_type in RERAISED_EXCEPTIONS:
60  raise exc_value
61  details = PythonErrorDetails \
62  if not isinstance(exc_value, Throwable) else JavaErrorDetails
63  return details(exc_type, exc_value, exc_traceback, exclude_robot_traces)
64 
65 
66 class _ErrorDetails():
67 
70  _generic_exception_names = ('AssertionError', 'AssertionFailedError',
71  'Exception', 'Error', 'RuntimeError',
72  'RuntimeException')
73 
74  def __init__(self, exc_type, exc_value, exc_traceback,
75  exclude_robot_traces=True):
76  self.errorerror = exc_value
77  self._exc_type_exc_type = exc_type
78  self._exc_traceback_exc_traceback = exc_traceback
79  self._exclude_robot_traces_exclude_robot_traces = exclude_robot_traces
80  self._message_message = None
81  self._traceback_traceback = None
82 
83  @property
84  message = property
85 
86  def message(self):
87  if self._message_message is None:
88  self._message_message = self._get_message_get_message()
89  return self._message_message
90 
91  def _get_message(self):
92  raise NotImplementedError
93 
94  @property
95  traceback = property
96 
97  def traceback(self):
98  if self._traceback_traceback is None:
99  self._traceback_traceback = self._get_details_get_details()
100  return self._traceback_traceback
101 
102  def _get_details(self):
103  raise NotImplementedError
104 
105  def _get_name(self, exc_type):
106  try:
107  return exc_type.__name__
108  except AttributeError:
109  return unic(exc_type)
110 
111  def _format_message(self, name, message):
112  message = unic(message or '')
113  message = self._clean_up_message_clean_up_message(message, name)
114  name = name.split('.')[-1] # Use only last part of the name
115  if not message:
116  return name
117  if self._is_generic_exception_is_generic_exception(name):
118  return message
119  return '%s: %s' % (name, message)
120 
121  def _is_generic_exception(self, name):
122  return (name in self._generic_exception_names_generic_exception_names or
123  isinstance(self.errorerror, RobotError) or
124  getattr(self.errorerror, 'ROBOT_SUPPRESS_NAME', False))
125 
126  def _clean_up_message(self, message, name):
127  return message
128 
129 
131 
132  def _get_message(self):
133  name = self._get_name_get_name(self._exc_type_exc_type)
134  return self._format_message_format_message(name, unic(self.errorerror))
135 
136  def _get_details(self):
137  if isinstance(self.errorerror, RobotError):
138  return self.errorerror.details
139  return 'Traceback (most recent call last):\n' + self._get_traceback_get_traceback()
140 
141  def _get_traceback(self):
142  tb = self._exc_traceback_exc_traceback
143  while tb and self._is_excluded_traceback_is_excluded_traceback(tb):
144  tb = tb.tb_next
145  return ''.join(traceback.format_tb(tb)).rstrip() or ' None'
146 
147  def _is_excluded_traceback(self, traceback):
148  if not self._exclude_robot_traces_exclude_robot_traces:
149  return False
150  module = traceback.tb_frame.f_globals.get('__name__')
151  return module and module.startswith('robot.')
152 
153 
155 
158  _java_trace_re = re.compile('^\s+at (\w.+)')
159 
162  _ignored_java_trace = ('org.python.', 'robot.running.', 'robot$py.',
163  'sun.reflect.', 'java.lang.reflect.')
164 
165  def _get_message(self):
166  exc_name = self._get_name_get_name(self._exc_type_exc_type)
167  # OOME.getMessage and even toString seem to throw NullPointerException
168  if not self._is_out_of_memory_error_is_out_of_memory_error(self._exc_type_exc_type):
169  exc_msg = self.errorerror.getMessage()
170  else:
171  exc_msg = str(self.errorerror)
172  return self._format_message_format_message(exc_name, exc_msg)
173 
174  def _is_out_of_memory_error(self, exc_type):
175  return exc_type is OutOfMemoryError
176 
177  def _get_details(self):
178  # OOME.printStackTrace seems to throw NullPointerException
179  if self._is_out_of_memory_error_is_out_of_memory_error(self._exc_type_exc_type):
180  return ''
181  output = StringWriter()
182  self.errorerror.printStackTrace(PrintWriter(output))
183  details = '\n'.join(line for line in output.toString().splitlines()
184  if not self._is_ignored_stack_trace_line_is_ignored_stack_trace_line(line))
185  msg = unic(self.errorerror.getMessage() or '')
186  if msg:
187  details = details.replace(msg, '', 1)
188  return details
189 
191  if not line:
192  return True
193  res = self._java_trace_re_java_trace_re.match(line)
194  if res is None:
195  return False
196  location = res.group(1)
197  for entry in self._ignored_java_trace_ignored_java_trace:
198  if location.startswith(entry):
199  return True
200  return False
201 
202  def _clean_up_message(self, msg, name):
203  msg = self._remove_stack_trace_lines_remove_stack_trace_lines(msg)
204  return self._remove_exception_name_remove_exception_name(msg, name).strip()
205 
207  lines = msg.splitlines()
208  while lines:
209  if self._java_trace_re_java_trace_re.match(lines[-1]):
210  lines.pop()
211  else:
212  break
213  return '\n'.join(lines)
214 
215  def _remove_exception_name(self, msg, name):
216  tokens = msg.split(':', 1)
217  if len(tokens) == 2 and tokens[0] == name:
218  msg = tokens[1]
219  return msg
def _remove_exception_name(self, msg, name)
Definition: error.py:215
def _format_message(self, name, message)
Definition: error.py:111
def _clean_up_message(self, message, name)
Definition: error.py:126
def __init__(self, exc_type, exc_value, exc_traceback, exclude_robot_traces=True)
Definition: error.py:75
def ErrorDetails(exc_info=None, exclude_robot_traces=EXCLUDE_ROBOT_TRACES)
This factory returns an object that wraps the last occurred exception.
Definition: error.py:57
def get_error_message()
Returns error message of the last occurred exception.
Definition: error.py:41
def get_error_details(exclude_robot_traces=EXCLUDE_ROBOT_TRACES)
Returns error message and details of the last occurred exception.
Definition: error.py:46