hardpy 0.2.0__py3-none-any.whl → 0.3.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.
@@ -36,19 +36,29 @@ class BaseStore(BaseConnector):
36
36
  """
37
37
  return glom(self._doc, key)
38
38
 
39
- def set_value(self, key: str, value):
40
- """Set a value in the state store."""
41
- assign(self._doc, key, value)
39
+ def update_doc(self, key: str, value):
40
+ """Update document.
41
+
42
+ HardPy collecting uses a simple key without dots.
43
+ Assign is used to update a document.
44
+ Assign is a longer function.
45
+
46
+ Args:
47
+ key (str): document key
48
+ value: document value
49
+ """
50
+ if "." in key:
51
+ assign(self._doc, key, value)
52
+ else:
53
+ self._doc[key] = value
54
+
55
+ def update_db(self):
56
+ """Update database by current document."""
42
57
  try:
43
58
  self._doc = self._db.save(self._doc)
44
- except Conflict as exc:
45
- self._log.error(
46
- f"Error while saving runner document: {exc} "
47
- f"when trying to save key={key}, value={value}. "
48
- "Current document will be changed by "
49
- "document from database."
50
- )
51
- self._doc = self._db.get(self._doc_id)
59
+ except Conflict:
60
+ self._doc["_rev"] = self._db.get(self._doc_id)["_rev"]
61
+ self._doc = self._db.save(self._doc)
52
62
 
53
63
  def get_document(self) -> ModelMetaclass:
54
64
  """Get document by schema.
@@ -9,6 +9,7 @@ from platform import system
9
9
 
10
10
  from natsort import natsorted
