<commit_before>import pytest

from allure.utils import now
from allure.utils import md5
from allure.utils import uuid4
from allure.logger import AllureLogger
from allure.model2 import TestStepResult, TestResult, TestBeforeResult, TestAfterResult
from allure.model2 import TestResultContainer
from allure.model2 import StatusDetails
from allure.model2 import Parameter
from allure.model2 import Label, Link
from allure.model2 import Status

from allure_pytest.utils import allure_parameters
from allure_pytest.utils import allure_labels, allure_links
from allure_pytest.utils import allure_full_name, allure_package


class AllureListener(object):

    def __init__(self, config):
        self.config = config
        self.allure_logger = AllureLogger(config.option.allure_report_dir)
        self._cache = ItemCache()

    @pytest.hookimpl
    def pytest_allure_before_step(self, uuid, title, params):
        parameters = [Parameter(name=name, value=value) for name, value in params]
        step = TestStepResult(name=title, start=now(), parameters=parameters)
        self.allure_logger.start_step(None, uuid, step)

    @pytest.hookimpl
    def pytest_allure_after_step(self, uuid, exc_type, exc_val, exc_tb):
        status = Status.PASSED
        if exc_type is not None:
            if exc_type == pytest.skip.Exception:
                status = Status.SKIPPED
            else:
                status = Status.FAILED

        self.allure_logger.stop_step(uuid, stop=now(), status=status)

    @pytest.hookimpl
    def pytest_allure_before_finalizer(self, parent_uuid, uuid, name):
        after_fixture = TestAfterResult(name=name, start=now())
        self.allure_logger.start_after_fixture(parent_uuid, uuid, after_fixture)

    @pytest.hookimpl
    def pytest_allure_after_finalizer(self, uuid, exc_type, exc_val, exc_tb):
        self.allure_logger.stop_after_fixture(uuid, stop=now())

    @pytest.hookimpl(hookwrapper=True, tryfirst=True)
    def pytest_runtest_protocol(self, item, nextitem):
        uuid = self._cache.set(item.nodeid)
        for fixturedef in _test_fixtures(item):
            group_uuid = self._cache.get(fixturedef)
            if not group_uuid:
                group_uuid = self._cache.set(fixturedef)
                group = TestResultContainer(uuid=group_uuid)
                self.allure_logger.start_group(group_uuid, group)
            self.allure_logger.update_group(group_uuid, children=uuid)

        test_case = TestResult(name=item.name, uuid=uuid)
        self.allure_logger.schedule_test(uuid, test_case)

        yield

        test_case.labels = [Label(name, value) for name, value in allure_labels(item)]
        test_case.links = [Link(link_type, url, name) for link_type, url, name in allure_links(item)]
        test_case.fullName = allure_full_name(item.nodeid)
        test_case.historyId = md5(test_case.fullName)
        test_case.labels.append(Label('package', allure_package(item.nodeid)))

        uuid = self._cache.pop(item.nodeid)
        self.allure_logger.close_test(uuid)

    @pytest.hookimpl(hookwrapper=True)
    def pytest_runtest_call(self, item):
        uuid = self._cache.get(item.nodeid)
        self.allure_logger.update_test(uuid, start=now())
        yield
        self.allure_logger.update_test(uuid, stop=now())

    @pytest.hookimpl(hookwrapper=True)
    def pytest_fixture_setup(self, fixturedef, request):
        fixture_name = fixturedef.argname

        container_uuid = self._cache.get(fixturedef)

        if not container_uuid:
            container_uuid = self._cache.set(fixturedef)
            container = TestResultContainer(uuid=container_uuid)
            self.allure_logger.start_group(container_uuid, container)

        self.allure_logger.update_group(container_uuid, start=now())

        before_fixture_uuid = uuid4
        before_fixture = TestBeforeResult(name=fixture_name, start=now())
        self.allure_logger.start_before_fixture(container_uuid, before_fixture_uuid, before_fixture)

        parameters = allure_parameters(fixturedef, request)
        if parameters:
            test_uuid = self._cache.get(request._pyfuncitem.nodeid)
            parameters = Parameter(**parameters) if parameters else []
            self.allure_logger.update_test(test_uuid, parameters=parameters)

        yield

        self.allure_logger.stop_before_fixture(before_fixture_uuid, stop=now())

        for index, finalizer in enumerate(fixturedef._finalizer or ()):
            fixturedef._finalizer[index] = FinalizerSpy(container_uuid, fixturedef.argname, finalizer, self.config)

    @pytest.hookimpl(hookwrapper=True)
    def pytest_fixture_post_finalizer(self, fixturedef):
        yield
        if hasattr(fixturedef, 'cached_result') and self._cache.get(fixturedef):
            container_uuid = self._cache.pop(fixturedef)
            self.allure_logger.stop_group(container_uuid, stop=now())

    @pytest.hookimpl(hookwrapper=True)
    def pytest_runtest_makereport(self, item, call):
        uuid = self._cache.set(item.nodeid)
        report = (yield).get_result()
        allure_item = self.allure_logger.get_item(uuid)
        status = allure_item.status or None
        status_details = None

        if call.excinfo and hasattr(call.excinfo.value, 'msg'):
            status_details = StatusDetails(message=call.excinfo.value.msg)
        elif hasattr(report, 'wasxfail'):
            status_details = StatusDetails(message=report.wasxfail)
        elif report.failed:
            status_details = StatusDetails(message=str(call.excinfo.exconly()), trace=str(report.longrepr))

        if report.when == 'setup':
            if report.passed:
                status = Status.PASSED
            if report.failed:
                status = Status.BROKEN
            if report.skipped:
                status = Status.SKIPPED

        if report.when == 'call':
            if report.passed and status == Status.PASSED:
                pass
            if report.failed:
                status = Status.FAILED
            if report.skipped:
                status = Status.SKIPPED

        if report.when == 'teardown':<commit_msg>Support for non-ascii symbols in stacktrace and failure message (fixes #77 via #78)<commit_after>import pytest

from allure.utils import now
from allure.utils import md5
from allure.utils import uuid4
from allure.logger import AllureLogger
from allure.model2 import TestStepResult, TestResult, TestBeforeResult, TestAfterResult
from allure.model2 import TestResultContainer
from allure.model2 import StatusDetails
from allure.model2 import Parameter
from allure.model2 import Label, Link
from allure.model2 import Status

from allure_pytest.utils import allure_parameters
from allure_pytest.utils import allure_labels, allure_links
from allure_pytest.utils import allure_full_name, allure_package


class AllureListener(object):

    def __init__(self, config):
        self.config = config
        self.allure_logger = AllureLogger(config.option.allure_report_dir)
        self._cache = ItemCache()

    @pytest.hookimpl
    def pytest_allure_before_step(self, uuid, title, params):
        parameters = [Parameter(name=name, value=value) for name, value in params]
        step = TestStepResult(name=title, start=now(), parameters=parameters)
        self.allure_logger.start_step(None, uuid, step)

    @pytest.hookimpl
    def pytest_allure_after_step(self, uuid, exc_type, exc_val, exc_tb):
        status = Status.PASSED
        if exc_type is not None:
            if exc_type == pytest.skip.Exception:
                status = Status.SKIPPED
            else:
                status = Status.FAILED

        self.allure_logger.stop_step(uuid, stop=now(), status=status)

    @pytest.hookimpl
    def pytest_allure_before_finalizer(self, parent_uuid, uuid, name):
        after_fixture = TestAfterResult(name=name, start=now())
        self.allure_logger.start_after_fixture(parent_uuid, uuid, after_fixture)

    @pytest.hookimpl
    def pytest_allure_after_finalizer(self, uuid, exc_type, exc_val, exc_tb):
        self.allure_logger.stop_after_fixture(uuid, stop=now())

    @pytest.hookimpl(hookwrapper=True, tryfirst=True)
    def pytest_runtest_protocol(self, item, nextitem):
        uuid = self._cache.set(item.nodeid)
        for fixturedef in _test_fixtures(item):
            group_uuid = self._cache.get(fixturedef)
            if not group_uuid:
                group_uuid = self._cache.set(fixturedef)
                group = TestResultContainer(uuid=group_uuid)
                self.allure_logger.start_group(group_uuid, group)
            self.allure_logger.update_group(group_uuid, children=uuid)

        test_case = TestResult(name=item.name, uuid=uuid)
        self.allure_logger.schedule_test(uuid, test_case)

        yield

        test_case.labels = [Label(name, value) for name, value in allure_labels(item)]
        test_case.links = [Link(link_type, url, name) for link_type, url, name in allure_links(item)]
        test_case.fullName = allure_full_name(item.nodeid)
        test_case.historyId = md5(test_case.fullName)
        test_case.labels.append(Label('package', allure_package(item.nodeid)))

        uuid = self._cache.pop(item.nodeid)
        self.allure_logger.close_test(uuid)

    @pytest.hookimpl(hookwrapper=True)
    def pytest_runtest_call(self, item):
        uuid = self._cache.get(item.nodeid)
        self.allure_logger.update_test(uuid, start=now())
        yield
        self.allure_logger.update_test(uuid, stop=now())

    @pytest.hookimpl(hookwrapper=True)
    def pytest_fixture_setup(self, fixturedef, request):
        fixture_name = fixturedef.argname

        container_uuid = self._cache.get(fixturedef)

        if not container_uuid:
            container_uuid = self._cache.set(fixturedef)
            container = TestResultContainer(uuid=container_uuid)
            self.allure_logger.start_group(container_uuid, container)

        self.allure_logger.update_group(container_uuid, start=now())

        before_fixture_uuid = uuid4
        before_fixture = TestBeforeResult(name=fixture_name, start=now())
        self.allure_logger.start_before_fixture(container_uuid, before_fixture_uuid, before_fixture)

        parameters = allure_parameters(fixturedef, request)
        if parameters:
            test_uuid = self._cache.get(request._pyfuncitem.nodeid)
            parameters = Parameter(**parameters) if parameters else []
            self.allure_logger.update_test(test_uuid, parameters=parameters)

        yield

        self.allure_logger.stop_before_fixture(before_fixture_uuid, stop=now())

        for index, finalizer in enumerate(fixturedef._finalizer or ()):
            fixturedef._finalizer[index] = FinalizerSpy(container_uuid, fixturedef.argname, finalizer, self.config)

    @pytest.hookimpl(hookwrapper=True)
    def pytest_fixture_post_finalizer(self, fixturedef):
        yield
        if hasattr(fixturedef, 'cached_result') and self._cache.get(fixturedef):
            container_uuid = self._cache.pop(fixturedef)
            self.allure_logger.stop_group(container_uuid, stop=now())

    @pytest.hookimpl(hookwrapper=True)
    def pytest_runtest_makereport(self, item, call):
        uuid = self._cache.set(item.nodeid)
        report = (yield).get_result()
        allure_item = self.allure_logger.get_item(uuid)
        status = allure_item.status or None
        status_details = None

        if call.excinfo and hasattr(call.excinfo.value, 'msg'):
            status_details = StatusDetails(message=call.excinfo.value.msg)
        elif hasattr(report, 'wasxfail'):
            status_details = StatusDetails(message=report.wasxfail)
        elif report.failed:
            status_details = StatusDetails(message=call.excinfo.exconly(), trace=report.longreprtext)

        if report.when == 'setup':
            if report.passed:
                status = Status.PASSED
            if report.failed:
                status = Status.BROKEN
            if report.skipped:
                status = Status.SKIPPED

        if report.when == 'call':
            if report.passed and status == Status.PASSED:
                pass
            if report.failed:
                status = Status.FAILED
            if report.skipped:
                status = Status.SKIPPED

        if report.when == 'teardown':
{'fraction_non_alphanumeric': 0.08823529411764706, 'fraction_numerical': 0.0019445794846864365, 'mean_word_length': 3.052199606040709, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6692356', 'n_tokens_mistral': 3741, 'n_tokens_neox': 3750, 'n_words': 703}