hardpy 0.14.0__py3-none-any.whl → 0.15.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@ from dataclasses import dataclass
6
6
  from inspect import stack
7
7
  from os import environ
8
8
  from time import sleep
9
- from typing import Any
9
+ from typing import TYPE_CHECKING, Any
10
10
  from uuid import uuid4
11
11
 
12
12
  from pycouchdb.exceptions import NotFound
@@ -19,17 +19,21 @@ from hardpy.pytest_hardpy.db import (
19
19
  )
20
20
  from hardpy.pytest_hardpy.reporter import RunnerReporter
21
21
  from hardpy.pytest_hardpy.utils import (
22
+ Chart,
22
23
  DialogBox,
23
- DuplicatePartNumberError,
24
- DuplicateSerialNumberError,
25
- DuplicateTestStandLocationError,
26
- DuplicateTestStandNameError,
27
- DuplicateTestStandNumberError,
24
+ DuplicateParameterError,
28
25
  HTMLComponent,
29
26
  ImageComponent,
27
+ Instrument,
28
+ NumericMeasurement,
29
+ StringMeasurement,
30
+ SubUnit,
30
31
  TestStandNumberError,
31
32
  )
32
33
 
34
+ if TYPE_CHECKING:
35
+ from collections.abc import Mapping
36
+
33
37
 
34
38
  @dataclass
35
39
  class CurrentTestInfo:
@@ -39,6 +43,42 @@ class CurrentTestInfo:
39
43
  case_id: str
40
44
 
41
45
 
46
+ class ErrorCodeMeta(type):
47
+ """Error code metaclass."""
48
+
49
+ def __call__(cls, code: int, message: str | None = None) -> str | None:
50
+ """Add error code to document.
51
+
52
+ Args:
53
+ code (int): non-negative error code.
54
+ message (str | None): error message.
55
+
56
+ Returns:
57
+ str | None: error message
58
+ """
59
+ if code < 0:
60
+ msg = "error code must be greater than 0"
61
+ raise ValueError(msg)
62
+ reporter = RunnerReporter()
63
+ key = reporter.generate_key(DF.ERROR_CODE)
64
+ if reporter.get_field(key) is None:
65
+ reporter.set_doc_value(key, code)
66
+ reporter.update_db_by_doc()
67
+ if message: # noqa: RET503
68
+ return message
69
+
70
+
71
+ class ErrorCode(metaclass=ErrorCodeMeta):
72
+ """Save error code and return error message.
73
+
74
+ It must be called from an assert.
75
+
76
+ Args:
77
+ code (int): error code.
78
+ message (str): error message.
79
+ """
80
+
81
+
42
82
  def get_current_report() -> ResultRunStore | None:
43
83
  """Get current report from runstore database.
44
84
 
@@ -56,11 +96,68 @@ def get_current_report() -> ResultRunStore | None:
56
96
  return None
57
97
 
58
98
 
59
- def set_dut_info(info: dict) -> None:
60
- """Add DUT info to document.
99
+ def set_user_name(name: str) -> None:
100
+ """Set operator panel user name.
61
101
 
62
102
  Args:
63
- info (dict): DUT info
103
+ name (str): user name
104
+
105
+ Raises:
106
+ DuplicateParameterError: if user name is already set
107
+ """
108
+ reporter = RunnerReporter()
109
+ key = reporter.generate_key(DF.USER)
110
+ if reporter.get_field(key):
111
+ msg = "user_name"
112
+ raise DuplicateParameterError(msg)
113
+ reporter.set_doc_value(key, name)
114
+ reporter.update_db_by_doc()
115
+
116
+
117
+ def set_batch_serial_number(serial_number: str) -> None:
118
+ """Add batch serial number to document.
119
+
120
+ Args:
121
+ serial_number (str): batch serial number
122
+
123
+ Raises:
124
+ DuplicateParameterError: if batch serial number is already set
125
+ """
126
+ reporter = RunnerReporter()
127
+ key = reporter.generate_key(DF.BATCH_SN)
128
+ if reporter.get_field(key):
129
+ msg = "batch_serial_number"
130
+ raise DuplicateParameterError(msg)
131
+ reporter.set_doc_value(key, serial_number)
132
+ reporter.update_db_by_doc()
133
+
134
+
135
+ def set_dut_sub_unit(sub_unit: SubUnit) -> int:
136
+ """Add sub unit to DUT sub units list.
137
+
138
+ Args:
139
+ sub_unit (SubUnit): Sub unit object of DUT.
140
+
141
+ Returns:
142
+ int: sub unit index
143
+ """
144
+ reporter = RunnerReporter()
145
+ key = reporter.generate_key(DF.DUT, DF.SUB_UNITS)
146
+
147
+ sub_units = reporter.get_field(key) or []
148
+ sub_units.append({k: v for k, v in vars(sub_unit).items() if v is not None})
149
+
150
+ reporter.set_doc_value(key, sub_units)
151
+ reporter.update_db_by_doc()
152
+
153
+ return len(sub_units) - 1
154
+
155
+
156
+ def set_dut_info(info: Mapping[str, str | int | float]) -> None:
157
+ """Set DUT info to document.
158
+
159
+ Args:
160
+ info (Mapping): DUT info
64
161
  """
