hardpy 0.5.1__py3-none-any.whl → 0.6.1__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 (42) hide show
  1. hardpy/__init__.py +10 -0
  2. hardpy/cli/__init__.py +0 -0
  3. hardpy/cli/cli.py +145 -0
  4. hardpy/cli/template.py +220 -0
  5. hardpy/common/__init__.py +0 -0
  6. hardpy/common/config.py +159 -0
  7. hardpy/hardpy_panel/api.py +49 -6
  8. hardpy/hardpy_panel/frontend/dist/asset-manifest.json +3 -3
  9. hardpy/hardpy_panel/frontend/dist/index.html +1 -1
  10. hardpy/hardpy_panel/frontend/dist/static/js/main.7c954faf.js +3 -0
  11. hardpy/hardpy_panel/frontend/dist/static/js/main.7c954faf.js.map +1 -0
  12. hardpy/pytest_hardpy/db/base_connector.py +7 -1
  13. hardpy/pytest_hardpy/db/base_server.py +4 -4
  14. hardpy/pytest_hardpy/db/base_store.py +13 -3
  15. hardpy/pytest_hardpy/db/const.py +3 -0
  16. hardpy/pytest_hardpy/db/schema.py +47 -11
  17. hardpy/pytest_hardpy/db/statestore.py +11 -0
  18. hardpy/pytest_hardpy/plugin.py +93 -33
  19. hardpy/pytest_hardpy/pytest_call.py +65 -5
  20. hardpy/pytest_hardpy/pytest_wrapper.py +62 -60
  21. hardpy/pytest_hardpy/reporter/base.py +1 -1
  22. hardpy/pytest_hardpy/reporter/hook_reporter.py +7 -3
  23. hardpy/pytest_hardpy/result/report_loader/couchdb_loader.py +3 -2
  24. hardpy/pytest_hardpy/result/report_reader/couchdb_reader.py +2 -2
  25. hardpy/pytest_hardpy/utils/__init__.py +7 -4
  26. hardpy/pytest_hardpy/utils/connection_data.py +17 -0
  27. hardpy/pytest_hardpy/utils/const.py +4 -14
  28. hardpy/pytest_hardpy/utils/dialog_box.py +1 -1
  29. hardpy/pytest_hardpy/utils/exception.py +14 -0
  30. hardpy/pytest_hardpy/utils/node_info.py +1 -1
  31. hardpy/pytest_hardpy/utils/progress_calculator.py +1 -1
  32. hardpy/pytest_hardpy/utils/singleton.py +1 -1
  33. {hardpy-0.5.1.dist-info → hardpy-0.6.1.dist-info}/METADATA +25 -57
  34. {hardpy-0.5.1.dist-info → hardpy-0.6.1.dist-info}/RECORD +38 -34
  35. {hardpy-0.5.1.dist-info → hardpy-0.6.1.dist-info}/entry_points.txt +1 -1
  36. hardpy/hardpy_panel/frontend/dist/static/js/main.da686f40.js +0 -3
  37. hardpy/hardpy_panel/frontend/dist/static/js/main.da686f40.js.map +0 -1
  38. hardpy/hardpy_panel/runner.py +0 -54
  39. hardpy/pytest_hardpy/utils/config_data.py +0 -35
  40. /hardpy/hardpy_panel/frontend/dist/static/js/{main.da686f40.js.LICENSE.txt → main.7c954faf.js.LICENSE.txt} +0 -0
  41. {hardpy-0.5.1.dist-info → hardpy-0.6.1.dist-info}/WHEEL +0 -0
  42. {hardpy-0.5.1.dist-info → hardpy-0.6.1.dist-info}/licenses/LICENSE +0 -0
hardpy/__init__.py CHANGED
@@ -4,6 +4,8 @@
4
4
  from hardpy.pytest_hardpy.result import CouchdbLoader
5
5
  from hardpy.pytest_hardpy.utils import (
6
6
  DuplicateSerialNumberError,
7
+ DuplicatePartNumberError,
8
+ DuplicateTestStandNameError,
7
9
  DuplicateDialogBoxError,
8
10
  )