11
11
  from pytest import (
12
+ skip,
12
13
  exit,
13
14
  TestReport,
14
15
  Item,
@@ -27,6 +28,7 @@ from hardpy.pytest_hardpy.utils import (
27
28
  ProgressCalculator,
28
29
  ConfigData,
29
30
  )
31
+ from hardpy.pytest_hardpy.utils.node_info import TestDependencyInfo
30
32
 
31
33
 
32
34
  def pytest_addoption(parser: Parser):
@@ -40,6 +42,7 @@ def pytest_addoption(parser: Parser):
40
42
  parser.addoption("--hardpy-pt", action="store_true", default=False, help="enable pytest-hardpy plugin") # noqa: E501
41
43
  # fmt: on
42
44
 
45
+
43
46
  # Bootstrapping hooks
44
47
  def pytest_load_initial_conftests(early_config, parser, args):
45
48
  if "--hardpy-pt" in args:
@@ -57,6 +60,7 @@ class HardpyPlugin(object):
57
60
  self._progress = ProgressCalculator()
58
61
  self._results = {}
59
62
  self._post_run_functions: list[Callable] = []
63
+ self._dependencies = {}
60
64
 
61
65
  if system() == "Linux":
62
66
  signal.signal(signal.SIGTERM, self._stop_handler)
@@ -64,7 +68,6 @@ class HardpyPlugin(object):
64
68
  signal.signal(signal.SIGBREAK, self._stop_handler)
65
69
  self._log = getLogger(__name__)
66
70
 
67
-
68
71
  # Initialization hooks
69
72
 
70
73
  def pytest_configure(self, config: Config):
@@ -77,6 +80,7 @@ class HardpyPlugin(object):
77
80
 
78
81
  config.addinivalue_line("markers", "case_name")
79
82
  config.addinivalue_line("markers", "module_name")
83
+ config.addinivalue_line("markers", "dependency")
80
84
 
81
85
  # must be init after config data is set
82
86
  self._reporter = HookReporter()
@@ -92,6 +96,8 @@ class HardpyPlugin(object):
92
96
  return
93
97
  status = self._get_run_status(exitstatus)
94
98
  self._reporter.finish(status)
99
+ self._reporter.update_db_by_doc()
100
+ self._reporter.compact_all()
95
101
 
96
102
  # call post run methods
97
103
  if self._post_run_functions:
@@ -107,6 +113,7 @@ class HardpyPlugin(object):
107
113
  self._reporter.init_doc(str(PurePath(config.rootpath).name))
108
114
 
109
115
  nodes = {}
116
+ modules = set()
110
117
 
111
118
  session.items = natsorted(
112
119
  session.items,
@@ -115,18 +122,26 @@ class HardpyPlugin(object):
115
122
  for item in session.items:
116
123
  if item.parent is None:
117
124
  continue
118
- node_info = NodeInfo(item)
125
+ try:
126
+ node_info = NodeInfo(item)
127
+ except ValueError:
128
+ error_msg = f"Error creating NodeInfo for item: {item}\n"
129
+ exit(error_msg, 1)
119
130
 
120
131
  self._init_case_result(node_info.module_id, node_info.case_id)
121
-
122
132
  if node_info.module_id not in nodes:
123
133
  nodes[node_info.module_id] = [node_info.case_id]
124
134
  else:
125
135
  nodes[node_info.module_id].append(node_info.case_id)
126
136
 
127
137
  self._reporter.add_case(node_info)
128
- self._reporter.set_module_status(node_info.module_id, TestStatus.READY)
138
+
139
+ self._add_dependency(node_info, nodes)
140
+ modules.add(node_info.module_id)
141
+ for module_id in modules:
142
+ self._reporter.set_module_status(module_id, TestStatus.READY)
129
143
  self._reporter.update_node_order(nodes)
144
+ self._reporter.update_db_by_doc()
130
145
 
131
146
  # Test running (runtest) hooks
132
147
 
@@ -139,6 +154,7 @@ class HardpyPlugin(object):
139
154
 
140
155
  # testrun entrypoint
141
156
  self._reporter.start()
157
+ self._reporter.update_db_by_doc()
142
158
 
143
159
  def pytest_runtest_setup(self, item: Item):
144
160
  """Call before each test setup phase."""
@@ -148,6 +164,8 @@ class HardpyPlugin(object):
148
164
 
149
165
  node_info = NodeInfo(item)
150
166
 
167
+ self._handle_dependency(node_info)
168
+
151
169
  self._reporter.set_module_status(node_info.module_id, TestStatus.RUN)
152
170
  self._reporter.set_module_start_time(node_info.module_id)
153
171
  self._reporter.set_case_status(
@@ -159,6 +177,7 @@ class HardpyPlugin(object):
159
177
  node_info.module_id,
160
178
  node_info.case_id,
161
179
  )
180
+ self._reporter.update_db_by_doc()
162
181
 
163
182
  # Reporting hooks
164
183
 
@@ -188,6 +207,7 @@ class HardpyPlugin(object):
188
207
 
189
208
  if None not in self._results[module_id].values():
190
209
  self._collect_module_result(module_id)
210
+ self._reporter.update_db_by_doc()
191
211
 
192
212
  # Fixture
193
213
 
@@ -250,3 +270,47 @@ class HardpyPlugin(object):
250
270
  index = report.find("\nE")
251
271
  return report[:index]
252
272
  return None
273
+
274
+ def _handle_dependency(self, node_info: NodeInfo):
275
+ dependency = self._dependencies.get(
276
+ TestDependencyInfo(
277
+ node_info.module_id,
278
+ node_info.case_id,
279
+ )
280
+ )
281
+ if dependency and self._is_dependency_failed(dependency):
282
+ self._log.debug(f"Skipping test due to dependency: {dependency}")
283
+ self._results[node_info.module_id][node_info.case_id] = TestStatus.SKIPPED
284
+ skip(f"Test {node_info.module_id}::{node_info.case_id} is skipped")
285
+
286
+ def _is_dependency_failed(self, dependency) -> bool:
287
+ if isinstance(dependency, TestDependencyInfo):
288
+ incorrect_status = {
289
+ TestStatus.FAILED,
290
+ TestStatus.SKIPPED,
291
+ TestStatus.ERROR,
292
+ }
293
+ module_id, case_id = dependency
294
+ if case_id is not None:
295
+ return self._results[module_id][case_id] in incorrect_status
296
+ return any(
297
+ status in incorrect_status
298
+ for status in set(self._results[module_id].values())
299
+ )
300
+ return False
301
+
302
+ def _add_dependency(self, node_info, nodes):
303
+ dependency = node_info.dependency
304
+ if dependency is None or dependency == "":
305
+ return
306
+ module_id, case_id = dependency
307
+ if module_id not in nodes:
308
+ error_message = f"Error: Module dependency '{dependency}' not found."
309
+ exit(error_message, 1)
310
+ elif case_id not in nodes[module_id] and case_id is not None:
311
+ error_message = f"Error: Case dependency '{dependency}' not found."
312
+ exit(error_message, 1)
313
+
314
+ self._dependencies[
315
+ TestDependencyInfo(node_info.module_id, node_info.case_id)
316
+ ] = dependency
@@ -52,7 +52,8 @@ def set_dut_info(info: dict):
52
52
  reporter = RunnerReporter()
53
53
  for dut_key, dut_value in info.items():
54
54
  key = reporter.generate_key(DF.DUT, DF.INFO, dut_key)
55
- reporter.set_db_value(key, dut_value)
55
+ reporter.set_doc_value(key, dut_value)
56
+ reporter.update_db_by_doc()
56
57
 
57
58
 
58
59
  def set_dut_serial_number(serial_number: str):
@@ -68,7 +69,8 @@ def set_dut_serial_number(serial_number: str):
68
69
  key = reporter.generate_key(DF.DUT, DF.SERIAL_NUMBER)
69
70
  if reporter.get_field(key):
70
71
  raise DuplicateSerialNumberError
71
- reporter.set_db_value(key, serial_number)
72
+ reporter.set_doc_value(key, serial_number)
73
+ reporter.update_db_by_doc()
72
74
 
73
75
 
74
76
  def set_stand_info(info: dict):
@@ -80,7 +82,8 @@ def set_stand_info(info: dict):
80
82
  reporter = RunnerReporter()
81
83
  for stand_key, stand_value in info.items():
82
84
  key = reporter.generate_key(DF.TEST_STAND, stand_key)
83
- reporter.set_db_value(key, stand_value)
85
+ reporter.set_doc_value(key, stand_value)
86
+ reporter.update_db_by_doc()
84
87
 
85
88
 
86
89
  def set_message(msg: str, msg_key: Optional[str] = None) -> None:
@@ -111,7 +114,8 @@ def set_message(msg: str, msg_key: Optional[str] = None) -> None:
111
114
 
112
115
  msgs[msg_key] = msg
113
116
 
114
- reporter.set_db_value(key, msgs)
117
+ reporter.set_doc_value(key, msgs)
118
+ reporter.update_db_by_doc()
115
119
 
116
120
 
117
121
  def set_case_artifact(data: dict):
@@ -134,7 +138,8 @@ def set_case_artifact(data: dict):
134
138
  DF.ARTIFACT,
135
139
  stand_key,
136
140
  )
137
- reporter.set_db_value(key, stand_value, is_statestore=False)
141
+ reporter.set_doc_value(key, stand_value, runstore_only=True)
142
+ reporter.update_db_by_doc()
138
143
 
139
144
 
140
145
  def set_module_artifact(data: dict):
@@ -155,7 +160,8 @@ def set_module_artifact(data: dict):
155
160
  DF.ARTIFACT,
156
161
  artifact_key,
157
162
  )
