hardpy 0.14.0__tar.gz → 0.15.1__tar.gz

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 (89) hide show
  1. {hardpy-0.14.0 → hardpy-0.15.1}/PKG-INFO +2 -1
  2. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/__init__.py +45 -10
  3. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/cli/cli.py +30 -28
  4. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/common/config.py +0 -4
  5. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/common/stand_cloud/connector.py +2 -2
  6. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/api.py +13 -3
  7. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/db/base_store.py +23 -0
  8. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/db/const.py +40 -19
  9. hardpy-0.15.1/hardpy/pytest_hardpy/db/schema/v1.py +238 -0
  10. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/plugin.py +32 -1
  11. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/pytest_call.py +329 -21
  12. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/pytest_wrapper.py +25 -34
  13. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/reporter/hook_reporter.py +53 -2
  14. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/result/report_reader/couchdb_reader.py +1 -5
  15. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/utils/__init__.py +25 -11
  16. hardpy-0.15.1/hardpy/pytest_hardpy/utils/const.py +91 -0
  17. hardpy-0.15.1/hardpy/pytest_hardpy/utils/exception.py +40 -0
  18. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/utils/node_info.py +55 -1
  19. hardpy-0.15.1/hardpy/pytest_hardpy/utils/stand_type.py +198 -0
  20. {hardpy-0.14.0 → hardpy-0.15.1}/pyproject.toml +6 -3
  21. hardpy-0.14.0/hardpy/pytest_hardpy/db/schema/v1.py +0 -425
  22. hardpy-0.14.0/hardpy/pytest_hardpy/utils/const.py +0 -19
  23. hardpy-0.14.0/hardpy/pytest_hardpy/utils/exception.py +0 -65
  24. {hardpy-0.14.0 → hardpy-0.15.1}/.gitignore +0 -0
  25. {hardpy-0.14.0 → hardpy-0.15.1}/LICENSE +0 -0
  26. {hardpy-0.14.0 → hardpy-0.15.1}/README.md +0 -0
  27. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/cli/__init__.py +0 -0
  28. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/cli/template.py +0 -0
  29. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/common/__init__.py +0 -0
  30. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/common/stand_cloud/__init__.py +0 -0
  31. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/common/stand_cloud/exception.py +0 -0
  32. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/common/stand_cloud/oauth2.py +0 -0
  33. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/common/stand_cloud/registration.py +0 -0
  34. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/common/stand_cloud/token_manager.py +0 -0
  35. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/common/stand_cloud/utils.py +0 -0
  36. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/__init__.py +0 -0
  37. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/allPaths-CV5wjLMB.js +0 -0
  38. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/allPathsLoader-JIzW_pSb.js +0 -0
  39. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-16-Bfs1BwbR.ttf +0 -0
  40. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-16-Btb8d-Hu.woff +0 -0
  41. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-16-CzsyEoPG.svg +0 -0
  42. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-16-DrH54W_x.woff2 +0 -0
  43. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-16-RCDSkC4W.eot +0 -0
  44. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-20-BGGGsqDJ.ttf +0 -0
  45. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-20-D9WO2FSG.woff2 +0 -0
  46. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-20-Doom1bSH.eot +0 -0
  47. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-20-DyVnGNfQ.svg +0 -0
  48. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-20-ZW-9JnPf.woff +0 -0
  49. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/browser-ponyfill-CccdstaD.js +0 -0
  50. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/index-6RIgWzcZ.js +0 -0
  51. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/index-BMEat_ws.js +0 -0
  52. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/index-BwCQzehg.css +0 -0
  53. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/index-xb4M2ucX.js +0 -0
  54. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/logo_smol-CK3jE85c.png +0 -0
  55. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/assets/splitPathsBySizeLoader-DkZadBcn.js +0 -0
  56. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/favicon.ico +0 -0
  57. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/index.html +0 -0
  58. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/locales/de/translation.json +0 -0
  59. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/locales/en/translation.json +0 -0
  60. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/locales/es/translation.json +0 -0
  61. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/locales/fr/translation.json +0 -0
  62. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/locales/ja/translation.json +0 -0
  63. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/locales/ru/translation.json +0 -0
  64. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/locales/zh/translation.json +0 -0
  65. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/logo192.png +0 -0
  66. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/logo512.png +0 -0
  67. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/hardpy_panel/frontend/dist/manifest.json +0 -0
  68. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/__init__.py +0 -0
  69. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/db/__init__.py +0 -0
  70. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/db/base_connector.py +0 -0
  71. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/db/base_server.py +0 -0
  72. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/db/runstore.py +0 -0
  73. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/db/schema/__init__.py +0 -0
  74. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/db/statestore.py +0 -0
  75. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/reporter/__init__.py +0 -0
  76. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/reporter/base.py +0 -0
  77. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/reporter/runner_reporter.py +0 -0
  78. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/result/__init__.py +0 -0
  79. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/result/couchdb_config.py +0 -0
  80. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/result/report_loader/__init__.py +0 -0
  81. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/result/report_loader/couchdb_loader.py +0 -0
  82. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/result/report_loader/stand_cloud_loader.py +0 -0
  83. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/result/report_reader/__init__.py +0 -0
  84. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/result/report_reader/stand_cloud_reader.py +0 -0
  85. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/utils/connection_data.py +0 -0
  86. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/utils/dialog_box.py +0 -0
  87. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/utils/machineid.py +0 -0
  88. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/utils/progress_calculator.py +0 -0
  89. {hardpy-0.14.0 → hardpy-0.15.1}/hardpy/pytest_hardpy/utils/singleton.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hardpy
