示例#1
0
def load_plugin(module_name):
    import importlib
    try:
        plugin_module = importlib.import_module(module_name + '.plugin')
    except ImportError:
        plugin_module = importlib.import_module(module_name)

    parser = FakePytestParser()
    try:
        if hasattr(plugin_module, 'pytest_load_initial_conftests'):
            plugin_module.pytest_load_initial_conftests(
                early_config=early_config, parser=parser, args=[])

        if hasattr(plugin_module, 'pytest_configure'):
            import inspect
            if inspect.signature(plugin_module.pytest_configure).parameters:
                plugin_module.pytest_configure(early_config)
            else:
                plugin_module.pytest_configure()
    except Exception:
        hammett.print(f'Loading plugin {module_name} failed: ')
        import traceback
        hammett.print(traceback.format_exc())
        hammett.g.results['abort'] += 1
        hammett.g.should_stop = True
        return
    try:
        importlib.import_module(module_name + '.fixtures')
    except ImportError:
        pass
    return True
示例#2
0
文件: impl.py 项目: rec/hammett
def _teardown_yield_fixture(fixturefunc, it):
    """Executes the teardown of a fixture function by advancing the iterator after the
    yield and ensure the iteration ends (if not it means there is more than one yield in the function)"""
    try:
        next(it)
    except StopIteration:
        pass
    else:
        hammett.print(f"yield_fixture {fixturefunc} function has more than one 'yield'")
        exit(1)
示例#3
0
文件: impl.py 项目: rec/hammett
def inc_test_result(status, _name, _f, duration, stdout, stderr):
    verbose = hammett.g.verbose
    message = MESSAGES[status]['v' if verbose else 's']
    if verbose:
        hammett.print(message + (str(duration) if duration else ''))
    else:
        hammett.print(message, end='', flush=True)

    if hammett.g.fail_fast and status not in ('success', 'skipped'):
        hammett.g.should_stop = True

    filename = _f.__module__.replace('.', os.sep) + '.py'
    assert _name.startswith(_f.__module__)
    _name = _name[len(_f.__module__) + 1:]
    hammett.g.result_db['test_results'][filename][_name] = dict(stdout=stdout, stderr=stderr, status=status)
示例#4
0
def register_fixture(fixture, *args, autouse=False, scope='function'):
    if scope == 'class':
        # hammett does not support class based tests
        return
    assert scope != 'package', 'Package scope is not supported at this time'

    name = fixture_function_name(fixture)
    # pytest uses shadowing.. I don't like it but I guess we have to follow that?
    # assert name not in fixtures, 'A fixture with this name is already registered'
    if hammett.g.verbose and name in fixtures and name != 'request':
        hammett.print(f'{fixture} shadows {fixtures[name]}')
    if autouse:
        auto_use_fixtures.add(name)
    assert scope in ('function', 'class', 'module', 'package', 'session')
    fixture_scope[name] = scope
    fixtures[name] = fixture
示例#5
0
def feedback_for_exception():
    type, value, tb = sys.exc_info()
    while tb.tb_next:
        tb = tb.tb_next

    local_variables = tb.tb_frame.f_locals
    if local_variables:
        hammett.print('--- Local variables ---')
        for k, v in sorted(local_variables.items()):
            hammett.print(f'{k}:')
            try:
                hammett.print(indent(pretty_format(v)))
            except Exception as e:
                hammett.print(f'   Error getting local variable repr: {e}')

    if type == AssertionError:
        analyze_assert(tb)
示例#6
0
def run_test(_name, _f, _module_request, **kwargs):
    if should_skip(_f):
        inc_test_result(SKIPPED, _name, _f, duration=0, stdout='', stderr='')
        return

    from io import StringIO

    req = hammett.Request(scope='function',
                          parent=_module_request,
                          function=_f)

    def request():
        return req

    register_fixture(request, autouse=True)
    del request

    hijacked_stdout = StringIO()
    hijacked_stderr = StringIO()
    prev_stdout = sys.stdout
    prev_stderr = sys.stderr

    status = None
    duration = None
    start = None
    setup_time = None

    if hammett.g.verbose:
        hammett.print(_name + '...', end='', flush=True)
    try:
        sys.stdout = hijacked_stdout
        sys.stderr = hijacked_stderr

        if hammett.g.durations:
            start = datetime.now()

        resolved_function, resolved_kwargs = dependency_injection(_f,
                                                                  fixtures,
                                                                  kwargs,
                                                                  request=req)

        if hammett.g.durations:
            setup_time = datetime.now() - start
            start = datetime.now()

        resolved_function(**resolved_kwargs)

        if hammett.g.durations:
            duration = datetime.now() - start
            hammett.g.durations_results.append((_name, duration, setup_time))

        sys.stdout = prev_stdout
        sys.stderr = prev_stderr
        status = SUCCESS
    except KeyboardInterrupt:
        sys.stdout = prev_stdout
        sys.stderr = prev_stderr

        hammett.print()
        hammett.print('ABORTED')
        hammett.g.results['abort'] += 1
        hammett.g.should_stop = True
    except SkipTest:
        sys.stdout = prev_stdout
        sys.stderr = prev_stderr

        status = SKIPPED
    except:
        sys.stdout = prev_stdout
        sys.stderr = prev_stderr

        hammett.print(RED)
        if not hammett.g.verbose:
            hammett.print()
        hammett.print('Failed:', _name)
        hammett.print()

        import traceback
        hammett.print(traceback.format_exc())

        hammett.print()
        if hijacked_stdout.getvalue():
            hammett.print(YELLOW)
            hammett.print('--- stdout ---')
            hammett.print(hijacked_stdout.getvalue())

        if hijacked_stderr.getvalue():
            hammett.print(RED)
            hammett.print('--- stderr ---')
            hammett.print(hijacked_stderr.getvalue())

        hammett.print(RESET_COLOR)

        if not hammett.g.quiet:
            feedback_for_exception()

        if hammett.g.drop_into_debugger:
            try:
                import ipdb as pdb
            except ImportError:
                import pdb
            pdb.set_trace()

        status = FAILED

    assert status is not None
    inc_test_result(status,
                    _name,
                    _f,
                    duration,
                    stdout=hijacked_stdout.getvalue(),
                    stderr=hijacked_stderr.getvalue())

    # Tests can change this which breaks everything. Reset!
    os.chdir(hammett.g.orig_cwd)
    req.teardown()
