diff options
| author | robot-piglet <[email protected]> | 2026-05-13 08:51:44 +0300 |
|---|---|---|
| committer | robot-piglet <[email protected]> | 2026-05-13 09:43:18 +0300 |
| commit | 21b994f3cab88fade95b9dabe9b1b491627b822d (patch) | |
| tree | e27d9725b1f4f23d6e137c5c115715c1070600df /contrib/python/allure-python-commons/allure_commons | |
| parent | 2e7284b4e24ef8749490a6bb96e6edb645520af1 (diff) | |
Intermediate changes
commit_hash:9dd0a391400eb50723299039cdf1b64398309ddd
Diffstat (limited to 'contrib/python/allure-python-commons/allure_commons')
11 files changed, 220 insertions, 72 deletions
diff --git a/contrib/python/allure-python-commons/allure_commons/__init__.py b/contrib/python/allure-python-commons/allure_commons/__init__.py index 111c2d06c28..e480aceab69 100644 --- a/contrib/python/allure-python-commons/allure_commons/__init__.py +++ b/contrib/python/allure-python-commons/allure_commons/__init__.py @@ -1,12 +1,12 @@ -from allure_commons._hooks import hookimpl # noqa: F401 -from allure_commons._core import plugin_manager # noqa: F401 -from allure_commons._allure import fixture # noqa: F401 -from allure_commons._allure import test # noqa: F401 +from allure_commons._hooks import hookimpl +from allure_commons._core import plugin_manager +from allure_commons._allure import fixture +from allure_commons._allure import test __all__ = [ - 'hookimpl', - 'plugin_manager', - 'fixture', - 'test' + "hookimpl", + "plugin_manager", + "fixture", + "test" ] diff --git a/contrib/python/allure-python-commons/allure_commons/_allure.py b/contrib/python/allure-python-commons/allure_commons/_allure.py index b7bbe2a5e07..607e1cb873b 100644 --- a/contrib/python/allure-python-commons/allure_commons/_allure.py +++ b/contrib/python/allure-python-commons/allure_commons/_allure.py @@ -4,6 +4,7 @@ from typing import Any, Callable, TypeVar, Union, overload from allure_commons._core import plugin_manager from allure_commons.types import LabelType, LinkType, ParameterMode from allure_commons.utils import uuid4 +from allure_commons.utils import format_exception, format_traceback from allure_commons.utils import func_parameters, represent _TFunc = TypeVar("_TFunc", bound=Callable[..., Any]) @@ -125,7 +126,7 @@ class Dynamic: Dynamic.label(LabelType.TAG, *tags) @staticmethod - def id(id): # noqa: A003,A002 + def id(id): # noqa: A002 Dynamic.label(LabelType.ID, id) @staticmethod @@ -216,6 +217,48 @@ class Attach: attach = Attach() +class GlobalAttach: + + def __call__(self, body, name=None, attachment_type=None, extension=None): + plugin_manager.hook.global_attach_data( + body=body, + name=name, + attachment_type=attachment_type, + extension=extension, + ) + + def file(self, source, name=None, attachment_type=None, extension=None): + plugin_manager.hook.global_attach_file( + source=source, + name=name, + attachment_type=attachment_type, + extension=extension, + ) + + +global_attach = GlobalAttach() + + +@overload +def global_error(value: BaseException) -> None: + ... + + +@overload +def global_error(value: str, trace: Union[str, None] = None) -> None: + ... + + +def global_error(value, trace=None): + message = None + if isinstance(value, BaseException): + message = format_exception(type(value), value) + trace = format_traceback(value.__traceback__) + else: + message = value + plugin_manager.hook.global_error(message=message, trace=trace) + + class fixture: def __init__(self, fixture_function, parent_uuid=None, name=None): self._fixture_function = fixture_function diff --git a/contrib/python/allure-python-commons/allure_commons/_core.py b/contrib/python/allure-python-commons/allure_commons/_core.py index 40d9deafb78..8687891cf75 100644 --- a/contrib/python/allure-python-commons/allure_commons/_core.py +++ b/contrib/python/allure-python-commons/allure_commons/_core.py @@ -8,7 +8,7 @@ class MetaPluginManager(type): @staticmethod def get_plugin_manager(): if not MetaPluginManager._plugin_manager: - MetaPluginManager._plugin_manager = PluginManager('allure') + MetaPluginManager._plugin_manager = PluginManager("allure") MetaPluginManager._plugin_manager.add_hookspecs(_hooks.AllureUserHooks) MetaPluginManager._plugin_manager.add_hookspecs(_hooks.AllureDeveloperHooks) diff --git a/contrib/python/allure-python-commons/allure_commons/_hooks.py b/contrib/python/allure-python-commons/allure_commons/_hooks.py index 0ff19a27d3a..84e916d900b 100644 --- a/contrib/python/allure-python-commons/allure_commons/_hooks.py +++ b/contrib/python/allure-python-commons/allure_commons/_hooks.py @@ -66,6 +66,18 @@ class AllureUserHooks: def attach_file(self, source, name, attachment_type, extension): """ attach file """ + @hookspec + def global_attach_data(self, body, name, attachment_type, extension): + """ attach global data """ + + @hookspec + def global_attach_file(self, source, name, attachment_type, extension): + """ attach global file """ + + @hookspec + def global_error(self, message, trace): + """ global error """ + class AllureDeveloperHooks: @@ -100,3 +112,7 @@ class AllureDeveloperHooks: @hookspec def report_attached_data(self, body, file_name): """ reporting """ + + @hookspec + def report_globals(self, globals_item): + """ reporting """ diff --git a/contrib/python/allure-python-commons/allure_commons/lifecycle.py b/contrib/python/allure-python-commons/allure_commons/lifecycle.py index 2e730e2e433..e2c2251ebcf 100644 --- a/contrib/python/allure-python-commons/allure_commons/lifecycle.py +++ b/contrib/python/allure-python-commons/allure_commons/lifecycle.py @@ -4,6 +4,7 @@ from allure_commons._core import plugin_manager from allure_commons.model2 import TestResultContainer from allure_commons.model2 import TestResult from allure_commons.model2 import Attachment, ATTACHMENT_PATTERN +from allure_commons.model2 import GlobalAttachment, GlobalError, Globals from allure_commons.model2 import TestStepResult from allure_commons.model2 import ExecutableItem from allure_commons.model2 import TestBeforeResult @@ -124,14 +125,11 @@ class AllureLifecycle: fixture.stop = now() def _attach(self, uuid, name=None, attachment_type=None, extension=None, parent_uuid=None): - mime_type = attachment_type - extension = extension if extension else 'attach' - - if type(attachment_type) is AttachmentType: - extension = attachment_type.extension - mime_type = attachment_type.mime_type - - file_name = ATTACHMENT_PATTERN.format(prefix=uuid, ext=extension) + file_name, mime_type = self.__resolve_attachment_filename_and_type( + uuid, + attachment_type=attachment_type, + extension=extension, + ) attachment = Attachment(source=file_name, name=name, type=mime_type) last_uuid = parent_uuid if parent_uuid else self._last_item_uuid(ExecutableItem) self._items[last_uuid].attachments.append(attachment) @@ -147,3 +145,41 @@ class AllureLifecycle: file_name = self._attach(uuid, name=name, attachment_type=attachment_type, extension=extension, parent_uuid=parent_uuid) plugin_manager.hook.report_attached_data(body=body, file_name=file_name) + + def global_attach_file(self, uuid, source, name=None, attachment_type=None, extension=None): + file_name, mime_type = self.__resolve_attachment_filename_and_type( + uuid, + attachment_type=attachment_type, + extension=extension, + ) + plugin_manager.hook.report_attached_file(source=source, file_name=file_name) + plugin_manager.hook.report_globals(globals_item=Globals(attachments=[ + GlobalAttachment(source=file_name, name=name, type=mime_type, timestamp=now()) + ])) + + def global_attach_data(self, uuid, body, name=None, attachment_type=None, extension=None): + file_name, mime_type = self.__resolve_attachment_filename_and_type( + uuid, + attachment_type=attachment_type, + extension=extension, + ) + plugin_manager.hook.report_attached_data(body=body, file_name=file_name) + plugin_manager.hook.report_globals(globals_item=Globals(attachments=[ + GlobalAttachment(source=file_name, name=name, type=mime_type, timestamp=now()) + ])) + + def global_error(self, message=None, trace=None): + plugin_manager.hook.report_globals(globals_item=Globals(errors=[ + GlobalError(message=message, trace=trace, timestamp=now()) + ])) + + def __resolve_attachment_filename_and_type(self, uuid, attachment_type=None, extension=None): + mime_type = attachment_type + extension = extension if extension else "attach" + + if type(attachment_type) is AttachmentType: + extension = attachment_type.extension + mime_type = attachment_type.mime_type + + file_name = ATTACHMENT_PATTERN.format(prefix=uuid, ext=extension) + return file_name, mime_type diff --git a/contrib/python/allure-python-commons/allure_commons/logger.py b/contrib/python/allure-python-commons/allure_commons/logger.py index 55f956f2507..4345bc77db0 100644 --- a/contrib/python/allure-python-commons/allure_commons/logger.py +++ b/contrib/python/allure-python-commons/allure_commons/logger.py @@ -22,7 +22,7 @@ class AllureFileLogger: indent = INDENT if os.environ.get("ALLURE_INDENT_OUTPUT") else None filename = item.file_pattern.format(prefix=uuid.uuid4()) data = asdict(item, filter=lambda _, v: v or v is False) - with io.open(self._report_dir / filename, 'w', encoding='utf8') as json_file: + with io.open(self._report_dir / filename, "w", encoding="utf8") as json_file: json.dump(data, json_file, indent=indent, ensure_ascii=False) @hookimpl @@ -41,12 +41,16 @@ class AllureFileLogger: @hookimpl def report_attached_data(self, body, file_name): destination = self._report_dir / file_name - with open(destination, 'wb') as attached_file: + with open(destination, "wb") as attached_file: if isinstance(body, str): - attached_file.write(body.encode('utf-8')) + attached_file.write(body.encode("utf-8")) else: attached_file.write(body) + @hookimpl + def report_globals(self, globals_item): + self._report_item(globals_item) + class AllureMemoryLogger: @@ -54,6 +58,7 @@ class AllureMemoryLogger: self.test_cases = [] self.test_containers = [] self.attachments = {} + self.globals = [] @hookimpl def report_result(self, result): @@ -72,3 +77,8 @@ class AllureMemoryLogger: @hookimpl def report_attached_data(self, body, file_name): self.attachments[file_name] = body + + @hookimpl + def report_globals(self, globals_item): + data = asdict(globals_item, filter=lambda _, v: v or v is False) + self.globals.append(data) diff --git a/contrib/python/allure-python-commons/allure_commons/mapping.py b/contrib/python/allure-python-commons/allure_commons/mapping.py index 737d3390a46..0cd099f0c3b 100644 --- a/contrib/python/allure-python-commons/allure_commons/mapping.py +++ b/contrib/python/allure-python-commons/allure_commons/mapping.py @@ -20,7 +20,7 @@ def allure_tag_sep(tag): def __is(kind, t): - return kind in [v for k, v in t.__dict__.items() if not k.startswith('__')] + return kind in [v for k, v in t.__dict__.items() if not k.startswith("__")] def parse_tag(tag, issue_pattern=None, link_pattern=None): @@ -51,7 +51,7 @@ def parse_tag(tag, issue_pattern=None, link_pattern=None): """ sep = allure_tag_sep(tag) schema, value = islice(chain(tag.split(sep, 1), [None]), 2) - prefix, kind, name = islice(chain(schema.split('.'), [None], [None]), 3) + prefix, kind, name = islice(chain(schema.split("."), [None], [None]), 3) if tag in [severity for severity in Severity]: return Label(name=LabelType.SEVERITY, value=tag) diff --git a/contrib/python/allure-python-commons/allure_commons/model2.py b/contrib/python/allure-python-commons/allure_commons/model2.py index d8591598533..cd069b176fd 100644 --- a/contrib/python/allure-python-commons/allure_commons/model2.py +++ b/contrib/python/allure-python-commons/allure_commons/model2.py @@ -4,7 +4,8 @@ from attr import Factory TEST_GROUP_PATTERN = "{prefix}-container.json" TEST_CASE_PATTERN = "{prefix}-result.json" -ATTACHMENT_PATTERN = '{prefix}-attachment.{ext}' +ATTACHMENT_PATTERN = "{prefix}-attachment.{ext}" +GLOBALS_PATTERN = "{prefix}-globals.json" INDENT = 4 @@ -54,7 +55,7 @@ class TestResult(ExecutableItem): @attrs class TestStepResult(ExecutableItem): - id = attrib(default=None) # noqa: A003 + id = attrib(default=None) @attrs @@ -83,7 +84,7 @@ class Label: @attrs class Link: - type = attrib(default=None) # noqa: A003 + type = attrib(default=None) url = attrib(default=None) name = attrib(default=None) @@ -100,12 +101,30 @@ class StatusDetails: class Attachment: name = attrib(default=None) source = attrib(default=None) - type = attrib(default=None) # noqa: A003 + type = attrib(default=None) + + +@attrs +class GlobalAttachment(Attachment): + timestamp = attrib(default=None) + + +@attrs +class GlobalError(StatusDetails): + timestamp = attrib(default=None) + + +@attrs +class Globals: + file_pattern = GLOBALS_PATTERN + + attachments = attrib(default=Factory(list)) + errors = attrib(default=Factory(list)) class Status: - FAILED = 'failed' - BROKEN = 'broken' - PASSED = 'passed' - SKIPPED = 'skipped' - UNKNOWN = 'unknown' + FAILED = "failed" + BROKEN = "broken" + PASSED = "passed" + SKIPPED = "skipped" + UNKNOWN = "unknown" diff --git a/contrib/python/allure-python-commons/allure_commons/reporter.py b/contrib/python/allure-python-commons/allure_commons/reporter.py index 2e1f4a89d3a..7e7b7594e77 100644 --- a/contrib/python/allure-python-commons/allure_commons/reporter.py +++ b/contrib/python/allure-python-commons/allure_commons/reporter.py @@ -5,6 +5,7 @@ from allure_commons.types import AttachmentType from allure_commons.model2 import ExecutableItem from allure_commons.model2 import TestResult from allure_commons.model2 import Attachment, ATTACHMENT_PATTERN +from allure_commons.model2 import GlobalAttachment, GlobalError, Globals from allure_commons.utils import now from allure_commons._core import plugin_manager @@ -140,14 +141,7 @@ class AllureReporter: self._items.pop(uuid) def _attach(self, uuid, name=None, attachment_type=None, extension=None, parent_uuid=None): - mime_type = attachment_type - extension = extension if extension else 'attach' - - if type(attachment_type) is AttachmentType: - extension = attachment_type.extension - mime_type = attachment_type.mime_type - - file_name = ATTACHMENT_PATTERN.format(prefix=uuid, ext=extension) + file_name, mime_type = self.__resolve_attachment_filename_and_type(uuid, attachment_type, extension) attachment = Attachment(source=file_name, name=name, type=mime_type) last_uuid = parent_uuid if parent_uuid else self._last_executable() self._items[last_uuid].attachments.append(attachment) @@ -163,3 +157,33 @@ class AllureReporter: file_name = self._attach(uuid, name=name, attachment_type=attachment_type, extension=extension, parent_uuid=parent_uuid) plugin_manager.hook.report_attached_data(body=body, file_name=file_name) + + def global_attach_file(self, uuid, source, name=None, attachment_type=None, extension=None): + file_name, mime_type = self.__resolve_attachment_filename_and_type(uuid, attachment_type, extension) + plugin_manager.hook.report_attached_file(source=source, file_name=file_name) + plugin_manager.hook.report_globals(globals_item=Globals(attachments=[ + GlobalAttachment(source=file_name, name=name, type=mime_type, timestamp=now()) + ])) + + def global_attach_data(self, uuid, body, name=None, attachment_type=None, extension=None): + file_name, mime_type = self.__resolve_attachment_filename_and_type(uuid, attachment_type, extension) + plugin_manager.hook.report_attached_data(body=body, file_name=file_name) + plugin_manager.hook.report_globals(globals_item=Globals(attachments=[ + GlobalAttachment(source=file_name, name=name, type=mime_type, timestamp=now()) + ])) + + def global_error(self, message=None, trace=None): + plugin_manager.hook.report_globals(globals_item=Globals(errors=[ + GlobalError(message=message, trace=trace, timestamp=now()) + ])) + + def __resolve_attachment_filename_and_type(self, uuid, attachment_type=None, extension=None): + mime_type = attachment_type + extension = extension if extension else "attach" + + if type(attachment_type) is AttachmentType: + extension = attachment_type.extension + mime_type = attachment_type.mime_type + + file_name = ATTACHMENT_PATTERN.format(prefix=uuid, ext=extension) + return file_name, mime_type diff --git a/contrib/python/allure-python-commons/allure_commons/types.py b/contrib/python/allure-python-commons/allure_commons/types.py index 1db7fd512f7..43b8d5edfda 100644 --- a/contrib/python/allure-python-commons/allure_commons/types.py +++ b/contrib/python/allure-python-commons/allure_commons/types.py @@ -1,37 +1,37 @@ from enum import Enum -ALLURE_UNIQUE_LABELS = ['severity', 'thread', 'host'] +ALLURE_UNIQUE_LABELS = ["severity", "thread", "host"] class Severity(str, Enum): - BLOCKER = 'blocker' - CRITICAL = 'critical' - NORMAL = 'normal' - MINOR = 'minor' - TRIVIAL = 'trivial' + BLOCKER = "blocker" + CRITICAL = "critical" + NORMAL = "normal" + MINOR = "minor" + TRIVIAL = "trivial" class LinkType: - LINK = 'link' - ISSUE = 'issue' - TEST_CASE = 'tms' + LINK = "link" + ISSUE = "issue" + TEST_CASE = "tms" class LabelType(str): - EPIC = 'epic' - FEATURE = 'feature' - STORY = 'story' - PARENT_SUITE = 'parentSuite' - SUITE = 'suite' - SUB_SUITE = 'subSuite' - SEVERITY = 'severity' - THREAD = 'thread' - HOST = 'host' - TAG = 'tag' - ID = 'as_id' - FRAMEWORK = 'framework' - LANGUAGE = 'language' - MANUAL = 'ALLURE_MANUAL' + EPIC = "epic" + FEATURE = "feature" + STORY = "story" + PARENT_SUITE = "parentSuite" + SUITE = "suite" + SUB_SUITE = "subSuite" + SEVERITY = "severity" + THREAD = "thread" + HOST = "host" + TAG = "tag" + ID = "as_id" + FRAMEWORK = "framework" + LANGUAGE = "language" + MANUAL = "ALLURE_MANUAL" class AttachmentType(Enum): @@ -67,6 +67,6 @@ class AttachmentType(Enum): class ParameterMode(Enum): - HIDDEN = 'hidden' - MASKED = 'masked' + HIDDEN = "hidden" + MASKED = "masked" DEFAULT = None diff --git a/contrib/python/allure-python-commons/allure_commons/utils.py b/contrib/python/allure-python-commons/allure_commons/utils.py index 5ba0d3775b7..c50cb7ecbd3 100644 --- a/contrib/python/allure-python-commons/allure_commons/utils.py +++ b/contrib/python/allure-python-commons/allure_commons/utils.py @@ -21,7 +21,7 @@ def md5(*args): if not isinstance(arg, bytes): if not isinstance(arg, str): arg = repr(arg) - arg = arg.encode('utf-8') + arg = arg.encode("utf-8") m.update(arg) return m.hexdigest() @@ -37,11 +37,11 @@ def now(): def platform_label(): major_version, *_ = platform.python_version_tuple() implementation = platform.python_implementation().lower() - return f'{implementation}{major_version}' + return f"{implementation}{major_version}" def thread_tag(): - return '{0}-{1}'.format(os.getpid(), threading.current_thread().name) + return "{0}-{1}".format(os.getpid(), threading.current_thread().name) def host_tag(): @@ -241,7 +241,7 @@ def func_parameters(func, *args, **kwargs): varargs = args[len(arg_spec.args):] parameters.update({arg_spec.varargs: varargs} if varargs else {}) - if arg_spec.args and arg_spec.args[0] in ['cls', 'self']: + if arg_spec.args and arg_spec.args[0] in ["cls", "self"]: args_dict.pop(arg_spec.args[0], None) if kwargs: @@ -269,7 +269,7 @@ def func_parameters(func, *args, **kwargs): def format_traceback(exc_traceback): - return ''.join(traceback.format_tb(exc_traceback)) if exc_traceback else None + return "".join(traceback.format_tb(exc_traceback)) if exc_traceback else None def format_exception(etype, value): @@ -320,7 +320,7 @@ def format_exception(etype, value): ... format_exception(etype, e) # doctest: +ELLIPSIS "AssertionError: \\nExpected:...but:..." """ - return '\n'.join(format_exception_only(etype, value)) if etype or value else None + return "\n".join(format_exception_only(etype, value)) if etype or value else None def get_testplan(): @@ -328,7 +328,7 @@ def get_testplan(): file_path = os.environ.get("ALLURE_TESTPLAN_PATH") if file_path and os.path.exists(file_path): - with open(file_path, 'r') as plan_file: + with open(file_path, "r") as plan_file: plan = json.load(plan_file) planned_tests = plan.get("tests", []) |
