hardpy 0.19.1__py3-none-any.whl → 0.20.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 +2 -0
- hardpy/cli/cli.py +6 -0
- hardpy/common/config.py +19 -0
- hardpy/hardpy_panel/api.py +62 -1
- hardpy/hardpy_panel/frontend/dist/assets/{allPaths-C_-7WXHD.js → allPaths-BXbcAtew.js} +1 -1
- hardpy/hardpy_panel/frontend/dist/assets/{allPathsLoader-DgH0Xily.js → allPathsLoader-lJLHMNNZ.js} +2 -2
- hardpy/hardpy_panel/frontend/dist/assets/{browser-ponyfill-BbOvdqIF.js → browser-ponyfill-DzwgrUwX.js} +1 -1
- hardpy/hardpy_panel/frontend/dist/assets/{index-DEJb2W0B.js → index-CVhA7vmQ.js} +158 -158
- hardpy/hardpy_panel/frontend/dist/assets/{splitPathsBySizeLoader-o5HCcdVL.js → splitPathsBySizeLoader-BdwEQHyO.js} +1 -1
- hardpy/hardpy_panel/frontend/dist/index.html +1 -1
- hardpy/pytest_hardpy/db/__init__.py +0 -2
- hardpy/pytest_hardpy/db/runstore.py +378 -10
- hardpy/pytest_hardpy/db/statestore.py +390 -5
- hardpy/pytest_hardpy/db/tempstore.py +219 -17
- hardpy/pytest_hardpy/plugin.py +2 -2
- hardpy/pytest_hardpy/result/__init__.py +2 -0
- hardpy/pytest_hardpy/result/report_loader/json_loader.py +49 -0
- hardpy/pytest_hardpy/result/report_synchronizer/synchronizer.py +25 -9
- {hardpy-0.19.1.dist-info → hardpy-0.20.0.dist-info}/METADATA +18 -3
- {hardpy-0.19.1.dist-info → hardpy-0.20.0.dist-info}/RECORD +23 -23
- hardpy/pytest_hardpy/db/base_store.py +0 -179
- {hardpy-0.19.1.dist-info → hardpy-0.20.0.dist-info}/WHEEL +0 -0
- {hardpy-0.19.1.dist-info → hardpy-0.20.0.dist-info}/entry_points.txt +0 -0
- {hardpy-0.19.1.dist-info → hardpy-0.20.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
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.result.report_loader.couchdb_loader import CouchdbLoader
|
|
5
|
+
from hardpy.pytest_hardpy.result.report_loader.json_loader import JsonLoader
|
|
5
6
|
from hardpy.pytest_hardpy.result.report_loader.stand_cloud_loader import (
|
|
6
7
|
StandCloudLoader,
|
|
7
8
|
)
|
|
@@ -13,6 +14,7 @@ from hardpy.pytest_hardpy.result.report_reader.stand_cloud_reader import (
|
|
|
13
14
|
__all__ = [
|
|
14
15
|
"CouchdbLoader",
|
|
15
16
|
"CouchdbReader",
|
|
17
|
+
"JsonLoader",
|
|
16
18
|
"StandCloudLoader",
|
|
17
19
|
"StandCloudReader",
|
|
18
20
|
]
|
|
@@ -0,0 +1,49 @@
|
|
|
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
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from logging import getLogger
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from uuid6 import uuid7
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from hardpy.pytest_hardpy.db.schema import ResultRunStore
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class JsonLoader:
|
|
17
|
+
"""JSON report generator."""
|
|
18
|
+
|
|
19
|
+
def __init__(self, storage_dir: Path | None = None) -> None:
|
|
20
|
+
if not storage_dir:
|
|
21
|
+
storage_dir = Path.cwd() / "reports"
|
|
22
|
+
self._storage_dir = storage_dir
|
|
23
|
+
self._storage_dir.mkdir(parents=True, exist_ok=True)
|
|
24
|
+
self._log = getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
def load(self, report: ResultRunStore, new_report_id: str | None = None) -> bool:
|
|
27
|
+
"""Load report to the report database.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
report (ResultRunStore): report
|
|
31
|
+
new_report_id (str | None, optional): user's report ID. Defaults to uuid7.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
bool: True if success, else False
|
|
35
|
+
"""
|
|
36
|
+
report_dict = report.model_dump()
|
|
37
|
+
report_id = new_report_id if new_report_id else str(uuid7())
|
|
38
|
+
report_dict["id"] = report_id
|
|
39
|
+
report_file = self._storage_dir / f"{report_id}.json"
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
with report_file.open("w") as f:
|
|
43
|
+
json.dump(report_dict, f, indent=2, default=str)
|
|
44
|
+
except Exception as exc: # noqa: BLE001
|
|
45
|
+
self._log.error(f"Error while saving report {report_id}: {exc}")
|
|
46
|
+
return False
|
|
47
|
+
else:
|
|
48
|
+
self._log.debug(f"Report saved with id: {report_id}")
|
|
49
|
+
return True
|
|
@@ -8,7 +8,7 @@ from typing import TYPE_CHECKING
|
|
|
8
8
|
from pydantic import ValidationError
|
|
9
9
|
|
|
10
10
|
from hardpy.common.stand_cloud.exception import StandCloudError
|
|
11
|
-
from hardpy.pytest_hardpy.db.tempstore import TempStore
|
|
11
|
+
from hardpy.pytest_hardpy.db.tempstore import CouchDBTempStore, TempStore
|
|
12
12
|
from hardpy.pytest_hardpy.result.report_loader.stand_cloud_loader import (
|
|
13
13
|
StandCloudLoader,
|
|
14
14
|
)
|
|
@@ -21,7 +21,18 @@ class StandCloudSynchronizer:
|
|
|
21
21
|
"""Synchronize reports with StandCloud."""
|
|
22
22
|
|
|
23
23
|
def __init__(self) -> None:
|
|
24
|
-
self._tempstore =
|
|
24
|
+
self._tempstore: TempStore | None = None
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def _get_tempstore(self) -> TempStore:
|
|
28
|
+
"""Get TempStore instance lazily.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
TempStore: TempStore singleton instance
|
|
32
|
+
"""
|
|
33
|
+
if self._tempstore is None:
|
|
34
|
+
self._tempstore = TempStore()
|
|
35
|
+
return self._tempstore
|
|
25
36
|
|
|
26
37
|
def sync(self) -> str:
|
|
27
38
|
"""Sync reports with StandCloud.
|
|
@@ -29,16 +40,21 @@ class StandCloudSynchronizer:
|
|
|
29
40
|
Returns:
|
|
30
41
|
str: Synchronization message
|
|
31
42
|
"""
|
|
32
|
-
|
|
43
|
+
_tempstore = self._get_tempstore
|
|
44
|
+
if not self._get_tempstore.reports():
|
|
33
45
|
return "All reports are synchronized with StandCloud"
|
|
34
46
|
loader = self._create_sc_loader()
|
|
35
47
|
|
|
36
48
|
invalid_reports = []
|
|
37
49
|
success_report_counter = 0
|
|
38
|
-
for _report in self.
|
|
50
|
+
for _report in self._get_tempstore.reports():
|
|
39
51
|
try:
|
|
40
|
-
|
|
41
|
-
|
|
52
|
+
if isinstance(_tempstore, CouchDBTempStore):
|
|
53
|
+
document: dict = _report.get("doc") # type: ignore[assignment]
|
|
54
|
+
report_id: str = _report.get("id") # type: ignore[assignment]
|
|
55
|
+
else:
|
|
56
|
+
document: dict = _report
|
|
57
|
+
report_id: str = _report.get("_id")
|
|
42
58
|
document.pop("rev")
|
|
43
59
|
except KeyError:
|
|
44
60
|
try:
|
|
@@ -50,7 +66,7 @@ class StandCloudSynchronizer:
|
|
|
50
66
|
invalid_reports.append({report_id: reason})
|
|
51
67
|
continue
|
|
52
68
|
try:
|
|
53
|
-
schema_report = self.
|
|
69
|
+
schema_report = self._get_tempstore.dict_to_schema(document)
|
|
54
70
|
except ValidationError as exc:
|
|
55
71
|
reason = f"Report has invalid format: {exc}"
|
|
56
72
|
invalid_reports.append({report_id: reason})
|
|
@@ -65,7 +81,7 @@ class StandCloudSynchronizer:
|
|
|
65
81
|
reason = f"Staus code: {response.status_code}, text: {response.text}"
|
|
66
82
|
invalid_reports.append({report_id: reason})
|
|
67
83
|
continue
|
|
68
|
-
if not self.
|
|
84
|
+
if not self._get_tempstore.delete(report_id):
|
|
69
85
|
reason = f"Report {report_id} not deleted from the temporary storage"
|
|
70
86
|
invalid_reports.append({report_id: reason})
|
|
71
87
|
success_report_counter += 1
|
|
@@ -80,7 +96,7 @@ class StandCloudSynchronizer:
|
|
|
80
96
|
Returns:
|
|
81
97
|
bool: True if success, else False
|
|
82
98
|
"""
|
|
83
|
-
return self.
|
|
99
|
+
return self._get_tempstore.push_report(report)
|
|
84
100
|
|
|
85
101
|
def push_to_sc(self, report: ResultRunStore) -> bool:
|
|
86
102
|
"""Push report to the StandCloud.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hardpy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.20.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/
|
|
@@ -42,6 +42,7 @@ Requires-Dist: tomli-w<2,>=1.1.0
|
|
|
42
42
|
Requires-Dist: tomli<3,>=2.0.1
|
|
43
43
|
Requires-Dist: typer<1,>=0.12
|
|
44
44
|
Requires-Dist: tzlocal~=5.2
|
|
45
|
+
Requires-Dist: uuid6
|
|
45
46
|
Requires-Dist: uvicorn>=0.23.2
|
|
46
47
|
Provides-Extra: build
|
|
47
48
|
Requires-Dist: build==1.0.3; extra == 'build'
|
|
@@ -69,7 +70,7 @@ HardPy is a python library for creating a test bench for devices.
|
|
|
69
70
|
[](https://docs.pytest.org/en/latest/)
|
|
70
71
|
[](https://everypinio.github.io/hardpy/)
|
|
71
72
|
[](https://www.reddit.com/r/HardPy)
|
|
72
|
-
[]()
|
|
73
|
+
[](https://discord.gg/98bWadmG8J)
|
|
73
74
|
[](https://t.me/everypin)
|
|
74
75
|
|
|
75
76
|
</div>
|
|
@@ -82,7 +83,7 @@ HardPy allows you to:
|
|
|
82
83
|
|
|
83
84
|
* Create test benches for devices using [pytest](https://docs.pytest.org/);
|
|
84
85
|
* Use a browser to view, start, stop, and interact with tests;
|
|
85
|
-
* Store test results in the [CouchDB](https://couchdb.apache.org/) database;
|
|
86
|
+
* Store test results in the [CouchDB](https://couchdb.apache.org/) database or to simple JSON files;
|
|
86
87
|
* Store test results on the [StandCloud](https://standcloud.io/) analytics platform.
|
|
87
88
|
|
|
88
89
|
<h1 align="center">
|
|
@@ -97,6 +98,8 @@ pip install hardpy
|
|
|
97
98
|
|
|
98
99
|
## Getting Started
|
|
99
100
|
|
|
101
|
+
### With CouchDB
|
|
102
|
+
|
|
100
103
|
1. Create your first test bench.
|
|
101
104
|
```bash
|
|
102
105
|
hardpy init
|
|
@@ -115,6 +118,18 @@ hardpy run
|
|
|
115
118
|
|
|
116
119
|
Login and password: **dev**, database - **runstore**.
|
|
117
120
|
|
|
121
|
+
### Without a database
|
|
122
|
+
|
|
123
|
+
1. Create your first test bench.
|
|
124
|
+
```bash
|
|
125
|
+
hardpy init --no-create-database --storage-type json
|
|
126
|
+
```
|
|
127
|
+
2. Launch HardPy operator panel.
|
|
128
|
+
```bash
|
|
129
|
+
hardpy run
|
|
130
|
+
```
|
|
131
|
+
3. View operator panel in browser: http://localhost:8000/
|
|
132
|
+
|
|
118
133
|
## Examples
|
|
119
134
|
|
|
120
135
|
For more examples of using **HardPy**, see the [examples](https://github.com/everypinio/hardpy/tree/main/examples) folder and the [documentation](https://everypinio.github.io/hardpy/examples/).
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
hardpy/__init__.py,sha256=
|
|
1
|
+
hardpy/__init__.py,sha256=UC-h56_4xL23SGY_esaN3hklenl1lKQ6KJEy5rYTeco,2991
|
|
2
2
|
hardpy/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
hardpy/cli/cli.py,sha256=
|
|
3
|
+
hardpy/cli/cli.py,sha256=P6ThIcIvcMwJht7994-0xcR6OTXALSIka58QU-wIOMc,11623
|
|
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=
|
|
6
|
+
hardpy/common/config.py,sha256=GmDCeCkv3eSY214x_n3f1q5G9qkbXRBp5sZ7llH_UFk,8340
|
|
7
7
|
hardpy/common/singleton.py,sha256=RVMqbluN-mhlJ4QOYcRzQLA68Hs8t83XNyihyUwhYGo,948
|
|
8
8
|
hardpy/common/stand_cloud/__init__.py,sha256=fezdiYAehtT2H-GAef-xZU12CbmCRe64XHA9UB3kJDU,456
|
|
9
9
|
hardpy/common/stand_cloud/connector.py,sha256=PD1Gr1QOuFUmCsnlPY2zb_WF9Nrr8BGTlbRC2_LTKFE,8147
|
|
@@ -13,14 +13,14 @@ hardpy/common/stand_cloud/registration.py,sha256=UW-JGcvON5CMQQ-s2Mb4Ee3u_jmdQfS
|
|
|
13
13
|
hardpy/common/stand_cloud/token_manager.py,sha256=oHLDip0a-0mmAiRQN5IuypTSNyOnSB43TSWlprOLRI0,4843
|
|
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=
|
|
16
|
+
hardpy/hardpy_panel/api.py,sha256=On7WeTBFg9efFAgsNjh5nAOrikrzX-D0T100y_dF6a4,12662
|
|
17
17
|
hardpy/hardpy_panel/frontend/dist/favicon.ico,sha256=sgIk5PKUKEKBDpkSrc8dJgjpObp0iF82Mec0GpfKId4,15406
|
|
18
|
-
hardpy/hardpy_panel/frontend/dist/index.html,sha256=
|
|
18
|
+
hardpy/hardpy_panel/frontend/dist/index.html,sha256=JtaLnshdTxzo6aKFuGaiJ4Hvcb70_D8vq4FYS9iX_iU,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-
|
|
23
|
-
hardpy/hardpy_panel/frontend/dist/assets/allPathsLoader-
|
|
22
|
+
hardpy/hardpy_panel/frontend/dist/assets/allPaths-BXbcAtew.js,sha256=O19nV0Z8066gVhAfp8IWcx_yvTGNeb52iR24YejQ8vA,309
|
|
23
|
+
hardpy/hardpy_panel/frontend/dist/assets/allPathsLoader-lJLHMNNZ.js,sha256=Zh3VVQfqIPs9FFKhyrusCS_TkFoX5Mi7hmU92oFvDBc,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-
|
|
34
|
+
hardpy/hardpy_panel/frontend/dist/assets/browser-ponyfill-DzwgrUwX.js,sha256=RFhwMCb6yd2G1Wed9APir2qK2Zhgxv71TNiPpLc3mx8,10294
|
|
35
35
|
hardpy/hardpy_panel/frontend/dist/assets/index-B-fsa5Ru.js,sha256=IonL7d7ppdDr-_FRJZQPWI4HHFTiygYvZGVlUxHY9R8,294235
|
|
36
36
|
hardpy/hardpy_panel/frontend/dist/assets/index-B7T9xvaW.css,sha256=5m7QXWbthqi_Va8qlvnTZeuRzSN_ZJUdhyeb3JD6ZME,315862
|
|
37
|
-
hardpy/hardpy_panel/frontend/dist/assets/index-
|
|
37
|
+
hardpy/hardpy_panel/frontend/dist/assets/index-CVhA7vmQ.js,sha256=aIaCyBi75O1XOfSLpfXtxreTMrV2_9MmMXOrlfamuY0,6027073
|
|
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-
|
|
40
|
+
hardpy/hardpy_panel/frontend/dist/assets/splitPathsBySizeLoader-BdwEQHyO.js,sha256=bOuL64ihCfZQao3ML5zVwlUdzkko3eqZno4Xs0rhCnQ,472
|
|
41
41
|
hardpy/hardpy_panel/frontend/dist/locales/cs/translation.json,sha256=kCSbBWfQQ6lrVKlOeByXAhAoG5bBxrxf7-PTvvQgR2M,2964
|
|
42
42
|
hardpy/hardpy_panel/frontend/dist/locales/de/translation.json,sha256=wZRO5iz8VvaEjACSWHJNjjKerd8YcPo7gpziCpjfF1Q,3073
|
|
43
43
|
hardpy/hardpy_panel/frontend/dist/locales/en/translation.json,sha256=_vsAG4aOto5C-xiCQK0zip02u6f9wHr-T_BRr_DUdTo,2776
|
|
@@ -47,32 +47,32 @@ hardpy/hardpy_panel/frontend/dist/locales/ja/translation.json,sha256=4_MrBUHCneX
|
|
|
47
47
|
hardpy/hardpy_panel/frontend/dist/locales/ru/translation.json,sha256=LvJavIT8_HdrIMIvgGtRBoGOCs3DeBNyYg0BHALwmEg,4097
|
|
48
48
|
hardpy/hardpy_panel/frontend/dist/locales/zh/translation.json,sha256=ZmoqrndiAtatXSVDpz6looKb_2U_XnJdIidfK9o-uXY,2781
|
|
49
49
|
hardpy/pytest_hardpy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
|
-
hardpy/pytest_hardpy/plugin.py,sha256=
|
|
50
|
+
hardpy/pytest_hardpy/plugin.py,sha256=1URbMU2jbZHCVWN7SvuwmKktetQu0AFF2IK5cCLJy10,24586
|
|
51
51
|
hardpy/pytest_hardpy/pytest_call.py,sha256=qUDrK1iUjhGEs4bmBFTk9E0YfFzsePoHhVDRY6ngRV8,22878
|
|
52
52
|
hardpy/pytest_hardpy/pytest_wrapper.py,sha256=TS-Ysm1ou-bkkc50A0tdJWXCNx51sB1EOkUUYxQ64GA,7737
|
|
53
|
-
hardpy/pytest_hardpy/db/__init__.py,sha256=
|
|
54
|
-
hardpy/pytest_hardpy/db/base_store.py,sha256=d1lkTB7CpHTKysD2yuuGQFai44OtOmtTbq-WaBYojhw,5545
|
|
53
|
+
hardpy/pytest_hardpy/db/__init__.py,sha256=3uNc4xjbxFnEGX8hErEbrhrbky_XlplVGr7LmiR1XTg,791
|
|
55
54
|
hardpy/pytest_hardpy/db/const.py,sha256=E_A0IKGeS3qyPX4fTfUE5ksARsrTKSVWqUkdmh8S_fo,1414
|
|
56
|
-
hardpy/pytest_hardpy/db/runstore.py,sha256=
|
|
55
|
+
hardpy/pytest_hardpy/db/runstore.py,sha256=qeg4mxlgEW7LCNklKOJvmJ18gXznfZj1LUqma-N9Y3o,13025
|
|
57
56
|
hardpy/pytest_hardpy/db/stand_type.py,sha256=p3AFtgMt-sn8QXRp60YM-xo2mEjZHUhYr_Mxhz1WyP0,7438
|
|
58
|
-
hardpy/pytest_hardpy/db/statestore.py,sha256=
|
|
59
|
-
hardpy/pytest_hardpy/db/tempstore.py,sha256=
|
|
57
|
+
hardpy/pytest_hardpy/db/statestore.py,sha256=xTWDZ2uKtVAJzGjHuyltZhesc3mVdU6PraJNUPiIpM8,13444
|
|
58
|
+
hardpy/pytest_hardpy/db/tempstore.py,sha256=QpN5VfX-dtfL6ZcTnHKt73DU-xaDK7YunuN5qRFqeCk,8084
|
|
60
59
|
hardpy/pytest_hardpy/db/schema/__init__.py,sha256=1S73W3PLQt8gX5Y33nbX1JdwLvnrtlKH4cElID3pwuc,263
|
|
61
60
|
hardpy/pytest_hardpy/db/schema/v1.py,sha256=0RGZP-2lDeA3r8-simEEnjlHOAyziYSMXb9BINQyVbM,6377
|
|
62
61
|
hardpy/pytest_hardpy/reporter/__init__.py,sha256=rztpM2HlLUpMOvad0JHbZU4Mk8PDDQyCFXLhpLktGQI,322
|
|
63
62
|
hardpy/pytest_hardpy/reporter/base.py,sha256=hUt0UTzZOa9KdHj66cOnqgDVakYh4GncE1YkCFqwCBs,3666
|
|
64
63
|
hardpy/pytest_hardpy/reporter/hook_reporter.py,sha256=Et312HLWQ-WUSjRSNa4Yg392HbRRbCNfzRQWvcCC11c,16199
|
|
65
64
|
hardpy/pytest_hardpy/reporter/runner_reporter.py,sha256=d9hyThq0tywelPnIIHVED2SyztavE5LbgcBSejXfnhA,787
|
|
66
|
-
hardpy/pytest_hardpy/result/__init__.py,sha256=
|
|
65
|
+
hardpy/pytest_hardpy/result/__init__.py,sha256=po1zsaNOqS-DaQO_6Xo2mW3fGdSopeZ646BdcU56SR4,687
|
|
67
66
|
hardpy/pytest_hardpy/result/couchdb_config.py,sha256=ujxyJYM2pdZzi3GZ2Zysbz2_ZeTRN5sQc8AGuzRJm_0,3243
|
|
68
67
|
hardpy/pytest_hardpy/result/report_loader/__init__.py,sha256=wq5Y-_JW2ExCRnQ9VVesKmTToEQrcTY5RxNJIWaT9ag,374
|
|
69
68
|
hardpy/pytest_hardpy/result/report_loader/couchdb_loader.py,sha256=KcZ0JkCgWhrj2J9M04JBDy0fpqtpVEYtu9GCLDG27pU,2255
|
|
69
|
+
hardpy/pytest_hardpy/result/report_loader/json_loader.py,sha256=7jiDiKnCnADC6JDxctKucXJSg33yraiJoeOem7KAHeo,1647
|
|
70
70
|
hardpy/pytest_hardpy/result/report_loader/stand_cloud_loader.py,sha256=CjvkS6N1OzKmMAqfs6bhQLK2mlB_NIKX-YnJn39SHqY,3991
|
|
71
71
|
hardpy/pytest_hardpy/result/report_reader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
72
72
|
hardpy/pytest_hardpy/result/report_reader/couchdb_reader.py,sha256=lnWSX-0QKbdMwtqfCtW0tiH9W_ZEPqQ3rb7Lc8gES7E,5726
|
|
73
73
|
hardpy/pytest_hardpy/result/report_reader/stand_cloud_reader.py,sha256=uT7YSBu1QyURH9IkgRCdpbinn8LKXUhgVEhwPmGZV7I,3636
|
|
74
74
|
hardpy/pytest_hardpy/result/report_synchronizer/__init__.py,sha256=QezaT_Yk8LrciygdsFPJeZn0EBUaKpd0GfCQjSuIo-I,273
|
|
75
|
-
hardpy/pytest_hardpy/result/report_synchronizer/synchronizer.py,sha256=
|
|
75
|
+
hardpy/pytest_hardpy/result/report_synchronizer/synchronizer.py,sha256=r26sfyf__HiYlC385D4Vc3gYNl46jlAc86CaasLzckg,5379
|
|
76
76
|
hardpy/pytest_hardpy/utils/__init__.py,sha256=zHln8ySBHesYAwYatLYkHol5TuuTTNOqrsMP7ONFEG0,1338
|
|
77
77
|
hardpy/pytest_hardpy/utils/const.py,sha256=xS3jBrW_D6IUTlAjSnLiHvSthieRHCj3uN_6fFAXS0w,1832
|
|
78
78
|
hardpy/pytest_hardpy/utils/dialog_box.py,sha256=eCLGQ-Z8rDPd_8ABHRtbkd7piSZcJoG-bCBmnyq29Pw,11375
|
|
@@ -80,8 +80,8 @@ hardpy/pytest_hardpy/utils/exception.py,sha256=1l2VBZLUnjPDoOs744MtaP7Y9FuXUq7ko
|
|
|
80
80
|
hardpy/pytest_hardpy/utils/machineid.py,sha256=6JAzUt7KtjTYn8kL9hSMaCQ20U8liH-zDT9v-5Ch7Q8,296
|
|
81
81
|
hardpy/pytest_hardpy/utils/node_info.py,sha256=DaW566WvsyWR66CThuZ38UoHwQa-pu-4WRLg61OXDnE,7134
|
|
82
82
|
hardpy/pytest_hardpy/utils/progress_calculator.py,sha256=TPl2gG0ZSvMe8otPythhF9hkD6fa6-mJAhy9yI83-yE,1071
|
|
83
|
-
hardpy-0.
|
|
84
|
-
hardpy-0.
|
|
85
|
-
hardpy-0.
|
|
86
|
-
hardpy-0.
|
|
87
|
-
hardpy-0.
|
|
83
|
+
hardpy-0.20.0.dist-info/METADATA,sha256=WdcxNOzCqsrSOLwKnjku-DtWSQN_qJ-CeXb-aF08X1Q,5416
|
|
84
|
+
hardpy-0.20.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
85
|
+
hardpy-0.20.0.dist-info/entry_points.txt,sha256=nL2sMkKMScNaOE0IPkYnu9Yr-BUswZvGSrwY-SxHY3E,102
|
|
86
|
+
hardpy-0.20.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
87
|
+
hardpy-0.20.0.dist-info/RECORD,,
|
|
@@ -1,179 +0,0 @@
|
|
|
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 json import dumps
|
|
5
|
-
from logging import getLogger
|
|
6
|
-
from typing import Any
|
|
7
|
-
|
|
8
|
-
from glom import assign, glom
|
|
9
|
-
from pycouchdb import Server as DbServer
|
|
10
|
-
from pycouchdb.client import Database
|
|
11
|
-
from pycouchdb.exceptions import Conflict, GenericError, NotFound
|
|
12
|
-
from pydantic._internal._model_construction import ModelMetaclass
|
|
13
|
-
from requests.exceptions import ConnectionError # noqa: A004
|
|
14
|
-
|
|
15
|
-
from hardpy.common.config import ConfigManager
|
|
16
|
-
from hardpy.pytest_hardpy.db.const import DatabaseField as DF # noqa: N817
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class BaseStore:
|
|
20
|
-
"""HardPy base storage interface for CouchDB."""
|
|
21
|
-
|
|
22
|
-
def __init__(self, db_name: str) -> None:
|
|
23
|
-
config_manager = ConfigManager()
|
|
24
|
-
config = config_manager.config
|
|
25
|
-
self._db_srv = DbServer(config.database.url)
|
|
26
|
-
self._db_name = db_name
|
|
27
|
-
self._db = self._init_db()
|
|
28
|
-
self._doc_id = config.database.doc_id
|
|
29
|
-
self._log = getLogger(__name__)
|
|
30
|
-
self._doc: dict = self._init_doc()
|
|
31
|
-
self._schema: ModelMetaclass
|
|
32
|
-
|
|
33
|
-
def compact(self) -> None:
|
|
34
|
-
"""Compact database."""
|
|
35
|
-
self._db.compact()
|
|
36
|
-
|
|
37
|
-
def get_field(self, key: str) -> Any: # noqa: ANN401
|
|
38
|
-
"""Get field from the state store.
|
|
39
|
-
|
|
40
|
-
Args:
|
|
41
|
-
key (str): field name
|
|
42
|
-
|
|
43
|
-
Returns:
|
|
44
|
-
Any: field value
|
|
45
|
-
"""
|
|
46
|
-
return glom(self._doc, key)
|
|
47
|
-
|
|
48
|
-
def update_doc_value(self, key: str, value: Any) -> None: # noqa: ANN401
|
|
49
|
-
"""Update document value.
|
|
50
|
-
|
|
51
|
-
HardPy collecting uses a simple key without dots.
|
|
52
|
-
Assign is used to update a document.
|
|
53
|
-
Assign is a longer function.
|
|
54
|
-
|
|
55
|
-
Args:
|
|
56
|
-
key (str): document key
|
|
57
|
-
value: document value
|
|
58
|
-
"""
|
|
59
|
-
try:
|
|
60
|
-
dumps(value)
|
|
61
|
-
except Exception: # noqa: BLE001
|
|
62
|
-
# serialize non-serializable objects as string
|
|
63
|
-
value = dumps(value, default=str)
|
|
64
|
-
if "." in key:
|
|
65
|
-
assign(self._doc, key, value)
|
|
66
|
-
else:
|
|
67
|
-
self._doc[key] = value
|
|
68
|
-
|
|
69
|
-
def update_db(self) -> None:
|
|
70
|
-
"""Update database by current document."""
|
|
71
|
-
try:
|
|
72
|
-
self._doc = self._db.save(self._doc)
|
|
73
|
-
except Conflict:
|
|
74
|
-
self._doc["_rev"] = self._db.get(self._doc_id)["_rev"]
|
|
75
|
-
self._doc = self._db.save(self._doc)
|
|
76
|
-
|
|
77
|
-
def update_doc(self) -> None:
|
|
78
|
-
"""Update current document by database."""
|
|
79
|
-
self._doc["_rev"] = self._db.get(self._doc_id)["_rev"]
|
|
80
|
-
self._doc = self._db.get(self._doc_id)
|
|
81
|
-
|
|
82
|
-
def get_document(self) -> ModelMetaclass:
|
|
83
|
-
"""Get document by schema.
|
|
84
|
-
|
|
85
|
-
Returns:
|
|
86
|
-
ModelMetaclass: document by schema
|
|
87
|
-
"""
|
|
88
|
-
self._doc = self._db.get(self._doc_id)
|
|
89
|
-
return self._schema(**self._doc)
|
|
90
|
-
|
|
91
|
-
def clear(self) -> None:
|
|
92
|
-
"""Clear database."""
|
|
93
|
-
try:
|
|
94
|
-
# Clear statestore and runstore databases before each launch
|
|
95
|
-
self._db.delete(self._doc_id)
|
|
96
|
-
except (Conflict, NotFound):
|
|
97
|
-
self._log.debug("Database will be created for the first time")
|
|
98
|
-
self._doc: dict = self._init_doc()
|
|
99
|
-
|
|
100
|
-
def _init_db(self) -> Database:
|
|
101
|
-
try:
|
|
102
|
-
return self._db_srv.create(self._db_name) # type: ignore
|
|
103
|
-
except Conflict:
|
|
104
|
-
# database is already created
|
|
105
|
-
return self._db_srv.database(self._db_name)
|
|
106
|
-
except GenericError as exc:
|
|
107
|
-
msg = f"Error initializing database {exc}"
|
|
108
|
-
raise RuntimeError(msg) from exc
|
|
109
|
-
except ConnectionError as exc:
|
|
110
|
-
msg = f"Error initializing database: {exc}"
|
|
111
|
-
raise RuntimeError(msg) from exc
|
|
112
|
-
|
|
113
|
-
def _init_doc(self) -> dict:
|
|
114
|
-
try:
|
|
115
|
-
doc = self._db.get(self._doc_id)
|
|
116
|
-
except NotFound:
|
|
117
|
-
return {
|
|
118
|
-
"_id": self._doc_id,
|
|
119
|
-
DF.MODULES: {},
|
|
120
|
-
DF.DUT: {
|
|
121
|
-
DF.TYPE: None,
|
|
122
|
-
DF.NAME: None,
|
|
123
|
-
DF.REVISION: None,
|
|
124
|
-
DF.SERIAL_NUMBER: None,
|
|
125
|
-
DF.PART_NUMBER: None,
|
|
126
|
-
DF.SUB_UNITS: [],
|
|
127
|
-
DF.INFO: {},
|
|
128
|
-
},
|
|
129
|
-
DF.TEST_STAND: {
|
|
130
|
-
DF.HW_ID: None,
|
|
131
|
-
DF.NAME: None,
|
|
132
|
-
DF.REVISION: None,
|
|
133
|
-
DF.TIMEZONE: None,
|
|
134
|
-
DF.LOCATION: None,
|
|
135
|
-
DF.NUMBER: None,
|
|
136
|
-
DF.INSTRUMENTS: [],
|
|
137
|
-
DF.DRIVERS: {},
|
|
138
|
-
DF.INFO: {},
|
|
139
|
-
},
|
|
140
|
-
DF.PROCESS: {
|
|
141
|
-
DF.NAME: None,
|
|
142
|
-
DF.NUMBER: None,
|
|
143
|
-
DF.INFO: {},
|
|
144
|
-
},
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
# init document
|
|
148
|
-
if DF.MODULES not in doc:
|
|
149
|
-
doc[DF.MODULES] = {}
|
|
150
|
-
|
|
151
|
-
doc[DF.DUT] = {
|
|
152
|
-
DF.TYPE: None,
|
|
153
|
-
DF.NAME: None,
|
|
154
|
-
DF.REVISION: None,
|
|
155
|
-
DF.SERIAL_NUMBER: None,
|
|
156
|
-
DF.PART_NUMBER: None,
|
|
157
|
-
DF.SUB_UNITS: [],
|
|
158
|
-
DF.INFO: {},
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
doc[DF.TEST_STAND] = {
|
|
162
|
-
DF.HW_ID: None,
|
|
163
|
-
DF.NAME: None,
|
|
164
|
-
DF.REVISION: None,
|
|
165
|
-
DF.TIMEZONE: None,
|
|
166
|
-
DF.LOCATION: None,
|
|
167
|
-
DF.NUMBER: None,
|
|
168
|
-
DF.INSTRUMENTS: [],
|
|
169
|
-
DF.DRIVERS: {},
|
|
170
|
-
DF.INFO: {},
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
doc[DF.PROCESS] = {
|
|
174
|
-
DF.NAME: None,
|
|
175
|
-
DF.NUMBER: None,
|
|
176
|
-
DF.INFO: {},
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return doc
|
|
File without changes
|
|
File without changes
|
|
File without changes
|