示例#7
0
def analyze_assert(tb):
    if hammett.g.disable_assert_analyze:
        return

    # grab assert source line
    try:
        with open(tb.tb_frame.f_code.co_filename) as f:
            source = f.read().split('\n')
    except FileNotFoundError:
        try:
            with open(
                    os.path.join(hammett.g.orig_cwd,
                                 tb.tb_frame.f_code.co_filename)) as f:
                source = f.read().split('\n')
        except FileNotFoundError:
            hammett.print(
                'Failed to analyze assert statement: file not found. Most likely there was a change of current directory.'
            )
            return

    line_no = tb.tb_frame.f_lineno - 1
    relevant_source = source[line_no]

    # if it spans multiple lines grab them all
    while line_no and not relevant_source.strip().startswith('assert '):
        line_no -= 1
        relevant_source = source[line_no] + '\n' + relevant_source

    if not relevant_source.strip().startswith('assert '):
        hammett.print(
            'Failed to analyze assert statement (Did not find the assert)')
        return

    import ast
    try:
        assert_statement = ast.parse(relevant_source.strip()).body[0]
    except SyntaxError:
        try:
            # grab one more line after the the one where we got an exception, and try again
            relevant_source += '\n' + source[tb.tb_frame.f_lineno]
            assert_statement = ast.parse(relevant_source.strip()).body[0]
        except SyntaxError:
            hammett.print('Failed to analyze assert statement (SyntaxError)')
            return

    # We only analyze further if it's a comparison
    if assert_statement.test.__class__.__name__ != 'Compare':
        return

    hammett.print()
    hammett.print('--- Assert components ---')
    from astunparse import unparse
    try:
        left = eval(unparse(assert_statement.test.left), tb.tb_frame.f_globals,
                    tb.tb_frame.f_locals)
        hammett.print('left:')
        hammett.print(indent(pretty_format(left)))
        right = eval(unparse(assert_statement.test.comparators),
                     tb.tb_frame.f_globals, tb.tb_frame.f_locals)
    except Exception as e:
        hammett.print(f'Failed to analyze assert statement ({type(e)}: {e})')
        return
    hammett.print('right:')
    hammett.print(indent(pretty_format(right)))
    if isinstance(left, str) and isinstance(
            right, str) and len(left) > DIFF_STRING_SIZE_CUTOFF and len(
                right) > DIFF_STRING_SIZE_CUTOFF and '\n' in left:
        hammett.print()
        hammett.print('--- Diff of left and right assert components ---')
        left_lines = left.split('\n')
        right_lines = right.split('\n')
        from difflib import unified_diff
        for line in unified_diff(left_lines,
                                 right_lines,
                                 fromfile='expected',
                                 tofile='actual',
                                 lineterm=''):
            color = ''
            if line:
                color = {
                    '+': GREEN,
                    '-': RED,
                    '@': MAGENTA,
                }.get(line[0], '')
            hammett.print(f'{color}{line}{RESET_COLOR}')
示例#8
0
def print_status(_name, result: Result):
    verbose = hammett.g.verbose
    message = MESSAGES[result.status]['v' if verbose else 's']
    if verbose:
        hammett.print(_name + ' ' + message +
                      (str(result.duration) if result.duration else ''))
    else:
        hammett.print(message, end='', flush=True)

    if result.status == FAILED:
        hammett.print(RED)
        if not hammett.g.verbose:
            hammett.print()
        hammett.print('Failed: ', _name)
        hammett.print()

        hammett.print(result.stack_trace)

        hammett.print()
        if result.stdout:
            hammett.print(YELLOW)
            hammett.print('--- stdout ---')
            hammett.print(result.stdout)

        if result.stderr:
            hammett.print(RED)
            hammett.print('--- stderr ---')
            hammett.print(result.stderr)

        hammett.print(RESET_COLOR)

    if result.feedback_for_exception:
        hammett.print(result.feedback_for_exception)