hardpy 0.17.1__py3-none-any.whl → 0.18.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.
Files changed (23) hide show
  1. hardpy/cli/cli.py +50 -7
  2. hardpy/common/config.py +14 -11
  3. hardpy/common/stand_cloud/connector.py +20 -1
  4. hardpy/common/stand_cloud/token_manager.py +26 -1
  5. hardpy/hardpy_panel/api.py +93 -2
  6. hardpy/hardpy_panel/frontend/dist/assets/{allPaths-LQifhvrX.js → allPaths-31ulJ0tA.js} +1 -1
  7. hardpy/hardpy_panel/frontend/dist/assets/{allPathsLoader-C-JecT3u.js → allPathsLoader-HPn4WHWu.js} +2 -2
  8. hardpy/hardpy_panel/frontend/dist/assets/{browser-ponyfill-B-CPdmQc.js → browser-ponyfill-BQ1ipruI.js} +1 -1
  9. hardpy/hardpy_panel/frontend/dist/assets/{index-B2oxSaK6.js → index-BK2y65ib.js} +119 -119
  10. hardpy/hardpy_panel/frontend/dist/assets/{splitPathsBySizeLoader-CBTnepth.js → splitPathsBySizeLoader-ev1ZiRR9.js} +1 -1
  11. hardpy/hardpy_panel/frontend/dist/index.html +1 -1
  12. hardpy/pytest_hardpy/db/__init__.py +3 -1
  13. hardpy/pytest_hardpy/db/tempstore.py +54 -0
  14. hardpy/pytest_hardpy/plugin.py +34 -1
  15. hardpy/pytest_hardpy/pytest_wrapper.py +2 -0
  16. hardpy/pytest_hardpy/result/report_loader/stand_cloud_loader.py +8 -4
  17. hardpy/pytest_hardpy/result/report_synchronizer/__init__.py +10 -0
  18. hardpy/pytest_hardpy/result/report_synchronizer/synchronizer.py +121 -0
  19. {hardpy-0.17.1.dist-info → hardpy-0.18.0.dist-info}/METADATA +3 -2
  20. {hardpy-0.17.1.dist-info → hardpy-0.18.0.dist-info}/RECORD +23 -20
  21. {hardpy-0.17.1.dist-info → hardpy-0.18.0.dist-info}/WHEEL +0 -0
  22. {hardpy-0.17.1.dist-info → hardpy-0.18.0.dist-info}/entry_points.txt +0 -0
  23. {hardpy-0.17.1.dist-info → hardpy-0.18.0.dist-info}/licenses/LICENSE +0 -0
@@ -1 +1 @@
1
- import{_ as o,a as _,b as i,p as c,I as u}from"./index-B2oxSaK6.js";var p=function(n,s){return o(void 0,void 0,void 0,function(){var a,r;return _(this,function(e){switch(e.label){case 0:return a=c(n),s!==u.STANDARD?[3,2]:[4,i(()=>import("./index-DLOviMB1.js").then(t=>t.I),[])];case 1:return r=e.sent(),[3,4];case 2:return[4,i(()=>import("./index-B-fsa5Ru.js").then(t=>t.I),[])];case 3:r=e.sent(),e.label=4;case 4:return[2,r[a]]}})})};export{p as splitPathsBySizeLoader};
1
+ import{_ as o,a as _,b as i,p as c,I as u}from"./index-BK2y65ib.js";var p=function(n,s){return o(void 0,void 0,void 0,function(){var a,r;return _(this,function(e){switch(e.label){case 0:return a=c(n),s!==u.STANDARD?[3,2]:[4,i(()=>import("./index-DLOviMB1.js").then(t=>t.I),[])];case 1:return r=e.sent(),[3,4];case 2:return[4,i(()=>import("./index-B-fsa5Ru.js").then(t=>t.I),[])];case 3:r=e.sent(),e.label=4;case 4:return[2,r[a]]}})})};export{p as splitPathsBySizeLoader};
@@ -25,7 +25,7 @@
25
25
  Learn how to configure a non-root public URL by running `npm run build`.
26
26
  -->
27
27
  <title>HardPy Operator Panel</title>
28
- <script type="module" crossorigin src="/assets/index-B2oxSaK6.js"></script>
28
+ <script type="module" crossorigin src="/assets/index-BK2y65ib.js"></script>
29
29
  <link rel="stylesheet" crossorigin href="/assets/index-B7T9xvaW.css">
30
30
  </head>
31
31
  <body>
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024 Everypin
1
+ # Copyright (c) 2025 Everypin
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.db.base_store import BaseStore
@@ -13,6 +13,7 @@ from hardpy.pytest_hardpy.db.stand_type import (
13
13
  SubUnit,
14
14
  )
