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.
Files changed (24) hide show
  1. hardpy/__init__.py +2 -0
  2. hardpy/cli/cli.py +6 -0
  3. hardpy/common/config.py +19 -0
  4. hardpy/hardpy_panel/api.py +62 -1
  5. hardpy/hardpy_panel/frontend/dist/assets/{allPaths-C_-7WXHD.js → allPaths-BXbcAtew.js} +1 -1
  6. hardpy/hardpy_panel/frontend/dist/assets/{allPathsLoader-DgH0Xily.js → allPathsLoader-lJLHMNNZ.js} +2 -2
  7. hardpy/hardpy_panel/frontend/dist/assets/{browser-ponyfill-BbOvdqIF.js → browser-ponyfill-DzwgrUwX.js} +1 -1
  8. hardpy/hardpy_panel/frontend/dist/assets/{index-DEJb2W0B.js → index-CVhA7vmQ.js} +158 -158
  9. hardpy/hardpy_panel/frontend/dist/assets/{splitPathsBySizeLoader-o5HCcdVL.js → splitPathsBySizeLoader-BdwEQHyO.js} +1 -1
  10. hardpy/hardpy_panel/frontend/dist/index.html +1 -1
  11. hardpy/pytest_hardpy/db/__init__.py +0 -2
  12. hardpy/pytest_hardpy/db/runstore.py +378 -10
  13. hardpy/pytest_hardpy/db/statestore.py +390 -5
  14. hardpy/pytest_hardpy/db/tempstore.py +219 -17
  15. hardpy/pytest_hardpy/plugin.py +2 -2
  16. hardpy/pytest_hardpy/result/__init__.py +2 -0
  17. hardpy/pytest_hardpy/result/report_loader/json_loader.py +49 -0
  18. hardpy/pytest_hardpy/result/report_synchronizer/synchronizer.py +25 -9
  19. {hardpy-0.19.1.dist-info → hardpy-0.20.0.dist-info}/METADATA +18 -3
  20. {hardpy-0.19.1.dist-info → hardpy-0.20.0.dist-info}/RECORD +23 -23
  21. hardpy/pytest_hardpy/db/base_store.py +0 -179
  22. {hardpy-0.19.1.dist-info → hardpy-0.20.0.dist-info}/WHEEL +0 -0
  23. {hardpy-0.19.1.dist-info → hardpy-0.20.0.dist-info}/entry_points.txt +0 -0
  24. {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 = 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
- if not self._tempstore.reports():
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._tempstore.reports():
50
+ for _report in self._get_tempstore.reports():
39
51
  try:
40
- report_id = _report.get("id")
41
- document: dict = _report.get("doc")
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._tempstore.dict_to_schema(document)
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._tempstore.delete(report_id):
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._tempstore.push_report(report)
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.19.1
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
  [![pytest versions](https://img.shields.io/badge/pytest-%3E%3D7.0-blue)](https://docs.pytest.org/en/latest/)
70
71
  [![Documentation](https://img.shields.io/badge/Documentation%20-Overview%20-%20%23007ec6)](https://everypinio.github.io/hardpy/)
71
72
  [![Reddit](https://img.shields.io/badge/-Reddit-FF4500?style=flat&logo=reddit&logoColor=white)](https://www.reddit.com/r/HardPy)
72
- [![Discord](https://img.shields.io/discord/1304494076799877172?color=7389D8&label&logo=discord&logoColor=ffffff)]()
73
+ [![Discord](https://img.shields.io/discord/1304494076799877172?color=7389D8&label&logo=discord&logoColor=ffffff)](https://discord.gg/98bWadmG8J)
73
74
  [![Telegram](https://img.shields.io/badge/-Telegram-2CA5E0?style=flat&logo=telegram&logoColor=white)](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=B99MElYhd8HHgOJaT-RVPyvIN18uPaG2pb78TJ3lqvE,2957
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=eg89XAcPSosykXyeWitcTigE-ZYiDeCknPWp9TpXxeA,11359
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=cgs4rGgRbKsDasM1NupmdERK2XaHZin3lLn346WRnKk,7730
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=F4wSHiE5kiFvthR_TdrcmXSbfq-gP00uZKC0Pnoyq-4,10744
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=Hhb9wXuzSNSaG5KgX_63fvg0XEzwkp80jc-g-uobwqQ,1851
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-C_-7WXHD.js,sha256=g19yyAeijLh7WccMXT8_tuk1S-uWTOyPFzWHpyUZLQc,309
23
- hardpy/hardpy_panel/frontend/dist/assets/allPathsLoader-DgH0Xily.js,sha256=CRNnNN2zycYIwYtzHnBbPj5EbtZSGVhLGfvbOswm4SM,550
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-BbOvdqIF.js,sha256=ga4pi7C6UzfwyVTi8QiAL0rpgvlXPi37PXqlLP8A-Ug,10294
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-DEJb2W0B.js,sha256=TVKRBm2PplF8vsQM_bEiA7VNhUKZHMDpD5Il33haQ40,6026022
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-o5HCcdVL.js,sha256=ZvdGFd8j0qHvEPUqfpcCFtwRg2ptF-uPZCoJMUUK2Ac,472
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=m8vbDAA_cuxOlraJ2V_DvQ81E_06zJaTLF771nLLQMI,24591
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=nat_tUO2cxPIp9e6U8Fvg6V4NcZ9TVg27u0GHoKelD4,865
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=humoVBDZJGh7j_v5Xrf3P0HHaeRXC8oRdIj1QWGZizg,946
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=1s615c4OdzHd5u-464O-lcXoKulMfZ6moblhTWDHwSg,583
59
- hardpy/pytest_hardpy/db/tempstore.py,sha256=WKIykL_4A9j8n-F7pIy_9fj4BNOfzqWkUwg0_8DR05s,1802
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=2afpuEuOcxYfIEOwWzsGZe960iQaPVCmsbYujijQg1s,592
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=b1DDDFgEJzsxYRvkzNqeuDvvuWFUIYat1UK0Ct_9N5Y,4745
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.19.1.dist-info/METADATA,sha256=nuj7JBfKBLgOYLW8ENRaflRnbGPZ0NesNnjjdKqGL7Y,5087
84
- hardpy-0.19.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
85
- hardpy-0.19.1.dist-info/entry_points.txt,sha256=nL2sMkKMScNaOE0IPkYnu9Yr-BUswZvGSrwY-SxHY3E,102
86
- hardpy-0.19.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
87
- hardpy-0.19.1.dist-info/RECORD,,
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