• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

testit-tms / adapters-python / 21937415766

12 Feb 2026 07:26AM UTC coverage: 37.16% (-4.1%) from 41.236%
21937415766

Pull #234

github

web-flow
Merge e908d8a92 into 2fcd27f6a
Pull Request #234: feat: TMS-37545: replace labels with tags when collecting autotest me…

17 of 73 new or added lines in 11 files covered. (23.29%)

2 existing lines in 2 files now uncovered.

1337 of 3598 relevant lines covered (37.16%)

0.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/testit-adapter-robotframework/src/testit_adapter_robotframework/models.py
1
import ast
×
2
import re
×
3

4
from attr import Factory, asdict, attrib, s
×
5

6
from robot.api import logger
×
7
from testit_python_commons.models.link import Link
×
8

9
from .utils import get_hash
×
10

11

12
LinkTypes = ['Related', 'BlockedBy', 'Defect', 'Issue', 'Requirement', 'Repository']
×
13

14

15
def link_type_check(self, attribute, value):
×
16
    if value.title() not in LinkTypes:
×
17
        raise ValueError(f"Incorrect Link type: {value}")
×
18

19

20
def url_check(self, attribute, value):
×
21
    if not bool(re.match(
×
22
            r"(https?|ftp)://"
23
            r"(\w+(-\w+)*\.)?"
24
            r"((\w+(-\w+)*)\.(\w+))"
25
            r"(\.\w+)*"
26
            r"([\w\-._~/]*)*(?<!\.)",
27
            value)):
28
        raise ValueError(f"Incorrect URL: {value}")
×
29

30

31
class Default:
×
32

33
    def order(self):
×
34
        return asdict(self)
×
35

36

37
@s
×
38
class StepResult(Default):
×
39
    title = attrib(default='')
×
40
    description = attrib(default='')
×
41
    started_on = attrib(default=None)
×
42
    completed_on = attrib(default=None)
×
43
    duration = attrib(default=None)
×
44
    outcome = attrib(default=None)
×
45
    step_results = attrib(default=Factory(list))
×
46
    attachments = attrib(default=Factory(list))
×
47
    parameters = attrib(default=Factory(dict))
×
48

49

50
@s
×
51
class Step(Default):
×
52
    title = attrib()
×
53
    description = attrib()
×
54
    steps = attrib(default=Factory(list))
×
55

56

57
@s
×
58
class Label:
×
59
    name = attrib()
×
60

61

62
@s(kw_only=True)
×
63
class Autotest(Default):
×
64
    externalID = attrib(default=None)  # noqa: N815
×
65
    autoTestName = attrib()  # noqa: N815
×
66
    steps = attrib(default=Factory(list))
×
67
    stepResults = attrib(default=Factory(list))  # noqa: N815
×
68
    setUp = attrib(default=Factory(list))  # noqa: N815
×
69
    setUpResults = attrib(default=Factory(list))  # noqa: N815
×
70
    tearDown = attrib(default=Factory(list))  # noqa: N815
×
71
    tearDownResults = attrib(default=Factory(list))  # noqa: N815
×
72
    resultLinks = attrib(default=Factory(list))  # noqa: N815
×
73
    duration = attrib(default=None)
×
74
    failureReasonNames = attrib(default=Factory(list))  # noqa: N815
×
75
    traces = attrib(default=None)
×
76
    outcome = attrib(default=None)
×
77
    namespace = attrib(default=None)
×
78
    attachments = attrib(default=Factory(list))
×
79
    parameters = attrib(default=Factory(dict))
×
80
    properties = attrib(default=Factory(dict))
×
81
    classname = attrib(default=None)
×
82
    title = attrib(default=None)
×
83
    description = attrib(default=None)
×
84
    links = attrib(default=Factory(list))
×
NEW
85
    tags = attrib(default=Factory(list))
×
86
    workItemsID = attrib(default=Factory(list))  # noqa: N815
×
87
    message = attrib(default="")
×
88
    started_on = attrib(default=None)
×
89
    completed_on = attrib(default=None)
×
90
    externalKey = attrib(default=None)
×
91

92
    step_depth = attrib(default=Factory(list))
×
93
    result_depth = attrib(default=Factory(list))
×
94

95
    def add_attributes(self, attrs):
×
96
        self.title = attrs['originalname']
×
97
        self.autoTestName = attrs['originalname']
×
98
        self.externalKey = attrs['originalname']
×
99
        self.description = attrs['doc']
×
100
        self.template = attrs['template']
×
101
        self.classname = attrs['longname'].split('.')[-2]
×
102
        for tag in attrs['tags']:
×
103
            if tag.lower().startswith('testit.'):
×
104
                attr = re.findall(r'(?<=\.).*?(?=:)', tag)[0].strip().lower()
×
105
                value = tag.split(':', 1)[-1].strip()
×
106
                if attr == 'externalid':
×
107
                    self.externalID = str(value).replace("'", "").replace('"', '')
×
108
                elif attr == 'displayname':
×
109
                    self.autoTestName = str(value).replace("'", "").replace('"', '')
×
110
                elif attr == 'title':
×
111
                    self.title = str(value).replace("'", "").replace('"', '')
×
112
                elif attr == 'description':
×
113
                    self.description = str(value).replace("'", "").replace('"', '')
×
114
                elif attr == 'workitemsid' or attr == 'workitemsids':
×
115
                    value = ast.literal_eval(value)
×
116
                    if isinstance(value, (str, int)):
×
117
                        self.workItemsID.append(str(value))
×
118
                    elif isinstance(value, list):
×
119
                        self.workItemsID.extend([str(i) for i in value])
×
120
                    else:
121
                        logger.error(f"[TestIt] Wrong workitem format: {value}")