15
15
  from hardpy.pytest_hardpy.db.statestore import StateStore
16
+ from hardpy.pytest_hardpy.db.tempstore import TempStore
16
17
 
17
18
  __all__ = [
18
19
  "BaseStore",
@@ -26,4 +27,5 @@ __all__ = [
26
27
  "StateStore",
27
28
  "StringMeasurement",
28
29
  "SubUnit",
30
+ "TempStore",
29
31
  ]
@@ -0,0 +1,54 @@
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 logging import getLogger
7
+ from typing import TYPE_CHECKING
8
+
9
+ from pycouchdb.exceptions import Conflict, NotFound
10
+
11
+ from hardpy.common.singleton import SingletonMeta
12
+ from hardpy.pytest_hardpy.db.base_store import BaseStore
13
+ from hardpy.pytest_hardpy.db.schema import ResultRunStore
14
+
15
+ if TYPE_CHECKING:
16
+ from collections.abc import Generator
17
+
18
+
19
+ class TempStore(BaseStore, metaclass=SingletonMeta):
20
+ """HardPy temporary storage for data syncronization."""
21
+
22
+ def __init__(self) -> None:
23
+ super().__init__("tempstore")
24
+ self._log = getLogger(__name__)
25
+ self._doc: dict = self._init_doc()
26
+ self._schema = ResultRunStore
27
+
28
+ def push_report(self, report: ResultRunStore) -> bool:
29
+ """Push report to the report database."""
30
+ report_dict = report.model_dump()
31
+ report_id = report_dict.pop("id")
32
+ try:
33
+ self._db.save(report_dict)
34
+ except Conflict as exc:
35
+ self._log.error(f"Error while saving report {report_id}: {exc}")
36
+ return False
37
+ self._log.debug(f"Report saved with id: {report_id}")
38
+ return True
39
+
40
+ def reports(self) -> Generator[ResultRunStore]:
41
+ """Get all reports from the report database."""
42
+ yield from self._db.all()
43
+
44
+ def delete(self, report_id: str) -> bool:
45
+ """Delete report from the report database."""
46
+ try:
47
+ self._db.delete(report_id)
48
+ except (NotFound, Conflict):
49
+ return False
50
+ return True
51
+
52
+ def dict_to_schema(self, report: dict) -> ResultRunStore:
53
+ """Convert report dict to report schema."""
54
+ return self._schema(**report)
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2024 Everypin
1
+ # Copyright (c) 2025 Everypin
2
2
  # GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
3
3
  from __future__ import annotations
4
4
 
@@ -35,6 +35,9 @@ from pytest import (
35
35
  from hardpy.common.config import ConfigManager, HardpyConfig
36
36
  from hardpy.common.stand_cloud.connector import StandCloudConnector, StandCloudError
37
37
  from hardpy.pytest_hardpy.reporter import HookReporter
38
+ from hardpy.pytest_hardpy.result.report_synchronizer.synchronizer import (
39
+ StandCloudSynchronizer,
40
+ )
38
41
  from hardpy.pytest_hardpy.utils import NodeInfo, ProgressCalculator, TestStatus
39
42
  from hardpy.pytest_hardpy.utils.node_info import TestDependencyInfo
40
43
 
@@ -95,6 +98,12 @@ def pytest_addoption(parser: Parser) -> None:
95
98
  default=default_config.stand_cloud.connection_only,
96
99
  help="check StandCloud availability",
97
100
  )
101
+ parser.addoption(
102
+ "--sc-autosync",
103
+ action="store_true",
104
+ default=default_config.stand_cloud.autosync,
105
+ help="StandCloud auto syncronization",
106
+ )
98
107
  parser.addoption(
99
108
  "--hardpy-start-arg",
100
109
  action="append",
@@ -129,6 +138,7 @@ class HardpyPlugin:
129
138
  self._tests_name: str = ""
130
139
  self._is_critical_not_passed = False
131
140
  self._start_args = {}
141
+ self._sc_syncronizer = StandCloudSynchronizer()
132
142
 
133
143
  if system() == "Linux":
134
144
  signal.signal(signal.SIGTERM, self._stop_handler)
@@ -166,6 +176,10 @@ class HardpyPlugin:
166
176
  if sc_connection_only:
167
177
  hardpy_config.stand_cloud.connection_only = bool(sc_connection_only) # type: ignore
168
178
 
179
+ sc_autosync = config.getoption("--sc-autosync")
180
+ if sc_autosync:
181
+ hardpy_config.stand_cloud.autosync = bool(sc_autosync) # type: ignore
182
+
169
183
  _args = config.getoption("--hardpy-start-arg") or []
170
184
  if _args:
171
185
  self._start_args = dict(arg.split("=", 1) for arg in _args if "=" in arg)
@@ -200,6 +214,11 @@ class HardpyPlugin:
200
214
  for action in self._post_run_functions:
201
215
  action()
202
216
 
217
+ config_manager = ConfigManager()
218
+
219
+ if config_manager.config.stand_cloud.autosync:
220
+ self._send_report_to_sc()
221
+
203
222
  # Collection hooks
204
223
 
205
224
  def pytest_collection_modifyitems(
@@ -264,6 +283,7 @@ class HardpyPlugin:
264
283
  try:
265
284
  sc_connector = StandCloudConnector(
266
285
  addr=config_manager.config.stand_cloud.address,
286
+ api_key=config_manager.config.stand_cloud.api_key,
267
287
  )
268
288
  except StandCloudError as exc:
269
289
  msg = str(exc)
@@ -514,6 +534,19 @@ class HardpyPlugin:
514
534
  self._reporter.set_case_status(module_id, case_id, case_status)
515
535
  return is_case_stopped
516
536
 
537
+ def _send_report_to_sc(self) -> None:
538
+ """Send report to StandCloud."""
539
+ report = self._reporter.get_report()
540
+ if not report:
541
+ msg = "Empty report cannot be uploaded to StandCloud"
542
+ self._reporter.set_alert(msg)
543
+ return
544
+ if self._sc_syncronizer.push_to_sc(report):
545
+ return
546
+ if not self._sc_syncronizer.push_to_tempstore(report):
547
+ msg = "Report not uploaded to temporary storage"
548
+ self._reporter.set_alert(msg)
549
+
517
550
  def _decode_assertion_msg(
518
551
  self,
519
552
  error: (
@@ -51,6 +51,8 @@ class PyTestWrapper:
51
51
  ]
52
52
  if self.config.stand_cloud.connection_only:
53
53
  cmd.append("--sc-connection-only")
54
+ if self.config.stand_cloud.autosync:
55
+ cmd.append("--sc-autosync")
54
56
  cmd.append("--hardpy-pt")
55
57
  if start_args:
56
58
  for key, value in start_args.items():
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  from typing import TYPE_CHECKING
6
6
 
7
7
  from oauthlib.oauth2.rfc6749.errors import OAuth2Error
8
- from requests.exceptions import HTTPError
8
+ from requests.exceptions import ConnectionError, HTTPError # noqa: A004
9
9
 
10
10
  from hardpy.common.config import ConfigManager
11
11
  from hardpy.common.stand_cloud.connector import StandCloudConnector, StandCloudError
@@ -30,7 +30,8 @@ class StandCloudLoader:
30
30
  self._verify_ssl = not __debug__
31
31
  config_manager = ConfigManager()
32
32
  sc_addr = address if address else config_manager.config.stand_cloud.address
33
- self._sc_connector = StandCloudConnector(sc_addr)
33
+ api_key = config_manager.config.stand_cloud.api_key
34
+ self._sc_connector = StandCloudConnector(sc_addr, api_key=api_key)
34
35
 
35
36
  def load(self, report: ResultRunStore, timeout: int = 20) -> Response:
36
37
  """Load report to the StandCloud.
@@ -46,7 +47,10 @@ class StandCloudLoader:
46
47
  Raises:
47
48
  StandCloudError: if report not uploaded to StandCloud
48
49
  """
49
- api = self._sc_connector.get_api("test_report")
50
+ try:
51
+ api = self._sc_connector.get_api("test_report")
52
+ except ConnectionError as exc:
53
+ raise StandCloudError(str(exc)) from exc
50
54
  sc_report = self._convert_to_sc_format(report)
51
55
 
52
56
  try:
@@ -55,7 +59,7 @@ class StandCloudLoader:
55
59
  json=sc_report.model_dump(),
56
60
  timeout=timeout,
57
61
  )
58
- except RuntimeError as exc:
62
+ except (RuntimeError, ConnectionError) as exc:
59
63
  raise StandCloudError(str(exc)) from exc
60
64
  except OAuth2Error as exc:
61
65
  raise StandCloudError(exc.description) from exc
@@ -0,0 +1,10 @@
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 hardpy.pytest_hardpy.result.report_synchronizer.synchronizer import (
5
+ StandCloudSynchronizer,
6
+ )
7
+
8
+ __all__ = [
9
+ "StandCloudSynchronizer",
10
+ ]
@@ -0,0 +1,121 @@
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
+ from __future__ import annotations
4
+
5
+ from http import HTTPStatus
6
+ from typing import TYPE_CHECKING
7
+
8
+ from pydantic import ValidationError
9
+
10
+ from hardpy.common.stand_cloud.exception import StandCloudError
11
+ from hardpy.pytest_hardpy.db.tempstore import TempStore
12
+ from hardpy.pytest_hardpy.result.report_loader.stand_cloud_loader import (
13
+ StandCloudLoader,
14
+ )
15
+
16
+ if TYPE_CHECKING:
17
+ from hardpy.pytest_hardpy.db.schema import ResultRunStore
18
+
19
+
20
+ class StandCloudSynchronizer:
21
+ """Synchronize reports with StandCloud."""
22
+
23
+ def __init__(self) -> None:
24
+ self._tempstore = TempStore()
25
+
26
+ def sync(self) -> str:
27
+ """Sync reports with StandCloud.
28
+
29
+ Returns:
30
+ str: Synchronization message
31
+ """
32
+ if not self._tempstore.reports():
33
+ return "All reports are synchronized with StandCloud"
34
+ try:
35
+ loader = self._create_sc_loader()
36
+ except StandCloudError as err:
37
+ raise StandCloudError(str(err)) from err
38
+
39
+ invalid_reports = []
40
+ success_report_counter = 0
41
+ for _report in self._tempstore.reports():
42
+ try:
43
+ report_id = _report.get("id")
44
+ document: dict = _report.get("doc")
45
+ document.pop("rev")
46
+ except KeyError:
47
+ try:
48
+ document.pop("_rev")
49
+ except KeyError:
50
+ reason = (
51
+ "The rev (or _rev) field is missing from the original report."
52
+ )
53
+ invalid_reports.append({report_id: reason})
54
+ continue
55
+ try:
56
+ schema_report = self._tempstore.dict_to_schema(document)
57
+ except ValidationError as exc:
58
+ reason = f"Report has invalid format: {exc}"
59
+ invalid_reports.append({report_id: reason})
60
+ continue
61
+ try:
62
+ response = loader.load(schema_report)
63
+ except StandCloudError as exc:
64
+ reason = f"StandCloud service problem: {exc}"
65
+ invalid_reports.append({report_id: reason})
66
+ continue
67
+ if response.status_code != HTTPStatus.CREATED:
68
+ reason = f"Staus code: {response.status_code}, text: {response.text}"
69
+ invalid_reports.append({report_id: reason})
70
+ continue
71
+ if not self._tempstore.delete(report_id):
72
+ reason = f"Report {report_id} not deleted from the temporary storage"
73
+ invalid_reports.append({report_id: reason})
74
+ success_report_counter += 1
75
+ return self._create_sync_message(success_report_counter, invalid_reports)
76
+
77
+ def push_to_tempstore(self, report: ResultRunStore) -> bool:
78
+ """Push report to the report database.
79
+
80
+ Args:
81
+ report (ResultRunStore): report
82
+
83
+ Returns:
84
+ bool: True if success, else False
85
+ """
86
+ return self._tempstore.push_report(report)
87
+
88
+ def push_to_sc(self, report: ResultRunStore) -> bool:
89
+ """Push report to the StandCloud.
90
+
91
+ Args:
92
+ report (ResultRunStore): report
93
+ """
94
+ try:
95
+ loader = self._create_sc_loader()
96
+ except StandCloudError:
97
+ return False
98
+ try:
99
+ response = loader.load(report)
100
+ except StandCloudError:
101
+ return False
102
+ return response.status_code == HTTPStatus.CREATED
103
+
104
+ def _create_sync_message(self, success_report: int, invalid_reports: list) -> str:
105
+ msg = ""
106
+ if success_report:
107
+ msg = f"Reports successfully uploaded to StandCloud: {success_report}"
108
+ if invalid_reports:
109
+ msg += "\nInvalid reports:\n\n"
110
+ for _report in invalid_reports:
111
+ report_id, reason = next(iter(_report.items()))
112
+ msg += f"{report_id}: {reason}\n"
113
+ raise StandCloudError(msg)
114
+ if not msg:
115
+ msg = "All reports are synchronized with StandCloud"
116
+ return msg
117
+
118
+ def _create_sc_loader(self) -> StandCloudLoader:
119
+ loader = StandCloudLoader()
120
+ loader.healthcheck()
121
+ return loader
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hardpy
3
- Version: 0.17.1
3
+ Version: 0.18.0
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/
@@ -81,7 +81,8 @@ HardPy allows you to:
81
81
 
82
82
  * Create test benches for devices using [pytest](https://docs.pytest.org/);
83
83
  * Use a browser to view, start, stop, and interact with tests;
84
- * Store test results in the [CouchDB](https://couchdb.apache.org/) database.
84
+ * Store test results in the [CouchDB](https://couchdb.apache.org/) database;
85
+ * Store test results on the [StandCloud](https://standcloud.io/) analytics platform.
85
86
 
86
87
  <h1 align="center">
87
88
  <img src="https://raw.githubusercontent.com/everypinio/hardpy/main/docs/img/hardpy_panel.gif" alt="hardpy panel" style="width:550px;">
@@ -1,26 +1,26 @@
1
1
  hardpy/__init__.py,sha256=B99MElYhd8HHgOJaT-RVPyvIN18uPaG2pb78TJ3lqvE,2957
2
2
  hardpy/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- hardpy/cli/cli.py,sha256=MmVup0jt_H0erPiqloPInbiZ9SjWHmJvqewHOtlqB10,9632
3
+ hardpy/cli/cli.py,sha256=L-yFMcMTm3JY3s1eK83q5sHxrF8altU8rhrwSF9VNG8,11195
4
4
  hardpy/cli/template.py,sha256=kOl8hsj6iBTFIDUli_dzHkH8mlnoJzOlr9muLpTEayg,6230
5
5
  hardpy/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- hardpy/common/config.py,sha256=XstzgQVOSgGz44_OH82jjxM90ZTI97odp-juICfx2h0,6289
6
+ hardpy/common/config.py,sha256=t1ij_-PiIuhIgXD0PP2fZeRJF-gQGGxthYsu1PQmDGQ,6430
7
7
  hardpy/common/singleton.py,sha256=RVMqbluN-mhlJ4QOYcRzQLA68Hs8t83XNyihyUwhYGo,948
8
8
  hardpy/common/stand_cloud/__init__.py,sha256=fezdiYAehtT2H-GAef-xZU12CbmCRe64XHA9UB3kJDU,456
9
- hardpy/common/stand_cloud/connector.py,sha256=scmKT09duPqqbQtwMNPnl59si_sErwqAY2PeiTSCZvg,7389
9
+ hardpy/common/stand_cloud/connector.py,sha256=OegkuPH8Vxo_cWjiNRHzY4ONmDGWzZbz8K7Y_WeCgUc,8135
10
10
  hardpy/common/stand_cloud/exception.py,sha256=eKkqu5ylDRIGN_yZhvz2xVGm49XmlZ8nryALgdRqpbY,287
11
11
  hardpy/common/stand_cloud/oauth2.py,sha256=SDqtIwcuMgqfBkEZyo3GXeVPnvRBOr6dzeXowx3ZkEw,2803
12
12
  hardpy/common/stand_cloud/registration.py,sha256=UW-JGcvON5CMQQ-s2Mb4Ee3u_jmdQfSj3vPfZ_FuhHY,2370
13
- hardpy/common/stand_cloud/token_manager.py,sha256=8dX802F0CnOrOjOQInyYCrvuRdK0CeiCrTDITAbSLgQ,4055
13
+ hardpy/common/stand_cloud/token_manager.py,sha256=0s4fdYrjAonv1DCzTE5D-fF6drZJ3AhTDUoCRlSlK68,4730
14
14
  hardpy/common/stand_cloud/utils.py,sha256=GN3wzbrmF-Xe5iUXf_HurGO-YKltqd3Gc_7vG2eEL7c,692
15
15
  hardpy/hardpy_panel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- hardpy/hardpy_panel/api.py,sha256=iO7zBH56X74mj1c_5NudRlQ7frnBu-fXAoRfpN_2jU8,4721
16
+ hardpy/hardpy_panel/api.py,sha256=3zNdXldYGXSnf7bwE-oqoI8xE0H1shwOWg3_bkUGCvs,8149
17
17
  hardpy/hardpy_panel/frontend/dist/favicon.ico,sha256=sgIk5PKUKEKBDpkSrc8dJgjpObp0iF82Mec0GpfKId4,15406
18
- hardpy/hardpy_panel/frontend/dist/index.html,sha256=cXpYNo5rQSx4sbz9B7bBkXFg2M0Zp_VcdQQfaw0WJ-U,1851
18
+ hardpy/hardpy_panel/frontend/dist/index.html,sha256=TOZiLD7WXiBB5W0GPF50u5zQtG0-gQ4Gd7n2757k-hU,1851
19
19
  hardpy/hardpy_panel/frontend/dist/logo192.png,sha256=E4K7drvhJCg9HcTpRihOXZhVJVBZ7-W97Se-3tDb46o,14485
20
20
  hardpy/hardpy_panel/frontend/dist/logo512.png,sha256=-fIMbqX7PYUpheK4kX1C1erRTe_hHZwFQYDLrAbhFRU,34188
21
21
  hardpy/hardpy_panel/frontend/dist/manifest.json,sha256=PfmJlN2JMJtHS6OnhU4b4X5wPQC_yRBdjesjoirObSA,502
22
- hardpy/hardpy_panel/frontend/dist/assets/allPaths-LQifhvrX.js,sha256=7_DF1_Eff4_SJH2rsCwWL446cZCdq_zGVNFMEw52RxA,309
23
- hardpy/hardpy_panel/frontend/dist/assets/allPathsLoader-C-JecT3u.js,sha256=9FRIQnmEmIVgrU1c-6fAYlBrzDo5Fvm0x2g6OabHg8o,550
22
+ hardpy/hardpy_panel/frontend/dist/assets/allPaths-31ulJ0tA.js,sha256=6aCDALhkvoqh_BkyemOBKdzLPJOhj18DEGp4U7VYW5s,309
23
+ hardpy/hardpy_panel/frontend/dist/assets/allPathsLoader-HPn4WHWu.js,sha256=8UGKsW3Y3J2koazg_rbu37B9r0t46FpctZmXpLbyLL0,550
24
24
  hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-16-B2twAPZE.ttf,sha256=OcrUHPBAaLvJxb2DOethXFXg8PClDcyvpsh0mToLFPM,136248
25
25
  hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-16-C0Unyq1d.eot,sha256=Bl93LjY8pyBj0Iip1lUxMM-0l1zLrRjoGmKPPnAQIgw,136456
26
26
  hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-16-CVy9qFng.svg,sha256=57jlcc-NFRVJNJ3t-1fOnJvgdbYhcrF5a06LJLhWc5A,601027
@@ -31,13 +31,13 @@ hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-20-CjKGIKxE.woff,sha256
31
31
  hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-20-DQ09GSQq.svg,sha256=3gLRYNxd_Y4iz6pspH4Bf7Ql4F6LH5haZzbTfxA53HQ,638634
32
32
  hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-20-DmR755bS.ttf,sha256=yr5g5Jw9ZnxJJ7e1quOv977VE3NU2GRB60BMRrOJrcI,139424
33
33
  hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-20-p9MhBXD8.eot,sha256=CFx8t8ONhB4INIrK860N56_t1dmS7FuRF7i0HKKo58k,139632
34
- hardpy/hardpy_panel/frontend/dist/assets/browser-ponyfill-B-CPdmQc.js,sha256=AT3hjyUgHdoxmhyl0GTfB4jtwDPxXTqIUcjdLS0fH8g,10294
34
+ hardpy/hardpy_panel/frontend/dist/assets/browser-ponyfill-BQ1ipruI.js,sha256=sdj30Rkv2EtP1NuDSPy76SFDtb5ygKg4SpWu00g1sPk,10294
35
35
  hardpy/hardpy_panel/frontend/dist/assets/index-B-fsa5Ru.js,sha256=IonL7d7ppdDr-_FRJZQPWI4HHFTiygYvZGVlUxHY9R8,294235
36
- hardpy/hardpy_panel/frontend/dist/assets/index-B2oxSaK6.js,sha256=BSl7jKiWRZWWzbp-0zqMtg-xjUfJEAKRLR7ALo38Igk,5949989
37
36
  hardpy/hardpy_panel/frontend/dist/assets/index-B7T9xvaW.css,sha256=5m7QXWbthqi_Va8qlvnTZeuRzSN_ZJUdhyeb3JD6ZME,315862
37
+ hardpy/hardpy_panel/frontend/dist/assets/index-BK2y65ib.js,sha256=Qu8WIJU1p-6KmwXRihdpyKcgjb-yz-INSmkYM5KSeM8,5952407
38
38
  hardpy/hardpy_panel/frontend/dist/assets/index-DLOviMB1.js,sha256=sI0W1vvwqvIwKP2_jglrwOhej3n5rJD72-d4ZhlUHqM,285612
39
39
  hardpy/hardpy_panel/frontend/dist/assets/logo_smol-CK3jE85c.png,sha256=E4K7drvhJCg9HcTpRihOXZhVJVBZ7-W97Se-3tDb46o,14485
40
- hardpy/hardpy_panel/frontend/dist/assets/splitPathsBySizeLoader-CBTnepth.js,sha256=701tUVw0n3Iuj5yVRfcTI7Q6xRay-AA0FSeEwsfZZsE,472
40
+ hardpy/hardpy_panel/frontend/dist/assets/splitPathsBySizeLoader-ev1ZiRR9.js,sha256=l_5r-kXzX37BmRmog1OcIzqWxU1KMjRagQcTGQu9sPU,472
41
41
  hardpy/hardpy_panel/frontend/dist/locales/de/translation.json,sha256=vYVYRpSrpGZi7s8tPoAZxtVCeuPqhlwK1qC_lm52Pzc,2575
42
42
  hardpy/hardpy_panel/frontend/dist/locales/en/translation.json,sha256=jJ1DEY6-fx--a5VQW6SOYCvPLQXfizs-JtsRf1rohiI,2333
43
43
  hardpy/hardpy_panel/frontend/dist/locales/es/translation.json,sha256=_biD1ve2CpvFDeRO7dzoFyvbeFcz-572UzhUzn002Z8,2628
@@ -46,15 +46,16 @@ hardpy/hardpy_panel/frontend/dist/locales/ja/translation.json,sha256=kGBJmHlhndu
46
46
  hardpy/hardpy_panel/frontend/dist/locales/ru/translation.json,sha256=81pqFajGhSwPwZV4j0HpziB1oX2iJ5Ud12cLiAaX8J0,3467
47
47
  hardpy/hardpy_panel/frontend/dist/locales/zh/translation.json,sha256=9W61N2MA15J5Zj6UqBqPmUDZXaRAH2HWm9m51BgvzJw,2322
48
48
  hardpy/pytest_hardpy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
- hardpy/pytest_hardpy/plugin.py,sha256=Qa_TaNjvDARlQoINxca4_3b3sS58V0CiJdV_QZ-3V_8,22125
49
+ hardpy/pytest_hardpy/plugin.py,sha256=6If9k_gyXYH2Eow0d5ty2Kpb3Qsij17gb3DlqIXauWQ,23355
50
50
  hardpy/pytest_hardpy/pytest_call.py,sha256=qUDrK1iUjhGEs4bmBFTk9E0YfFzsePoHhVDRY6ngRV8,22878
51
- hardpy/pytest_hardpy/pytest_wrapper.py,sha256=j3zfSHgtx7V_LdUErGAjy0KZ14YYkXyYTwNO59NcIWI,4745
52
- hardpy/pytest_hardpy/db/__init__.py,sha256=scaWueM5N_aMEuFCcMVkicpcqjx5JUi2IdEN9HmzuGs,792
51
+ hardpy/pytest_hardpy/pytest_wrapper.py,sha256=bbk1BYy7CEBeg3Z2pcONb-xFzb3uDYLKcJV7316-Szo,4830
52
+ hardpy/pytest_hardpy/db/__init__.py,sha256=nat_tUO2cxPIp9e6U8Fvg6V4NcZ9TVg27u0GHoKelD4,865
53
53
  hardpy/pytest_hardpy/db/base_store.py,sha256=d1lkTB7CpHTKysD2yuuGQFai44OtOmtTbq-WaBYojhw,5545
54
54
  hardpy/pytest_hardpy/db/const.py,sha256=E_A0IKGeS3qyPX4fTfUE5ksARsrTKSVWqUkdmh8S_fo,1414
55
55
  hardpy/pytest_hardpy/db/runstore.py,sha256=humoVBDZJGh7j_v5Xrf3P0HHaeRXC8oRdIj1QWGZizg,946
56
56
  hardpy/pytest_hardpy/db/stand_type.py,sha256=p3AFtgMt-sn8QXRp60YM-xo2mEjZHUhYr_Mxhz1WyP0,7438
57
57
  hardpy/pytest_hardpy/db/statestore.py,sha256=1s615c4OdzHd5u-464O-lcXoKulMfZ6moblhTWDHwSg,583
58
+ hardpy/pytest_hardpy/db/tempstore.py,sha256=WKIykL_4A9j8n-F7pIy_9fj4BNOfzqWkUwg0_8DR05s,1802
58
59
  hardpy/pytest_hardpy/db/schema/__init__.py,sha256=1S73W3PLQt8gX5Y33nbX1JdwLvnrtlKH4cElID3pwuc,263
59
60
  hardpy/pytest_hardpy/db/schema/v1.py,sha256=0RGZP-2lDeA3r8-simEEnjlHOAyziYSMXb9BINQyVbM,6377
60
61
  hardpy/pytest_hardpy/reporter/__init__.py,sha256=rztpM2HlLUpMOvad0JHbZU4Mk8PDDQyCFXLhpLktGQI,322
@@ -65,10 +66,12 @@ hardpy/pytest_hardpy/result/__init__.py,sha256=2afpuEuOcxYfIEOwWzsGZe960iQaPVCms
65
66
  hardpy/pytest_hardpy/result/couchdb_config.py,sha256=ujxyJYM2pdZzi3GZ2Zysbz2_ZeTRN5sQc8AGuzRJm_0,3243
66
67
  hardpy/pytest_hardpy/result/report_loader/__init__.py,sha256=wq5Y-_JW2ExCRnQ9VVesKmTToEQrcTY5RxNJIWaT9ag,374
67
68
  hardpy/pytest_hardpy/result/report_loader/couchdb_loader.py,sha256=KcZ0JkCgWhrj2J9M04JBDy0fpqtpVEYtu9GCLDG27pU,2255
68
- hardpy/pytest_hardpy/result/report_loader/stand_cloud_loader.py,sha256=7iwk9E94jFkn_s0wRKjrRz0O00H4D4K75s6wZGlSoMI,3755
69
+ hardpy/pytest_hardpy/result/report_loader/stand_cloud_loader.py,sha256=CjvkS6N1OzKmMAqfs6bhQLK2mlB_NIKX-YnJn39SHqY,3991
69
70
  hardpy/pytest_hardpy/result/report_reader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
71
  hardpy/pytest_hardpy/result/report_reader/couchdb_reader.py,sha256=lnWSX-0QKbdMwtqfCtW0tiH9W_ZEPqQ3rb7Lc8gES7E,5726
71
72
  hardpy/pytest_hardpy/result/report_reader/stand_cloud_reader.py,sha256=uT7YSBu1QyURH9IkgRCdpbinn8LKXUhgVEhwPmGZV7I,3636
73
+ hardpy/pytest_hardpy/result/report_synchronizer/__init__.py,sha256=QezaT_Yk8LrciygdsFPJeZn0EBUaKpd0GfCQjSuIo-I,273
74
+ hardpy/pytest_hardpy/result/report_synchronizer/synchronizer.py,sha256=-RnYMhnZTDci0NniwnCoG5-Pg-R22TKWQLfyfTgyA_w,4309
72
75
  hardpy/pytest_hardpy/utils/__init__.py,sha256=zHln8ySBHesYAwYatLYkHol5TuuTTNOqrsMP7ONFEG0,1338
73
76
  hardpy/pytest_hardpy/utils/const.py,sha256=xS3jBrW_D6IUTlAjSnLiHvSthieRHCj3uN_6fFAXS0w,1832
74
77
  hardpy/pytest_hardpy/utils/dialog_box.py,sha256=eCLGQ-Z8rDPd_8ABHRtbkd7piSZcJoG-bCBmnyq29Pw,11375
@@ -76,8 +79,8 @@ hardpy/pytest_hardpy/utils/exception.py,sha256=1l2VBZLUnjPDoOs744MtaP7Y9FuXUq7ko
76
79
  hardpy/pytest_hardpy/utils/machineid.py,sha256=6JAzUt7KtjTYn8kL9hSMaCQ20U8liH-zDT9v-5Ch7Q8,296
77
80
  hardpy/pytest_hardpy/utils/node_info.py,sha256=DaW566WvsyWR66CThuZ38UoHwQa-pu-4WRLg61OXDnE,7134
78
81
  hardpy/pytest_hardpy/utils/progress_calculator.py,sha256=TPl2gG0ZSvMe8otPythhF9hkD6fa6-mJAhy9yI83-yE,1071
79
- hardpy-0.17.1.dist-info/METADATA,sha256=YzWTDF-5099MNYk_0pQUKU1Nv-XtSfNXIiV355ZW51o,4898
80
- hardpy-0.17.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
81
- hardpy-0.17.1.dist-info/entry_points.txt,sha256=nL2sMkKMScNaOE0IPkYnu9Yr-BUswZvGSrwY-SxHY3E,102
82
- hardpy-0.17.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
83
- hardpy-0.17.1.dist-info/RECORD,,
82
+ hardpy-0.18.0.dist-info/METADATA,sha256=sZ2hohzC2kZlfrBnO5j3IjoJkfiSeElIsDjra0G2fQs,4983
83
+ hardpy-0.18.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
84
+ hardpy-0.18.0.dist-info/entry_points.txt,sha256=nL2sMkKMScNaOE0IPkYnu9Yr-BUswZvGSrwY-SxHY3E,102
85
+ hardpy-0.18.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
86
+ hardpy-0.18.0.dist-info/RECORD,,