158
- reporter.set_db_value(key, artifact_value, is_statestore=False)
163
+ reporter.set_doc_value(key, artifact_value, runstore_only=True)
164
+ reporter.update_db_by_doc()
159
165
 
160
166
 
161
167
  def set_run_artifact(data: dict):
@@ -173,7 +179,8 @@ def set_run_artifact(data: dict):
173
179
  DF.ARTIFACT,
174
180
  artifact_key,
175
181
  )
176
- reporter.set_db_value(key, artifact_value, is_statestore=False)
182
+ reporter.set_doc_value(key, artifact_value, runstore_only=True)
183
+ reporter.update_db_by_doc()
177
184
 
178
185
 
179
186
  def set_driver_info(drivers: dict) -> None:
@@ -192,7 +199,8 @@ def set_driver_info(drivers: dict) -> None:
192
199
  DF.DRIVERS,
193
200
  driver_name,
194
201
  )
195
- reporter.set_db_value(key, driver_data)
202
+ reporter.set_doc_value(key, driver_data)
203
+ reporter.update_db_by_doc()
196
204
 
197
205
 
198
206
  def _get_current_test() -> CurrentTestInfo:
@@ -14,21 +14,39 @@ class BaseReporter(object):
14
14
  self._runstore = RunStore()
15
15
  self._log = getLogger(__name__)
16
16
 
17
- def set_db_value(self, key: str, value, is_statestore=True, is_runstore=True):
18
- """Set value to database.
17
+ def set_doc_value(
18
+ self, key: str, value, runstore_only=False, statestore_only=False
19
+ ):
20
+ """Set value to the document.
21
+
22
+ Update a document without writing to the database.
19
23
 
20
24
  Args:
