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.
- hardpy/__init__.py +45 -10
- hardpy/cli/cli.py +30 -28
- hardpy/common/config.py +0 -4
- hardpy/common/stand_cloud/connector.py +2 -2
- hardpy/hardpy_panel/api.py +13 -3
- hardpy/pytest_hardpy/db/base_store.py +23 -0
- hardpy/pytest_hardpy/db/const.py +40 -19
- hardpy/pytest_hardpy/db/schema/v1.py +139 -326
- hardpy/pytest_hardpy/plugin.py +32 -1
- hardpy/pytest_hardpy/pytest_call.py +329 -21
- hardpy/pytest_hardpy/pytest_wrapper.py +25 -34
- hardpy/pytest_hardpy/reporter/hook_reporter.py +53 -2
- hardpy/pytest_hardpy/result/report_reader/couchdb_reader.py +1 -5
- hardpy/pytest_hardpy/utils/__init__.py +25 -11
- hardpy/pytest_hardpy/utils/const.py +72 -0
- hardpy/pytest_hardpy/utils/exception.py +7 -32
- hardpy/pytest_hardpy/utils/node_info.py +55 -1
- hardpy/pytest_hardpy/utils/stand_type.py +198 -0
- {hardpy-0.14.0.dist-info → hardpy-0.15.1.dist-info}/METADATA +2 -1
- {hardpy-0.14.0.dist-info → hardpy-0.15.1.dist-info}/RECORD +23 -22
- {hardpy-0.14.0.dist-info → hardpy-0.15.1.dist-info}/WHEEL +0 -0
- {hardpy-0.14.0.dist-info → hardpy-0.15.1.dist-info}/entry_points.txt +0 -0
- {hardpy-0.14.0.dist-info → hardpy-0.15.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
# GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
3
3
|
|
|
4
4
|
from hardpy.pytest_hardpy.utils.connection_data import ConnectionData
|
|
5
|
-
from hardpy.pytest_hardpy.utils.const import
|
|
5
|
+
from hardpy.pytest_hardpy.utils.const import (
|
|
6
|
+
ChartType,
|
|
7
|
+
ComparisonOperation,
|
|
8
|
+
Group,
|
|
9
|
+
MeasurementType,
|
|
10
|
+
TestStatus,
|
|
11
|
+
)
|
|
6
12
|
from hardpy.pytest_hardpy.utils.dialog_box import (
|
|
7
13
|
BaseWidget,
|
|
8
14
|
CheckboxWidget,
|
|
@@ -16,11 +22,7 @@ from hardpy.pytest_hardpy.utils.dialog_box import (
|
|
|
16
22
|
TextInputWidget,
|
|
17
23
|
)
|
|
18
24
|
from hardpy.pytest_hardpy.utils.exception import (
|
|
19
|
-
|
|
20
|
-
DuplicateSerialNumberError,
|
|
21
|
-
DuplicateTestStandLocationError,
|
|
22
|
-
DuplicateTestStandNameError,
|
|
23
|
-
DuplicateTestStandNumberError,
|
|
25
|
+
DuplicateParameterError,
|
|
24
26
|
ImageError,
|
|
25
27
|
TestStandNumberError,
|
|
26
28
|
WidgetInfoError,
|
|
@@ -29,27 +31,39 @@ from hardpy.pytest_hardpy.utils.machineid import machine_id
|
|
|
29
31
|
from hardpy.pytest_hardpy.utils.node_info import NodeInfo
|
|
30
32
|
from hardpy.pytest_hardpy.utils.progress_calculator import ProgressCalculator
|
|
31
33
|
from hardpy.pytest_hardpy.utils.singleton import SingletonMeta
|
|
34
|
+
from hardpy.pytest_hardpy.utils.stand_type import (
|
|
35
|
+
Chart,
|
|
36
|
+
Instrument,
|
|
37
|
+
NumericMeasurement,
|
|
38
|
+
StringMeasurement,
|
|
39
|
+
SubUnit,
|
|
40
|
+
)
|
|
32
41
|
|
|
33
42
|
__all__ = [
|
|
34
43
|
"BaseWidget",
|
|
44
|
+
"Chart",
|
|
45
|
+
"ChartType",
|
|
35
46
|
"CheckboxWidget",
|
|
47
|
+
"ComparisonOperation",
|
|
36
48
|
"ConnectionData",
|
|
37
49
|
"DialogBox",
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"DuplicateTestStandLocationError",
|
|
41
|
-
"DuplicateTestStandNameError",
|
|
42
|
-
"DuplicateTestStandNumberError",
|
|
50
|
+
"DuplicateParameterError",
|
|
51
|
+
"Group",
|
|
43
52
|
"HTMLComponent",
|
|
44
53
|
"ImageComponent",
|
|
45
54
|
"ImageError",
|
|
55
|
+
"Instrument",
|
|
56
|
+
"MeasurementType",
|
|
46
57
|
"MultistepWidget",
|
|
47
58
|
"NodeInfo",
|
|
48
59
|
"NumericInputWidget",
|
|
60
|
+
"NumericMeasurement",
|
|
49
61
|
"ProgressCalculator",
|
|
50
62
|
"RadiobuttonWidget",
|
|
51
63
|
"SingletonMeta",
|
|
52
64
|
"StepWidget",
|
|
65
|
+
"StringMeasurement",
|
|
66
|
+
"SubUnit",
|
|
53
67
|
"TestStandNumberError",
|
|
54
68
|
"TestStatus",
|
|
55
69
|
"TextInputWidget",
|
|
@@ -17,3 +17,75 @@ class TestStatus(str, Enum):
|
|
|
17
17
|
RUN = "run"
|
|
18
18
|
READY = "ready"
|
|
19
19
|
STOPPED = "stopped"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Group(str, Enum):
|
|
23
|
+
"""Test group."""
|
|
24
|
+
|
|
25
|
+
SETUP = "setup"
|
|
26
|
+
MAIN = "main"
|
|
27
|
+
TEARDOWN = "teardown"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class MeasurementType(str, Enum):
|
|
31
|
+
"""Measurement type."""
|
|
32
|
+
|
|
33
|
+
NUMERIC = "numeric"
|
|
34
|
+
"""Numeric measurement"""
|
|
35
|
+
|
|
36
|
+
STRING = "string"
|
|
37
|
+
"""String measurement"""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ComparisonOperation(str, Enum):
|
|
41
|
+
"""Comparison operator."""
|
|
42
|
+
|
|
43
|
+
EQ = "eq"
|
|
44
|
+
"""Equal"""
|
|
45
|
+
|
|
46
|
+
NE = "ne"
|
|
47
|
+
"""Not equal"""
|
|
48
|
+
|
|
49
|
+
GT = "gt"
|
|
50
|
+
"""Greater than"""
|
|
51
|
+
|
|
52
|
+
GE = "ge"
|
|
53
|
+
"""Greater or equal"""
|
|
54
|
+
|
|
55
|
+
LT = "lt"
|
|
56
|
+
"""Less than"""
|
|
57
|
+
|
|
58
|
+
LE = "le"
|
|
59
|
+
"""Less or equal"""
|
|
60
|
+
|
|
61
|
+
GTLT = "gtlt"
|
|
62
|
+
"""Greater than lower limit, less than upper limit"""
|
|
63
|
+
|
|
64
|
+
GELE = "gele"
|
|
65
|
+
"""Greater or equal than lower limit, less or equal than upper limit"""
|
|
66
|
+
|
|
67
|
+
GELT = "gelt"
|
|
68
|
+
"""Greater or equal than lower limit, less than upper limit"""
|
|
69
|
+
|
|
70
|
+
GTLE = "gtle"
|
|
71
|
+
"""Greater than lower limit, less or equal than upper limit"""
|
|
72
|
+
|
|
73
|
+
LTGT = "ltgt"
|
|
74
|
+
"""Less than lower limit or greater than upper limit"""
|
|
75
|
+
|
|
76
|
+
LEGE = "lege"
|
|
77
|
+
"""Less or equal than lower limit or greater or equal than upper limit"""
|
|
78
|
+
|
|
79
|
+
LEGT = "legt"
|
|
80
|
+
"""Less or equal than lower limit or greater than upper limit"""
|
|
81
|
+
|
|
82
|
+
LTGE = "ltge"
|
|
83
|
+
"""Less than lower limit or greater or equal than upper limit"""
|
|
84
|
+
|
|
85
|
+
class ChartType(str, Enum):
|
|
86
|
+
"""Chart type."""
|
|
87
|
+
|
|
88
|
+
LINE = "line"
|
|
89
|
+
LINE_LOG_X = "line_log_x"
|
|
90
|
+
LINE_LOG_Y = "line_log_y"
|
|
91
|
+
LOG_X_Y = "log_x_y"
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
# GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
5
8
|
class HardpyError(Exception):
|
|
6
9
|
"""Base HardPy exception."""
|
|
7
10
|
|
|
@@ -9,39 +12,11 @@ class HardpyError(Exception):
|
|
|
9
12
|
super().__init__(f"HardPy error: {msg}")
|
|
10
13
|
|
|
11
14
|
|
|
12
|
-
class
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
def __init__(self) -> None:
|
|
16
|
-
super().__init__(self.__doc__) # type: ignore
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class DuplicatePartNumberError(HardpyError):
|
|
20
|
-
"""The part number has already been determined."""
|
|
21
|
-
|
|
22
|
-
def __init__(self) -> None:
|
|
23
|
-
super().__init__(self.__doc__) # type: ignore
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class DuplicateTestStandNameError(HardpyError):
|
|
27
|
-
"""The test stand name has already been determined."""
|
|
15
|
+
class DuplicateParameterError(HardpyError):
|
|
16
|
+
"""A parameter has already been defined."""
|
|
28
17
|
|
|
29
|
-
def __init__(self) -> None:
|
|
30
|
-
super().__init__(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class DuplicateTestStandLocationError(HardpyError):
|
|
34
|
-
"""The test stand location has already been determined."""
|
|
35
|
-
|
|
36
|
-
def __init__(self) -> None:
|
|
37
|
-
super().__init__(self.__doc__) # type: ignore
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class DuplicateTestStandNumberError(HardpyError):
|
|
41
|
-
"""The test stand number has already been determined."""
|
|
42
|
-
|
|
43
|
-
def __init__(self) -> None:
|
|
44
|
-
super().__init__(self.__doc__) # type: ignore
|
|
18
|
+
def __init__(self, param_name: Any) -> None: # noqa: ANN401
|
|
19
|
+
super().__init__(f"Parameter {param_name} is already defined")
|
|
45
20
|
|
|
46
21
|
|
|
47
22
|
class TestStandNumberError(HardpyError):
|
|
@@ -7,6 +7,8 @@ from logging import getLogger
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import TYPE_CHECKING, NamedTuple
|
|
9
9
|
|
|
10
|
+
from hardpy.pytest_hardpy.utils.const import Group
|
|
11
|
+
|
|
10
12
|
if TYPE_CHECKING:
|
|
11
13
|
from pytest import Item, Mark
|
|
12
14
|
|
|
@@ -45,6 +47,9 @@ class NodeInfo:
|
|
|
45
47
|
|
|
46
48
|
self._critical = self._get_critical(item.own_markers + item.parent.own_markers)
|
|
47
49
|
|
|
50
|
+
self._module_group = self._get_group(item.parent.own_markers, "module_group")
|
|
51
|
+
self._case_group = self._get_group(item.own_markers, "case_group")
|
|
52
|
+
|
|
48
53
|
self._module_id = Path(item.parent.nodeid).stem # type: ignore
|
|
49
54
|
self._case_id = item.name
|
|
50
55
|
|
|
@@ -111,6 +116,24 @@ class NodeInfo:
|
|
|
111
116
|
"""
|
|
112
117
|
return self._critical
|
|
113
118
|
|
|
119
|
+
@property
|
|
120
|
+
def module_group(self) -> Group:
|
|
121
|
+
"""Get module group.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
Group: module group
|
|
125
|
+
"""
|
|
126
|
+
return self._module_group
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def case_group(self) -> Group:
|
|
130
|
+
"""Get case group.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
Group: case group
|
|
134
|
+
"""
|
|
135
|
+
return self._case_group
|
|
136
|
+
|
|
114
137
|
def _get_human_name(self, markers: list[Mark], marker_name: str) -> str:
|
|
115
138
|
"""Get human name from markers.
|
|
116
139
|
|
|
@@ -143,7 +166,8 @@ class NodeInfo:
|
|
|
143
166
|
return names
|
|
144
167
|
|
|
145
168
|
def _get_dependency_info(
|
|
146
|
-
self,
|
|
169
|
+
self,
|
|
170
|
+
markers: list[Mark],
|
|
147
171
|
) -> list[TestDependencyInfo] | None:
|
|
148
172
|
"""Extract and parse dependency information.
|
|
149
173
|
|
|
@@ -197,3 +221,33 @@ class NodeInfo:
|
|
|
197
221
|
bool: True if test or module is critical, False otherwise
|
|
198
222
|
"""
|
|
199
223
|
return any(marker.name == "critical" for marker in markers)
|
|
224
|
+
|
|
225
|
+
def _get_group(
|
|
226
|
+
self,
|
|
227
|
+
markers: list[Mark],
|
|
228
|
+
marker_name: str,
|
|
229
|
+
) -> Group:
|
|
230
|
+
"""Get group from markers or use default.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
markers (list[Mark]): item markers list
|
|
234
|
+
marker_name (str): marker name
|
|
235
|
+
Returns:
|
|
236
|
+
Group: group from marker or default (Group.MAIN)
|
|
237
|
+
"""
|
|
238
|
+
for marker in markers:
|
|
239
|
+
if marker.name == marker_name and marker.args:
|
|
240
|
+
arg = marker.args[0]
|
|
241
|
+
|
|
242
|
+
if isinstance(arg, Group):
|
|
243
|
+
return arg
|
|
244
|
+
if isinstance(arg, str):
|
|
245
|
+
valid_groups = {group.value for group in Group}
|
|
246
|
+
if arg not in valid_groups:
|
|
247
|
+
msg = f"Invalid group '{arg}'. Valid groups are: {', '.join(valid_groups)}" # noqa: E501
|
|
248
|
+
raise ValueError(msg)
|
|
249
|
+
return Group(arg)
|
|
250
|
+
msg = f"Group marker argument must be either string or Group enum, got {type(arg)}" # noqa: E501
|
|
251
|
+
raise ValueError(msg)
|
|
252
|
+
|
|
253
|
+
return Group.MAIN
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Copyright (c) 2025 Everypin
|
|
2
|
+
# GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from pydantic import model_validator
|
|
7
|
+
|
|
8
|
+
from hardpy.pytest_hardpy.db.schema.v1 import (
|
|
9
|
+
Chart as ChartModel,
|
|
10
|
+
Instrument as InstrumentModel,
|
|
11
|
+
NumericMeasurement as NumericMeasurementModel,
|
|
12
|
+
StringMeasurement as StringMeasurementModel,
|
|
13
|
+
SubUnit as SubUnitModel,
|
|
14
|
+
)
|
|
15
|
+
from hardpy.pytest_hardpy.utils.const import ComparisonOperation as CompOp
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Instrument(InstrumentModel):
|
|
19
|
+
"""Test stand instrument (equipment)."""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SubUnit(SubUnitModel):
|
|
23
|
+
"""Sub unit of DUT."""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class NumericMeasurement(NumericMeasurementModel):
|
|
27
|
+
"""Represents a numeric measurement with value and comparison operation.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
value (int | float): The value of the measurement.
|
|
31
|
+
name (str | None): The name of the measurement.
|
|
32
|
+
unit (str | None): The unit of the measurement.
|
|
33
|
+
operation (CompOp | None): The comparison operation to apply.
|
|
34
|
+
comparison_value (int | float | None): The value to compare against.
|
|
35
|
+
lower_limit (int | float | None): The lower limit for range operations.
|
|
36
|
+
upper_limit (int | float | None): The upper limit for range operations.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
@model_validator(mode="after")
|
|
40
|
+
def validate_operation_requirements(self) -> NumericMeasurement:
|
|
41
|
+
"""Validate field requirements based on selected operation."""
|
|
42
|
+
if (
|
|
43
|
+
self.operation
|
|
44
|
+
in (CompOp.EQ, CompOp.NE, CompOp.GT, CompOp.LT, CompOp.GE, CompOp.LE)
|
|
45
|
+
and self.comparison_value is None
|
|
46
|
+
):
|
|
47
|
+
msg = f"Comparison_value required for {self.operation} operation"
|
|
48
|
+
raise ValueError(msg)
|
|
49
|
+
|
|
50
|
+
if self.operation in (
|
|
51
|
+
CompOp.GTLT,
|
|
52
|
+
CompOp.GELE,
|
|
53
|
+
CompOp.GELT,
|
|
54
|
+
CompOp.GTLE,
|
|
55
|
+
CompOp.LTGT,
|
|
56
|
+
CompOp.LEGE,
|
|
57
|
+
CompOp.LEGT,
|
|
58
|
+
CompOp.LTGE,
|
|
59
|
+
) and (self.lower_limit is None or self.upper_limit is None):
|
|
60
|
+
msg = "lower_limit and upper_limit required for range operations"
|
|
61
|
+
raise ValueError(msg)
|
|
62
|
+
|
|
63
|
+
if self.operation:
|
|
64
|
+
self.result = self._check_condition()
|
|
65
|
+
|
|
66
|
+
return self
|
|
67
|
+
|
|
68
|
+
def _check_condition(self) -> bool: # noqa: C901,PLR0912
|
|
69
|
+
"""Evaluate the measurement based on the selected operation."""
|
|
70
|
+
res = False
|
|
71
|
+
match self.operation:
|
|
72
|
+
case CompOp.EQ:
|
|
73
|
+
res = self.value == self.comparison_value
|
|
74
|
+
case CompOp.NE:
|
|
75
|
+
res = self.value != self.comparison_value
|
|
76
|
+
case CompOp.GT:
|
|
77
|
+
res = self.value > self.comparison_value
|
|
78
|
+
case CompOp.LT:
|
|
79
|
+
res = self.value < self.comparison_value
|
|
80
|
+
case CompOp.GE:
|
|
81
|
+
res = self.value >= self.comparison_value
|
|
82
|
+
case CompOp.LE:
|
|
83
|
+
res = self.value <= self.comparison_value
|
|
84
|
+
case CompOp.GTLT:
|
|
85
|
+
res = self.value > self.lower_limit and self.value < self.upper_limit
|
|
86
|
+
case CompOp.GELE:
|
|
87
|
+
res = self.value >= self.lower_limit and self.value <= self.upper_limit
|
|
88
|
+
case CompOp.GELT:
|
|
89
|
+
res = self.value >= self.lower_limit and self.value < self.upper_limit
|
|
90
|
+
case CompOp.GTLE:
|
|
91
|
+
res = self.value > self.lower_limit and self.value <= self.upper_limit
|
|
92
|
+
case CompOp.LTGT:
|
|
93
|
+
res = self.value < self.lower_limit or self.value > self.upper_limit
|
|
94
|
+
case CompOp.LEGE:
|
|
95
|
+
res = self.value <= self.lower_limit or self.value >= self.upper_limit
|
|
96
|
+
case CompOp.LEGT:
|
|
97
|
+
res = self.value <= self.lower_limit or self.value > self.upper_limit
|
|
98
|
+
case CompOp.LTGE:
|
|
99
|
+
res = self.value < self.lower_limit or self.value >= self.upper_limit
|
|
100
|
+
return res
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class StringMeasurement(StringMeasurementModel):
|
|
104
|
+
"""Represents a string measurement with value and comparison operation.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
value (str): The value of the measurement.
|
|
108
|
+
name (str | None): The name of the measurement.
|
|
109
|
+
operation (CompOp | None): The comparison operation to apply.
|
|
110
|
+
comparison_value (str | None): The value to compare against.
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
@model_validator(mode="after")
|
|
114
|
+
def validate_operation_requirements(self) -> StringMeasurement:
|
|
115
|
+
"""Validate field requirements based on selected operation."""
|
|
116
|
+
string_operations = (CompOp.EQ, CompOp.NE)
|
|
117
|
+
if self.operation in string_operations and self.comparison_value is None:
|
|
118
|
+
msg = f"Comparison_value required for {self.operation} operation"
|
|
119
|
+
raise ValueError(msg)
|
|
120
|
+
|
|
121
|
+
if self.operation and self.operation not in string_operations:
|
|
122
|
+
msg = f"{self.operation} is not a valid string operation"
|
|
123
|
+
raise ValueError(msg)
|
|
124
|
+
|
|
125
|
+
if self.operation:
|
|
126
|
+
self.result = self._check_condition()
|
|
127
|
+
|
|
128
|
+
return self
|
|
129
|
+
|
|
130
|
+
def _check_condition(self) -> bool:
|
|
131
|
+
"""Evaluate the measurement based on the selected operation."""
|
|
132
|
+
res = False
|
|
133
|
+
match self.operation:
|
|
134
|
+
case CompOp.EQ:
|
|
135
|
+
if self.casesensitive:
|
|
136
|
+
res = self.value == self.comparison_value
|
|
137
|
+
else:
|
|
138
|
+
res = self.value.lower() == self.comparison_value.lower()
|
|
139
|
+
case CompOp.NE:
|
|
140
|
+
if self.casesensitive:
|
|
141
|
+
res = self.value != self.comparison_value
|
|
142
|
+
else:
|
|
143
|
+
res = self.value.lower() != self.comparison_value.lower()
|
|
144
|
+
return res
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class Chart(ChartModel):
|
|
148
|
+
"""Represents a chart with data and labels.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
type (ChartType | None): chart type.
|
|
152
|
+
title (str | None): chart title.
|
|
153
|
+
x_label (str | None): X label.
|
|
154
|
+
y_label (str | None): Y label.
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
@model_validator(mode="after")
|
|
158
|
+
def validate_lines(self) -> Chart:
|
|
159
|
+
"""Validate field requirements based on selected operation."""
|
|
160
|
+
self._diff_list_len_validator(self.x_data, self.y_data)
|
|
161
|
+
self._diff_list_len_validator(self.x_data, self.marker_name)
|
|
162
|
+
|
|
163
|
+
if len(self.x_data):
|
|
164
|
+
for i in range(len(self.x_data)):
|
|
165
|
+
self._diff_list_len_validator(self.x_data[i], self.y_data[i])
|
|
166
|
+
self._empty_list_validator(self.x_data[0])
|
|
167
|
+
self._empty_list_validator(self.marker_name)
|
|
168
|
+
|
|
169
|
+
return self
|
|
170
|
+
|
|
171
|
+
def add_series(
|
|
172
|
+
self,
|
|
173
|
+
x_data: list[int | float],
|
|
174
|
+
y_data: list[int | float],
|
|
175
|
+
marker_name: str | None = None,
|
|
176
|
+
) -> None:
|
|
177
|
+
"""Add data series to chart.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
x_data (list[int | float]): X data.
|
|
181
|
+
y_data (list[int | float]): Y data.
|
|
182
|
+
marker_name (str | None): series marker name.
|
|
183
|
+
"""
|
|
184
|
+
self._diff_list_len_validator(x_data, y_data)
|
|
185
|
+
self._empty_list_validator(x_data)
|
|
186
|
+
self.x_data.append(x_data)
|
|
187
|
+
self.y_data.append(y_data)
|
|
188
|
+
self.marker_name.append(marker_name)
|
|
189
|
+
|
|
190
|
+
def _diff_list_len_validator(self, data1: list, data2: list) -> None:
|
|
191
|
+
if len(data1) != len(data2):
|
|
192
|
+
msg = "data in single series must have the same length"
|
|
193
|
+
raise ValueError(msg)
|
|
194
|
+
|
|
195
|
+
def _empty_list_validator(self, data: list) -> None:
|
|
196
|
+
if len(data) == 0:
|
|
197
|
+
msg = "data series cannot be empty"
|
|
198
|
+
raise ValueError(msg)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hardpy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.1
|
|
4
4
|
Summary: HardPy library for device testing
|
|
5
5
|
Project-URL: Homepage, https://github.com/everypinio/hardpy/
|
|
6
6
|
Project-URL: Documentation, https://everypinio.github.io/hardpy/
|
|
@@ -51,6 +51,7 @@ Requires-Dist: ruff==0.8.0; extra == 'dev'
|
|
|
51
51
|
Requires-Dist: wemake-python-styleguide>=0.19.2; extra == 'dev'
|
|
52
52
|
Provides-Extra: tests
|
|
53
53
|
Requires-Dist: psutil~=7.0.0; extra == 'tests'
|
|
54
|
+
Requires-Dist: pytest-timeout==2.4.0; extra == 'tests'
|
|
54
55
|
Description-Content-Type: text/markdown
|
|
55
56
|
|
|
56
57
|
<h1 align="center">
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
hardpy/__init__.py,sha256=
|
|
1
|
+
hardpy/__init__.py,sha256=wIDpTCST_Cod8rJ3k-ilLHGjhbF6pU3_TFZUtwcwQZM,2866
|
|
2
2
|
hardpy/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
hardpy/cli/cli.py,sha256
|
|
3
|
+
hardpy/cli/cli.py,sha256=-KS8qggaCGz0Hcdd4TLJPwKpVSDfubSp5t5cWuXoMUc,9434
|
|
4
4
|
hardpy/cli/template.py,sha256=44phTqeKgFch5xdAJmDQ-za1mM1_z60izRVbmCQHU-8,6225
|
|
5
5
|
hardpy/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
hardpy/common/config.py,sha256=
|
|
6
|
+
hardpy/common/config.py,sha256=ei-NhZ72qdkNM1HnjWu6vgEgB4lEzTbWokZRaL2GAug,4998
|
|
7
7
|
hardpy/common/stand_cloud/__init__.py,sha256=fezdiYAehtT2H-GAef-xZU12CbmCRe64XHA9UB3kJDU,456
|
|
8
|
-
hardpy/common/stand_cloud/connector.py,sha256=
|
|
8
|
+
hardpy/common/stand_cloud/connector.py,sha256=scmKT09duPqqbQtwMNPnl59si_sErwqAY2PeiTSCZvg,7389
|
|
9
9
|
hardpy/common/stand_cloud/exception.py,sha256=eKkqu5ylDRIGN_yZhvz2xVGm49XmlZ8nryALgdRqpbY,287
|
|
10
10
|
hardpy/common/stand_cloud/oauth2.py,sha256=SDqtIwcuMgqfBkEZyo3GXeVPnvRBOr6dzeXowx3ZkEw,2803
|
|
11
11
|
hardpy/common/stand_cloud/registration.py,sha256=UW-JGcvON5CMQQ-s2Mb4Ee3u_jmdQfSj3vPfZ_FuhHY,2370
|
|
12
12
|
hardpy/common/stand_cloud/token_manager.py,sha256=8dX802F0CnOrOjOQInyYCrvuRdK0CeiCrTDITAbSLgQ,4055
|
|
13
13
|
hardpy/common/stand_cloud/utils.py,sha256=GN3wzbrmF-Xe5iUXf_HurGO-YKltqd3Gc_7vG2eEL7c,692
|
|
14
14
|
hardpy/hardpy_panel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
hardpy/hardpy_panel/api.py,sha256=
|
|
15
|
+
hardpy/hardpy_panel/api.py,sha256=xQZBv9zJ3uIVvMO_pb-zyty6vrOkFGHZCZpdvg_clVI,3865
|
|
16
16
|
hardpy/hardpy_panel/frontend/dist/favicon.ico,sha256=sgIk5PKUKEKBDpkSrc8dJgjpObp0iF82Mec0GpfKId4,15406
|
|
17
17
|
hardpy/hardpy_panel/frontend/dist/index.html,sha256=HgsuTaNZg-rq6m18f8RRijfxcEPwQNDzb9Dxc1rkaCY,1851
|
|
18
18
|
hardpy/hardpy_panel/frontend/dist/logo192.png,sha256=E4K7drvhJCg9HcTpRihOXZhVJVBZ7-W97Se-3tDb46o,14485
|
|
@@ -45,21 +45,21 @@ hardpy/hardpy_panel/frontend/dist/locales/ja/translation.json,sha256=xSDe9TN1f3g
|
|
|
45
45
|
hardpy/hardpy_panel/frontend/dist/locales/ru/translation.json,sha256=Zo_5GhOFIwOnpQITD5x2Q7CYTI9Pdpvv844_ieW56jY,2609
|
|
46
46
|
hardpy/hardpy_panel/frontend/dist/locales/zh/translation.json,sha256=uxYSv8eXTMDewPvbFZSh21ZP0Wy4mx32XbbVkzXzlls,1790
|
|
47
47
|
hardpy/pytest_hardpy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
|
-
hardpy/pytest_hardpy/plugin.py,sha256=
|
|
49
|
-
hardpy/pytest_hardpy/pytest_call.py,sha256=
|
|
50
|
-
hardpy/pytest_hardpy/pytest_wrapper.py,sha256=
|
|
48
|
+
hardpy/pytest_hardpy/plugin.py,sha256=2B-jNRfuY30m6i0TPjeVetR9_oGs15bnYXd_gQ2hSDI,21102
|
|
49
|
+
hardpy/pytest_hardpy/pytest_call.py,sha256=v5ACrfxlFA9JOfwPiv2ELhiuoggE_tAgNZkuBKQzBwo,21503
|
|
50
|
+
hardpy/pytest_hardpy/pytest_wrapper.py,sha256=0tG725R3qhLI6t6zi0-OL17FCwt3YI-mwrBjWe4U9A4,4694
|
|
51
51
|
hardpy/pytest_hardpy/db/__init__.py,sha256=G6y13JPh8HaH2O9E3_LTH_bTUVSgiezQFjDGaNIljec,557
|
|
52
52
|
hardpy/pytest_hardpy/db/base_connector.py,sha256=5a476F5LwvFUfQ4Yc0Q6biacULDrCk8UHPlpc6n0NRQ,1111
|
|
53
53
|
hardpy/pytest_hardpy/db/base_server.py,sha256=XqTff225iIymPYUGGEja9r9WOilVw7ljcAVp1M8VuAI,404
|
|
54
|
-
hardpy/pytest_hardpy/db/base_store.py,sha256=
|
|
55
|
-
hardpy/pytest_hardpy/db/const.py,sha256=
|
|
54
|
+
hardpy/pytest_hardpy/db/base_store.py,sha256=hj2ACXIbVzYD28VL49ZjSo-uDmFLaVsBTBgCCwhqb4s,4484
|
|
55
|
+
hardpy/pytest_hardpy/db/const.py,sha256=E_A0IKGeS3qyPX4fTfUE5ksARsrTKSVWqUkdmh8S_fo,1414
|
|
56
56
|
hardpy/pytest_hardpy/db/runstore.py,sha256=tCXWo2AW0er3lbDcCqYbYxOBbINMZNtfnnjlIJpXmIA,949
|
|
57
57
|
hardpy/pytest_hardpy/db/statestore.py,sha256=0sv4AqzwW_J34O-cb7aN3zmgULIVtZRi_qg4XvC2_L0,586
|
|
58
58
|
hardpy/pytest_hardpy/db/schema/__init__.py,sha256=1S73W3PLQt8gX5Y33nbX1JdwLvnrtlKH4cElID3pwuc,263
|
|
59
|
-
hardpy/pytest_hardpy/db/schema/v1.py,sha256=
|
|
59
|
+
hardpy/pytest_hardpy/db/schema/v1.py,sha256=L-x3xunLtP3FnBRdduSP5SpqaNARwwbp1ICXy58VdcA,6238
|
|
60
60
|
hardpy/pytest_hardpy/reporter/__init__.py,sha256=rztpM2HlLUpMOvad0JHbZU4Mk8PDDQyCFXLhpLktGQI,322
|
|
61
61
|
hardpy/pytest_hardpy/reporter/base.py,sha256=KRkc5a7yk9ZsQ92gnBdHhJEXSSQiTWbEMSMzRMpJDFY,2915
|
|
62
|
-
hardpy/pytest_hardpy/reporter/hook_reporter.py,sha256=
|
|
62
|
+
hardpy/pytest_hardpy/reporter/hook_reporter.py,sha256=vkN78UtXs5M-rmpDdxjFEwrAPOFIpSEU8TRZUdnuWJY,14619
|
|
63
63
|
hardpy/pytest_hardpy/reporter/runner_reporter.py,sha256=YsK8wrLIulsixePG6WNfC4MagpKfhP5j0CUaXkcfeL0,790
|
|
64
64
|
hardpy/pytest_hardpy/result/__init__.py,sha256=2afpuEuOcxYfIEOwWzsGZe960iQaPVCmsbYujijQg1s,592
|
|
65
65
|
hardpy/pytest_hardpy/result/couchdb_config.py,sha256=ujxyJYM2pdZzi3GZ2Zysbz2_ZeTRN5sQc8AGuzRJm_0,3243
|
|
@@ -67,19 +67,20 @@ hardpy/pytest_hardpy/result/report_loader/__init__.py,sha256=wq5Y-_JW2ExCRnQ9VVe
|
|
|
67
67
|
hardpy/pytest_hardpy/result/report_loader/couchdb_loader.py,sha256=KcZ0JkCgWhrj2J9M04JBDy0fpqtpVEYtu9GCLDG27pU,2255
|
|
68
68
|
hardpy/pytest_hardpy/result/report_loader/stand_cloud_loader.py,sha256=daS4cM3egwj8ej6yjLAMlM5zBIOwbWBBroF47nukQ5s,2478
|
|
69
69
|
hardpy/pytest_hardpy/result/report_reader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
70
|
-
hardpy/pytest_hardpy/result/report_reader/couchdb_reader.py,sha256=
|
|
70
|
+
hardpy/pytest_hardpy/result/report_reader/couchdb_reader.py,sha256=lnWSX-0QKbdMwtqfCtW0tiH9W_ZEPqQ3rb7Lc8gES7E,5726
|
|
71
71
|
hardpy/pytest_hardpy/result/report_reader/stand_cloud_reader.py,sha256=uT7YSBu1QyURH9IkgRCdpbinn8LKXUhgVEhwPmGZV7I,3636
|
|
72
|
-
hardpy/pytest_hardpy/utils/__init__.py,sha256=
|
|
72
|
+
hardpy/pytest_hardpy/utils/__init__.py,sha256=fXIPMCP6QTIQAR18RnPTxBYo-fQibN3ceaBgONdRJVc,1752
|
|
73
73
|
hardpy/pytest_hardpy/utils/connection_data.py,sha256=Oq1LdIpmYkwakNCNwAPD-FTH4W7lj_v8vYkQCqJTof8,449
|
|
74
|
-
hardpy/pytest_hardpy/utils/const.py,sha256=
|
|
74
|
+
hardpy/pytest_hardpy/utils/const.py,sha256=xS3jBrW_D6IUTlAjSnLiHvSthieRHCj3uN_6fFAXS0w,1832
|
|
75
75
|
hardpy/pytest_hardpy/utils/dialog_box.py,sha256=LNukQ7ukUzLUFmwwH6L6M8wWmF-Mo4HF-UpVkyf8nY8,11224
|
|
76
|
-
hardpy/pytest_hardpy/utils/exception.py,sha256=
|
|
76
|
+
hardpy/pytest_hardpy/utils/exception.py,sha256=1l2VBZLUnjPDoOs744MtaP7Y9FuXUq7koSdH2Eo31nk,1042
|
|
77
77
|
hardpy/pytest_hardpy/utils/machineid.py,sha256=6JAzUt7KtjTYn8kL9hSMaCQ20U8liH-zDT9v-5Ch7Q8,296
|
|
78
|
-
hardpy/pytest_hardpy/utils/node_info.py,sha256=
|
|
78
|
+
hardpy/pytest_hardpy/utils/node_info.py,sha256=DaW566WvsyWR66CThuZ38UoHwQa-pu-4WRLg61OXDnE,7134
|
|
79
79
|
hardpy/pytest_hardpy/utils/progress_calculator.py,sha256=TPl2gG0ZSvMe8otPythhF9hkD6fa6-mJAhy9yI83-yE,1071
|
|
80
80
|
hardpy/pytest_hardpy/utils/singleton.py,sha256=tjUGs48o_vBeVpRsEBZEOTCoCUikpIFmQ1c3rsfymso,948
|
|
81
|
-
hardpy
|
|
82
|
-
hardpy-0.
|
|
83
|
-
hardpy-0.
|
|
84
|
-
hardpy-0.
|
|
85
|
-
hardpy-0.
|
|
81
|
+
hardpy/pytest_hardpy/utils/stand_type.py,sha256=p3AFtgMt-sn8QXRp60YM-xo2mEjZHUhYr_Mxhz1WyP0,7438
|
|
82
|
+
hardpy-0.15.1.dist-info/METADATA,sha256=d22v4-7WgRCOwz7YDfQcl-F7DHA0KsmtOM0E81x77AA,4058
|
|
83
|
+
hardpy-0.15.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
84
|
+
hardpy-0.15.1.dist-info/entry_points.txt,sha256=nL2sMkKMScNaOE0IPkYnu9Yr-BUswZvGSrwY-SxHY3E,102
|
|
85
|
+
hardpy-0.15.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
86
|
+
hardpy-0.15.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|