×
122
                elif attr == 'links':
×
123
                    value = ast.literal_eval(value)
×
124
                    try:
×
125
                        if isinstance(value, dict):
×
126
                            self.links.append(Link()\
×
127
                                .set_url(value['url'])\
128
                                .set_title(value.get('title', None))\
129
                                .set_link_type(value.get('type', None))\
130
                                .set_description(value.get('description', None)))
131
                        elif isinstance(value, list):
×
132
                            self.links.extend([Link()\
×
133
                                .set_url(link['url'])\
134
                                .set_title(link.get('title', None))\
135
                                .set_link_type(link.get('type', None))\
136
                                .set_description(link.get('description', None)) for link in value if isinstance(link, dict)])
137
                    except ValueError as e:
×
138
                        logger.error(f"[TestIt] Link Error: {e}")
×
NEW
139
                elif attr in ('labels', 'tags'):
×
140
                    value = ast.literal_eval(value)
×
141
                    if isinstance(value, (str, int)):
×
NEW
142
                        self.tags.append(str(value))
×
143
                    elif isinstance(value, list):
×
NEW
144
                        self.tags.extend([str(item) for item in value if isinstance(item, (str, int))])
×
145
                elif attr == 'namespace':
×
146
                    self.namespace = str(value).replace("'", "").replace('"', '')
×
147
                elif attr == 'classname':
×
148
                    self.classname = str(value).replace("'", "").replace('"', '')
×
149
                else:
150
                    logger.error(f"[TestIt] Unknown attribute: {attr}")
×
151
        if not self.externalID:
×
152
            self.externalID = get_hash(attrs['longname'])
×
153

154
    def add_step(self, step_type, title, description, parameters):
×
155
        if len(self.step_depth) == 0:
×
156
            if step_type.lower() == 'setup':
×
157
                self.setUp.append(Step(title, description))
×
158
                self.step_depth.append(self.setUp[-1])
×
159
                self.setUpResults.append(StepResult(title, description, parameters=parameters))
×
160
                self.result_depth.append(self.setUpResults[-1])
×
161
            elif step_type.lower() == 'teardown':
×
162
                self.tearDown.append(Step(title, description))
×
163
                self.step_depth.append(self.tearDown[-1])
×
164
                self.tearDownResults.append(StepResult(title, description, parameters=parameters))
×
165
                self.result_depth.append(self.tearDownResults[-1])
×
166
            else:
167
                self.steps.append(Step(title, description))
×
168
                self.step_depth.append(self.steps[-1])
×
169
                self.stepResults.append(StepResult(title, description, parameters=parameters))
×
170
                self.result_depth.append(self.stepResults[-1])
×
171
        elif 1 <= len(self.step_depth) < 14:
×
172
            self.step_depth[-1].steps.append(Step(title, description))
×
173
            self.step_depth.append(self.step_depth[-1].steps[-1])
×
174
            self.result_depth[-1].step_results.append(StepResult(title, description, parameters=parameters))
×
175
            self.result_depth.append(self.result_depth[-1].step_results[-1])
×
176

177
    def add_step_result(self, title, start, complete, duration, outcome, attachments):
×
178
        if self.result_depth:
×
179
            if self.result_depth[-1].title == title:
×
180
                step = self.result_depth.pop()
×
181
                step.started_on = start
×
182
                step.completed_on = complete
×
183
                step.duration = duration
×
184
                step.outcome = outcome
×
185
                step.attachments = attachments
×
186
        if self.step_depth:
×
187
            if self.step_depth[-1].title == title:
×
188
                self.step_depth.pop()
×
189

190

191
class Option:
×
192

193
    def __init__(self, **kwargs):
×
194
        if kwargs.get('tmsUrl', None):
×
195
            self.set_url = kwargs.get('tmsUrl', None)
×
196
        if kwargs.get('tmsPrivateToken', None):
×
197
            self.set_private_token = kwargs.get('tmsPrivateToken', None)
×
198
        if kwargs.get('tmsProjectId', None):
×
199
            self.set_project_id = kwargs.get('tmsProjectId', None)
×
200
        if kwargs.get('tmsConfigurationId', None):
×
201
            self.set_configuration_id = kwargs.get('tmsConfigurationId', None)
×
202
        if kwargs.get('tmsTestRunId', None):
×
203
            self.set_test_run_id = kwargs.get('tmsTestRunId', None)
×
204
        if kwargs.get('tmsProxy', None):
×
205
            self.set_tms_proxy = kwargs.get('tmsProxy', None)
×
206
        if kwargs.get('tmsTestRunName', None):
×
207
            self.set_test_run_name = kwargs.get('tmsTestRunName', None)
×
208
        if kwargs.get('tmsAdapterMode', None):
×
209
            self.set_adapter_mode = kwargs.get('tmsAdapterMode', None)
×
210
        if kwargs.get('tmsConfigFile', None):
×
211
            self.set_config_file = kwargs.get('tmsConfigFile', None)
×
212
        if kwargs.get('tmsCertValidation', None):
×
213
            self.set_cert_validation = kwargs.get('tmsCertValidation', None)
×
214
        if kwargs.get('tmsAutomaticCreationTestCases', None):
×
215
            self.set_automatic_creation_test_cases = kwargs.get('tmsAutomaticCreationTestCases', None)
×
216
        if kwargs.get('tmsAutomaticUpdationLinksToTestCases', None):
×
217
            self.set_automatic_updation_links_to_test_cases = kwargs.get('tmsAutomaticUpdationLinksToTestCases', None)
×
218
        if kwargs.get('tmsImportRealtime', None):
×
219
            self.set_import_realtime = kwargs.get('tmsImportRealtime', None)
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc