| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- """
- Unit tests for the stack formatting utilities
- """
- # Author: Gael Varoquaux <gael dot varoquaux at normalesup dot org>
- # Copyright (c) 2010 Gael Varoquaux
- # License: BSD Style, 3 clauses.
- import imp
- import os
- import re
- import sys
- import pytest
- from joblib.format_stack import safe_repr, _fixed_getframes, format_records
- from joblib.format_stack import format_exc
- from joblib.test.common import with_numpy, np
- ###############################################################################
- class Vicious(object):
- def __repr__(self):
- raise ValueError
- def test_safe_repr():
- safe_repr(Vicious())
- def _change_file_extensions_to_pyc(record):
- _1, filename, _2, _3, _4, _5 = record
- if filename.endswith('.py'):
- filename += 'c'
- return _1, filename, _2, _3, _4, _5
- def _raise_exception(a, b):
- """Function that raises with a non trivial call stack
- """
- def helper(a, b):
- raise ValueError('Nope, this can not work')
- helper(a, b)
- def test_format_records():
- try:
- _raise_exception('a', 42)
- except ValueError:
- etb = sys.exc_info()[2]
- records = _fixed_getframes(etb)
- # Modify filenames in traceback records from .py to .pyc
- pyc_records = [_change_file_extensions_to_pyc(record)
- for record in records]
- formatted_records = format_records(pyc_records)
- # Check that the .py file and not the .pyc one is listed in
- # the traceback
- for fmt_rec in formatted_records:
- assert 'test_format_stack.py in' in fmt_rec
- # Check exception stack
- arrow_regex = r'^-+>\s+\d+\s+'
- assert re.search(arrow_regex + r"_raise_exception\('a', 42\)",
- formatted_records[0],
- re.MULTILINE)
- assert re.search(arrow_regex + r'helper\(a, b\)',
- formatted_records[1],
- re.MULTILINE)
- assert "a = 'a'" in formatted_records[1]
- assert 'b = 42' in formatted_records[1]
- assert re.search(arrow_regex +
- r"raise ValueError\('Nope, this can not work'\)",
- formatted_records[2],
- re.MULTILINE)
- def test_format_records_file_with_less_lines_than_context(tmpdir):
- # See https://github.com/joblib/joblib/issues/420
- filename = os.path.join(tmpdir.strpath, 'small_file.py')
- code_lines = ['def func():', ' 1/0']
- code = '\n'.join(code_lines)
- with open(filename, 'w') as f:
- f.write(code)
- small_file = imp.load_source('small_file', filename)
- if not hasattr(small_file, 'func'):
- pytest.skip("PyPy bug?")
- try:
- small_file.func()
- except ZeroDivisionError:
- etb = sys.exc_info()[2]
- records = _fixed_getframes(etb, context=10)
- # Check that if context is bigger than the number of lines in
- # the file you do not get padding
- frame, tb_filename, line, func_name, context, _ = records[-1]
- assert [l.rstrip() for l in context] == code_lines
- formatted_records = format_records(records)
- # 2 lines for header in the traceback: lines of ...... +
- # filename with function
- len_header = 2
- nb_lines_formatted_records = len(formatted_records[1].splitlines())
- assert (nb_lines_formatted_records == len_header + len(code_lines))
- # Check exception stack
- arrow_regex = r'^-+>\s+\d+\s+'
- assert re.search(arrow_regex + r'1/0',
- formatted_records[1],
- re.MULTILINE)
- @with_numpy
- def test_format_exc_with_compiled_code():
- # Trying to tokenize compiled C code raise SyntaxError.
- # See https://github.com/joblib/joblib/issues/101 for more details.
- try:
- np.random.uniform('invalid_value')
- except Exception:
- exc_type, exc_value, exc_traceback = sys.exc_info()
- formatted_exc = format_exc(exc_type, exc_value,
- exc_traceback, context=10)
- # The name of the extension can be something like
- # mtrand.cpython-33m.so
- pattern = r'mtrand[a-z0-9._-]*\.(so|pyd)'
- assert re.search(pattern, formatted_exc)
|