21
- key (str): database key
22
- value (_type_): database value
23
- is_statestore (bool, optional): indicates whether data should
24
- be written to StateStore. Defaults to True.
25
- is_runstore (bool, optional): indicates whether data should
26
- be written to RunStore. Defaults to True.
25
+ key (str): document key
26
+ value: document value
27
+ runstore_only (bool, optional): indicates whether data should
28
+ be written to RunStore. Defaults to True.
29
+ statestore_only (bool, optional): indicates whether data should
30
+ be written to StateStore. Defaults to True.
31
+
32
+ Raises:
33
+ ValueError: if both runstore_only and statestore_only are True
27
34
  """
28
- if is_statestore:
29
- self._statestore.set_value(key, value)
30
- if is_runstore:
31
- self._runstore.set_value(key, value)
35
+ if runstore_only and statestore_only:
36
+ raise ValueError("Both runstore_only and statestore_only cannot be True")
37
+ if runstore_only:
38
+ self._runstore.update_doc(key, value)
39
+ return
40
+ if statestore_only:
41
+ self._statestore.update_doc(key, value)
42
+ return
43
+ self._runstore.update_doc(key, value)
44
+ self._statestore.update_doc(key, value)
45
+
46
+ def update_db_by_doc(self):
47
+ """Update database by current document."""
48
+ self._statestore.update_db()
49
+ self._runstore.update_db()
32
50
 
33
51
  def generate_key(self, *args) -> str:
34
52
  """Generate key for database.
@@ -25,23 +25,23 @@ class HookReporter(BaseReporter):
25
25
  Args:
26
26
  doc_name (str): test run name