3
- Version: 0.14.0
3
+ Version: 0.15.1
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/
@@ -51,6 +51,7 @@ Requires-Dist: ruff==0.8.0; extra == 'dev'
51
51
  Requires-Dist: wemake-python-styleguide>=0.19.2; extra == 'dev'
52
52
  Provides-Extra: tests
53
53
  Requires-Dist: psutil~=7.0.0; extra == 'tests'
54
+ Requires-Dist: pytest-timeout==2.4.0; extra == 'tests'
54
55
  Description-Content-Type: text/markdown
55
56
 
56
57
  <h1 align="center">
@@ -3,23 +3,37 @@
3
3
 
4
4
  from hardpy.common.stand_cloud import StandCloudConnector, StandCloudError
5
5
  from hardpy.pytest_hardpy.pytest_call import (
6
+ ErrorCode,
6
7
  clear_operator_message,
7
8
  get_current_attempt,
8
9
  get_current_report,
9
10
  run_dialog_box,
11
+ set_batch_serial_number,
10
12
  set_case_artifact,
13
+ set_case_chart,
14
+ set_case_measurement,
11
15
  set_driver_info,
12
16
  set_dut_info,
17
+ set_dut_name,
13
18
  set_dut_part_number,
19
+ set_dut_revision,
14
20
  set_dut_serial_number,
21
+ set_dut_sub_unit,
22
+ set_dut_type,
23
+ set_instrument,
15
24
  set_message,
16
25
  set_module_artifact,
17
26
  set_operator_message,
27
+ set_process_info,
28
+ set_process_name,
29
+ set_process_number,
18
30
  set_run_artifact,
19
31
  set_stand_info,
20
32
  set_stand_location,
21
33
  set_stand_name,
22
34
  set_stand_number,
35
+ set_stand_revision,
36
+ set_user_name,
23
37
  )
