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:
Stan Lagun 2014-06-17 22:26:57 +04:00
parent a6d377d992
commit 705a0f5838
5 changed files with 58 additions and 24 deletions

View File

@ -123,7 +123,7 @@ class TaskExecutor(object):
self._invoke(exc)
except Exception as e:
if isinstance(e, dsl_exception.MuranoPlException):
LOG.error(e.format())
LOG.error('\n' + e.format(prefix=' '))
else:
LOG.exception(e)
reporter = status_reporter.StatusReporter()

View File

@ -71,8 +71,8 @@ class MuranoPlException(Exception):
else:
return self._names
def format(self, prefix=' '):
text = '\n{3}{0}: {1}\n' \
def format(self, prefix=''):
text = '{3}{0}: {1}\n' \
'{3}Traceback (most recent call last):\n' \
'{2}'.format(self._format_name(), self.message,
self.stacktrace.toString(prefix + ' '), prefix)

View File

@ -45,25 +45,15 @@ class StackTrace(murano_object.MuranoObject):
frames.reverse()
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 = []
for frame in inspect.trace()[1:]:
info = inspect.getframeinfo(frame[0])
position = yaql_expression.YaqlExpressionFilePosition(
os.path.abspath(info.filename), info.lineno,
location = yaql_expression.YaqlExpressionFilePosition(
os.path.abspath(frame[1]), frame[2],
-1, -1, -1, -1, -1)
instruction = InstructionStub(
info.code_context[0].strip(), position)
method = info.function
method = frame[3]
native_frames.append({
'instruction': instruction,
'instruction': frame[4][0].strip(),
'location': location,
'method': method,
'class': None
})
@ -77,6 +67,8 @@ class StackTrace(murano_object.MuranoObject):
method = frame['method']
murano_class = frame['class']
location = frame['location']
if murano_class:
method += ' of class ' + murano_class.name
if location:
args = (
@ -86,14 +78,12 @@ class StackTrace(murano_object.MuranoObject):
if location.start_column >= 0 else '',
method,
instruction,
prefix,
'' if not murano_class else murano_class.name + '::'
prefix
)
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)
else:
return '{2}File <unknown> in method {3}{0}\n{2} {1}'.format(
method, instruction, prefix,
'' if not murano_class else murano_class.name + '::')
return '{2}File <unknown> in method {0}\n{2} {1}'.format(
method, instruction, prefix)
return '\n'.join([format_frame(t)for t in self.get_property('frames')])

View File

@ -49,3 +49,7 @@ Methods:
- Return:
Value: $enum
testStackTrace:
Body:
raisePythonException()

View File

@ -12,6 +12,12 @@
# License for the specific language governing permissions and limitations
# under the License.
import inspect
import os.path
import re
from testtools import matchers
from murano.dsl import dsl_exception
from murano.tests.dsl.foundation import object_model as om
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):
def setUp(self):
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'))
def test_throw_catch(self):
@ -54,3 +70,27 @@ class TestExceptions(test_case.DslTestCase):
self.assertEqual(
['enter try', 'exit try', 'else section', 'finally section'],
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))