65
162
  reporter = RunnerReporter()
66
163
  for dut_key, dut_value in info.items():
@@ -76,12 +173,13 @@ def set_dut_serial_number(serial_number: str) -> None:
76
173
  serial_number (str): DUT serial number
77
174
 
78
175
  Raises:
79
- DuplicateSerialNumberError: if serial number is already set
176
+ DuplicateParameterError: if serial number is already set
80
177
  """
81
178
  reporter = RunnerReporter()
82
179
  key = reporter.generate_key(DF.DUT, DF.SERIAL_NUMBER)
83
180
  if reporter.get_field(key):
84
- raise DuplicateSerialNumberError
181
+ msg = "dut_serial_number"
182
+ raise DuplicateParameterError(msg)
85
183
  reporter.set_doc_value(
86
184
  key,
87
185
  serial_number if isinstance(serial_number, str) else str(serial_number),
@@ -96,16 +194,71 @@ def set_dut_part_number(part_number: str) -> None:
96
194
  part_number (str): DUT part number
97
195
 
98
196
  Raises:
99
- DuplicatePartNumberError: if part number is already set
197
+ DuplicateParameterError: if part number is already set
100
198
  """
101
199
  reporter = RunnerReporter()
102
200
  key = reporter.generate_key(DF.DUT, DF.PART_NUMBER)
103
201
  if reporter.get_field(key):
104
- raise DuplicatePartNumberError
202
+ msg = "dut_part_number"
203
+ raise DuplicateParameterError(msg)
105
204
  reporter.set_doc_value(key, part_number)
106
205
  reporter.update_db_by_doc()
107
206
 
108
207
 
208
+ def set_dut_name(name: str) -> None:
209
+ """Set DUT name to document.
210
+
211
+ Args:
212
+ name (str): DUT name
213
+
214
+ Raises:
215
+ DuplicateParameterError: if DUT name is already set
216
+ """
217
+ reporter = RunnerReporter()
218
+ key = reporter.generate_key(DF.DUT, DF.NAME)
219
+ if reporter.get_field(key):
220
+ msg = "dut_name"
221
+ raise DuplicateParameterError(msg)
222
+ reporter.set_doc_value(key, name)
223
+ reporter.update_db_by_doc()
224
+
225
+
226
+ def set_dut_type(dut_type: str) -> None:
227
+ """Set DUT type to document.
228
+
229
+ Args:
230
+ dut_type (str): DUT type
231
+
232
+ Raises:
233
+ DuplicateParameterError: if DUT type is already set
234
+ """
235
+ reporter = RunnerReporter()
236
+ key = reporter.generate_key(DF.DUT, DF.TYPE)
237
+ if reporter.get_field(key):
238
+ msg = "dut_type"
239
+ raise DuplicateParameterError(msg)
240
+ reporter.set_doc_value(key, dut_type)
241
+ reporter.update_db_by_doc()
242
+
243
+
244
+ def set_dut_revision(revision: str) -> None:
245
+ """Set DUT revision to document.
246
+
247
+ Args:
248
+ revision (str): DUT revision
249
+
250
+ Raises:
251
+ DuplicateParameterError: if DUT revision is already set
252
+ """
253
+ reporter = RunnerReporter()
254
+ key = reporter.generate_key(DF.DUT, DF.REVISION)
255
+ if reporter.get_field(key):
256
+ msg = "dut_revision"
257
+ raise DuplicateParameterError(msg)
258
+ reporter.set_doc_value(key, revision)
259
+ reporter.update_db_by_doc()
260
+
261
+
109
262
  def set_stand_name(name: str) -> None:
110
263
  """Add test stand name to document.
111
264
 
@@ -113,21 +266,23 @@ def set_stand_name(name: str) -> None:
113
266
  name (str): test stand name
114
267
 
115
268
  Raises:
116
- DuplicateTestStandNameError: if test stand name is already set
269
+ DuplicateParameterError: if test stand name is already set
117
270
  """
118
271
  reporter = RunnerReporter()
119
272
  key = reporter.generate_key(DF.TEST_STAND, DF.NAME)
120
273
  if reporter.get_field(key):
121
- raise DuplicateTestStandNameError
274
+ msg = "stand_name"
275
+ raise DuplicateParameterError(msg)
122
276
  reporter.set_doc_value(key, name)
123
277
  reporter.update_db_by_doc()
124
278
 
125
279
 
126
- def set_stand_info(info: dict) -> None:
280
+ def set_stand_info(info: Mapping[str, str | int | float]) -> None:
127
281
  """Add test stand info to document.
128
282
 
129
283
  Args:
130
- info (dict): test stand info
284
+ info (Mapping[str, str | int | float ]): test stand info as a mapping
285
+ where keys are strings and values can be strings, integers, floats objects
131
286
  """
132
287
  reporter = RunnerReporter()
133
288
  for stand_key, stand_value in info.items():
@@ -143,12 +298,13 @@ def set_stand_location(location: str) -> None:
143
298
  location (str): test stand location
144
299
 
145
300
  Raises:
146
- DuplicateTestStandLocationError: if test stand location is already set
301
+ DuplicateParameterError: if test stand location is already set
147
302
  """
148
303
  reporter = RunnerReporter()
149
304
  key = reporter.generate_key(DF.TEST_STAND, DF.LOCATION)
150
305
  if reporter.get_field(key):
151
- raise DuplicateTestStandLocationError
306
+ msg = "stand_location"
307
+ raise DuplicateParameterError(msg)
152
308
  reporter.set_doc_value(key, location)
153
309
  reporter.update_db_by_doc()
154
310
 
@@ -160,7 +316,7 @@ def set_stand_number(number: int) -> None:
160
316
  number (int): test stand number (non negative integer)
161
317
 
162
318
  Raises:
163
- DuplicateTestStandNumberError: if stand number is already set
319
+ DuplicateParameterError: if stand number is already set
164
320
  TestStandNumberError: if stand number is incorrect (negative or non integer)
165
321
  """
166
322
  reporter = RunnerReporter()
@@ -168,11 +324,30 @@ def set_stand_number(number: int) -> None:
168
324
  if not isinstance(number, int) or number < 0:
169
325
  raise TestStandNumberError
170
326
  if reporter.get_field(key):
171
- raise DuplicateTestStandNumberError
327
+ msg = "stand_number"
328
+ raise DuplicateParameterError(msg)
172
329
  reporter.set_doc_value(key, number)
173
330
  reporter.update_db_by_doc()
174
331
 
175
332
 
333
+ def set_stand_revision(revision: str) -> None:
334
+ """Add test stand revision to document.
335
+
336
+ Args:
337
+ revision (str): test stand revision
338
+
339
+ Raises:
340
+ DuplicateParameterError: if test stand revision is already set
341
+ """
342
+ reporter = RunnerReporter()
343
+ key = reporter.generate_key(DF.TEST_STAND, DF.REVISION)
344
+ if reporter.get_field(key):
345
+ msg = "stand_revision"
346
+ raise DuplicateParameterError(msg)
347
+ reporter.set_doc_value(key, revision)
348
+ reporter.update_db_by_doc()
349
+
350
+
176
351
  def set_message(msg: str, msg_key: str | None = None) -> None:
177
352
  """Add or update message in current test.
178
353
 
@@ -291,6 +466,135 @@ def set_driver_info(drivers: dict) -> None:
291
466
  reporter.update_db_by_doc()
292
467
 
293
468
 
469
+ def set_instrument(instrument: Instrument) -> int:
470
+ """Add instrument to test stand instruments list.
471
+
472
+ Args:
473
+ instrument (Instrument): Instrument object containing all instrument data
474
+
475
+ Returns:
476
+ int: instrument index
477
+ """
478
+ reporter = RunnerReporter()
479
+ key = reporter.generate_key(DF.TEST_STAND, DF.INSTRUMENTS)
480
+
481
+ instruments = reporter.get_field(key) or []
482
+ instruments.append({k: v for k, v in vars(instrument).items() if v is not None})
483
+
484
+ reporter.set_doc_value(key, instruments)
485
+ reporter.update_db_by_doc()
486
+
487
+ return len(instruments) - 1
488
+
489
+
490
+ def set_process_name(name: str) -> None:
491
+ """Set process name to document.
492
+
493
+ Args:
494
+ name (str): process name
495
+
496
+ Raises:
497
+ DuplicateParameterError: if process name is already set
498
+ """
499
+ reporter = RunnerReporter()
500
+ key = reporter.generate_key(DF.PROCESS, DF.NAME)
501
+ if reporter.get_field(key):
502
+ msg = "process_name"
503
+ raise DuplicateParameterError(msg)
504
+ reporter.set_doc_value(key, name)
505
+ reporter.update_db_by_doc()
506
+
507
+
508
+ def set_process_number(number: int) -> None:
509
+ """Set process number to document.
510
+
511
+ Args:
512
+ number (int): process number
513
+
514
+ Raises:
515
+ DuplicateParameterError: if process number is already set
516
+ """
517
+ reporter = RunnerReporter()
518
+ key = reporter.generate_key(DF.PROCESS, DF.NUMBER)
519
+ if reporter.get_field(key):
520
+ msg = "process_number"
521
+ raise DuplicateParameterError(msg)
522
+ reporter.set_doc_value(key, number)
523
+ reporter.update_db_by_doc()
524
+
525
+
526
+ def set_process_info(info: Mapping[str, str | int | float]) -> None:
527
+ """Set process info to document.
528
+
529
+ Args:
530
+ info (Mapping): process info
531
+ """
532
+ reporter = RunnerReporter()
533
+ for key, value in info.items():
534
+ full_key = reporter.generate_key(DF.PROCESS, DF.INFO, key)
535
+ reporter.set_doc_value(full_key, value)
536
+ reporter.update_db_by_doc()
537
+
538
+
539
+ def set_case_measurement(measurement: NumericMeasurement | StringMeasurement) -> int:
540
+ """Add measurement to document.
541
+
542
+ Args:
543
+ measurement (NumericMeasurement | StringMeasurement): measurement object
544
+
545
+ Returns:
546
+ int: measurement index from measurements list
547
+ """
548
+ current_test = _get_current_test()
549
+ reporter = RunnerReporter()
550
+
551
+ key = reporter.generate_key(
552
+ DF.MODULES,
553
+ current_test.module_id,
554
+ DF.CASES,
555
+ current_test.case_id,
556
+ DF.MEASUREMENTS,
557
+ )
558
+
559
+ measurements = reporter.get_field(key) or []
560
+ measurements.append({k: v for k, v in vars(measurement).items() if v is not None})
561
+
562
+ reporter.set_doc_value(key, measurements)
563
+ reporter.update_db_by_doc()
564
+
565
+ return len(measurements) - 1
566
+
567
+
568
+ def set_case_chart(chart: Chart) -> None:
569
+ """Add chart to document.
570
+
571
+ Args:
572
+ chart (Chart): chart object
573
+ """
574
+ if not chart.x_data or not chart.y_data:
575
+ msg = "x_data and y_data must be set"
576
+ raise ValueError(msg)
577
+ current_test = _get_current_test()
578
+ reporter = RunnerReporter()
579
+
580
+ key = reporter.generate_key(
581
+ DF.MODULES,
582
+ current_test.module_id,
583
+ DF.CASES,
584
+ current_test.case_id,
585
+ DF.CHART,
586
+ )
587
+
588
+ if reporter.get_field(key):
589
+ msg = "chart"
590
+ raise DuplicateParameterError(msg)
591
+
592
+ chart_dict = {k: v for k, v in vars(chart).items() if v is not None}
593
+
594
+ reporter.set_doc_value(key, chart_dict)
595
+ reporter.update_db_by_doc()
596
+
597
+
294
598
  def run_dialog_box(dialog_box_data: DialogBox) -> Any: # noqa: ANN401
295
599
  """Display a dialog box.
296
600
 
