Skip to content

Commit b162be9

Browse files
committed
Data model type hints
- Type hints on common data models - Standardised internal types to string-based enums - Updated `ParameterMode.DEFAULT` from `None` to `"default"` - Updated `ALLURE_UNIQUE_LABELS` to use `LabelType` values - Introduced missing 'Stage' enum - Corrected `TestResult` to initialise with required UUID
1 parent 2031724 commit b162be9

File tree

6 files changed

+92
-69
lines changed

6 files changed

+92
-69
lines changed

allure-python-commons/src/allure_commons/lifecycle.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ def _last_item_uuid(self, item_type=None):
3535

3636
@contextmanager
3737
def schedule_test_case(self, uuid=None):
38-
test_result = TestResult()
39-
test_result.uuid = uuid or uuid4()
38+
test_result = TestResult(uuid=uuid or uuid4())
4039
self._items[test_result.uuid] = test_result
4140
yield test_result
4241

allure-python-commons/src/allure_commons/logger.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,20 @@
44
import json
55
import uuid
66
import shutil
7+
from enum import Enum
78
from attr import asdict
89
from allure_commons import hookimpl
910

1011
INDENT = 4
1112

1213

14+
def _enum_value_serializer(inst, field, value):
15+
"""Convert enum values to their string representation for serialization."""
16+
if isinstance(value, Enum):
17+
return value.value
18+
return value
19+
20+
1321
class AllureFileLogger:
1422

1523
def __init__(self, report_dir, clean=False):
@@ -21,7 +29,7 @@ def __init__(self, report_dir, clean=False):
2129
def _report_item(self, item):
2230
indent = INDENT if os.environ.get("ALLURE_INDENT_OUTPUT") else None
2331
filename = item.file_pattern.format(prefix=uuid.uuid4())
24-
data = asdict(item, filter=lambda _, v: v or v is False)
32+
data = asdict(item, filter=lambda _, v: v or v is False, value_serializer=_enum_value_serializer)
2533
with io.open(self._report_dir / filename, 'w', encoding='utf8') as json_file:
2634
json.dump(data, json_file, indent=indent, ensure_ascii=False)
2735

@@ -57,12 +65,12 @@ def __init__(self):
5765

5866
@hookimpl
5967
def report_result(self, result):
60-
data = asdict(result, filter=lambda _, v: v or v is False)
68+
data = asdict(result, filter=lambda _, v: v or v is False, value_serializer=_enum_value_serializer)
6169
self.test_cases.append(data)
6270

6371
@hookimpl
6472
def report_container(self, container):
65-
data = asdict(container, filter=lambda _, v: v or v is False)
73+
data = asdict(container, filter=lambda _, v: v or v is False, value_serializer=_enum_value_serializer)
6674
self.test_containers.append(data)
6775

6876
@hookimpl