24
38
  from hardpy.pytest_hardpy.result import (
25
39
  CouchdbLoader,
@@ -29,61 +43,82 @@ from hardpy.pytest_hardpy.result import (
29
43
  from hardpy.pytest_hardpy.result.couchdb_config import CouchdbConfig
30
44
  from hardpy.pytest_hardpy.utils import (
31
45
  BaseWidget,
46
+ Chart,
47
+ ChartType,
32
48
  CheckboxWidget,
49
+ ComparisonOperation,
33
50
  DialogBox,
34
- DuplicatePartNumberError,
35
- DuplicateSerialNumberError,
36
- DuplicateTestStandLocationError,
37
- DuplicateTestStandNameError,
38
- DuplicateTestStandNumberError,
51
+ DuplicateParameterError,
39
52
  HTMLComponent,
40
53
  ImageComponent,
54
+ Instrument,
41
55
  MultistepWidget,
42
56
  NumericInputWidget,
57
+ NumericMeasurement,
43
58
  RadiobuttonWidget,
44
59
  StepWidget,
60
+ StringMeasurement,
61
+ SubUnit,
45
62
  TestStandNumberError,
46
63
  TextInputWidget,
47
64
  )
48
65
 
49
66
  __all__ = [
50
67
  "BaseWidget",
68
+ "Chart",
69
+ "ChartType",
51
70
  "CheckboxWidget",
71
+ "ComparisonOperation",
52
72
  "CouchdbConfig",
53
73
  "CouchdbLoader",
54
74
  "DialogBox",
55
- "DuplicatePartNumberError",
56
- "DuplicateSerialNumberError",
57
- "DuplicateTestStandLocationError",
58
- "DuplicateTestStandNameError",
59
- "DuplicateTestStandNumberError",
75
+ "DuplicateParameterError",
76
+ "ErrorCode",
60
77
  "HTMLComponent",
61
78
  "ImageComponent",
79
+ "Instrument",
62
80
  "MultistepWidget",
63
81
  "NumericInputWidget",
82
+ "NumericMeasurement",
64
83
  "RadiobuttonWidget",
65
84
  "StandCloudConnector",
66
85
  "StandCloudError",
67
86
  "StandCloudLoader",
68
87
  "StandCloudReader",
69
88
  "StepWidget",
89
+ "StringMeasurement",
90
+ "SubUnit",
70
91
  "TestStandNumberError",
71
92
  "TextInputWidget",
72
93
  "clear_operator_message",
73
94
  "get_current_attempt",
74
95
  "get_current_report",
75
96
  "run_dialog_box",
97
+ "set_batch_serial_number",
76
98
  "set_case_artifact",
99
+ "set_case_chart",
100
+ "set_case_measurement",
77
101
  "set_driver_info",
102
+ "set_dut",
78
103
  "set_dut_info",
104
+ "set_dut_name",
79
105
  "set_dut_part_number",
106
+ "set_dut_revision",
80
107
  "set_dut_serial_number",
108
+ "set_dut_sub_unit",
109
+ "set_dut_type",
110
+ "set_instrument",
81
111
  "set_message",
82
112
  "set_module_artifact",
83
113
  "set_operator_message",
114
+ "set_process_info",
115
+ "set_process_name",
116
+ "set_process_number",
84
117
  "set_run_artifact",
85
118
  "set_stand_info",
86
119
  "set_stand_location",
87
120
  "set_stand_name",
88
121
  "set_stand_number",
122
+ "set_stand_revision",
123
+ "set_user_name",
89
124
  ]
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import socket
6
6
  import sys
7
+ import urllib
7
8
  from pathlib import Path
8
9
  from typing import Annotated, Optional
9
10
 
@@ -90,11 +91,9 @@ def init( # noqa: PLR0913
90
91
  sc_address (str): StandCloud address
91
92
  sc_connection_only (bool): Flag to check StandCloud service availability
92
93
  """
93
- _tests_dir = tests_dir if tests_dir else default_config.tests_dir
94
- _tests_name = tests_name if tests_name else default_config.tests_name
94
+ dir_path = Path(Path.cwd() / tests_dir if tests_dir else "tests")
95
95
  ConfigManager().init_config(
96
- tests_dir=str(_tests_dir),
97
- tests_name=_tests_name,
96
+ tests_name=tests_name if tests_name else dir_path.name,
98
97
  database_user=database_user,
99
98
  database_password=database_password,
100
99
  database_host=database_host,
@@ -106,7 +105,6 @@ def init( # noqa: PLR0913
106
105
  sc_connection_only=sc_connection_only,
107
106
  )
108
107
  # create tests directory
109
- dir_path = Path(Path.cwd() / _tests_dir)
110
108
  Path.mkdir(dir_path, exist_ok=True, parents=True)
111
109
 
112
110
  if create_database:
@@ -115,11 +113,8 @@ def init( # noqa: PLR0913
115
113
 
116
114
  # create hardpy.toml
117
115
  ConfigManager().create_config(dir_path)
118
- config = ConfigManager().read_config(dir_path)
119
- if not config:
120
- print(f"hardpy.toml config by path {dir_path} not detected.")
121
- sys.exit()
122
116
 
117
+ config = _get_config(dir_path)
123
118
  template = TemplateGenerator(config)
124
119
 
125
120
  files = {}
@@ -145,12 +140,7 @@ def run(tests_dir: Annotated[Optional[str], typer.Argument()] = None) -> None:
145
140
  Args:
146
141
  tests_dir (Optional[str]): Test directory. Current directory by default
147
142
  """
148
- dir_path = Path.cwd() / tests_dir if tests_dir else Path.cwd()
149
- config = ConfigManager().read_config(dir_path)
150
-
151
- if not config:
152
- print(f"Config at path {dir_path} not found.")
153
- sys.exit()
143
+ config = _get_config(tests_dir)
154
144
 
155
145
  print("\nLaunch the HardPy operator panel...")
156
146
 
@@ -170,16 +160,29 @@ def run(tests_dir: Annotated[Optional[str], typer.Argument()] = None) -> None:
170
160
 
171
161
 
172
162
  @cli.command()
173
- def start(tests_dir: Annotated[Optional[str], typer.Argument()] = None) -> None:
163
+ def start(
164
+ ctx: typer.Context,
165
+ tests_dir: Annotated[Optional[str], typer.Argument()] = None,
166
+ arg: list[str] = typer.Option( # noqa: B008
167
+ [],
168
+ "--arg",
169
+ "-a",
170
+ help="Dynamic start arguments (format: key=value)",
171
+ ),
172
+ ) -> None:
174
173
  """Start HardPy tests.
175
174
 
176
175
  Args:
176
+ ctx: Typer context for accessing arguments from other sources
177
177
  tests_dir (Optional[str]): Test directory. Current directory by default
178
+ arg (list[str]): Dynamic arguments for test execution
178
179
  """
179
- config = _get_config(tests_dir)
180
- _check_config(config)
180
+ context_args = getattr(ctx, "hardpy_args", [])
181
+ all_args = arg + context_args
181
182
 
182
- url = f"http://{config.frontend.host}:{config.frontend.port}/api/start"
183
+ config = _get_config(tests_dir, validate=True)
184
+ query_args = "&".join([f"args={urllib.parse.quote(a)}" for a in all_args])
185
+ url = f"http://{config.frontend.host}:{config.frontend.port}/api/start?{query_args}"
183
186
  _request_hardpy(url)
184
187
 
185
188
 
@@ -190,9 +193,7 @@ def stop(tests_dir: Annotated[Optional[str], typer.Argument()] = None) -> None:
190
193
  Args:
191
194
  tests_dir (Optional[str]): Test directory. Current directory by default
192
195
  """
193
- config = _get_config(tests_dir)
194
- _check_config(config)
195
-
196
+ config = _get_config(tests_dir, validate=True)
196
197
  url = f"http://{config.frontend.host}:{config.frontend.port}/api/stop"
197
198
  _request_hardpy(url)
198
199
 
@@ -204,9 +205,7 @@ def status(tests_dir: Annotated[Optional[str], typer.Argument()] = None) -> None
204
205
  Args:
205
206
  tests_dir (Optional[str]): Test directory. Current directory by default
206
207
  """
207
- config = _get_config(tests_dir)
208
- _check_config(config)
209
-
208
+ config = _get_config(tests_dir, validate=True)
210
209
  url = f"http://{config.frontend.host}:{config.frontend.port}/api/status"
211
210
  _request_hardpy(url)
212
211
 
@@ -259,7 +258,7 @@ def sc_logout(address: Annotated[str, typer.Argument()]) -> None:
259
258
  print(f"HardPy logout failed from {address}")
260
259
 
261
260
 
262
- def _get_config(tests_dir: str | None = None) -> HardpyConfig:
261
+ def _get_config(tests_dir: str | None = None, validate: bool = False) -> HardpyConfig:
263
262
  dir_path = Path.cwd() / tests_dir if tests_dir else Path.cwd()
264
263
  config = ConfigManager().read_config(dir_path)
265
264
 
@@ -267,12 +266,15 @@ def _get_config(tests_dir: str | None = None) -> HardpyConfig:
267
266
  print(f"Config at path {dir_path} not found.")
268
267
  sys.exit()
269
268
 
269
+ if validate:
270
+ _validate_config(config, dir_path)
271
+
270
272
  return config
271
273
 
272
274
 
273
- def _check_config(config: HardpyConfig) -> None:
275
+ def _validate_config(config: HardpyConfig, tests_dir: str) -> None:
274
276
  url = f"http://{config.frontend.host}:{config.frontend.port}/api/hardpy_config"
275
- error_msg = f"HardPy in directory {config.tests_dir} does not run."
277
+ error_msg = f"HardPy in directory {tests_dir} does not run."
276
278
  try:
277
279
  response = requests.get(url, timeout=2)
278
280
  except Exception:
@@ -58,7 +58,6 @@ class HardpyConfig(BaseModel, extra="allow"):
58
58
  model_config = ConfigDict(extra="forbid")
59
59
 
60
60
  title: str = "HardPy TOML config"
61
- tests_dir: str = "tests"
62
61
  tests_name: str = ""
63
62
  database: DatabaseConfig = DatabaseConfig()
64
63
  frontend: FrontendConfig = FrontendConfig()
@@ -74,7 +73,6 @@ class ConfigManager:
74
73
  @classmethod
75
74
  def init_config( # noqa: PLR0913
76
75
  cls,
77
- tests_dir: str,
78
76
  tests_name: str,
79
77
  database_user: str,
80
78
  database_password: str,
@@ -89,7 +87,6 @@ class ConfigManager:
89
87
  """Initialize HardPy configuration.
90
88
 
91
89
  Args:
92
- tests_dir (str): Tests directory.
93
90
  tests_name (str): Tests suite name.
94
91
  database_user (str): Database user name.
95
92
  database_password (str): Database password.
@@ -101,7 +98,6 @@ class ConfigManager:
101
98
  sc_address (str): StandCloud address.
102
99
  sc_connection_only (bool): StandCloud check availability.
103
100
  """
104
- cls.obj.tests_dir = str(tests_dir)
105
101
  cls.obj.tests_name = tests_name
106
102
  cls.obj.database.user = database_user
107
103
  cls.obj.database.password = database_password
@@ -96,7 +96,6 @@ class StandCloudConnector:
96
96
  return False
97
97
  return True
98
98
 
99
-
100
99
  def get_access_token(self) -> BearerToken | None:
101
100
  """Read access token from token store.
102
101
 
@@ -125,7 +124,8 @@ class StandCloudConnector:
125
124
  timeout=10,
126
125
  )
127
126
  if req.status_code != HTTPStatus.OK:
128
- raise StandCloudError(req.text)
127
+ msg = f"status code {req.status_code}, {req.reason}, {req.text}"
128
+ raise StandCloudError(msg)
129
129
  return json.loads(req.content)
130
130
 
131
131
  def get_api(self, endpoint: str) -> ApiClient:
@@ -1,13 +1,15 @@
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
5
  import os
5
6
  import re
6
7
  from enum import Enum
7
8
  from pathlib import Path
9
+ from typing import Annotated
8
10
  from urllib.parse import unquote
9
11
 
10
- from fastapi import FastAPI
12
+ from fastapi import FastAPI, Query
11
13
  from fastapi.staticfiles import StaticFiles
12
14
 
13
15
  from hardpy.common.config import ConfigManager
@@ -42,13 +44,21 @@ def hardpy_config() -> dict:
42
44
 
43
45
 
44
46
  @app.get("/api/start")
45
- def start_pytest() -> dict:
47
+ def start_pytest(args: Annotated[list[str] | None, Query()] = None) -> dict:
46
48
  """Start pytest subprocess.
47
49
 
50
+ Args:
51
+ args: List of arguments in key=value format
52
+
48
53
  Returns:
49
54
  dict[str, RunStatus]: run status
50
55
  """
51
- if app.state.pytest_wrp.start():
56
+ if args is None:
57
+ args_dict = []
58
+ else:
59
+ args_dict = dict(arg.split("=", 1) for arg in args if "=" in arg)
60
+
61
+ if app.state.pytest_wrp.start(start_args=args_dict):
52
62
  return {"status": Status.STARTED}
53
63
  return {"status": Status.BUSY}
54
64
 
@@ -91,19 +91,30 @@ class BaseStore(BaseConnector):
91
91
  "_id": self._doc_id,
92
92
  DF.MODULES: {},
93
93
  DF.DUT: {
94
+ DF.TYPE: None,
95
+ DF.NAME: None,
96
+ DF.REVISION: None,
94
97
  DF.SERIAL_NUMBER: None,
95
98
  DF.PART_NUMBER: None,
99
+ DF.SUB_UNITS: [],
96
100
  DF.INFO: {},
97
101
  },
98
102
  DF.TEST_STAND: {
99
103
  DF.HW_ID: None,
100
104
  DF.NAME: None,
105
+ DF.REVISION: None,
101
106
  DF.TIMEZONE: None,
102
107
  DF.LOCATION: None,
103
108
  DF.NUMBER: None,
109
+ DF.INSTRUMENTS: [],
104
110
  DF.DRIVERS: {},
105
111
  DF.INFO: {},
106
112
  },
113
+ DF.PROCESS: {
114
+ DF.NAME: None,
115
+ DF.NUMBER: None,
116
+ DF.INFO: {},
117
+ },
107
118
  }
108
119
 
109
120
  # init document
@@ -111,19 +122,31 @@ class BaseStore(BaseConnector):
111
122
  doc[DF.MODULES] = {}
112
123
 
113
124
  doc[DF.DUT] = {
125
+ DF.TYPE: None,
126
+ DF.NAME: None,
127
+ DF.REVISION: None,
114
128
  DF.SERIAL_NUMBER: None,
115
129
  DF.PART_NUMBER: None,
130
+ DF.SUB_UNITS: [],
116
131
  DF.INFO: {},
117
132
  }
118
133
 
119
134
  doc[DF.TEST_STAND] = {
120
135
  DF.HW_ID: None,
121
136
  DF.NAME: None,
137
+ DF.REVISION: None,
122
138
  DF.TIMEZONE: None,
123
139
  DF.LOCATION: None,
124
140
  DF.NUMBER: None,
141
+ DF.INSTRUMENTS: [],
125
142
  DF.DRIVERS: {},
126
143
  DF.INFO: {},
127
144
  }
128
145
 
146
+ doc[DF.PROCESS] = {
147
+ DF.NAME: None,
148
+ DF.NUMBER: None,
149
+ DF.INFO: {},
150
+ }
151
+
129
152
  return doc
@@ -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 enum import Enum
@@ -7,35 +7,56 @@ from enum import Enum
7
7
  class DatabaseField(str, Enum):
8
8
  """Database field."""
9
9
 
10
+ # common
10
11
  NAME = "name"
12
+ USER = "user"
13
+ BATCH_SN = "batch_serial_number"
14
+ CAUSED_DUT_FAILURE_ID = "caused_dut_failure_id"
15
+ GROUP = "group"
16
+ ERROR_CODE = "error_code"
11
17
  STATUS = "status"
12
18
  START_TIME = "start_time"
13
19
  STOP_TIME = "stop_time"
14
- ASSERTION_MSG = "assertion_msg"
15
- MSG = "msg"
16
- MODULES = "modules"
17
- CASES = "cases"
20
+ NUMBER = "number"
21
+ REVISION = "revision"
22
+ INFO = "info"
18
23
  TIMEZONE = "timezone"
19
- PROGRESS = "progress"
20
- ARTIFACT = "artifact"
21
- DUT = "dut"
24
+ MSG = "msg"
25
+ ASSERTION_MSG = "assertion_msg"
22
26
  PART_NUMBER = "part_number"
23
- INFO = "info"
24
- TEST_STAND = "test_stand"
25
27
  SERIAL_NUMBER = "serial_number"
26
- DRIVERS = "drivers"
27
- DIALOG_BOX = "dialog_box"
28
- OPERATOR_MSG = "operator_msg"
28
+ SUB_UNITS = "sub_units"
29
29
  ATTEMPT = "attempt"
30
30
  LOCATION = "location"
31
31
  HW_ID = "hw_id"
32
- TITLE = "title"
33
- VISIBLE = "visible"
34
- IMAGE = "image"
35
- HTML = "html"
36
- ID = "id"
32
+ DRIVERS = "drivers"
33
+ TYPE = "type"
34
+ CHART = "chart"
35
+
36
+ # table name
37
+ DUT = "dut"
38
+ TEST_STAND = "test_stand"
39
+ PROCESS = "process"
40
+
41
+ # collection
42
+ MODULES = "modules"
43
+ CASES = "cases"
44
+ INSTRUMENTS = "instruments"
45
+ MEASUREMENTS = "measurements"
46
+
47
+ # statestore
48
+ PROGRESS = "progress"
49
+ DIALOG_BOX = "dialog_box"
50
+ OPERATOR_MSG = "operator_msg"
37
51
  FONT_SIZE = "font_size"
38
52
  ALERT = "alert"
39
53
  OPERATOR_DATA = "operator_data"
40
54
  DIALOG = "dialog"
41
- NUMBER = "number"
55
+ VISIBLE = "visible"
56
+ TITLE = "title"
57
+ IMAGE = "image"
58
+ HTML = "html"
59
+ ID = "id"
60
+
61
+ # runstore
62
+ ARTIFACT = "artifact"