9
11
  from hardpy.pytest_hardpy.result.couchdb_config import CouchdbConfig
@@ -21,6 +23,8 @@ from hardpy.pytest_hardpy.pytest_call import (
21
23
  get_current_report,
22
24
  set_dut_info,
23
25
  set_dut_serial_number,
26
+ set_dut_part_number,
27
+ set_stand_name,
24
28
  set_stand_info,
25
29
  set_case_artifact,
26
30
  set_module_artifact,
@@ -28,6 +32,7 @@ from hardpy.pytest_hardpy.pytest_call import (
28
32
  set_message,
29
33
  set_driver_info,
30
34
  run_dialog_box,
35
+ set_operator_message,
31
36
  )
32
37
 
33
38
  __all__ = [
@@ -37,16 +42,21 @@ __all__ = [
37
42
  "get_current_report",
38
43
  # Errors
39
44
  "DuplicateSerialNumberError",
45
+ "DuplicatePartNumberError",
46
+ "DuplicateTestStandNameError",
40
47
  "DuplicateDialogBoxError",
41
48
  # Database info
42
49
  "set_dut_info",
43
50
  "set_dut_serial_number",
51
+ "set_dut_part_number",
52
+ "set_stand_name",
44
53
  "set_stand_info",
45
54
  "set_case_artifact",
46
55
  "set_module_artifact",
47
56
  "set_run_artifact",
48
57
  "set_message",
49
58
  "set_driver_info",
59
+ "set_operator_message",
50
60
  # Dialog boxes
51
61
  "run_dialog_box",
52
62
  "DialogBox",
hardpy/cli/__init__.py ADDED
File without changes
hardpy/cli/cli.py ADDED
@@ -0,0 +1,145 @@
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
+ import os
5
+ import sys
6
+ from pathlib import Path
7
+ from typing import Optional
8
+ from typing_extensions import Annotated
9
+
10
+ import typer
11
+ from uvicorn import run as uvicorn_run
12
+
13
+ from hardpy.cli.template import TemplateGenerator
14
+ from hardpy.common.config import ConfigManager
15
+
16
+ cli = typer.Typer(add_completion=False)
17
+ default_config = ConfigManager().get_config()
18
+
19
+
20
+ @cli.command()
21
+ def init( # noqa: WPS211
22
+ tests_dir: Annotated[Optional[str], typer.Argument()] = None,
23
+ create_database: bool = typer.Option(
24
+ True,
25
+ help="Create CouchDB database.",
26
+ ),
27
+ database_user: str = typer.Option(
28
+ default_config.database.user,
29
+ help="Specify a database user.",
30
+ ),
31
+ database_password: str = typer.Option(
32
+ default_config.database.password,
33
+ help="Specify a database user password.",
34
+ ),
35
+ database_host: str = typer.Option(
36
+ default_config.database.host,
37
+ help="Specify a database host.",
38
+ ),
39
+ database_port: int = typer.Option(
40
+ default_config.database.port,
41
+ help="Specify a database port.",
42
+ ),
43
+ frontend_host: str = typer.Option(
44
+ default_config.frontend.host,
45
+ help="Specify a frontend host.",
46
+ ),
47
+ frontend_port: int = typer.Option(
48
+ default_config.frontend.port,
49
+ help="Specify a frontend port.",
50
+ ),
51
+ socket_host: str = typer.Option(
52
+ default_config.socket.host,
53
+ help="Specify a socket host.",
54
+ ),
55
+ socket_port: int = typer.Option(
56
+ default_config.socket.port,
57
+ help="Specify a socket port.",
58
+ ),
59
+ ):
60
+ """Initialize HardPy tests directory.
61
+
62
+ Args:
63
+ tests_dir (str | None): Tests directory. Current directory + `tests` by default
64
+ create_database (bool): Flag to create database
65
+ database_user (str): Database user name
66
+ database_password (str): Database password
67
+ database_host (str): Database host
68
+ database_port (int): Database port
69
+ frontend_host (str): Panel operator host
70
+ frontend_port (int): Panel operator port
71
+ socket_host (str): Socket host
72
+ socket_port (int): Socket port
73
+ """
74
+ _tests_dir = tests_dir if tests_dir else default_config.tests_dir
75
+ ConfigManager().init_config(
76
+ tests_dir=str(_tests_dir),
77
+ database_user=database_user,
78
+ database_password=database_password,
79
+ database_host=database_host,
80
+ database_port=database_port,
81
+ frontend_host=frontend_host,
82
+ frontend_port=frontend_port,
83
+ socket_host=socket_host,
84
+ socket_port=socket_port,
85
+ )
86
+ # create tests directory
87
+ dir_path = Path(Path.cwd() / _tests_dir)
88
+ os.makedirs(dir_path, exist_ok=True)
89
+
90
+ if create_database:
91
+ # create database directory
92
+ os.makedirs(dir_path / "database", exist_ok=True)
93
+
94
+ # create hardpy.toml
95
+ ConfigManager().create_config(dir_path)
96
+ config = ConfigManager().read_config(dir_path)
97
+ if not config:
98
+ print(f"hardpy.toml config by path {dir_path} not detected.")
99
+ sys.exit()
100
+
101
+ template = TemplateGenerator(config)
102
+
103
+ files = {}
104
+
105
+ if create_database:
106
+ files[Path(dir_path / "docker-compose.yaml")] = template.docker_compose_yaml
107
+ files[Path(dir_path / "database" / "couchdb.ini")] = template.couchdb_ini
108
+
109
+ files[Path(dir_path / "pytest.ini")] = template.pytest_ini
110
+ files[Path(dir_path / "test_1.py")] = template.test_1_py
111
+ files[Path(dir_path / "conftest.py")] = template.conftest_py
112
+
113
+ for key, value in files.items():
114
+ template.create_file(key, value)
115
+
116
+ print(f"HardPy project {dir_path.name} initialized successfully.")
117
+
118
+
119
+ @cli.command()
120
+ def run(tests_dir: Annotated[Optional[str], typer.Argument()] = None):
121
+ """Run HardPy server.
122
+
123
+ Args:
124
+ tests_dir (Optional[str]): Test directory. Current directory by default
125
+ """
126
+ dir_path = Path.cwd() / tests_dir if tests_dir else Path.cwd()
127
+ config = ConfigManager().read_config(dir_path)
128
+
129
+ if not config:
130
+ print(f"Config at path {dir_path} not found.")
131
+ sys.exit()
132
+
133
+ print("\nLaunch the HardPy operator panel...")
134
+ print(f"http://{config.frontend.host}:{config.frontend.port}\n")
135
+
136
+ uvicorn_run(
137
+ "hardpy.hardpy_panel.api:app",
138
+ host=config.frontend.host,
139
+ port=config.frontend.port,
140
+ log_level="critical",
141
+ )
142
+
143
+
144
+ if __name__ == "__main__":
145
+ cli()
hardpy/cli/template.py ADDED
@@ -0,0 +1,220 @@
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 pathlib import Path
5
+
6
+ from hardpy.common.config import HardpyConfig
7
+
8
+ docker_compose_yaml = """version: "3.8"
9
+
10
+ services:
11
+ couchserver:
12
+ image: couchdb:3.3.2
13
+ ports:
14
+ - "{}:5984"
15
+ environment:
16
+ COUCHDB_USER: {}
17
+ COUCHDB_PASSWORD: {}
18
+ volumes:
19
+ - ./database/dbdata:/opt/couchdb/data
20
+ - ./database/couchdb.ini:/opt/couchdb/etc/local.ini
21
+ """
22
+
23
+ couchdb_ini = """; CouchDB Configuration Settings
24
+
25
+ ; Custom settings should be made in this file. They will override settings
26
+ ; in default.ini, but unlike changes made to default.ini, this file won't be
27
+ ; overwritten on server upgrade.
28
+
29
+ [couchdb]
30
+ ;max_document_size = 4294967296 ; bytes
31
+ ;os_process_timeout = 5000
32
+
33
+ [couch_peruser]
34
+ ; If enabled, couch_peruser ensures that a private per-user database
35
+ ; exists for each document in _users. These databases are writable only
36
+ ; by the corresponding user. Databases are in the following form:
37
+ ; userdb-{{hex encoded username}}
38
+ ;enable = true
39
+
40
+ ; If set to true and a user is deleted, the respective database gets
41
+ ; deleted as well.
42
+ ;delete_dbs = true
43
+
44
+ ; Set a default q value for peruser-created databases that is different from
45
+ ; cluster / q
46
+ ;q = 1
47
+
48
+ [chttpd]
49
+ ;port = {}
50
+ ;bind_address = {}
51
+
52
+ ; Options for the MochiWeb HTTP server.
53
+ ;server_options = [{{backlog, 128}}, {{acceptor_pool_size, 16}}]
54
+
55
+ ; For more socket options, consult Erlang's module 'inet' man page.
56
+ ;socket_options = [{{sndbuf, 262144}}, {{nodelay, true}}]
57
+
58
+ enable_cors=true
59
+
60
+ [httpd]
61
+ ; NOTE that this only configures the "backend" node-local port, not the
62
+ ; "frontend" clustered port. You probably don't want to change anything in
63
+ ; this section.
64
+ ; Uncomment next line to trigger basic-auth popup on unauthorized requests.
65
+ ;WWW-Authenticate = Basic realm="administrator"
66
+
67
+ ; Uncomment next line to set the configuration modification whitelist. Only
68
+ ; whitelisted values may be changed via the /_config URLs. To allow the admin
69
+ ; to change this value over HTTP, remember to include {{httpd,config_whitelist}}
70
+ ; itself. Excluding it from the list would require editing this file to update
71
+ ; the whitelist.
72
+ ;config_whitelist = [{{httpd,config_whitelist}}, {{log,level}}, {{etc,etc}}]
73
+
74
+ [cors]
75
+ origins = *
76
+ methods = GET, PUT, POST, HEAD, DELETE
77
+ credentials = true
78
+ headers = accept, authorization, content-type, origin, referer, x-csrf-token
79
+
80
+
81
+ [ssl]
82
+ ;enable = true
83
+ ;cert_file = /full/path/to/server_cert.pem
84
+ ;key_file = /full/path/to/server_key.pem
85
+ ;password = somepassword
86
+
87
+ ; set to true to validate peer certificates
88
+ ;verify_ssl_certificates = false
89
+
90
+ ; Set to true to fail if the client does not send a certificate. Only used if verify_ssl_certificates is true.
91
+ ;fail_if_no_peer_cert = false
92
+
93
+ ; Path to file containing PEM encoded CA certificates (trusted
94
+ ; certificates used for verifying a peer certificate). May be omitted if
95
+ ; you do not want to verify the peer.
96
+ ;cacert_file = /full/path/to/cacertf
97
+
98
+ ; The verification fun (optional) if not specified, the default
99
+ ; verification fun will be used.
100
+ ;verify_fun = {{Module, VerifyFun}}
101
+
102
+ ; maximum peer certificate depth
103
+ ;ssl_certificate_max_depth = 1
104
+
105
+ ; Reject renegotiations that do not live up to RFC 5746.
106
+ ;secure_renegotiate = true
107
+
108
+ ; The cipher suites that should be supported.
109
+ ; Can be specified in erlang format "{{ecdhe_ecdsa,aes_128_cbc,sha256}}"
110
+ ; or in OpenSSL format "ECDHE-ECDSA-AES128-SHA256".
111
+ ;ciphers = ["ECDHE-ECDSA-AES128-SHA256", "ECDHE-ECDSA-AES128-SHA"]
112
+
113
+ ; The SSL/TLS versions to support
114
+ ;tls_versions = [tlsv1, 'tlsv1.1', 'tlsv1.2']
115
+
116
+ ; To enable Virtual Hosts in CouchDB, add a vhost = path directive. All requests to
117
+ ; the Virtual Host will be redirected to the path. In the example below all requests
118
+ ; to http://example.com/ are redirected to /database.
119
+ ; If you run CouchDB on a specific port, include the port number in the vhost:
120
+ ; example.com:5984 = /database
121
+ [vhosts]
122
+ ;example.com = /database/
123
+
124
+ ; To create an admin account uncomment the '[admins]' section below and add a
125
+ ; line in the format 'username = password'. When you next start CouchDB, it
126
+ ; will change the password to a hash (so that your passwords don't linger
127
+ ; around in plain-text files). You can add more admin accounts with more
128
+ ; 'username = password' lines. Don't forget to restart CouchDB after
129
+ ; changing this.
130
+ [admins]
131
+ ;admin = mysecretpassword
132
+ """
133
+
134
+ pytest_ini = """[pytest]
135
+ log_cli = true
136
+ log_cli_level = INFO
137
+ log_cli_format = %%(asctime)s [%%(levelname)s] %%(message)s
138
+ log_cli_date_format = %H:%M:%S
139
+ addopts = --hardpy-pt
140
+ --hardpy-db-url http://{}:{}@{}:{}/
141
+ --hardpy-sh {}
142
+ --hardpy-sp {}
143
+ """
144
+
145
+ test_1_py = """import pytest
146
+ import hardpy
147
+
148
+
149
+ pytestmark = pytest.mark.module_name("HardPy template")
150
+
151
+
152
+ @pytest.mark.case_name("Test 1")
153
+ def test_one():
154
+ assert True
155
+ """
156
+
157
+ conftest_py = """import pytest
158
+ import hardpy
159
+
160
+
161
+ def finish_executing():
162
+ print("Testing completed")
163
+
164
+
165
+ @pytest.fixture(scope="session", autouse=True)
166
+ def fill_actions_after_test(post_run_functions: list):
167
+ post_run_functions.append(finish_executing)
168
+ yield
169
+ """
170
+
171
+
172
+ class TemplateGenerator:
173
+ """HardPy template files generator."""
174
+
175
+ def __init__(self, config: HardpyConfig):
176
+ self._config = config
177
+
178
+ def create_file(self, file_path: Path, content: str):
179
+ """Create HardPy template file.
180
+
181
+ Args:
182
+ file_path (Path): file path
183
+ content (str): file content
184
+ """
185
+ with open(file_path, "w") as file:
186
+ file.write(content)
187
+
188
+ @property
189
+ def docker_compose_yaml(self) -> str:
190
+ return docker_compose_yaml.format(
191
+ self._config.database.port,
192
+ self._config.database.user,
193
+ self._config.database.password,
194
+ )
195
+
196
+ @property
197
+ def couchdb_ini(self) -> str:
198
+ return couchdb_ini.format(
199
+ self._config.database.port,
200
+ self._config.database.host,
201
+ )
202
+
203
+ @property
204
+ def pytest_ini(self) -> str:
205
+ return pytest_ini.format(
206
+ self._config.database.user,
207
+ self._config.database.password,
208
+ self._config.database.host,
209
+ self._config.database.port,
210
+ self._config.socket.host,
211
+ self._config.socket.port,
212
+ )
213
+
214
+ @property
215
+ def test_1_py(self) -> str: # noqa: WPS114
216
+ return test_1_py
217
+
218
+ @property
219
+ def conftest_py(self) -> str:
220
+ return conftest_py
File without changes
@@ -0,0 +1,159 @@
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 logging import getLogger
5
+ from pathlib import Path
6
+
7
+ import rtoml
8
+ from pydantic import BaseModel, ConfigDict, ValidationError
9
+
10
+ logger = getLogger(__name__)
11
+
12
+
13
+ class DatabaseConfig(BaseModel):
14
+ """Database configuration."""
15
+
16
+ model_config = ConfigDict(extra="forbid")
17
+
18
+ user: str = "dev"
19
+ password: str = "dev"
20
+ host: str = "localhost"
21
+ port: int = 5984
22
+
23
+ def connection_url(self) -> str:
24
+ """Get database connection url.
25
+
26
+ Returns:
27
+ str: database connection url
28
+ """
29
+ credentials = f"{self.user}:{self.password}"
30
+ uri = f"{self.host}:{str(self.port)}" # noqa: WPS237
31
+ return f"http://{credentials}@{uri}/"
32
+
33
+
34
+ class FrontendConfig(BaseModel):
35
+ """Frontend configuration."""
36
+
37
+ model_config = ConfigDict(extra="forbid")
38
+
39
+ host: str = "localhost"
40
+ port: int = 8000
41
+
42
+
43
+ class SocketConfig(BaseModel):
44
+ """Socket configuration."""
45
+
46
+ model_config = ConfigDict(extra="forbid")
47
+
48
+ host: str = "localhost"
49
+ port: int = 6525
50
+
51
+
52
+ class HardpyConfig(BaseModel):
53
+ """HardPy configuration."""
54
+
55
+ model_config = ConfigDict(extra="forbid")
56
+
57
+ title: str = "HardPy TOML config"
58
+ tests_dir: str = "tests"
59
+ database: DatabaseConfig = DatabaseConfig()
60
+ frontend: FrontendConfig = FrontendConfig()
61
+ socket: SocketConfig = SocketConfig()
62
+
63
+
64
+ class ConfigManager:
65
+ """HardPy configuration manager."""
66
+
67
+ obj = HardpyConfig()
68
+ tests_path = Path.cwd()
69
+
70
+ @classmethod
71
+ def init_config( # noqa: WPS211
72
+ cls,
73
+ tests_dir: str,
74
+ database_user: str,
75
+ database_password: str,
76
+ database_host: str,
77
+ database_port: int,
78
+ frontend_host: str,
79
+ frontend_port: int,
80
+ socket_host: str,
81
+ socket_port: int,
82
+ ):
83
+ """Initialize HardPy configuration.
84
+
85
+ Args:
86
+ tests_dir (str): Tests directory.
87
+ database_user (str): Database user name.
88
+ database_password (str): Database password.
89
+ database_host (str): Database host.
90
+ database_port (int): Database port.
91
+ frontend_host (str): Operator panel host.
92
+ frontend_port (int): Operator panel port.
93
+ socket_host (str): Socket host.
94
+ socket_port (int): Socket port.
95
+ """
96
+ cls.obj.tests_dir = str(tests_dir)
97
+ cls.obj.database.user = database_user
98
+ cls.obj.database.password = database_password
99
+ cls.obj.database.host = database_host
100
+ cls.obj.database.port = database_port
101
+ cls.obj.frontend.host = frontend_host
102
+ cls.obj.frontend.port = frontend_port
103
+ cls.obj.socket.host = socket_host
104
+ cls.obj.socket.port = socket_port
105
+
106
+ @classmethod
107
+ def create_config(cls, parent_dir: Path):
108
+ """Create HardPy configuration.
109
+
110
+ Args:
111
+ parent_dir (Path): Configuration file parent directory.
112
+ """
113
+ with open(parent_dir / "hardpy.toml", "w") as file:
114
+ file.write(rtoml.dumps(cls.obj.model_dump()))
115
+
116
+ @classmethod
117
+ def read_config(cls, toml_path: Path) -> HardpyConfig | None:
118
+ """Read HardPy configuration.
119
+
120
+ Args:
121
+ toml_path (Path): hardpy.toml file path.
122
+
123
+ Returns:
124
+ HardpyConfig | None: HardPy configuration
125
+ """
126
+ cls.tests_path = toml_path
127
+ toml_file = toml_path / "hardpy.toml"
128
+ if not toml_file.exists():
129
+ logger.error(f"File hardpy.toml not found at path: {toml_file}")
130
+ return None
131
+ 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}")
141
+ return None
142
+
143
+ @classmethod
144
+ def get_config(cls) -> HardpyConfig:
145
+ """Get HardPy configuration.
146
+
147
+ Returns:
148
+ HardpyConfig: HardPy configuration
149
+ """
150
+ return cls.obj
151
+
152
+ @classmethod
153
+ def get_tests_path(cls) -> Path: # noqa: WPS615
154
+ """Get tests path.
155
+
156
+ Returns:
157
+ Path: HardPy tests path
158
+ """
159
+ return cls.tests_path
@@ -2,17 +2,34 @@
2
2
  # GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
3
3
 
4
4
  import os
5
+ import re
6
+ from enum import Enum
7
+ from urllib.parse import unquote
5
8
 
6
9
  from fastapi import FastAPI
7
10
  from fastapi.staticfiles import StaticFiles
8
11
 
9
- from hardpy.pytest_hardpy.utils import ConfigData, RunStatus as Status
12
+ from hardpy.common.config import ConfigManager
10
13
  from hardpy.pytest_hardpy.pytest_wrapper import PyTestWrapper
11
14
 
12
15
  app = FastAPI()
13
16
  app.state.pytest_wrp = PyTestWrapper()
14
17
 
15
18
 
19
+ class Status(str, Enum): # noqa: WPS600
20
+ """Pytest run status.
21
+
22
+ Statuses, that can be returned by HardPy to frontend.
23
+ """
24
+
25
+ STOPPED = "stopped"
26
+ STARTED = "started"
27
+ COLLECTED = "collected"
28
+ BUSY = "busy"
29
+ READY = "ready"
30
+ ERROR = "error"
31
+
32
+
16
33
  @app.get("/api/start")
17
34
  def start_pytest():
18
35
  """Start pytest subprocess.
@@ -55,12 +72,12 @@ def couch_connection():
55
72
  """Get couchdb connection string.
56
73
 
57
74
  Returns:
58
- dict[str, str, str]: couchdb connection string
75
+ dict[str, str]: couchdb connection string
59
76
  """
60
- config_data = ConfigData()
77
+ connection_url = ConfigManager().get_config().database.connection_url()
61
78
 
62
79
  return {
63
- "connection_str": config_data.connection_string,
80
+ "connection_str": connection_url,
64
81
  }
65
82
 
66
83
 
@@ -74,13 +91,39 @@ def confirm_dialog_box(dialog_box_output: str):
74
91
  Returns:
75
92
  dict[str, RunStatus]: run status
76
93
  """
77
- if app.state.pytest_wrp.confirm_dialog_box(dialog_box_output):
94
+ hex_base = 16
95
+ unquoted_string = unquote(dialog_box_output)
96
+ decoded_string = re.sub(
97
+ "%([0-9a-fA-F]{2})",
98
+ lambda match: chr(int(match.group(1), hex_base)),
99
+ unquoted_string,
100
+ )
101
+
102
+ if app.state.pytest_wrp.send_data(str(decoded_string)):
103
+ return {"status": Status.BUSY}
104
+ return {"status": Status.ERROR}
105
+
106
+
107
+ @app.post("/api/confirm_operator_msg/{is_msg_visible}")
108
+ def confirm_operator_msg(is_msg_visible: bool):
109
+ """Confirm operator msg.
110
+
111
+ Args:
112
+ is_msg_visible (bool): is operator message is visible
113
+
114
+ Returns:
115
+ dict[str, RunStatus]: run status
116
+ """
117
+ if app.state.pytest_wrp.send_data(str(is_msg_visible)):
78
118
  return {"status": Status.BUSY}
79
119
  return {"status": Status.ERROR}
80
120
 
81
121
 
82
122
  app.mount(
83
123
  "/",
84
- StaticFiles(directory=(os.path.dirname(__file__)) + "/frontend/dist", html=True),
124
+ StaticFiles(
125
+ directory=(os.path.dirname(__file__)) + "/frontend/dist", # noqa: WPS336
126
+ html=True,
127
+ ),
85
128
  name="static",
86
129
  )
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "files": {
3
3
  "main.css": "/static/css/main.e8a862f1.css",
4
- "main.js": "/static/js/main.da686f40.js",
4
+ "main.js": "/static/js/main.7c954faf.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.da686f40.js.map": "/static/js/main.da686f40.js.map",
24
+ "main.7c954faf.js.map": "/static/js/main.7c954faf.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.da686f40.js"
34
+ "static/js/main.7c954faf.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.da686f40.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.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>