@@ -373,6 +677,10 @@ def set_operator_message( # noqa: PLR0913
373
677
  msg = "The 'font_size' argument cannot be less than 1"
374
678
  raise ValueError(msg)
375
679
 
680
+ if not msg:
681
+ msg = "The 'msg' argument cannot be empty"
682
+ raise ValueError(msg)
683
+
376
684
  msg_data = {
377
685
  DF.MSG: msg,
378
686
  DF.TITLE: title,
@@ -25,7 +25,7 @@ class PyTestWrapper:
25
25
  self.config = ConfigManager().get_config()
26
26
  self.collect(is_clear_database=True)
27
27
 
28
- def start(self) -> bool:
28
+ def start(self, start_args: dict | None = None) -> bool:
29
29
  """Start pytest subprocess.
30
30
 
31
31
  Returns:
@@ -37,44 +37,35 @@ class PyTestWrapper:
37
37
  if self.is_running():
38
38
  return False
39
39
 
40
- if system() == "Linux":
40
+ cmd = [
41
+ self.python_executable,
42
+ "-m",
43
+ "pytest",
44
+ "--hardpy-db-url",
45
+ self.config.database.connection_url(),
46
+ "--hardpy-tests-name",
47
+ self.config.tests_name,
48
+ "--sc-address",
49
+ self.config.stand_cloud.address,
50
+ ]
51
+ if self.config.stand_cloud.connection_only:
52
+ cmd.append("--sc-connection-only")
53
+ cmd.append("--hardpy-pt")
54
+ if start_args:
55
+ for key, value in start_args.items():
56
+ arg_str = f"{key}={value}"
57
+ cmd.extend(["--hardpy-start-arg", arg_str])
58
+
59
+ if system() == "Windows":
41
60
  self._proc = subprocess.Popen( # noqa: S603
42
- [
43
- self.python_executable,
44
- "-m",
45
- "pytest",
46
- "--hardpy-db-url",
47
- self.config.database.connection_url(),
48
- "--hardpy-tests-name",
49
- self.config.tests_name,
50
- "--sc-address",
51
- self.config.stand_cloud.address,
52
- "--sc-connection-only"
53
- if self.config.stand_cloud.connection_only
54
- else "",
55
- "--hardpy-pt",
56
- ],
61
+ cmd,
57
62
  cwd=ConfigManager().get_tests_path(),
63
+ creationflags=subprocess.CREATE_NEW_PROCESS_GROUP,
58
64
  )
59
- elif system() == "Windows":
65
+ if system() == "Linux":
60
66
  self._proc = subprocess.Popen( # noqa: S603
61
- [
62
- self.python_executable,
63
- "-m",
64
- "pytest",
65
- "--hardpy-db-url",
66
- self.config.database.connection_url(),
67
- "--hardpy-tests-name",
68
- self.config.tests_name,
69
- "--sc-address",
70
- self.config.stand_cloud.address,
71
- "--sc-connection-only"
72
- if self.config.stand_cloud.connection_only
73
- else "",
74
- "--hardpy-pt",
75
- ],
67
+ cmd,
76
68
  cwd=ConfigManager().get_tests_path(),
77
- creationflags=subprocess.CREATE_NEW_PROCESS_GROUP, # type: ignore
78
69
  )
79
70
 
80
71
  return True
@@ -31,6 +31,10 @@ class HookReporter(BaseReporter):
31
31
  doc_name (str): test run name
32
32
  """
33
33
  self.set_doc_value(DF.NAME, doc_name)
34
+ self.set_doc_value(DF.USER, None)
35
+ self.set_doc_value(DF.BATCH_SN, None)
36
+ self.set_doc_value(DF.CAUSED_DUT_FAILURE_ID, None)
37
+ self.set_doc_value(DF.ERROR_CODE, None)
34
38
  self.set_doc_value(DF.STATUS, TestStatus.READY)
35
39
  self.set_doc_value(DF.START_TIME, None)
36
40
  self.set_doc_value(DF.STOP_TIME, None)
@@ -217,7 +221,7 @@ class HookReporter(BaseReporter):
217
221
  case_id,
218
222
  DF.ATTEMPT,
219
223
  )
220
- self.set_doc_value(key, attempt, statestore_only=True)
224
+ self.set_doc_value(key, attempt)
221
225
 
222
226
  def get_module_start_time(self, module_id: str) -> int:
223
227
  """Get module start time.
@@ -237,6 +241,26 @@ class HookReporter(BaseReporter):
237
241
  key = self.generate_key(DF.MODULES, module_id, DF.CASES, case_id, DF.START_TIME)
238
242
  return self._statestore.get_field(key)
239
243
 
244
+ def set_caused_dut_failure_id(self, module_id: str, case_id: str) -> None:
245
+ """Set caused DUT failure id.
246
+
247
+ Args:
248
+ module_id (str): module id
249
+ case_id (str): case id
250
+ """
251
+ key = self.generate_key(DF.CAUSED_DUT_FAILURE_ID)
252
+ failure_id = f"{module_id}::{case_id}"
253
+ self.set_doc_value(key, failure_id)
254
+
255
+ def get_caused_dut_failure_id(self) -> str | None:
256
+ """Get caused DUT failure id.
257
+
258
+ Returns:
259
+ str | None: failure id
260
+ """
261
+ key = self.generate_key(DF.CAUSED_DUT_FAILURE_ID)
262
+ return self._statestore.get_field(key)
263
+
240
264
  def update_node_order(self, nodes: dict) -> None:
241
265
  """Update node order.
242
266
 
@@ -267,6 +291,7 @@ class HookReporter(BaseReporter):
267
291
  module_default = {
268
292
  DF.STATUS: TestStatus.READY,
269
293
  DF.NAME: self._get_module_name(node_info),
294
+ DF.GROUP: self._get_module_group(node_info),
270
295
  DF.START_TIME: None,
271
296
  DF.STOP_TIME: None,
272
297
  DF.CASES: {},
@@ -274,10 +299,14 @@ class HookReporter(BaseReporter):
274
299
  case_default = {
275
300
  DF.STATUS: TestStatus.READY,
276
301
  DF.NAME: self._get_case_name(node_info),
302
+ DF.GROUP: self._get_case_group(node_info),
277
303
  DF.START_TIME: None,
278
304
  DF.STOP_TIME: None,
279
305
  DF.ASSERTION_MSG: None,
280
306
  DF.MSG: None,
307
+ DF.ATTEMPT: 0,
308
+ DF.MEASUREMENTS: [],
309
+ DF.CHART: None,
281
310
  }
282
311
 
283
312
  if item.get(node_info.module_id) is None:
@@ -287,6 +316,7 @@ class HookReporter(BaseReporter):
287
316
  else:
288
317
  item[node_info.module_id][DF.STATUS] = TestStatus.READY
289
318
  item[node_info.module_id][DF.NAME] = self._get_module_name(node_info)
319
+ item[node_info.module_id][DF.GROUP] = self._get_module_group(node_info)
290
320
  item[node_info.module_id][DF.START_TIME] = None
291
321
  item[node_info.module_id][DF.STOP_TIME] = None
292
322
  item[node_info.module_id][DF.NAME] = self._get_module_name(node_info)
@@ -296,7 +326,6 @@ class HookReporter(BaseReporter):
296
326
 
297
327
  if is_only_statestore:
298
328
  case_default[DF.DIALOG_BOX] = {}
299
- case_default[DF.ATTEMPT] = 0
300
329
  item[node_info.module_id][DF.CASES][node_info.case_id] = case_default
301
330
 
302
331
  def _remove_outdate_node(
@@ -378,6 +407,28 @@ class HookReporter(BaseReporter):
378
407
  """
379
408
  return node_info.module_name if node_info.module_name else node_info.module_id
380
409
 
410
+ def _get_module_group(self, node_info: NodeInfo) -> str:
411
+ """Get module group from markers or use default.
412
+
413
+ Args:
414
+ node_info (NodeInfo): node info
415
+
416
+ Returns:
417
+ str: module group
418
+ """
419
+ return node_info.module_group
420
+
421
+ def _get_case_group(self, node_info: NodeInfo) -> str:
422
+ """Get case group from markers or use default.
423
+
424
+ Args:
425
+ node_info (NodeInfo): node info
426
+
427
+ Returns:
428
+ str: case group
429
+ """
430
+ return node_info.case_group
431
+
381
432
  def _get_case_name(self, node_info: NodeInfo) -> str:
382
433
  """Get case name from markers or use default.
383
434
 
@@ -88,11 +88,7 @@ class CouchdbReader:
88
88
  str: report status
89
89
  """
90
90
  doc = self._db.get(report_name)
91
- status = doc[DF.STATUS]
92
- if status not in {TestStatus.PASSED, TestStatus.FAILED, TestStatus.SKIPPED}:
93
- msg = "Invalid report status"
94
- raise ValueError(msg)
95
- return status
91
+ return doc[DF.STATUS]
96
92
 
97
93
  def get_report_infos(self) -> list[ReportInfo]:
98
94
  """Get a list of information about all reports in the database.