27
27
  """
28
- self.set_db_value(DF.NAME, doc_name)
29
- self.set_db_value(DF.STATUS, TestStatus.READY)
30
- self.set_db_value(DF.START_TIME, None)
31
- self.set_db_value(DF.TIMEZONE, None)
32
- self.set_db_value(DF.STOP_TIME, None)
33
- self.set_db_value(DF.PROGRESS, 0)
34
- self.set_db_value(DF.DRIVERS, {})
35
- self.set_db_value(DF.ARTIFACT, {}, is_statestore=False)
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.set_db_value(DF.START_TIME, start_time)
42
- self.set_db_value(DF.STATUS, TestStatus.RUN)
43
- self.set_db_value(DF.TIMEZONE, tzname) # noqa: WPS432
44
- self.set_db_value(DF.PROGRESS, 0)
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.set_db_value(DF.STOP_TIME, stop_time)
54
- self.set_db_value(DF.STATUS, status)
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.set_db_value(DF.PROGRESS, progress)
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.set_db_value(key, msg)
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
- new_item_statestore = self._init_case(item_statestore, node_info)
97
- new_item_runstore = self._init_case(
98
- item_runstore,
99
- node_info,
100
- is_use_artifact=True,
101
- )
93
+ self._init_case(item_statestore, node_info)
94
+ self._init_case(item_runstore, node_info, is_use_artifact=True)
102
95
 
103
- self.set_db_value(key, new_item_statestore, is_runstore=False)
104
- self.set_db_value(key, new_item_runstore, is_statestore=False)
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.set_db_value(key, status)
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.set_db_value(key, status)
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,16 @@ 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.set_db_value(key, updated_module_order, is_runstore=False)
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.set_db_value(key, int(time()))
176
+ self.set_doc_value(key, int(time()))
184
177
 
185
178
  def _init_case(
186
179
  self, item: dict, node_info: NodeInfo, is_use_artifact: bool = False
187
- ) -> dict:
180
+ ):
188
181
  module_default = { # noqa: WPS204
189
182
  DF.STATUS: TestStatus.READY,
190
183
  DF.NAME: self._get_module_name(node_info),
@@ -216,8 +209,6 @@ class HookReporter(BaseReporter):
216
209
  case_default[DF.ARTIFACT] = {}
217
210
  item[node_info.module_id][DF.CASES][node_info.case_id] = case_default
218
211
 
219
- return item
220
-
221
212
  def _remove_outdate_node(
222
213
  self, old_modules: dict, new_modules: dict, nodes: dict
223
214
  ) -> dict:
@@ -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.2.0
3
+ Version: 0.3.0
4
4
  Summary: HardPy library for device testing
5
5
  Project-URL: repository, https://github.com/everypindevices/hardpy
6
6
  Author: Everypin
@@ -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
@@ -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=_qVu3F54qikloIGhV6Enb0-m2Oy6h_VBOo4jwNzOLdc,8415
40
- hardpy/pytest_hardpy/pytest_call.py,sha256=wyMDt4AwQC4qg6pYnevQv7FIhIvHNYreQdU1kEenqdY,5910
39
+ hardpy/pytest_hardpy/plugin.py,sha256=lL3ZNVVSlS7VzpVDiF_SWbnbFBbK9vXtD6JZwqBoObA,10973
40
+ hardpy/pytest_hardpy/pytest_call.py,sha256=CrbAw_W6A1HU06xIcylivgNKVUzGoo0B0ikNqflHbDo,6171
41
41
  hardpy/pytest_hardpy/pytest_wrapper.py,sha256=bC8ROwAEjo3TpXpNtHXUS-C_fpIyeCPtgfGBSZ82aI8,3554
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=iKh8qN-sPu79Ogp5857TR0t5RbGssC8V7iFAZAF5aFU,2504
45
+ hardpy/pytest_hardpy/db/base_store.py,sha256=DiYaBOwufEOdtDpo9dUb3ZaZ7-c1FInAWjLpUXSEFHA,2668
46
46
  hardpy/pytest_hardpy/db/const.py,sha256=ffYW54TP0aNF5LhW3g_2G5kVuvqAMWfuJqNDzWZg2nI,618
47
47
  hardpy/pytest_hardpy/db/runstore.py,sha256=50amoTIO7OTqd5Ks1_7uTzqjCldLpTapkxbIQOgj1sQ,1023
48
48
  hardpy/pytest_hardpy/db/schema.py,sha256=iIclTudP0tauTWLYiEW9MMlvBfuWOteA7eRzDU5gKwI,6859
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=kHYSLVxiq5Fyf4V-xGtgfOS3nImN1j5c13zcvqK1sq0,1343
52
- hardpy/pytest_hardpy/reporter/hook_reporter.py,sha256=_7mM3B0U_vsuGGAKuX7jtuS045XVRouCeF0Q8uSUAwY,10181
51
+ hardpy/pytest_hardpy/reporter/base.py,sha256=M-lwli64ty9FW8HlGEpUyoFsZv48tyNgzPjCWVUrATY,1941
52
+ hardpy/pytest_hardpy/reporter/hook_reporter.py,sha256=TE6IzQVH10ce8JXWtep80kgyVOicU02C75FDpV6NfSQ,9895
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
@@ -61,11 +61,11 @@ hardpy/pytest_hardpy/utils/__init__.py,sha256=IeOr27pgzvMolQtEXJxODJKNdQAFww8Ejj
61
61
  hardpy/pytest_hardpy/utils/config_data.py,sha256=F8khHsvkEsJjDnoHeLjI0rgsAfETN7nSlEP2snf2kio,990
62
62
  hardpy/pytest_hardpy/utils/const.py,sha256=rjW1Rzhe2vCr8GeQqeN_pafepGDYhjhY4u1VfTOVI6U,625
63
63
  hardpy/pytest_hardpy/utils/exception.py,sha256=5GnVkOchSPDEXaOXaruO0YzKXoY7b3Y5mVU5-51ZKRg,457
64
- hardpy/pytest_hardpy/utils/node_info.py,sha256=9aK8X-lNrY3unjHAR-DBS6GFKyo7rEoDH-CTy_WGdFw,1437
64
+ hardpy/pytest_hardpy/utils/node_info.py,sha256=VnEbhKBNAL5xpuFtJTCg90TmkjkFCQA59F5W2RcOlx4,3157
65
65
  hardpy/pytest_hardpy/utils/progress_calculator.py,sha256=r0qb3p6_yDIyLeCshF3Ceo5pCzd3BoTahL4rCD2oMNw,1041
66
66
  hardpy/pytest_hardpy/utils/singleton.py,sha256=C8cgRDydnG2b5dcN1LCLw4aM-AUMAvJc1W39mTkNWlQ,614
67
- hardpy-0.2.0.dist-info/METADATA,sha256=ZyxZaCBvj2QYXPcwWFvrEvZaOGPKeK1kY8VByYTEtCY,3870
68
- hardpy-0.2.0.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
69
- hardpy-0.2.0.dist-info/entry_points.txt,sha256=q73g5GfznSUpjkayi0SV4uaAtrf7D-7rmDoWoEZmZe0,120
70
- hardpy-0.2.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
71
- hardpy-0.2.0.dist-info/RECORD,,
67
+ hardpy-0.3.0.dist-info/METADATA,sha256=lWSZtZSy7b_PISotSgTw3lyM1X2uJPj0dVmOfI2A9N8,4096
68
+ hardpy-0.3.0.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
69
+ hardpy-0.3.0.dist-info/entry_points.txt,sha256=q73g5GfznSUpjkayi0SV4uaAtrf7D-7rmDoWoEZmZe0,120
70
+ hardpy-0.3.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
71
+ hardpy-0.3.0.dist-info/RECORD,,
File without changes