allure-python-commons/src/allure_commons/mapping.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def __is(kind, t):
2626
def parse_tag(tag, issue_pattern=None, link_pattern=None):
2727
"""
2828
>>> parse_tag("blocker")
29-
Label(name='severity', value='blocker')
29+
Label(name=<LabelType.SEVERITY: 'severity'>, value='blocker')
3030
3131
>>> parse_tag("allure.issue:http://example.com/BUG-42")
3232
Link(type='issue', url='http://example.com/BUG-42', name='http://example.com/BUG-42')
@@ -44,10 +44,10 @@ def parse_tag(tag, issue_pattern=None, link_pattern=None):
4444
Label(name='owner', value='me')
4545
4646
>>> parse_tag("foo.label:1")
47-
Label(name='tag', value='foo.label:1')
47+
Label(name=<LabelType.TAG: 'tag'>, value='foo.label:1')
4848
4949
>>> parse_tag("allure.foo:1")
50-
Label(name='tag', value='allure.foo:1')
50+
Label(name=<LabelType.TAG: 'tag'>, value='allure.foo:1')
5151
"""
5252
sep = allure_tag_sep(tag)
5353
schema, value = islice(chain(tag.split(sep, 1), [None]), 2)
@@ -82,7 +82,7 @@ def labels_set(labels):
8282
>>> labels_set([Label(name=LabelType.SEVERITY, value=Severity.NORMAL),
8383
... Label(name=LabelType.SEVERITY, value=Severity.BLOCKER)
8484
... ])
85-
[Label(name='severity', value=<Severity.BLOCKER: 'blocker'>)]
85+
[Label(name=<LabelType.SEVERITY: 'severity'>, value=<Severity.BLOCKER: 'blocker'>)]
8686
8787
>>> labels_set([Label(name=LabelType.SEVERITY, value=Severity.NORMAL),
8888
... Label(name='severity', value='minor')
@@ -92,12 +92,12 @@ def labels_set(labels):
9292
>>> labels_set([Label(name=LabelType.EPIC, value="Epic"),
9393
... Label(name=LabelType.EPIC, value="Epic")
9494
... ])
95-
[Label(name='epic', value='Epic')]
95+
[Label(name=<LabelType.EPIC: 'epic'>, value='Epic')]
9696
9797
>>> labels_set([Label(name=LabelType.EPIC, value="Epic1"),
9898
... Label(name=LabelType.EPIC, value="Epic2")
9999
... ])
100-
[Label(name='epic', value='Epic1'), Label(name='epic', value='Epic2')]
100+
[Label(name=<LabelType.EPIC: 'epic'>, value='Epic1'), Label(name=<LabelType.EPIC: 'epic'>, value='Epic2')]
101101
"""
102102
class Wl:
103103
def __init__(self, label):
Lines changed: 59 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
from __future__ import annotations
2+
3+
from enum import Enum
4+
15
from attr import attrs, attrib
26
from attr import Factory
37

8+
from allure_commons.types import AttachmentType, LabelType, LinkType, ParameterMode
49

510
TEST_GROUP_PATTERN = "{prefix}-container.json"
611
TEST_CASE_PATTERN = "{prefix}-result.json"
@@ -12,49 +17,49 @@
1217
class TestResultContainer:
1318
file_pattern = TEST_GROUP_PATTERN
1419

15-
uuid = attrib(default=None)
16-
name = attrib(default=None)
17-
children = attrib(default=Factory(list))
18-
description = attrib(default=None)
19-
descriptionHtml = attrib(default=None)
20-
befores = attrib(default=Factory(list))
21-
afters = attrib(default=Factory(list))
22-
links = attrib(default=Factory(list))
23-
start = attrib(default=None)
24-
stop = attrib(default=None)
20+
uuid: str = attrib(default=None)
21+
name: str | None = attrib(default=None)
22+
children: list[str] = attrib(default=Factory(list))
23+
description: str | None = attrib(default=None)
24+
descriptionHtml: str | None = attrib(default=None)
25+
befores: list[TestBeforeResult] = attrib(default=Factory(list))
26+
afters: list[TestAfterResult] = attrib(default=Factory(list))
27+
links: list[Link] = attrib(default=Factory(list))
28+
start: int | None = attrib(default=None)
29+
stop: int | None = attrib(default=None)
2530

2631

2732
@attrs
2833
class ExecutableItem:
29-
name = attrib(default=None)
30-
status = attrib(default=None)
31-
statusDetails = attrib(default=None)
32-
stage = attrib(default=None)
33-
description = attrib(default=None)
34-
descriptionHtml = attrib(default=None)
35-
steps = attrib(default=Factory(list))
36-
attachments = attrib(default=Factory(list))
37-
parameters = attrib(default=Factory(list))
38-
start = attrib(default=None)
39-
stop = attrib(default=None)
34+
name: str | None = attrib(default=None)
35+
status: Status | None = attrib(default=None)
36+
statusDetails: StatusDetails | None = attrib(default=None)
37+
stage: Stage | None = attrib(default=None)
38+
description: str | None = attrib(default=None)
39+
descriptionHtml: str | None = attrib(default=None)
40+
steps: list[TestStepResult] = attrib(default=Factory(list))
41+
attachments: list[Attachment] = attrib(default=Factory(list))
42+
parameters: list[Parameter] = attrib(default=Factory(list))
43+
start: int | None = attrib(default=None)
44+
stop: int | None = attrib(default=None)
4045

4146

4247
@attrs
4348
class TestResult(ExecutableItem):
4449
file_pattern = TEST_CASE_PATTERN
4550

46-
uuid = attrib(default=None)
47-
historyId = attrib(default=None)
48-
testCaseId = attrib(default=None)
49-
fullName = attrib(default=None)
50-
labels = attrib(default=Factory(list))
51-
links = attrib(default=Factory(list))
52-
titlePath = attrib(default=Factory(list))
51+
uuid: str = attrib(default=None)
52+
historyId: str | None = attrib(default=None)
53+
testCaseId: str | None = attrib(default=None)
54+
fullName: str | None = attrib(default=None)
55+
labels: list[Label] = attrib(default=Factory(list))
56+
links: list[Link] = attrib(default=Factory(list))
57+
titlePath: list[str] = attrib(default=Factory(list))
5358

5459

5560
@attrs
5661
class TestStepResult(ExecutableItem):
57-
id = attrib(default=None) # noqa: A003
62+
id: str | None = attrib(default=None) # noqa: A003
5863

5964

6065
@attrs
@@ -69,43 +74,51 @@ class TestAfterResult(ExecutableItem):
6974

7075
@attrs
7176
class Parameter:
72-
name = attrib(default=None)
73-
value = attrib(default=None)
74-
excluded = attrib(default=None)
75-
mode = attrib(default=None)
77+
name: str = attrib(default=None)
78+
value: str = attrib(default=None)
79+
excluded: bool | None = attrib(default=None)
80+
mode: ParameterMode | None = attrib(default=None)
7681

7782

7883
@attrs
7984
class Label:
80-
name = attrib(default=None)
81-
value = attrib(default=None)
85+
name: LabelType | str = attrib(default=None)
86+
value: str = attrib(default=None)
8287

8388

8489
@attrs
8590
class Link:
86-
type = attrib(default=None) # noqa: A003
87-
url = attrib(default=None)
88-
name = attrib(default=None)
91+
type: LinkType | str | None = attrib(default=None) # noqa: A003
92+
url: str = attrib(default=None)
93+
name: str | None = attrib(default=None)
8994

9095

9196
@attrs
9297
class StatusDetails:
93-
known = attrib(default=None)
94-
flaky = attrib(default=None)
95-
message = attrib(default=None)
96-
trace = attrib(default=None)
98+
known: bool | None = attrib(default=None)
99+
flaky: bool | None = attrib(default=None)
100+
message: str | None = attrib(default=None)
101+
trace: str | None = attrib(default=None)
97102

98103

99104
@attrs
100105
class Attachment:
101-
name = attrib(default=None)
102-
source = attrib(default=None)
103-
type = attrib(default=None) # noqa: A003
106+
name: str = attrib(default=None)
107+
source: str = attrib(default=None)
108+
type: AttachmentType | str | None = attrib(default=None) # noqa: A003
104109

105110

106-
class Status:
111+
class Status(str, Enum):
107112
FAILED = 'failed'
108113
BROKEN = 'broken'
109114
PASSED = 'passed'
110115
SKIPPED = 'skipped'
111116
UNKNOWN = 'unknown'
117+
118+
119+
class Stage(str, Enum):
120+
SCHEDULED = "scheduled"
121+
RUNNING = "running"
122+
FINISHED = "finished"
123+
PENDING = "pending"
124+
INTERRUPTED = "interrupted"

allure-python-commons/src/allure_commons/types.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from enum import Enum
1+
from __future__ import annotations
22

3-
ALLURE_UNIQUE_LABELS = ['severity', 'thread', 'host']
3+
from enum import Enum
44

55

66
class Severity(str, Enum):
@@ -11,13 +11,13 @@ class Severity(str, Enum):
1111
TRIVIAL = 'trivial'
1212

1313

14-
class LinkType:
14+
class LinkType(str, Enum):
1515
LINK = 'link'
1616
ISSUE = 'issue'
1717
TEST_CASE = 'tms'
1818

1919

20-
class LabelType(str):
20+
class LabelType(str, Enum):
2121
EPIC = 'epic'
2222
FEATURE = 'feature'
2323
STORY = 'story'
@@ -34,9 +34,12 @@ class LabelType(str):
3434
MANUAL = 'ALLURE_MANUAL'
3535

3636

37+
ALLURE_UNIQUE_LABELS = [LabelType.SEVERITY, LabelType.THREAD, LabelType.HOST]
38+
39+
3740
class AttachmentType(Enum):
3841

39-
def __init__(self, mime_type, extension):
42+
def __init__(self, mime_type: str, extension: str) -> None:
4043
self.mime_type = mime_type
4144
self.extension = extension
4245

@@ -66,7 +69,7 @@ def __init__(self, mime_type, extension):
6669
PDF = ("application/pdf", "pdf")
6770

6871

69-
class ParameterMode(Enum):
72+
class ParameterMode(str, Enum):
7073
HIDDEN = 'hidden'
7174
MASKED = 'masked'
72-
DEFAULT = None
75+
DEFAULT = 'default'

allure-robotframework/src/listener/utils.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ def get_allure_parameters(parameters):
2626
def get_allure_suites(longname):
2727
"""
2828
>>> get_allure_suites('Suite1.Test')
29-
[Label(name='suite', value='Suite1')]
29+
[Label(name=<LabelType.SUITE: 'suite'>, value='Suite1')]
3030
>>> get_allure_suites('Suite1.Suite2.Test') # doctest: +NORMALIZE_WHITESPACE
31-
[Label(name='suite', value='Suite1'), Label(name='subSuite', value='Suite2')]
31+
[Label(name=<LabelType.SUITE: 'suite'>, value='Suite1'), Label(name=<LabelType.SUB_SUITE: 'subSuite'>, value='Suite2')]
3232
>>> get_allure_suites('Suite1.Suite2.Suite3.Test') # doctest: +NORMALIZE_WHITESPACE
33-
[Label(name='parentSuite', value='Suite1'),
34-
Label(name='suite', value='Suite2'),
35-
Label(name='subSuite', value='Suite3')]
33+
[Label(name=<LabelType.PARENT_SUITE: 'parentSuite'>, value='Suite1'),
34+
Label(name=<LabelType.SUITE: 'suite'>, value='Suite2'),
35+
Label(name=<LabelType.SUB_SUITE: 'subSuite'>, value='Suite3')]
3636
"""
3737
labels = []
3838
suites = longname.split('.')

0 commit comments

Comments
 (0)