Fixed incorrect information on Python frames in MuranoPL stack traces
Python frames in mixed stack traces were missing file name and pointed to a line below correct position Change-Id: I335292f40b3b6ea3dbca80b84f1d8dbed9a6581d Fixes: bug #1331113
This commit is contained in:
@@ -123,7 +123,7 @@ class TaskExecutor(object):
|
|||||||
self._invoke(exc)
|
self._invoke(exc)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if isinstance(e, dsl_exception.MuranoPlException):
|
if isinstance(e, dsl_exception.MuranoPlException):
|
||||||
LOG.error(e.format())
|
LOG.error('\n' + e.format(prefix=' '))
|
||||||
else:
|
else:
|
||||||
LOG.exception(e)
|
LOG.exception(e)
|
||||||
reporter = status_reporter.StatusReporter()
|
reporter = status_reporter.StatusReporter()
|
||||||
|
@@ -71,8 +71,8 @@ class MuranoPlException(Exception):
|
|||||||
else:
|
else:
|
||||||
return self._names
|
return self._names
|
||||||
|
|
||||||
def format(self, prefix=' '):
|
def format(self, prefix=''):
|
||||||
text = '\n{3}{0}: {1}\n' \
|
text = '{3}{0}: {1}\n' \
|
||||||
'{3}Traceback (most recent call last):\n' \
|
'{3}Traceback (most recent call last):\n' \
|
||||||
'{2}'.format(self._format_name(), self.message,
|
'{2}'.format(self._format_name(), self.message,
|
||||||
self.stacktrace.toString(prefix + ' '), prefix)
|
self.stacktrace.toString(prefix + ' '), prefix)
|
||||||
|
@@ -45,25 +45,15 @@ class StackTrace(murano_object.MuranoObject):
|
|||||||
frames.reverse()
|
frames.reverse()
|
||||||
|
|
||||||
if includeNativeFrames:
|
if includeNativeFrames:
|
||||||
class InstructionStub(object):
|
|
||||||
def __init__(self, title, position):
|
|
||||||
self._title = title
|
|
||||||
self.source_file_position = position
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self._title
|
|
||||||
|
|
||||||
native_frames = []
|
native_frames = []
|
||||||
for frame in inspect.trace()[1:]:
|
for frame in inspect.trace()[1:]:
|
||||||
info = inspect.getframeinfo(frame[0])
|
location = yaql_expression.YaqlExpressionFilePosition(
|
||||||
position = yaql_expression.YaqlExpressionFilePosition(
|
os.path.abspath(frame[1]), frame[2],
|
||||||
os.path.abspath(info.filename), info.lineno,
|
|
||||||
-1, -1, -1, -1, -1)
|
-1, -1, -1, -1, -1)
|
||||||
instruction = InstructionStub(
|
method = frame[3]
|
||||||
info.code_context[0].strip(), position)
|
|
||||||
method = info.function
|
|
||||||
native_frames.append({
|
native_frames.append({
|
||||||
'instruction': instruction,
|
'instruction': frame[4][0].strip(),
|
||||||
|
'location': location,
|
||||||
'method': method,
|
'method': method,
|
||||||
'class': None
|
'class': None
|
||||||
})
|
})
|
||||||
@@ -77,6 +67,8 @@ class StackTrace(murano_object.MuranoObject):
|
|||||||
method = frame['method']
|
method = frame['method']
|
||||||
murano_class = frame['class']
|
murano_class = frame['class']
|
||||||
location = frame['location']
|
location = frame['location']
|
||||||
|
if murano_class:
|
||||||
|
method += ' of class ' + murano_class.name
|
||||||
|
|
||||||
if location:
|
if location:
|
||||||
args = (
|
args = (
|
||||||
@@ -86,14 +78,12 @@ class StackTrace(murano_object.MuranoObject):
|
|||||||
if location.start_column >= 0 else '',
|
if location.start_column >= 0 else '',
|
||||||
method,
|
method,
|
||||||
instruction,
|
instruction,
|
||||||
prefix,
|
prefix
|
||||||
'' if not murano_class else murano_class.name + '::'
|
|
||||||
)
|
)
|
||||||
return '{5}File "{0}", line {1}{2} in method {6}{3}\n' \
|
return '{5}File "{0}", line {1}{2} in method {3}\n' \
|
||||||
'{5} {4}'.format(*args)
|
'{5} {4}'.format(*args)
|
||||||
else:
|
else:
|
||||||
return '{2}File <unknown> in method {3}{0}\n{2} {1}'.format(
|
return '{2}File <unknown> in method {0}\n{2} {1}'.format(
|
||||||
method, instruction, prefix,
|
method, instruction, prefix)
|
||||||
'' if not murano_class else murano_class.name + '::')
|
|
||||||
|
|
||||||
return '\n'.join([format_frame(t)for t in self.get_property('frames')])
|
return '\n'.join([format_frame(t)for t in self.get_property('frames')])
|
||||||
|
@@ -49,3 +49,7 @@ Methods:
|
|||||||
- Return:
|
- Return:
|
||||||
Value: $enum
|
Value: $enum
|
||||||
|
|
||||||
|
testStackTrace:
|
||||||
|
Body:
|
||||||
|
raisePythonException()
|
||||||
|
|
||||||
|
@@ -12,6 +12,12 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import inspect
|
||||||
|
import os.path
|
||||||
|
import re
|
||||||
|
|
||||||
|
from testtools import matchers
|
||||||
|
|
||||||
from murano.dsl import dsl_exception
|
from murano.dsl import dsl_exception
|
||||||
from murano.tests.dsl.foundation import object_model as om
|
from murano.tests.dsl.foundation import object_model as om
|
||||||
from murano.tests.dsl.foundation import test_case
|
from murano.tests.dsl.foundation import test_case
|
||||||
@@ -20,6 +26,16 @@ from murano.tests.dsl.foundation import test_case
|
|||||||
class TestExceptions(test_case.DslTestCase):
|
class TestExceptions(test_case.DslTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestExceptions, self).setUp()
|
super(TestExceptions, self).setUp()
|
||||||
|
|
||||||
|
def exception_func():
|
||||||
|
exc = LookupError('just random Python exception')
|
||||||
|
frameinfo = inspect.getframeinfo(inspect.currentframe())
|
||||||
|
exc._position = \
|
||||||
|
os.path.basename(frameinfo.filename), frameinfo.lineno + 4
|
||||||
|
# line below must be exactly 4 lines after currentframe()
|
||||||
|
raise exc
|
||||||
|
|
||||||
|
self.register_function(exception_func, 'raisePythonException')
|
||||||
self._runner = self.new_runner(om.Object('ExceptionHandling'))
|
self._runner = self.new_runner(om.Object('ExceptionHandling'))
|
||||||
|
|
||||||
def test_throw_catch(self):
|
def test_throw_catch(self):
|
||||||
@@ -54,3 +70,27 @@ class TestExceptions(test_case.DslTestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
['enter try', 'exit try', 'else section', 'finally section'],
|
['enter try', 'exit try', 'else section', 'finally section'],
|
||||||
self.traces)
|
self.traces)
|
||||||
|
|
||||||
|
def test_stack_trace(self):
|
||||||
|
self._runner.preserve_exception = True
|
||||||
|
e = self.assertRaises(
|
||||||
|
dsl_exception.MuranoPlException,
|
||||||
|
self._runner.testStackTrace)
|
||||||
|
call_stack = e.format()
|
||||||
|
self.assertThat(
|
||||||
|
call_stack,
|
||||||
|
matchers.StartsWith(
|
||||||
|
'exceptions.LookupError: just random Python exception'))
|
||||||
|
|
||||||
|
self.assertIsInstance(e.original_exception, LookupError)
|
||||||
|
|
||||||
|
filename, line = e.original_exception._position
|
||||||
|
self.assertThat(
|
||||||
|
call_stack,
|
||||||
|
matchers.MatchesRegex(
|
||||||
|
r'.*^ File \".*ExceptionHandling\.yaml\", '
|
||||||
|
r'line \d+:\d+ in method testStackTrace .*'
|
||||||
|
r'of class ExceptionHandling$.*'
|
||||||
|
r'^ File \".*{0}\", line {1} '
|
||||||
|
r'in method exception_func$.*'.format(filename, line),
|
||||||
|
re.MULTILINE | re.DOTALL))
|
||||||
|
Reference in New Issue
Block a user