hardpy 0.6.1__py3-none-any.whl → 0.8.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 (47) hide show
  1. hardpy/__init__.py +49 -49
  2. hardpy/cli/cli.py +8 -9
  3. hardpy/cli/template.py +6 -6
  4. hardpy/common/config.py +19 -18
  5. hardpy/hardpy_panel/api.py +9 -9
  6. hardpy/hardpy_panel/frontend/dist/asset-manifest.json +3 -3
  7. hardpy/hardpy_panel/frontend/dist/index.html +1 -1
  8. hardpy/hardpy_panel/frontend/dist/logo192.png +0 -0
  9. hardpy/hardpy_panel/frontend/dist/static/css/main.e8a862f1.css.map +1 -1
  10. hardpy/hardpy_panel/frontend/dist/static/js/main.6f09d61a.js +3 -0
  11. hardpy/hardpy_panel/frontend/dist/static/js/{main.7c954faf.js.map → main.6f09d61a.js.map} +1 -1
  12. hardpy/pytest_hardpy/db/__init__.py +4 -5
  13. hardpy/pytest_hardpy/db/base_connector.py +6 -5
  14. hardpy/pytest_hardpy/db/base_server.py +1 -1
  15. hardpy/pytest_hardpy/db/base_store.py +23 -9
  16. hardpy/pytest_hardpy/db/const.py +3 -1
  17. hardpy/pytest_hardpy/db/runstore.py +13 -15
  18. hardpy/pytest_hardpy/db/schema/__init__.py +9 -0
  19. hardpy/pytest_hardpy/db/{schema.py → schema/v1.py} +120 -79
  20. hardpy/pytest_hardpy/db/statestore.py +7 -20
  21. hardpy/pytest_hardpy/plugin.py +128 -85
  22. hardpy/pytest_hardpy/pytest_call.py +80 -32
  23. hardpy/pytest_hardpy/pytest_wrapper.py +8 -8
  24. hardpy/pytest_hardpy/reporter/__init__.py +2 -2
  25. hardpy/pytest_hardpy/reporter/base.py +32 -7
  26. hardpy/pytest_hardpy/reporter/hook_reporter.py +66 -37
  27. hardpy/pytest_hardpy/reporter/runner_reporter.py +6 -8
  28. hardpy/pytest_hardpy/result/__init__.py +2 -2
  29. hardpy/pytest_hardpy/result/couchdb_config.py +20 -16
  30. hardpy/pytest_hardpy/result/report_loader/couchdb_loader.py +2 -2
  31. hardpy/pytest_hardpy/result/report_reader/couchdb_reader.py +36 -20
  32. hardpy/pytest_hardpy/utils/__init__.py +34 -29
  33. hardpy/pytest_hardpy/utils/connection_data.py +6 -8
  34. hardpy/pytest_hardpy/utils/const.py +1 -1
  35. hardpy/pytest_hardpy/utils/dialog_box.py +105 -66
  36. hardpy/pytest_hardpy/utils/exception.py +14 -8
  37. hardpy/pytest_hardpy/utils/machineid.py +15 -0
  38. hardpy/pytest_hardpy/utils/node_info.py +45 -16
  39. hardpy/pytest_hardpy/utils/progress_calculator.py +4 -3
  40. hardpy/pytest_hardpy/utils/singleton.py +23 -16
  41. {hardpy-0.6.1.dist-info → hardpy-0.8.0.dist-info}/METADATA +26 -33
  42. {hardpy-0.6.1.dist-info → hardpy-0.8.0.dist-info}/RECORD +46 -43
  43. hardpy/hardpy_panel/frontend/dist/static/js/main.7c954faf.js +0 -3
  44. /hardpy/hardpy_panel/frontend/dist/static/js/{main.7c954faf.js.LICENSE.txt → main.6f09d61a.js.LICENSE.txt} +0 -0
  45. {hardpy-0.6.1.dist-info → hardpy-0.8.0.dist-info}/WHEEL +0 -0
  46. {hardpy-0.6.1.dist-info → hardpy-0.8.0.dist-info}/entry_points.txt +0 -0
  47. {hardpy-0.6.1.dist-info → hardpy-0.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,18 +1,17 @@
1
1
  # Copyright (c) 2024 Everypin
2
2
  # GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
3
3
 
4
- from hardpy.pytest_hardpy.db.schema import ResultRunStore, ResultStateStore
5
- from hardpy.pytest_hardpy.db.statestore import StateStore
6
- from hardpy.pytest_hardpy.db.runstore import RunStore
7
4
  from hardpy.pytest_hardpy.db.base_store import BaseStore
8
5
  from hardpy.pytest_hardpy.db.const import DatabaseField
9
-
6
+ from hardpy.pytest_hardpy.db.runstore import RunStore
7
+ from hardpy.pytest_hardpy.db.schema import ResultRunStore, ResultStateStore
8
+ from hardpy.pytest_hardpy.db.statestore import StateStore
10
9
 
11
10
  __all__ = [
12
11
  "BaseStore",
13
12
  "DatabaseField",
14
13
  "ResultRunStore",
15
14
  "ResultStateStore",
16
- "StateStore",
17
15
  "RunStore",
16
+ "StateStore",
18
17
  ]
@@ -1,10 +1,9 @@
1
1
  # Copyright (c) 2024 Everypin
2
2
  # GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
3
3
 
4
- from requests.exceptions import ConnectionError
5
-
6
4
  from pycouchdb.client import Database
7
5
  from pycouchdb.exceptions import Conflict, GenericError
6
+ from requests.exceptions import ConnectionError # noqa: A004
8
7
 
9
8
  from hardpy.pytest_hardpy.db.base_server import BaseServer
10
9
 
@@ -12,7 +11,7 @@ from hardpy.pytest_hardpy.db.base_server import BaseServer
12
11
  class BaseConnector(BaseServer):
13
12
  """Base class for CouchDB connector."""
14
13
 
15
- def __init__(self, db_name: str):
14
+ def __init__(self, db_name: str) -> None:
16
15
  super().__init__()
17
16
  self._db_name = db_name
18
17
  self._db = self._init_db()
@@ -25,6 +24,8 @@ class BaseConnector(BaseServer):
25
24
  # database is already created
26
25
  return self._db_srv.database(self._db_name)
27
26
  except GenericError as exc:
28
- raise RuntimeError(f"Error initializing database {exc}") from exc
27
+ msg = f"Error initializing database {exc}"
28
+ raise RuntimeError(msg) from exc
29
29
  except ConnectionError as exc:
30
- raise RuntimeError(f"Error initializing database: {exc}") from exc
30
+ msg = f"Error initializing database: {exc}"
31
+ raise RuntimeError(msg) from exc
@@ -9,6 +9,6 @@ from hardpy.pytest_hardpy.utils import ConnectionData
9
9
  class BaseServer:
10
10
  """Base class for CouchDB server."""
11
11
 
12
- def __init__(self):
12
+ def __init__(self) -> None:
13
13
  con_data = ConnectionData()
14
14
  self._db_srv = DbServer(con_data.database_url)
@@ -9,23 +9,23 @@ from pycouchdb.exceptions import Conflict, NotFound
9
9
  from pydantic._internal._model_construction import ModelMetaclass
10
10
 
11
11
  from hardpy.pytest_hardpy.db.base_connector import BaseConnector
12
- from hardpy.pytest_hardpy.db.const import DatabaseField as DF
12
+ from hardpy.pytest_hardpy.db.const import DatabaseField as DF # noqa: N817
13
13
 
14
14
 
15
15
  class BaseStore(BaseConnector):
16
16
  """HardPy base storage interface for CouchDB."""
17
17
 
18
- def __init__(self, db_name: str):
18
+ def __init__(self, db_name: str) -> None:
19
19
  super().__init__(db_name)
20
20
  self._log = getLogger(__name__)
21
21
  self._doc: dict = self._init_doc()
22
22
  self._schema: ModelMetaclass
23
23
 
24
- def compact(self):
24
+ def compact(self) -> None:
25
25
  """Compact database."""
26
26
  self._db.compact()
27
27
 
28
- def get_field(self, key: str) -> Any:
28
+ def get_field(self, key: str) -> Any: # noqa: ANN401
29
29
  """Get field from the state store.
30
30
 
31
31
  Args:
@@ -36,7 +36,7 @@ class BaseStore(BaseConnector):
36
36
  """
37
37
  return glom(self._doc, key)
38
38
 
39
- def update_doc(self, key: str, value):
39
+ def update_doc(self, key: str, value: Any) -> None: # noqa: ANN401
40
40
  """Update document.
41
41
 
42
42
  HardPy collecting uses a simple key without dots.
@@ -52,7 +52,7 @@ class BaseStore(BaseConnector):
52
52
  else:
53
53
  self._doc[key] = value
54
54
 
55
- def update_db(self):
55
+ def update_db(self) -> None:
56
56
  """Update database by current document."""
57
57
  try:
58
58
  self._doc = self._db.save(self._doc)
@@ -69,6 +69,15 @@ class BaseStore(BaseConnector):
69
69
  self._doc = self._db.get(self._doc_id)
70
70
  return self._schema(**self._doc)
71
71
 
72
+ def clear(self) -> None:
73
+ """Clear database."""
74
+ try:
75
+ # Clear statestore and runstore databases before each launch
76
+ self._db.delete(self._doc_id)
77
+ except (Conflict, NotFound):
78
+ self._log.debug("Database will be created for the first time")
79
+ self._doc: dict = self._init_doc()
80
+
72
81
  def _init_doc(self) -> dict:
73
82
  try:
74
83
  doc = self._db.get(self._doc_id)
@@ -82,18 +91,19 @@ class BaseStore(BaseConnector):
82
91
  DF.INFO: {},
83
92
  },
84
93
  DF.TEST_STAND: {
94
+ DF.HW_ID: None,
85
95
  DF.NAME: None,
96
+ DF.TIMEZONE: None,
97
+ DF.LOCATION: None,
98
+ DF.DRIVERS: {},
86
99
  DF.INFO: {},
87
100
  },
88
- DF.DRIVERS: {},
89
101
  }
90
102
 
91
103
  # init document
92
104
  if DF.MODULES not in doc:
93
105
  doc[DF.MODULES] = {}
94
106
 
95
- doc[DF.DRIVERS] = {}
96
-
97
107
  doc[DF.DUT] = {
98
108
  DF.SERIAL_NUMBER: None,
99
109
  DF.PART_NUMBER: None,
@@ -101,7 +111,11 @@ class BaseStore(BaseConnector):
101
111
  }
102
112
 
103
113
  doc[DF.TEST_STAND] = {
114
+ DF.HW_ID: None,
104
115
  DF.NAME: None,
116
+ DF.TIMEZONE: None,
117
+ DF.LOCATION: None,
118
+ DF.DRIVERS: {},
105
119
  DF.INFO: {},
106
120
  }
107
121
 
@@ -4,7 +4,7 @@
4
4
  from enum import Enum
5
5
 
6
6
 
7
- class DatabaseField(str, Enum): # noqa: WPS600
7
+ class DatabaseField(str, Enum):
8
8
  """Database field."""
9
9
 
10
10
  NAME = "name"
@@ -27,3 +27,5 @@ class DatabaseField(str, Enum): # noqa: WPS600
27
27
  DIALOG_BOX = "dialog_box"
28
28
  OPERATOR_MSG = "operator_msg"
29
29
  ATTEMPT = "attempt"
30
+ LOCATION = "location"
31
+ HW_ID = "hw_id"
@@ -6,25 +6,23 @@ from logging import getLogger
6
6
  from pycouchdb.exceptions import Conflict, NotFound
7
7
 
8
8
  from hardpy.pytest_hardpy.db.base_store import BaseStore
9
- from hardpy.pytest_hardpy.db import ResultRunStore
10
- from hardpy.pytest_hardpy.utils import Singleton
9
+ from hardpy.pytest_hardpy.db.schema import ResultRunStore
10
+ from hardpy.pytest_hardpy.utils import SingletonMeta
11
11
 
12
12
 
13
- class RunStore(Singleton, BaseStore):
13
+ class RunStore(BaseStore, metaclass=SingletonMeta):
14
14
  """HardPy run storage interface for CouchDB.
15
15
 
16
16
  Save state and case artifact.
17
17
  """
18
18
 
19
- def __init__(self):
20
- if not self._initialized:
21
- super().__init__("runstore")
22
- self._log = getLogger(__name__)
23
- try:
24
- # Clear the runstore database before each launch
25
- self._db.delete(self._doc_id)
26
- except (Conflict, NotFound):
27
- self._log.debug("Runstore database will be created for the first time")
28
- self._doc: dict = self._init_doc()
29
- self._schema = ResultRunStore
30
- self._initialized = True
19
+ def __init__(self) -> None:
20
+ super().__init__("runstore")
21
+ self._log = getLogger(__name__)
22
+ try:
23
+ # Clear the runstore database before each launch
24
+ self._db.delete(self._doc_id)
25
+ except (Conflict, NotFound):
26
+ self._log.debug("Runstore database will be created for the first time")
27
+ self._doc: dict = self._init_doc()
28
+ self._schema = ResultRunStore
@@ -0,0 +1,9 @@
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 hardpy.pytest_hardpy.db.schema.v1 import ResultRunStore, ResultStateStore
5
+
6
+ __all__ = [
7
+ "ResultRunStore",
8
+ "ResultStateStore",
9
+ ]
@@ -1,9 +1,12 @@
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
+ from __future__ import annotations
3
4
 
4
- from pydantic import BaseModel, Field, ConfigDict
5
+ from typing import ClassVar
5
6
 
6
- from hardpy.pytest_hardpy.utils import TestStatus as Status
7
+ from pydantic import BaseModel, ConfigDict, Field
8
+
9
+ from hardpy.pytest_hardpy.utils import TestStatus as Status # noqa: TC001
7
10
 
8
11
 
9
12
  class IBaseResult(BaseModel):
@@ -21,7 +24,9 @@ class CaseStateStore(IBaseResult):
21
24
  """Test case description.
22
25
 
23
26
  Example:
24
- "test_one": {
27
+ ```
28
+ {
29
+ "test_one": {
25
30
  "status": "passed",
26
31
  "name": "Test 2",
27
32
  "start_time": 1695817188,
@@ -39,7 +44,9 @@ class CaseStateStore(IBaseResult):
39
44
  "type": "textinput"
40
45
  }
41
46
  }
47
+ }
42
48
  }
49
+ ```
43
50
  """
44
51
 
45
52
  assertion_msg: str | None = None
@@ -52,44 +59,50 @@ class CaseRunStore(IBaseResult):
52
59
  """Test case description with artifact.
53
60
 
54
61
  Example:
55
- "test_one": {
62
+ ```
63
+ {
64
+ "test_one": {
56
65
  "status": "passed",
57
66
  "name": "Test 2",
58
67
  "start_time": 1695817188,
59
68
  "stop_time": 1695817189,
60
69
  "assertion_msg": null,
61
70
  "msg": null,
62
- "attempt": 1,
63
71
  "artifact": {}
72
+ }
64
73
  }
74
+ ```
65
75
  """
66
76
 
67
77
  assertion_msg: str | None = None
68
78
  msg: dict | None = None
69
79
  artifact: dict = {}
70
- attempt: int = 0
71
80
 
72
81
 
73
82
  class ModuleStateStore(IBaseResult):
74
83
  """Test module description.
75
84
 
76
85
  Example:
77
- "test_2_b": {
78
- "status": "passed",
79
- "name": "Module 2",
80
- "start_time": 1695816886,
81
- "stop_time": 1695817016,
82
- "cases": {
83
- "test_one": {
84
- "status": "passed",
85
- "name": "Test 1",
86
- "start_time": 1695817015,
87
- "stop_time": 1695817016,
88
- "assertion_msg": null,
89
- "msg": null
86
+ ```
87
+ {
88
+ "test_2_b": {
89
+ "status": "passed",
90
+ "name": "Module 2",
91
+ "start_time": 1695816886,
92
+ "stop_time": 1695817016,
93
+ "cases": {
94
+ "test_one": {
95
+ "status": "passed",
96
+ "name": "Test 1",
97
+ "start_time": 1695817015,
98
+ "stop_time": 1695817016,
99
+ "assertion_msg": null,
100
+ "msg": null
101
+ }
90
102
  }
91
103
  }
92
104
  }
105
+ ```
93
106
  """
94
107
 
95
108
  cases: dict[str, CaseStateStore] = {}
@@ -99,24 +112,28 @@ class ModuleRunStore(IBaseResult):
99
112
  """Test module description.
100
113
 
101
114
  Example:
102
- "test_2_b": {
103
- "status": "passed",
104
- "name": "Module 2",
105
- "start_time": 1695816886,
106
- "stop_time": 1695817016,
107
- "artifact": {},
108
- "cases": {
109
- "test_one": {
110
- "status": "passed",
111
- "name": "Test 1",
112
- "start_time": 1695817015,
113
- "stop_time": 1695817016,
114
- "assertion_msg": null,
115
- "msg": null,
116
- "artifact": {}
115
+ ```
116
+ {
117
+ "test_2_b": {
118
+ "status": "passed",
119
+ "name": "Module 2",
120
+ "start_time": 1695816886,
121
+ "stop_time": 1695817016,
122
+ "artifact": {},
123
+ "cases": {
124
+ "test_one": {
125
+ "status": "passed",
126
+ "name": "Test 1",
127
+ "start_time": 1695817015,
128
+ "stop_time": 1695817016,
129
+ "assertion_msg": null,
130
+ "msg": null,
131
+ "artifact": {}
132
+ }
117
133
  }
118
134
  }
119
135
  }
136
+ ```
120
137
  """
121
138
 
122
139
  cases: dict[str, CaseRunStore] = {}
@@ -127,14 +144,18 @@ class Dut(BaseModel):
127
144
  """Device under test description.
128
145
 
129
146
  Example:
130
- "dut": {
147
+ ```
148
+ {
149
+ "dut": {
131
150
  "serial_number": "a9ad8dca-2c64-4df8-a358-c21e832a32e4",
132
151
  "part_number": "part_number_1",
133
152
  "info": {
134
153
  "batch": "test_batch",
135
154
  "board_rev": "rev_1"
136
155
  }
137
- },
156
+ }
157
+ }
158
+ ```
138
159
  """
139
160
 
140
161
  model_config = ConfigDict(extra="forbid")
@@ -148,33 +169,48 @@ class TestStand(BaseModel):
148
169
  """Test stand description.
149
170
 
150
171
  Example:
151
- "test_stand": {
172
+ ```
173
+ {
174
+ "test_stand": {
175
+ "hw_id": "840982098ca2459a7b22cc608eff65d4",
152
176
  "name": "test_stand_1",
153
177
  "info": {
154
- "geo": "Belgrade",
155
- }
156
- },
178
+ "geo": "Belgrade"
179
+ },
180
+ "timezone": "Europe/Belgrade",
181
+ "drivers": {
182
+ "driver_1": "driver info",
183
+ "driver_2": {
184
+ "state": "active",
185
+ "port": 8000
186
+ }
187
+ },
188
+ "location": "Belgrade_1"
189
+ }
190
+ }
191
+ ```
157
192
  """
158
193
 
159
194
  model_config = ConfigDict(extra="forbid")
160
195
 
161
- name: str | None
196
+ hw_id: str | None = None
197
+ name: str | None = None
198
+ timezone: str | None = None
199
+ drivers: dict = {}
162
200
  info: dict = {}
201
+ location: str | None = None
163
202
 
164
203
 
165
204
  class ResultStateStore(IBaseResult):
166
205
  """Test run description.
167
206
 
168
207
  Example:
208
+ ```
169
209
  {
170
210
  "_rev": "44867-3888ae85c19c428cc46685845953b483",
171
211
  "_id": "current",
172
212
  "progress": 100,
173
213
  "stop_time": 1695817266,
174
- "timezone": [
175
- "CET",
176
- "CET"
177
- ],
178
214
  "start_time": 1695817263,
179
215
  "status": "failed",
180
216
  "name": "hardpy-stand",
@@ -187,15 +223,20 @@ class ResultStateStore(IBaseResult):
187
223
  }
188
224
  },
189
225
  "test_stand": {
190
- "name": "Test stand 1"
191
- "info": {}
192
- },
193
- "drivers": {
194
- "driver_1": "driver info",
195
- "driver_2": {
196
- "state": "active",
197
- "port": 8000
198
- }
226
+ "hw_id": "840982098ca2459a7b22cc608eff65d4",
227
+ "name": "test_stand_1",
228
+ "info": {
229
+ "geo": "Belgrade"
230
+ },
231
+ "timezone": "Europe/Belgrade",
232
+ "drivers": {
233
+ "driver_1": "driver info",
234
+ "driver_2": {
235
+ "state": "active",
236
+ "port": 8000
237
+ }
238
+ },
239
+ "location": "Belgrade_1"
199
240
  },
200
241
  "operator_msg": {
201
242
  "msg": "Operator message",
@@ -238,11 +279,12 @@ class ResultStateStore(IBaseResult):
238
279
  "msg": [
239
280
  "Current minute 21"
240
281
  ]
241
- },
282
+ }
242
283
  }
243
- },
284
+ }
244
285
  }
245
286
  }
287
+ ```
246
288
  """
247
289
 
248
290
  model_config = ConfigDict(extra="forbid")
@@ -250,11 +292,9 @@ class ResultStateStore(IBaseResult):
250
292
  rev: str = Field(..., alias="_rev")
251
293
  id: str = Field(..., alias="_id")
252
294
  progress: int
253
- timezone: tuple[str, str] | None = None
254
295
  test_stand: TestStand
255
296
  dut: Dut
256
297
  modules: dict[str, ModuleStateStore] = {}
257
- drivers: dict = {}
258
298
  operator_msg: dict = {}
259
299
 
260
300
 
@@ -262,15 +302,11 @@ class ResultRunStore(IBaseResult):
262
302
  """Test run description.
263
303
 
264
304
  Example:
305
+ ```
265
306
  {
266
307
  "_rev": "44867-3888ae85c19c428cc46685845953b483",
267
308
  "_id": "current",
268
- "progress": 100,
269
309
  "stop_time": 1695817266,
270
- "timezone": [
271
- "CET",
272
- "CET"
273
- ],
274
310
  "start_time": 1695817263,
275
311
  "status": "failed",
276
312
  "name": "hardpy-stand",
@@ -283,15 +319,20 @@ class ResultRunStore(IBaseResult):
283
319
  }
284
320
  },
285
321
  "test_stand": {
286
- "name": "Test stand 1"
287
- "info": {}
288
- },
289
- "drivers": {
290
- "driver_1": "driver info",
291
- "driver_2": {
292
- "state": "active",
293
- "port": 8000
294
- }
322
+ "hw_id": "840982098ca2459a7b22cc608eff65d4",
323
+ "name": "test_stand_1",
324
+ "info": {
325
+ "geo": "Belgrade"
326
+ },
327
+ "timezone": "Europe/Belgrade",
328
+ "drivers": {
329
+ "driver_1": "driver info",
330
+ "driver_2": {
331
+ "state": "active",
332
+ "port": 8000
333
+ }
334
+ },
335
+ "location": "Belgrade_1"
295
336
  },
296
337
  "artifact": {},
297
338
  "modules": {
@@ -309,7 +350,6 @@ class ResultRunStore(IBaseResult):
309
350
  "stop_time": 1695817264,
310
351
  "assertion_msg": null,
311
352
  "msg": null,
312
- "attempt": 1,
313
353
  "artifact": {}
314
354
  },
315
355
  "test_minute_parity": {
@@ -321,7 +361,6 @@ class ResultRunStore(IBaseResult):
321
361
  "msg": [
322
362
  "Current minute 21"
323
363
  ],
324
- "attempt": 1,
325
364
  "artifact": {
326
365
  "data_str": "123DATA",
327
366
  "data_int": 12345,
@@ -329,21 +368,23 @@ class ResultRunStore(IBaseResult):
329
368
  "test_key": "456DATA"
330
369
  }
331
370
  }
332
- },
371
+ }
333
372
  }
334
- },
373
+ }
335
374
  }
336
375
  }
376
+ ```
337
377
  """
338
378
 
339
379
  model_config = ConfigDict(extra="forbid")
380
+ # Create the new schema class with version update
381
+ # when you change this class or fields in this class.
382
+ __version__: ClassVar[int] = 1
340
383
 
341
384
  rev: str = Field(..., alias="_rev")
342
385
  id: str = Field(..., alias="_id")
343
- progress: int
344
- timezone: tuple[str, str] | None = None
386
+
345
387
  test_stand: TestStand
346
388
  dut: Dut
347
389
  modules: dict[str, ModuleRunStore] = {}
348
- drivers: dict = {}
349
390
  artifact: dict = {}
@@ -3,28 +3,15 @@
3
3
 
4
4
  from logging import getLogger
5
5
 
6
- from pycouchdb.exceptions import Conflict, NotFound
7
-
8
6
  from hardpy.pytest_hardpy.db.base_store import BaseStore
9
- from hardpy.pytest_hardpy.db import ResultStateStore
10
- from hardpy.pytest_hardpy.utils import Singleton
7
+ from hardpy.pytest_hardpy.db.schema import ResultStateStore
8
+ from hardpy.pytest_hardpy.utils import SingletonMeta
11
9
 
12
10
 
13
- class StateStore(Singleton, BaseStore):
11
+ class StateStore(BaseStore, metaclass=SingletonMeta):
14
12
  """HardPy state storage interface for CouchDB."""
15
13
 
16
- def __init__(self):
17
- if not self._initialized:
18
- super().__init__("statestore")
19
- self._log = getLogger(__name__)
20
- self._schema = ResultStateStore
21
- self._initialized = True
22
-
23
- def clear(self):
24
- """Clear database."""
25
- try:
26
- # Clear the statestore database before each launch
27
- self._db.delete(self._doc_id)
28
- except (Conflict, NotFound):
29
- self._log.debug("Statestore database will be created for the first time")
30
- self._doc: dict = self._init_doc()
14
+ def __init__(self) -> None:
15
+ super().__init__("statestore")
16
+ self._log = getLogger(__name__)
17
+ self._schema = ResultStateStore