hardpy 0.2.0__py3-none-any.whl → 0.4.0__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 +9 -1
- hardpy/hardpy_panel/api.py +15 -0
- hardpy/hardpy_panel/frontend/dist/asset-manifest.json +3 -3
- hardpy/hardpy_panel/frontend/dist/index.html +1 -1
- hardpy/hardpy_panel/frontend/dist/static/js/main.37744128.js +3 -0
- hardpy/hardpy_panel/frontend/dist/static/js/main.37744128.js.map +1 -0
- hardpy/hardpy_panel/runner.py +2 -0
- hardpy/pytest_hardpy/db/base_store.py +21 -11
- hardpy/pytest_hardpy/db/const.py +1 -0
- hardpy/pytest_hardpy/db/schema.py +23 -2
- hardpy/pytest_hardpy/plugin.py +72 -4
- hardpy/pytest_hardpy/pytest_call.py +100 -11
- hardpy/pytest_hardpy/pytest_wrapper.py +29 -0
- hardpy/pytest_hardpy/reporter/base.py +30 -12
- hardpy/pytest_hardpy/reporter/hook_reporter.py +38 -40
- hardpy/pytest_hardpy/utils/__init__.py +17 -1
- hardpy/pytest_hardpy/utils/config_data.py +5 -1
- hardpy/pytest_hardpy/utils/dialog_box.py +100 -0
- hardpy/pytest_hardpy/utils/exception.py +7 -0
- hardpy/pytest_hardpy/utils/node_info.py +66 -0
- {hardpy-0.2.0.dist-info → hardpy-0.4.0.dist-info}/METADATA +9 -2
- {hardpy-0.2.0.dist-info → hardpy-0.4.0.dist-info}/RECORD +26 -25
- hardpy/hardpy_panel/frontend/dist/static/js/main.8ef63e9b.js +0 -3
- hardpy/hardpy_panel/frontend/dist/static/js/main.8ef63e9b.js.map +0 -1
- /hardpy/hardpy_panel/frontend/dist/static/js/{main.8ef63e9b.js.LICENSE.txt → main.37744128.js.LICENSE.txt} +0 -0
- {hardpy-0.2.0.dist-info → hardpy-0.4.0.dist-info}/WHEEL +0 -0
- {hardpy-0.2.0.dist-info → hardpy-0.4.0.dist-info}/entry_points.txt +0 -0
- {hardpy-0.2.0.dist-info → hardpy-0.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -25,23 +25,23 @@ class HookReporter(BaseReporter):
|
|
|
25
25
|
Args:
|
|
26
26
|
doc_name (str): test run name
|
|
27
27
|
"""
|
|
28
|
-
self.
|
|
29
|
-
self.
|
|
30
|
-
self.
|
|
31
|
-
self.
|
|
32
|
-
self.
|
|
33
|
-
self.
|
|
34
|
-
self.
|
|
35
|
-
self.
|
|
28
|
+
self.set_doc_value(DF.NAME, doc_name)
|
|
29
|
+
self.set_doc_value(DF.STATUS, TestStatus.READY)
|
|
30
|
+
self.set_doc_value(DF.START_TIME, None)
|
|
31
|
+
self.set_doc_value(DF.TIMEZONE, None)
|
|
32
|
+
self.set_doc_value(DF.STOP_TIME, None)
|
|
33
|
+
self.set_doc_value(DF.PROGRESS, 0)
|
|
34
|
+
self.set_doc_value(DF.DRIVERS, {})
|
|
35
|
+
self.set_doc_value(DF.ARTIFACT, {}, runstore_only=True)
|
|
36
36
|
|
|
37
37
|
def start(self):
|
|
38
38
|
"""Start test."""
|
|
39
39
|
self._log.debug("Starting test run.")
|
|
40
40
|
start_time = int(time())
|
|
41
|
-
self.
|
|
42
|
-
self.
|
|
43
|
-
self.
|
|
44
|
-
self.
|
|
41
|
+
self.set_doc_value(DF.START_TIME, start_time)
|
|
42
|
+
self.set_doc_value(DF.STATUS, TestStatus.RUN)
|
|
43
|
+
self.set_doc_value(DF.TIMEZONE, tzname) # noqa: WPS432
|
|
44
|
+
self.set_doc_value(DF.PROGRESS, 0)
|
|
45
45
|
|
|
46
46
|
def finish(self, status: RunStatus):
|
|
47
47
|
"""Finish test.
|
|
@@ -50,15 +50,11 @@ class HookReporter(BaseReporter):
|
|
|
50
50
|
"""
|
|
51
51
|
self._log.debug("Finishing test run.")
|
|
52
52
|
stop_time = int(time())
|
|
53
|
-
self.
|
|
54
|
-
self.
|
|
55
|
-
|
|
56
|
-
if self._statestore.get_document():
|
|
57
|
-
self._log.debug("Report StateStore has been successfully validated.")
|
|
58
|
-
|
|
59
|
-
if self._runstore.get_document():
|
|
60
|
-
self._log.debug("Report RunStore has been successfully validated.")
|
|
53
|
+
self.set_doc_value(DF.STOP_TIME, stop_time)
|
|
54
|
+
self.set_doc_value(DF.STATUS, status)
|
|
61
55
|
|
|
56
|
+
def compact_all(self):
|
|
57
|
+
"""Compact all databases"""
|
|
62
58
|
self._statestore.compact()
|
|
63
59
|
self._runstore.compact()
|
|
64
60
|
|
|
@@ -68,7 +64,7 @@ class HookReporter(BaseReporter):
|
|
|
68
64
|
Args:
|
|
69
65
|
progress (int): test progress
|
|
70
66
|
"""
|
|
71
|
-
self.
|
|
67
|
+
self.set_doc_value(DF.PROGRESS, progress)
|
|
72
68
|
|
|
73
69
|
def set_assertion_msg(self, module_id: str, case_id: str, msg: str | None):
|
|
74
70
|
"""Set case assertion message.
|
|
@@ -81,7 +77,7 @@ class HookReporter(BaseReporter):
|
|
|
81
77
|
key = self.generate_key(
|
|
82
78
|
DF.MODULES, module_id, DF.CASES, case_id, DF.ASSERTION_MSG
|
|
83
79
|
)
|
|
84
|
-
self.
|
|
80
|
+
self.set_doc_value(key, msg)
|
|
85
81
|
|
|
86
82
|
def add_case(self, node_info: NodeInfo):
|
|
87
83
|
"""Add test case to document.
|
|
@@ -90,18 +86,15 @@ class HookReporter(BaseReporter):
|
|
|
90
86
|
node_info (NodeInfo): node info
|
|
91
87
|
"""
|
|
92
88
|
key = DF.MODULES
|
|
89
|
+
|
|
93
90
|
item_statestore = self._statestore.get_field(key)
|
|
94
91
|
item_runstore = self._runstore.get_field(key)
|
|
95
92
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
item_runstore,
|
|
99
|
-
node_info,
|
|
100
|
-
is_use_artifact=True,
|
|
101
|
-
)
|
|
93
|
+
self._init_case(item_statestore, node_info, is_only_statestore=True)
|
|
94
|
+
self._init_case(item_runstore, node_info, is_only_runstore=True)
|
|
102
95
|
|
|
103
|
-
self.
|
|
104
|
-
self.
|
|
96
|
+
self.set_doc_value(key, item_statestore, statestore_only=True)
|
|
97
|
+
self.set_doc_value(key, item_runstore, runstore_only=True)
|
|
105
98
|
|
|
106
99
|
def set_case_status(self, module_id: str, case_id: str, status: TestStatus):
|
|
107
100
|
"""Set test case status.
|
|
@@ -112,7 +105,7 @@ class HookReporter(BaseReporter):
|
|
|
112
105
|
status (TestStatus): test case status
|
|
113
106
|
"""
|
|
114
107
|
key = self.generate_key(DF.MODULES, module_id, DF.CASES, case_id, DF.STATUS)
|
|
115
|
-
self.
|
|
108
|
+
self.set_doc_value(key, status)
|
|
116
109
|
|
|
117
110
|
def set_case_start_time(self, module_id: str, case_id: str):
|
|
118
111
|
"""Set test case start_time.
|
|
@@ -142,7 +135,7 @@ class HookReporter(BaseReporter):
|
|
|
142
135
|
status (TestStatus): test module status
|
|
143
136
|
"""
|
|
144
137
|
key = self.generate_key(DF.MODULES, module_id, DF.STATUS)
|
|
145
|
-
self.
|
|
138
|
+
self.set_doc_value(key, status)
|
|
146
139
|
|
|
147
140
|
def set_module_start_time(self, module_id: str):
|
|
148
141
|
"""Set test module status.
|
|
@@ -175,16 +168,20 @@ class HookReporter(BaseReporter):
|
|
|
175
168
|
rm_outdated_nodes = self._remove_outdate_node(old_modules, modules_copy, nodes)
|
|
176
169
|
updated_case_order = self._update_case_order(rm_outdated_nodes, nodes)
|
|
177
170
|
updated_module_order = self._update_module_order(updated_case_order)
|
|
178
|
-
self.
|
|
171
|
+
self.set_doc_value(key, updated_module_order, statestore_only=True)
|
|
179
172
|
|
|
180
173
|
def _set_time(self, key: str):
|
|
181
174
|
current_time = self._statestore.get_field(key)
|
|
182
175
|
if current_time is None:
|
|
183
|
-
self.
|
|
176
|
+
self.set_doc_value(key, int(time()))
|
|
184
177
|
|
|
185
178
|
def _init_case(
|
|
186
|
-
self,
|
|
187
|
-
|
|
179
|
+
self,
|
|
180
|
+
item: dict,
|
|
181
|
+
node_info: NodeInfo,
|
|
182
|
+
is_only_runstore: bool = False,
|
|
183
|
+
is_only_statestore: bool = False,
|
|
184
|
+
):
|
|
188
185
|
module_default = { # noqa: WPS204
|
|
189
186
|
DF.STATUS: TestStatus.READY,
|
|
190
187
|
DF.NAME: self._get_module_name(node_info),
|
|
@@ -202,7 +199,7 @@ class HookReporter(BaseReporter):
|
|
|
202
199
|
}
|
|
203
200
|
|
|
204
201
|
if item.get(node_info.module_id) is None: # noqa: WPS204
|
|
205
|
-
if
|
|
202
|
+
if is_only_runstore:
|
|
206
203
|
module_default[DF.ARTIFACT] = {}
|
|
207
204
|
item[node_info.module_id] = module_default # noqa: WPS204
|
|
208
205
|
else:
|
|
@@ -212,11 +209,12 @@ class HookReporter(BaseReporter):
|
|
|
212
209
|
item[node_info.module_id][DF.STOP_TIME] = None
|
|
213
210
|
item[node_info.module_id][DF.NAME] = self._get_module_name(node_info)
|
|
214
211
|
|
|
215
|
-
if
|
|
212
|
+
if is_only_runstore:
|
|
216
213
|
case_default[DF.ARTIFACT] = {}
|
|
217
|
-
item[node_info.module_id][DF.CASES][node_info.case_id] = case_default
|
|
218
214
|
|
|
219
|
-
|
|
215
|
+
if is_only_statestore:
|
|
216
|
+
case_default[DF.DIALOG_BOX] = {}
|
|
217
|
+
item[node_info.module_id][DF.CASES][node_info.case_id] = case_default
|
|
220
218
|
|
|
221
219
|
def _remove_outdate_node(
|
|
222
220
|
self, old_modules: dict, new_modules: dict, nodes: dict
|
|
@@ -6,7 +6,17 @@ from hardpy.pytest_hardpy.utils.progress_calculator import ProgressCalculator
|
|
|
6
6
|
from hardpy.pytest_hardpy.utils.const import TestStatus, RunStatus
|
|
7
7
|
from hardpy.pytest_hardpy.utils.singleton import Singleton
|
|
8
8
|
from hardpy.pytest_hardpy.utils.config_data import ConfigData
|
|
9
|
-
from hardpy.pytest_hardpy.utils.exception import
|
|
9
|
+
from hardpy.pytest_hardpy.utils.exception import (
|
|
10
|
+
DuplicateSerialNumberError,
|
|
11
|
+
DuplicateDialogBoxError,
|
|
12
|
+
)
|
|
13
|
+
from hardpy.pytest_hardpy.utils.dialog_box import (
|
|
14
|
+
DialogBox,
|
|
15
|
+
DialogBoxWidget,
|
|
16
|
+
DialogBoxWidgetType,
|
|
17
|
+
generate_dialog_box_dict,
|
|
18
|
+
get_dialog_box_data,
|
|
19
|
+
)
|
|
10
20
|
|
|
11
21
|
__all__ = [
|
|
12
22
|
"NodeInfo",
|
|
@@ -16,4 +26,10 @@ __all__ = [
|
|
|
16
26
|
"Singleton",
|
|
17
27
|
"ConfigData",
|
|
18
28
|
"DuplicateSerialNumberError",
|
|
29
|
+
"DuplicateDialogBoxError",
|
|
30
|
+
"DialogBox",
|
|
31
|
+
"DialogBoxWidget",
|
|
32
|
+
"DialogBoxWidgetType",
|
|
33
|
+
"generate_dialog_box_dict",
|
|
34
|
+
"get_dialog_box_data",
|
|
19
35
|
]
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# Copyright (c) 2024 Everypin
|
|
2
2
|
# GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
3
3
|
|
|
4
|
-
from
|
|
4
|
+
from socket import gethostname
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
|
+
from hardpy.pytest_hardpy.utils.singleton import Singleton
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
class ConfigData(Singleton):
|
|
9
11
|
"""Web connection data storage."""
|
|
@@ -17,6 +19,8 @@ class ConfigData(Singleton):
|
|
|
17
19
|
self.web_host: str = "0.0.0.0"
|
|
18
20
|
self.web_port: int = 8000
|
|
19
21
|
self.tests_dir = Path.cwd()
|
|
22
|
+
self.socket_port: int = 6525
|
|
23
|
+
self.socket_addr: str = gethostname()
|
|
20
24
|
self._initialized = True
|
|
21
25
|
|
|
22
26
|
@property
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Copyright (c) 2024 Everypin
|
|
2
|
+
# GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
3
|
+
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DialogBoxWidgetType(Enum):
|
|
10
|
+
"""Dialog box widget type."""
|
|
11
|
+
|
|
12
|
+
RADIOBUTTON = "radiobutton"
|
|
13
|
+
CHECKBOX = "checkbox"
|
|
14
|
+
TEXT_INPUT = "textinput"
|
|
15
|
+
NUMERIC_INPUT = "numericinput"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class DialogBoxWidget:
|
|
20
|
+
"""Dialog box widget.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
type (DialogBoxWidgetType): widget type
|
|
24
|
+
info (dict | None): widget info
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
type: DialogBoxWidgetType
|
|
28
|
+
info: dict | None = None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class DialogBox:
|
|
33
|
+
"""Dialog box data.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
dialog_text (str): dialog text
|
|
37
|
+
title_bar (str | None): title bar
|
|
38
|
+
widget (DialogBoxWidget | None): widget info
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
dialog_text: str
|
|
42
|
+
title_bar: str | None = None
|
|
43
|
+
widget: DialogBoxWidget | None = None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def generate_dialog_box_dict(dialog_box_data: DialogBox) -> dict:
|
|
47
|
+
"""Generate dialog box dictionary.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
dialog_box_data (DialogBox): dialog box data
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
dict: dialog box dictionary
|
|
54
|
+
"""
|
|
55
|
+
if dialog_box_data.widget is None:
|
|
56
|
+
data_dict = {
|
|
57
|
+
"title_bar": dialog_box_data.title_bar,
|
|
58
|
+
"dialog_text": dialog_box_data.dialog_text,
|
|
59
|
+
"widget": None,
|
|
60
|
+
}
|
|
61
|
+
else:
|
|
62
|
+
data_dict = {
|
|
63
|
+
"title_bar": dialog_box_data.title_bar,
|
|
64
|
+
"dialog_text": dialog_box_data.dialog_text,
|
|
65
|
+
"widget": {
|
|
66
|
+
"info": dialog_box_data.widget.info,
|
|
67
|
+
"type": dialog_box_data.widget.type.value,
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
return data_dict
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def get_dialog_box_data(
|
|
74
|
+
input_data: str, widget: DialogBoxWidget | None
|
|
75
|
+
) -> Any:
|
|
76
|
+
"""Get the dialog box data in the correct format.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
input_data (str): input string
|
|
80
|
+
widget (DialogBoxWidget | None): widget info
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Any: Dialog box data in the correct format
|
|
84
|
+
"""
|
|
85
|
+
if widget is None:
|
|
86
|
+
return None
|
|
87
|
+
|
|
88
|
+
if widget.type is None:
|
|
89
|
+
raise ValueError("Widget type is `None`, but widget data is not empty")
|
|
90
|
+
|
|
91
|
+
match widget.type:
|
|
92
|
+
case DialogBoxWidgetType.NUMERIC_INPUT:
|
|
93
|
+
try:
|
|
94
|
+
return float(input_data)
|
|
95
|
+
except ValueError:
|
|
96
|
+
return None
|
|
97
|
+
case DialogBoxWidgetType.TEXT_INPUT:
|
|
98
|
+
return input_data
|
|
99
|
+
case _:
|
|
100
|
+
return None
|
|
@@ -14,3 +14,10 @@ class DuplicateSerialNumberError(HardpyError):
|
|
|
14
14
|
|
|
15
15
|
def __init__(self):
|
|
16
16
|
super().__init__(self.__doc__) # type: ignore
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class DuplicateDialogBoxError(HardpyError):
|
|
20
|
+
"""The dialog box has already been determined."""
|
|
21
|
+
|
|
22
|
+
def __init__(self):
|
|
23
|
+
super().__init__(self.__doc__) # type: ignore
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
# Copyright (c) 2024 Everypin
|
|
2
2
|
# GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
3
3
|
|
|
4
|
+
import re
|
|
4
5
|
from logging import getLogger
|
|
5
6
|
from pathlib import Path
|
|
7
|
+
from typing import NamedTuple
|
|
6
8
|
|
|
7
9
|
from pytest import Item, Mark
|
|
8
10
|
|
|
9
11
|
|
|
12
|
+
class TestDependencyInfo(NamedTuple):
|
|
13
|
+
"""Test info."""
|
|
14
|
+
|
|
15
|
+
def __repr__(self) -> str:
|
|
16
|
+
return f"Dependency: {self.module_id}::{self.case_id}"
|
|
17
|
+
|
|
18
|
+
module_id: str
|
|
19
|
+
case_id: str | None
|
|
20
|
+
|
|
21
|
+
|
|
10
22
|
class NodeInfo(object):
|
|
11
23
|
"""Test node info."""
|
|
12
24
|
|
|
@@ -22,25 +34,59 @@ class NodeInfo(object):
|
|
|
22
34
|
item.parent.own_markers,
|
|
23
35
|
"module_name",
|
|
24
36
|
)
|
|
37
|
+
|
|
38
|
+
self._dependency = self._get_dependency_info(
|
|
39
|
+
item.own_markers + item.parent.own_markers
|
|
40
|
+
)
|
|
41
|
+
|
|
25
42
|
self._module_id = Path(item.parent.nodeid).stem
|
|
26
43
|
self._case_id = item.name
|
|
27
44
|
|
|
28
45
|
@property
|
|
29
46
|
def module_id(self):
|
|
47
|
+
"""Get module id.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
str: module id
|
|
51
|
+
"""
|
|
30
52
|
return self._module_id
|
|
31
53
|
|
|
32
54
|
@property
|
|
33
55
|
def case_id(self):
|
|
56
|
+
"""Get case id.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
str: case id
|
|
60
|
+
"""
|
|
34
61
|
return self._case_id
|
|
35
62
|
|
|
36
63
|
@property
|
|
37
64
|
def module_name(self):
|
|
65
|
+
"""Get module name.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
str: module name
|
|
69
|
+
"""
|
|
38
70
|
return self._module_name
|
|
39
71
|
|
|
40
72
|
@property
|
|
41
73
|
def case_name(self):
|
|
74
|
+
"""Get case name.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
str: case name
|
|
78
|
+
"""
|
|
42
79
|
return self._case_name
|
|
43
80
|
|
|
81
|
+
@property
|
|
82
|
+
def dependency(self):
|
|
83
|
+
"""Get dependency information.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
TestDependencyInfo | str: Parsed dependency information.
|
|
87
|
+
"""
|
|
88
|
+
return self._dependency
|
|
89
|
+
|
|
44
90
|
def _get_human_name(self, markers: list[Mark], marker_name: str) -> str:
|
|
45
91
|
"""Get human name from markers.
|
|
46
92
|
|
|
@@ -57,3 +103,23 @@ class NodeInfo(object):
|
|
|
57
103
|
return marker.args[0]
|
|
58
104
|
|
|
59
105
|
return ""
|
|
106
|
+
|
|
107
|
+
def _get_dependency_info(self, markers: list[Mark]) -> TestDependencyInfo | str:
|
|
108
|
+
"""Extract and parse dependency information.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
markers (list[Mark]): item markers list
|
|
112
|
+
marker_name (str): marker name
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
TestDependencyInfo | str | None: Parsed dependency information.
|
|
116
|
+
"""
|
|
117
|
+
dependency_value = self._get_human_name(markers, "dependency")
|
|
118
|
+
dependency_data = re.search(r"(\w+)::(\w+)", dependency_value)
|
|
119
|
+
if dependency_data:
|
|
120
|
+
return TestDependencyInfo(*dependency_data.groups())
|
|
121
|
+
elif re.search(r"^\w+$", dependency_value):
|
|
122
|
+
return TestDependencyInfo(dependency_value, None)
|
|
123
|
+
elif dependency_data is None and dependency_value == "":
|
|
124
|
+
return ""
|
|
125
|
+
raise ValueError
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hardpy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: HardPy library for device testing
|
|
5
5
|
Project-URL: repository, https://github.com/everypindevices/hardpy
|
|
6
6
|
Author: Everypin
|
|
@@ -62,7 +62,7 @@ HardPy is a python library for creating a test bench for devices.
|
|
|
62
62
|
HardPy allows you to:
|
|
63
63
|
|
|
64
64
|
* Create test benches for devices using [pytest](https://docs.pytest.org/);
|
|
65
|
-
* Use a browser to view,
|
|
65
|
+
* Use a browser to view, start, stop, and interact with tests;
|
|
66
66
|
* Store test results in the [CouchDB](https://couchdb.apache.org/) database.
|
|
67
67
|
|
|
68
68
|
## To Install
|
|
@@ -84,6 +84,7 @@ For Windows, follow the instructions from the
|
|
|
84
84
|
[documentation](https://everypinio.github.io/hardpy/documentation/database/#couchdb-instance).
|
|
85
85
|
|
|
86
86
|
Launch CouchDB with Docker.
|
|
87
|
+
The Docker version must be 24.0.0 or higher.
|
|
87
88
|
Create `couchdb.ini` file:
|
|
88
89
|
|
|
89
90
|
```ini
|
|
@@ -103,6 +104,12 @@ Run the Docker container from folder with couchdb.ini file:
|
|
|
103
104
|
docker run --rm --name couchdb -p 5984:5984 -e COUCHDB_USER=dev -e COUCHDB_PASSWORD=dev -v ./couchdb.ini:/opt/couchdb/etc/local.ini couchdb:3.3
|
|
104
105
|
```
|
|
105
106
|
|
|
107
|
+
Command for Windows:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
docker run --rm --name couchdb -p 5984:5984 -e COUCHDB_USER=dev -e COUCHDB_PASSWORD=dev -v .\couchdb.ini:/opt/couchdb/etc/local.ini couchdb:3.3.2
|
|
111
|
+
```
|
|
112
|
+
|
|
106
113
|
#### Test steps
|
|
107
114
|
|
|
108
115
|
Add simple test to `tests` folder
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
hardpy/__init__.py,sha256=
|
|
1
|
+
hardpy/__init__.py,sha256=kn64nKBEVYJMYJedvIV2sQqR1ucoes_LeO7gemwO7oA,1043
|
|
2
2
|
hardpy/hardpy_panel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
hardpy/hardpy_panel/api.py,sha256=
|
|
4
|
-
hardpy/hardpy_panel/runner.py,sha256=
|
|
5
|
-
hardpy/hardpy_panel/frontend/dist/asset-manifest.json,sha256=
|
|
3
|
+
hardpy/hardpy_panel/api.py,sha256=zm24Spyhl7bqqJTcfyIydajq0_mqrAaxzac53V-Y_-Q,1979
|
|
4
|
+
hardpy/hardpy_panel/runner.py,sha256=lJFVFAbh-y6utBKW7pEqlbAPgS1PLGTP3s-YRE52Sq4,2121
|
|
5
|
+
hardpy/hardpy_panel/frontend/dist/asset-manifest.json,sha256=dknw2XV7tgYq_ciUOwtYAon3pURFH1LNSEpgbcCDehw,2824
|
|
6
6
|
hardpy/hardpy_panel/frontend/dist/favicon.ico,sha256=sgIk5PKUKEKBDpkSrc8dJgjpObp0iF82Mec0GpfKId4,15406
|
|
7
|
-
hardpy/hardpy_panel/frontend/dist/index.html,sha256=
|
|
7
|
+
hardpy/hardpy_panel/frontend/dist/index.html,sha256=RLLhIgyucL-mXa6EWwU9_ZH6QFgyUhFAfKuyZ6cVYc0,656
|
|
8
8
|
hardpy/hardpy_panel/frontend/dist/logo512.png,sha256=-fIMbqX7PYUpheK4kX1C1erRTe_hHZwFQYDLrAbhFRU,34188
|
|
9
9
|
hardpy/hardpy_panel/frontend/dist/manifest.json,sha256=PfmJlN2JMJtHS6OnhU4b4X5wPQC_yRBdjesjoirObSA,502
|
|
10
10
|
hardpy/hardpy_panel/frontend/dist/static/css/main.e8a862f1.css,sha256=gNl6kGMBhtswNrUU6X2S6uosRU7xhxqI_p9gsEtBUqE,318244
|
|
@@ -21,9 +21,9 @@ hardpy/hardpy_panel/frontend/dist/static/js/blueprint-icons-all-paths.f63155c9.c
|
|
|
21
21
|
hardpy/hardpy_panel/frontend/dist/static/js/blueprint-icons-all-paths.f63155c9.chunk.js.map,sha256=p1xKHRK4AZutkZsQHiWSNU61tYp7I3iUuyLLm3eqkHQ,2833
|
|
22
22
|
hardpy/hardpy_panel/frontend/dist/static/js/blueprint-icons-split-paths-by-size-loader.52a072d3.chunk.js,sha256=Jl5xm_jQ9IXKhCagHHvnIhwYXb379Q5FFBiqPoKdUIE,605
|
|
23
23
|
hardpy/hardpy_panel/frontend/dist/static/js/blueprint-icons-split-paths-by-size-loader.52a072d3.chunk.js.map,sha256=amJiG2QaJMRR9Y2M0C2soOqd75xdQHhsVKjwrDSIIT0,2224
|
|
24
|
-
hardpy/hardpy_panel/frontend/dist/static/js/main.
|
|
25
|
-
hardpy/hardpy_panel/frontend/dist/static/js/main.
|
|
26
|
-
hardpy/hardpy_panel/frontend/dist/static/js/main.
|
|
24
|
+
hardpy/hardpy_panel/frontend/dist/static/js/main.37744128.js,sha256=ssTeNO5sKL6UzOS2wHRWcbOjD8pp951j5cVNEGMd3Gs,1050817
|
|
25
|
+
hardpy/hardpy_panel/frontend/dist/static/js/main.37744128.js.LICENSE.txt,sha256=ForPNukClWMEP3pF9LMYoU-ve-LsyCH-rYU8eLki_FY,2315
|
|
26
|
+
hardpy/hardpy_panel/frontend/dist/static/js/main.37744128.js.map,sha256=6jCBcnbF5mXljOi7LGADG-lE2NN1oWTo5h5dGdNMBS8,5247867
|
|
27
27
|
hardpy/hardpy_panel/frontend/dist/static/media/blueprint-icons-16.520846c6beb41df528c8.eot,sha256=PTCTrQYNHX2hIPUaYWtOKrI30-iQGXt_EGxq6JCXie0,117628
|
|
28
28
|
hardpy/hardpy_panel/frontend/dist/static/media/blueprint-icons-16.5c52b39c697f2323ce8b.svg,sha256=lDCQy06aS-9bmhwuFOUs-EdcR8MP2wqwAwky5oamtkQ,509417
|
|
29
29
|
hardpy/hardpy_panel/frontend/dist/static/media/blueprint-icons-16.84db1772f4bfb529f64f.woff,sha256=edyqQN0nw4dNBs1pgr7pQB7nJhhR6T_YfklFcG_fHj0,53344
|
|
@@ -36,20 +36,20 @@ hardpy/hardpy_panel/frontend/dist/static/media/blueprint-icons-20.afbadb627d43b7
|
|
|
36
36
|
hardpy/hardpy_panel/frontend/dist/static/media/blueprint-icons-20.e857f5a5132b8bfa71a1.woff,sha256=mQZTxE1PyyAL16VWuASOvXlZFwuI4aCPvbrhfgpdIdU,55356
|
|
37
37
|
hardpy/hardpy_panel/frontend/dist/static/media/logo_smol.5b16f92447a4a9e80331.png,sha256=E4K7drvhJCg9HcTpRihOXZhVJVBZ7-W97Se-3tDb46o,14485
|
|
38
38
|
hardpy/pytest_hardpy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
39
|
-
hardpy/pytest_hardpy/plugin.py,sha256=
|
|
40
|
-
hardpy/pytest_hardpy/pytest_call.py,sha256=
|
|
41
|
-
hardpy/pytest_hardpy/pytest_wrapper.py,sha256=
|
|
39
|
+
hardpy/pytest_hardpy/plugin.py,sha256=JjVFuAiea5sP_G1kQ1LJKJf2pZ6iWKqJuasu5mU4rWY,11369
|
|
40
|
+
hardpy/pytest_hardpy/pytest_call.py,sha256=ds3Xofm_gbqCVvM99qFonp8l6dbI2UDQ8URqn3A1TWc,8449
|
|
41
|
+
hardpy/pytest_hardpy/pytest_wrapper.py,sha256=18kCuS-TVXcXC2QiMsrbc5gHjv48tIMv0F3xAJCdi_U,4508
|
|
42
42
|
hardpy/pytest_hardpy/db/__init__.py,sha256=MxDufncz0zgRAxrndvPXXW4NrU7rRP7MzIrR7S5Cwwo,558
|
|
43
43
|
hardpy/pytest_hardpy/db/base_connector.py,sha256=7KUgPY-GmAo8MFN4OFpG5y3WH1xjohRnpeQ1gxQF1tg,751
|
|
44
44
|
hardpy/pytest_hardpy/db/base_server.py,sha256=uBnq5zGkzEIq_EGzLw0C8kfDEDvQyN52Y6L41KKL9FQ,397
|
|
45
|
-
hardpy/pytest_hardpy/db/base_store.py,sha256=
|
|
46
|
-
hardpy/pytest_hardpy/db/const.py,sha256=
|
|
45
|
+
hardpy/pytest_hardpy/db/base_store.py,sha256=DiYaBOwufEOdtDpo9dUb3ZaZ7-c1FInAWjLpUXSEFHA,2668
|
|
46
|
+
hardpy/pytest_hardpy/db/const.py,sha256=b4Hq0gaT8SF5YBg21EIHoF3RMMHD3nRJBpvGmvVYQn0,648
|
|
47
47
|
hardpy/pytest_hardpy/db/runstore.py,sha256=50amoTIO7OTqd5Ks1_7uTzqjCldLpTapkxbIQOgj1sQ,1023
|
|
48
|
-
hardpy/pytest_hardpy/db/schema.py,sha256=
|
|
48
|
+
hardpy/pytest_hardpy/db/schema.py,sha256=AAf1qXEge0Bd2xwwx4A2DBOtUkbE36DTpbsOPczPUZ4,7529
|
|
49
49
|
hardpy/pytest_hardpy/db/statestore.py,sha256=1BUfA4oqG4vx7z5v_uUYi_Un6YA769JeuShxDicrl9Q,636
|
|
50
50
|
hardpy/pytest_hardpy/reporter/__init__.py,sha256=RONapygH3c_FyXokAlyCVJXGV2cV_jCYDxLymvvA1uE,322
|
|
51
|
-
hardpy/pytest_hardpy/reporter/base.py,sha256=
|
|
52
|
-
hardpy/pytest_hardpy/reporter/hook_reporter.py,sha256=
|
|
51
|
+
hardpy/pytest_hardpy/reporter/base.py,sha256=M-lwli64ty9FW8HlGEpUyoFsZv48tyNgzPjCWVUrATY,1941
|
|
52
|
+
hardpy/pytest_hardpy/reporter/hook_reporter.py,sha256=kZ3jx--ne9l3a27TmVdZCPBoqy53EuHYg2fHDGuJNes,10068
|
|
53
53
|
hardpy/pytest_hardpy/reporter/runner_reporter.py,sha256=NXkBIoERqmLI-GYtHavmOWC5t6NIpcAE-NECrUKIAJs,827
|
|
54
54
|
hardpy/pytest_hardpy/result/__init__.py,sha256=NMeCGx3yh8ds9VpaUpuNFDxbwgYFq3e-o7W6rYIv8uI,346
|
|
55
55
|
hardpy/pytest_hardpy/result/couchdb_config.py,sha256=QZryfA2QoHIjzbVT3OAD76DCNppCghtRWdZMZ5v7KhY,611
|
|
@@ -57,15 +57,16 @@ hardpy/pytest_hardpy/result/report_loader/__init__.py,sha256=FuHuD6IFZyaKj0yu5ur
|
|
|
57
57
|
hardpy/pytest_hardpy/result/report_loader/couchdb_loader.py,sha256=1BGncK1NnwYJanm5TYETjMkqR7tmrUfGK8Sgnp2JZC8,2203
|
|
58
58
|
hardpy/pytest_hardpy/result/report_reader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
59
59
|
hardpy/pytest_hardpy/result/report_reader/couchdb_reader.py,sha256=WqetspIsQzu3iJ_HGo3XNkx4iXj6RC9o_SaRqyT-c-c,5634
|
|
60
|
-
hardpy/pytest_hardpy/utils/__init__.py,sha256=
|
|
61
|
-
hardpy/pytest_hardpy/utils/config_data.py,sha256=
|
|
60
|
+
hardpy/pytest_hardpy/utils/__init__.py,sha256=nG06N4aT95i7RU-xIzFu18nbz4Jtg-5kJlBtodg8kes,1049
|
|
61
|
+
hardpy/pytest_hardpy/utils/config_data.py,sha256=953nSUndqfiqk6oVMb7GYA4RYCFPIKkPpSthXgKtKKY,1113
|
|
62
62
|
hardpy/pytest_hardpy/utils/const.py,sha256=rjW1Rzhe2vCr8GeQqeN_pafepGDYhjhY4u1VfTOVI6U,625
|
|
63
|
-
hardpy/pytest_hardpy/utils/
|
|
64
|
-
hardpy/pytest_hardpy/utils/
|
|
63
|
+
hardpy/pytest_hardpy/utils/dialog_box.py,sha256=TC2kNFOmvu0-Z84aT-sV3IW50Ii5pucoxmIYN-7_csY,2460
|
|
64
|
+
hardpy/pytest_hardpy/utils/exception.py,sha256=VRBYs8zL7r2L1VTe_G336HYpjNdJ_ajwyxioFFhERUk,637
|
|
65
|
+
hardpy/pytest_hardpy/utils/node_info.py,sha256=VnEbhKBNAL5xpuFtJTCg90TmkjkFCQA59F5W2RcOlx4,3157
|
|
65
66
|
hardpy/pytest_hardpy/utils/progress_calculator.py,sha256=r0qb3p6_yDIyLeCshF3Ceo5pCzd3BoTahL4rCD2oMNw,1041
|
|
66
67
|
hardpy/pytest_hardpy/utils/singleton.py,sha256=C8cgRDydnG2b5dcN1LCLw4aM-AUMAvJc1W39mTkNWlQ,614
|
|
67
|
-
hardpy-0.
|
|
68
|
-
hardpy-0.
|
|
69
|
-
hardpy-0.
|
|
70
|
-
hardpy-0.
|
|
71
|
-
hardpy-0.
|
|
68
|
+
hardpy-0.4.0.dist-info/METADATA,sha256=Zy37donDAM87tsAVl6m8Qk7BYIPLf5J-ctoxrTpJowo,4113
|
|
69
|
+
hardpy-0.4.0.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
|
|
70
|
+
hardpy-0.4.0.dist-info/entry_points.txt,sha256=q73g5GfznSUpjkayi0SV4uaAtrf7D-7rmDoWoEZmZe0,120
|
|
71
|
+
hardpy-0.4.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
72
|
+
hardpy-0.4.0.dist-info/RECORD,,
|