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
hardpy/__init__.py CHANGED
@@ -1,70 +1,70 @@
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.result import CouchdbLoader
5
- from hardpy.pytest_hardpy.utils import (
6
- DuplicateSerialNumberError,
7
- DuplicatePartNumberError,
8
- DuplicateTestStandNameError,
9
- DuplicateDialogBoxError,
4
+ from hardpy.pytest_hardpy.pytest_call import (
5
+ get_current_attempt,
6
+ get_current_report,
7
+ run_dialog_box,
8
+ set_case_artifact,
9
+ set_driver_info,
10
+ set_dut_info,
11
+ set_dut_part_number,
12
+ set_dut_serial_number,
13
+ set_message,
14
+ set_module_artifact,
15
+ set_operator_message,
16
+ set_run_artifact,
17
+ set_stand_info,
18
+ set_stand_location,
19
+ set_stand_name,
10
20
  )
21
+ from hardpy.pytest_hardpy.result import CouchdbLoader
11
22
  from hardpy.pytest_hardpy.result.couchdb_config import CouchdbConfig
12
23
  from hardpy.pytest_hardpy.utils import (
24
+ BaseWidget,
25
+ CheckboxWidget,
13
26
  DialogBox,
14
- TextInputWidget,
27
+ DuplicatePartNumberError,
28
+ DuplicateSerialNumberError,
29
+ DuplicateTestStandLocationError,
30
+ DuplicateTestStandNameError,
31
+ ImageComponent,
32
+ MultistepWidget,
15
33
  NumericInputWidget,
16
- CheckboxWidget,
17
34
  RadiobuttonWidget,
18
- ImageWidget,
19
35
  StepWidget,
20
- MultistepWidget,
21
- )
22
- from hardpy.pytest_hardpy.pytest_call import (
23
- get_current_report,
24
- set_dut_info,
25
- set_dut_serial_number,
26
- set_dut_part_number,
27
- set_stand_name,
28
- set_stand_info,
29
- set_case_artifact,
30
- set_module_artifact,
31
- set_run_artifact,
32
- set_message,
33
- set_driver_info,
34
- run_dialog_box,
35
- set_operator_message,
36
+ TextInputWidget,
36
37
  )
37
38
 
38
39
  __all__ = [
39
- # CouchDB
40
- "CouchdbLoader",
40
+ "BaseWidget",
41
+ "CheckboxWidget",
41
42
  "CouchdbConfig",
42
- "get_current_report",
43
- # Errors
44
- "DuplicateSerialNumberError",
43
+ "CouchdbLoader",
44
+ "DialogBox",
45
45
  "DuplicatePartNumberError",
46
+ "DuplicateSerialNumberError",
47
+ "DuplicateTestStandLocationError",
46
48
  "DuplicateTestStandNameError",
47
- "DuplicateDialogBoxError",
48
- # Database info
49
+ "ImageComponent",
50
+ "MultistepWidget",
51
+ "NumericInputWidget",
52
+ "RadiobuttonWidget",
53
+ "StepWidget",
54
+ "TextInputWidget",
55
+ "get_current_attempt",
56
+ "get_current_report",
57
+ "run_dialog_box",
58
+ "set_case_artifact",
59
+ "set_driver_info",
49
60
  "set_dut_info",
50
- "set_dut_serial_number",
51
61
  "set_dut_part_number",
52
- "set_stand_name",
53
- "set_stand_info",
54
- "set_case_artifact",
55
- "set_module_artifact",
56
- "set_run_artifact",
62
+ "set_dut_serial_number",
57
63
  "set_message",
58
- "set_driver_info",
64
+ "set_module_artifact",
59
65
  "set_operator_message",
60
- # Dialog boxes
61
- "run_dialog_box",
62
- "DialogBox",
63
- "TextInputWidget",
64
- "NumericInputWidget",
65
- "CheckboxWidget",
66
- "RadiobuttonWidget",
67
- "ImageWidget",
68
- "StepWidget",
69
- "MultistepWidget",
66
+ "set_run_artifact",
67
+ "set_stand_info",
68
+ "set_stand_location",
69
+ "set_stand_name",
70
70
  ]
hardpy/cli/cli.py CHANGED
@@ -1,11 +1,10 @@
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
- import os
5
5
  import sys
6
6
  from pathlib import Path
7
- from typing import Optional
8
- from typing_extensions import Annotated
7
+ from typing import Annotated, Optional
9
8
 
10
9
  import typer
11
10
  from uvicorn import run as uvicorn_run
@@ -18,8 +17,8 @@ default_config = ConfigManager().get_config()
18
17
 
19
18
 
20
19
  @cli.command()
21
- def init( # noqa: WPS211
22
- tests_dir: Annotated[Optional[str], typer.Argument()] = None,
20
+ def init( # noqa: PLR0913
21
+ tests_dir: Annotated[Optional[str], typer.Argument()] = None, # noqa: UP007
23
22
  create_database: bool = typer.Option(
24
23
  True,
25
24
  help="Create CouchDB database.",
@@ -56,7 +55,7 @@ def init( # noqa: WPS211
56
55
  default_config.socket.port,
57
56
  help="Specify a socket port.",
58
57
  ),
59
- ):
58
+ ) -> None:
60
59
  """Initialize HardPy tests directory.
61
60
 
62
61
  Args:
@@ -85,11 +84,11 @@ def init( # noqa: WPS211
85
84
  )
86
85
  # create tests directory
87
86
  dir_path = Path(Path.cwd() / _tests_dir)
88
- os.makedirs(dir_path, exist_ok=True)
87
+ Path.mkdir(dir_path, exist_ok=True, parents=True)
89
88
 
90
89
  if create_database:
91
90
  # create database directory
92
- os.makedirs(dir_path / "database", exist_ok=True)
91
+ Path.mkdir(dir_path / "database", exist_ok=True, parents=True)
93
92
 
94
93
  # create hardpy.toml
95
94
  ConfigManager().create_config(dir_path)
@@ -117,7 +116,7 @@ def init( # noqa: WPS211
117
116
 
118
117
 
119
118
  @cli.command()
120
- def run(tests_dir: Annotated[Optional[str], typer.Argument()] = None):
119
+ def run(tests_dir: Annotated[Optional[str], typer.Argument()] = None) -> None: # noqa: UP007
121
120
  """Run HardPy server.
122
121
 
123
122
  Args:
hardpy/cli/template.py CHANGED
@@ -9,7 +9,7 @@ docker_compose_yaml = """version: "3.8"
9
9
 
10
10
  services:
11
11
  couchserver:
12
- image: couchdb:3.3.2
12
+ image: couchdb:3.4
13
13
  ports:
14
14
  - "{}:5984"
15
15
  environment:
@@ -129,7 +129,7 @@ headers = accept, authorization, content-type, origin, referer, x-csrf-token
129
129
  ; changing this.
130
130
  [admins]
131
131
  ;admin = mysecretpassword
132
- """
132
+ """ # noqa: E501
133
133
 
134
134
  pytest_ini = """[pytest]
135
135
  log_cli = true
@@ -172,17 +172,17 @@ def fill_actions_after_test(post_run_functions: list):
172
172
  class TemplateGenerator:
173
173
  """HardPy template files generator."""
174
174
 
175
- def __init__(self, config: HardpyConfig):
175
+ def __init__(self, config: HardpyConfig) -> None:
176
176
  self._config = config
177
177
 
178
- def create_file(self, file_path: Path, content: str):
178
+ def create_file(self, file_path: Path, content: str) -> None:
179
179
  """Create HardPy template file.
180
180
 
181
181
  Args:
182
182
  file_path (Path): file path
183
183
  content (str): file content
184
184
  """
185
- with open(file_path, "w") as file:
185
+ with Path.open(file_path, "w") as file:
186
186
  file.write(content)
187
187
 
188
188
  @property
@@ -212,7 +212,7 @@ class TemplateGenerator:
212
212
  )
213
213
 
214
214
  @property
215
- def test_1_py(self) -> str: # noqa: WPS114
215
+ def test_1_py(self) -> str:
216
216
  return test_1_py
217
217
 
218
218
  @property
hardpy/common/config.py CHANGED
@@ -1,10 +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
5
  from logging import getLogger
5
6
  from pathlib import Path
6
7
 
7
- import rtoml
8
+ import tomli
9
+ import tomli_w
8
10
  from pydantic import BaseModel, ConfigDict, ValidationError
9
11
 
10
12
  logger = getLogger(__name__)
@@ -27,7 +29,7 @@ class DatabaseConfig(BaseModel):
27
29
  str: database connection url
28
30
  """
29
31
  credentials = f"{self.user}:{self.password}"
30
- uri = f"{self.host}:{str(self.port)}" # noqa: WPS237
32
+ uri = f"{self.host}:{self.port!s}"
31
33
  return f"http://{credentials}@{uri}/"
32
34
 
33
35
 
@@ -68,7 +70,7 @@ class ConfigManager:
68
70
  tests_path = Path.cwd()
69
71
 
70
72
  @classmethod
71
- def init_config( # noqa: WPS211
73
+ def init_config( # noqa: PLR0913
72
74
  cls,
73
75
  tests_dir: str,
74
76
  database_user: str,
@@ -79,7 +81,7 @@ class ConfigManager:
79
81
  frontend_port: int,
80
82
  socket_host: str,
81
83
  socket_port: int,
82
- ):
84
+ ) -> None:
83
85
  """Initialize HardPy configuration.
84
86
 
85
87
  Args:
@@ -104,14 +106,15 @@ class ConfigManager:
104
106
  cls.obj.socket.port = socket_port
105
107
 
106
108
  @classmethod
107
- def create_config(cls, parent_dir: Path):
109
+ def create_config(cls, parent_dir: Path) -> None:
108
110
  """Create HardPy configuration.
109
111
 
110
112
  Args:
111
113
  parent_dir (Path): Configuration file parent directory.
112
114
  """
113
- with open(parent_dir / "hardpy.toml", "w") as file:
114
- file.write(rtoml.dumps(cls.obj.model_dump()))
115
+ config_str = tomli_w.dumps(cls.obj.model_dump())
116
+ with Path.open(parent_dir / "hardpy.toml", "w") as file:
117
+ file.write(config_str)
115
118
 
116
119
  @classmethod
117
120
  def read_config(cls, toml_path: Path) -> HardpyConfig | None:
@@ -126,18 +129,16 @@ class ConfigManager:
126
129
  cls.tests_path = toml_path
127
130
  toml_file = toml_path / "hardpy.toml"
128
131
  if not toml_file.exists():
129
- logger.error(f"File hardpy.toml not found at path: {toml_file}")
132
+ logger.error("File hardpy.toml not found at path: %s", toml_file)
130
133
  return None
131
134
  try:
132
- with open(toml_path / "hardpy.toml", "r") as f:
133
- cls.obj = HardpyConfig(**rtoml.load(f))
134
- return cls.obj
135
- except rtoml.TomlParsingError as exc:
136
- logger.error(f"Error parsing TOML: {exc}")
137
- except rtoml.TomlSerializationError as exc:
138
- logger.error(f"Error parsing TOML: {exc}")
139
- except ValidationError as exc:
140
- logger.error(f"Error parsing TOML: {exc}")
135
+ with Path.open(toml_path / "hardpy.toml", "rb") as f:
136
+ cls.obj = HardpyConfig(**tomli.load(f))
137
+ return cls.obj # noqa: TRY300
138
+ except tomli.TOMLDecodeError:
139
+ logger.exception("Error parsing TOML")
140
+ except ValidationError:
141
+ logger.exception("Error parsing TOML")
141
142
  return None
142
143
 
143
144
  @classmethod
@@ -150,7 +151,7 @@ class ConfigManager:
150
151
  return cls.obj
151
152
 
152
153
  @classmethod
153
- def get_tests_path(cls) -> Path: # noqa: WPS615
154
+ def get_tests_path(cls) -> Path:
154
155
  """Get tests path.
155
156
 
156
157
  Returns:
@@ -1,9 +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
- import os
5
4
  import re
6
5
  from enum import Enum
6
+ from pathlib import Path
7
7
  from urllib.parse import unquote
8
8
 
9
9
  from fastapi import FastAPI
@@ -16,7 +16,7 @@ app = FastAPI()
16
16
  app.state.pytest_wrp = PyTestWrapper()
17
17
 
18
18
 
19
- class Status(str, Enum): # noqa: WPS600
19
+ class Status(str, Enum):
20
20
  """Pytest run status.
21
21
 
22
22
  Statuses, that can be returned by HardPy to frontend.
@@ -31,7 +31,7 @@ class Status(str, Enum): # noqa: WPS600
31
31
 
32
32
 
33
33
  @app.get("/api/start")
34
- def start_pytest():
34
+ def start_pytest() -> dict:
35
35
  """Start pytest subprocess.
36
36
 
37
37
  Returns:
@@ -43,7 +43,7 @@ def start_pytest():
43
43
 
44
44
 
45
45
  @app.get("/api/stop")
46
- def stop_pytest():
46
+ def stop_pytest() -> dict:
47
47
  """Stop pytest subprocess.
48
48
 
49
49
  Returns:
@@ -55,7 +55,7 @@ def stop_pytest():
55
55
 
56
56
 
57
57
  @app.get("/api/collect")
58
- def collect_pytest():
58
+ def collect_pytest() -> dict:
59
59
  """Collect pytest subprocess.
60
60
 
61
61
  Returns:
@@ -68,7 +68,7 @@ def collect_pytest():
68
68
 
69
69
 
70
70
  @app.get("/api/couch")
71
- def couch_connection():
71
+ def couch_connection() -> dict:
72
72
  """Get couchdb connection string.
73
73
 
74
74
  Returns:
@@ -82,7 +82,7 @@ def couch_connection():
82
82
 
83
83
 
84
84
  @app.post("/api/confirm_dialog_box/{dialog_box_output}")
85
- def confirm_dialog_box(dialog_box_output: str):
85
+ def confirm_dialog_box(dialog_box_output: str) -> dict:
86
86
  """Confirm dialog box.
87
87
 
88
88
  Args:
@@ -105,7 +105,7 @@ def confirm_dialog_box(dialog_box_output: str):
105
105
 
106
106
 
107
107
  @app.post("/api/confirm_operator_msg/{is_msg_visible}")
108
- def confirm_operator_msg(is_msg_visible: bool):
108
+ def confirm_operator_msg(is_msg_visible: str) -> dict:
109
109
  """Confirm operator msg.
110
110
 
111
111
  Args:
@@ -122,7 +122,7 @@ def confirm_operator_msg(is_msg_visible: bool):
122
122
  app.mount(
123
123
  "/",
124
124
  StaticFiles(
125
- directory=(os.path.dirname(__file__)) + "/frontend/dist", # noqa: WPS336
125
+ directory=Path(__file__).parent / "frontend/dist",
126
126
  html=True,
127
127
  ),
128
128
  name="static",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "files": {
3
3
  "main.css": "/static/css/main.e8a862f1.css",
4
- "main.js": "/static/js/main.7c954faf.js",
4
+ "main.js": "/static/js/main.6f09d61a.js",
5
5
  "blueprint-icons-all-paths-loader.js": "/static/js/blueprint-icons-all-paths-loader.0aa89747.chunk.js",
6
6
  "blueprint-icons-split-paths-by-size-loader.js": "/static/js/blueprint-icons-split-paths-by-size-loader.52a072d3.chunk.js",
7
7
  "static/js/808.ce070002.chunk.js": "/static/js/808.ce070002.chunk.js",
@@ -21,7 +21,7 @@
21
21
  "static/media/logo_smol.png": "/static/media/logo_smol.5b16f92447a4a9e80331.png",
22
22
  "index.html": "/index.html",
23
23
  "main.e8a862f1.css.map": "/static/css/main.e8a862f1.css.map",
24
- "main.7c954faf.js.map": "/static/js/main.7c954faf.js.map",
24
+ "main.6f09d61a.js.map": "/static/js/main.6f09d61a.js.map",
25
25
  "blueprint-icons-all-paths-loader.0aa89747.chunk.js.map": "/static/js/blueprint-icons-all-paths-loader.0aa89747.chunk.js.map",
26
26
  "blueprint-icons-split-paths-by-size-loader.52a072d3.chunk.js.map": "/static/js/blueprint-icons-split-paths-by-size-loader.52a072d3.chunk.js.map",
27
27
  "808.ce070002.chunk.js.map": "/static/js/808.ce070002.chunk.js.map",
@@ -31,6 +31,6 @@
31
31
  },
32
32
  "entrypoints": [
33
33
  "static/css/main.e8a862f1.css",
34
- "static/js/main.7c954faf.js"
34
+ "static/js/main.6f09d61a.js"
35
35
  ]
36
36
  }
@@ -1 +1 @@
1
- <!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>HardPy Operator Panel</title><script defer="defer" src="/static/js/main.7c954faf.js"></script><link href="/static/css/main.e8a862f1.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
1
+ <!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>HardPy Operator Panel</title><script defer="defer" src="/static/js/main.6f09d61a.js"></script><link href="/static/css/main.e8a862f1.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>