hardpy 0.5.0__tar.gz → 0.6.0__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 (83) hide show
  1. {hardpy-0.5.0 → hardpy-0.6.0}/PKG-INFO +25 -57
  2. hardpy-0.6.0/README.md +70 -0
  3. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/__init__.py +10 -0
  4. hardpy-0.6.0/hardpy/cli/cli.py +145 -0
  5. hardpy-0.6.0/hardpy/cli/template.py +210 -0
  6. hardpy-0.6.0/hardpy/common/config.py +159 -0
  7. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/api.py +49 -6
  8. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/asset-manifest.json +3 -3
  9. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/index.html +1 -1
  10. hardpy-0.6.0/hardpy/hardpy_panel/frontend/dist/static/js/main.7c954faf.js +3 -0
  11. hardpy-0.6.0/hardpy/hardpy_panel/frontend/dist/static/js/main.7c954faf.js.map +1 -0
  12. hardpy-0.6.0/hardpy/pytest_hardpy/__init__.py +0 -0
  13. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/db/base_server.py +4 -4
  14. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/db/base_store.py +13 -3
  15. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/db/const.py +3 -0
  16. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/db/schema.py +47 -11
  17. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/db/statestore.py +11 -0
  18. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/plugin.py +90 -33
  19. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/pytest_call.py +65 -5
  20. hardpy-0.6.0/hardpy/pytest_hardpy/pytest_wrapper.py +151 -0
  21. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/reporter/base.py +1 -1
  22. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/reporter/hook_reporter.py +7 -3
  23. hardpy-0.6.0/hardpy/pytest_hardpy/result/couchdb_config.py +96 -0
  24. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/result/report_loader/couchdb_loader.py +3 -2
  25. hardpy-0.6.0/hardpy/pytest_hardpy/result/report_reader/__init__.py +0 -0
  26. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/result/report_reader/couchdb_reader.py +2 -2
  27. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/utils/__init__.py +7 -4
  28. hardpy-0.6.0/hardpy/pytest_hardpy/utils/connection_data.py +17 -0
  29. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/utils/const.py +4 -14
  30. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/utils/dialog_box.py +1 -1
  31. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/utils/exception.py +14 -0
  32. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/utils/node_info.py +1 -1
  33. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/utils/progress_calculator.py +1 -1
  34. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/utils/singleton.py +1 -1
  35. {hardpy-0.5.0 → hardpy-0.6.0}/pyproject.toml +6 -4
  36. hardpy-0.5.0/README.md +0 -104
  37. hardpy-0.5.0/hardpy/hardpy_panel/frontend/dist/static/js/main.da686f40.js +0 -3
  38. hardpy-0.5.0/hardpy/hardpy_panel/frontend/dist/static/js/main.da686f40.js.map +0 -1
  39. hardpy-0.5.0/hardpy/hardpy_panel/runner.py +0 -54
  40. hardpy-0.5.0/hardpy/pytest_hardpy/pytest_wrapper.py +0 -149
  41. hardpy-0.5.0/hardpy/pytest_hardpy/result/couchdb_config.py +0 -22
  42. hardpy-0.5.0/hardpy/pytest_hardpy/utils/config_data.py +0 -35
  43. {hardpy-0.5.0 → hardpy-0.6.0}/.gitignore +0 -0
  44. {hardpy-0.5.0 → hardpy-0.6.0}/LICENSE +0 -0
  45. {hardpy-0.5.0/hardpy/hardpy_panel → hardpy-0.6.0/hardpy/cli}/__init__.py +0 -0
  46. {hardpy-0.5.0/hardpy/pytest_hardpy → hardpy-0.6.0/hardpy/common}/__init__.py +0 -0
  47. {hardpy-0.5.0/hardpy/pytest_hardpy/result/report_reader → hardpy-0.6.0/hardpy/hardpy_panel}/__init__.py +0 -0
  48. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/favicon.ico +0 -0
  49. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/logo512.png +0 -0
  50. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/manifest.json +0 -0
  51. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/css/main.e8a862f1.css +0 -0
  52. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/css/main.e8a862f1.css.map +0 -0
  53. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/js/808.ce070002.chunk.js +0 -0
  54. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/js/808.ce070002.chunk.js.map +0 -0
  55. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/js/blueprint-icons-16px-paths.d605910e.chunk.js +0 -0
  56. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/js/blueprint-icons-16px-paths.d605910e.chunk.js.map +0 -0
  57. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/js/blueprint-icons-20px-paths.7ee05cc8.chunk.js +0 -0
  58. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/js/blueprint-icons-20px-paths.7ee05cc8.chunk.js.map +0 -0
  59. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/js/blueprint-icons-all-paths-loader.0aa89747.chunk.js +0 -0
  60. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/js/blueprint-icons-all-paths-loader.0aa89747.chunk.js.map +0 -0
  61. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/js/blueprint-icons-all-paths.f63155c9.chunk.js +0 -0
  62. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/js/blueprint-icons-all-paths.f63155c9.chunk.js.map +0 -0
  63. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/js/blueprint-icons-split-paths-by-size-loader.52a072d3.chunk.js +0 -0
  64. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/js/blueprint-icons-split-paths-by-size-loader.52a072d3.chunk.js.map +0 -0
  65. /hardpy-0.5.0/hardpy/hardpy_panel/frontend/dist/static/js/main.da686f40.js.LICENSE.txt → /hardpy-0.6.0/hardpy/hardpy_panel/frontend/dist/static/js/main.7c954faf.js.LICENSE.txt +0 -0
  66. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/media/blueprint-icons-16.520846c6beb41df528c8.eot +0 -0
  67. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/media/blueprint-icons-16.5c52b39c697f2323ce8b.svg +0 -0
  68. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/media/blueprint-icons-16.84db1772f4bfb529f64f.woff +0 -0
  69. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/media/blueprint-icons-16.b67ee1736e20e37a3225.woff2 +0 -0
  70. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/media/blueprint-icons-16.e02ecf515378db143652.ttf +0 -0
  71. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/media/blueprint-icons-20.429cacb8accf72488451.ttf +0 -0
  72. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/media/blueprint-icons-20.6ae3791ee2d86fc228a6.svg +0 -0
  73. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/media/blueprint-icons-20.8cecf62de42997e4d82f.woff2 +0 -0
  74. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/media/blueprint-icons-20.afbadb627d43b7857223.eot +0 -0
  75. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/media/blueprint-icons-20.e857f5a5132b8bfa71a1.woff +0 -0
  76. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/hardpy_panel/frontend/dist/static/media/logo_smol.5b16f92447a4a9e80331.png +0 -0
  77. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/db/__init__.py +0 -0
  78. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/db/base_connector.py +0 -0
  79. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/db/runstore.py +0 -0
  80. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/reporter/__init__.py +0 -0
  81. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/reporter/runner_reporter.py +0 -0
  82. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/result/__init__.py +0 -0
  83. {hardpy-0.5.0 → hardpy-0.6.0}/hardpy/pytest_hardpy/result/report_loader/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hardpy
3
- Version: 0.5.0
3
+ Version: 0.6.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/
@@ -28,7 +28,9 @@ Requires-Dist: glom>=23.3.0
28
28
  Requires-Dist: natsort>=8.4.0
29
29
  Requires-Dist: pycouchdb>=1.14.2
30
30
  Requires-Dist: pydantic>=2.4.0
31
- Requires-Dist: pytest<9,>7
31
+ Requires-Dist: pytest<9,>=7
32
+ Requires-Dist: rtoml~=0.11.0
33
+ Requires-Dist: typer<1.0,>=0.12
32
34
  Requires-Dist: uvicorn>=0.23.2
33
35
  Provides-Extra: build
34
36
  Requires-Dist: build==1.0.3; extra == 'build'
@@ -74,71 +76,37 @@ HardPy allows you to:
74
76
  pip install hardpy
75
77
  ```
76
78
 
77
- ## Examples
78
-
79
- Find examples of using the **HardPy** in the `examples` folder.
80
-
81
79
  ## Getting Started
82
80
 
83
- #### CouchDB
84
-
85
- This is a simple instruction for Linux.
86
- For Windows, follow the instructions from the
87
- [documentation](https://everypinio.github.io/hardpy/documentation/database/#couchdb-instance).
88
-
89
- Launch CouchDB with Docker.
90
- The Docker version must be 24.0.0 or higher.
91
- Create `couchdb.ini` file:
92
-
93
- ```ini
94
- [chttpd]
95
- enable_cors=true
96
-
97
- [cors]
98
- origins = *
99
- methods = GET, PUT, POST, HEAD, DELETE
100
- credentials = true
101
- headers = accept, authorization, content-type, origin, referer, x-csrf-token
81
+ 1. Create your first test bench.
82
+ ```bash
83
+ hardpy init
102
84
  ```
103
-
104
- Run the Docker container from folder with couchdb.ini file:
105
-
85
+ 2. Launch [CouchDB](https://couchdb.apache.org/) database via [docker compose](https://docs.docker.com/compose/) in the background.
106
86
  ```bash
107
- docker run --rm --name couchdb -p 5984:5984 -e COUCHDB_USER=dev -e COUCHDB_PASSWORD=dev -v ./couchdb.ini:/opt/couchdb/etc/local.ini couchdb:3.3
87
+ cd tests
88
+ docker compose up -d
108
89
  ```
109
-
110
- Command for Windows:
111
-
90
+ 3. Launch HardPy operator panel.
112
91
  ```bash
113
- docker run --rm --name couchdb -p 5984:5984 -e COUCHDB_USER=dev -e COUCHDB_PASSWORD=dev -v .\couchdb.ini:/opt/couchdb/etc/local.ini couchdb:3.3.2
92
+ hardpy run
114
93
  ```
94
+ 4. View operator panel in browser: http://localhost:8000/
115
95
 
116
- #### Test steps
117
-
118
- Add simple test to `tests` folder
119
-
120
- ```python
121
- # test_1.py
122
- import pytest
123
-
124
- def test_one():
125
- assert True
126
- ```
127
- #### Operator panel
96
+ <h1 align="center">
97
+ <img src="https://everypinio.github.io/hardpy/img/hardpy_operator_panel_hello_hardpy.png"
98
+ alt="hardpy operator panel" style="width:600px;">
99
+ </h1>
128
100
 
129
- Launch `hardpy-panel` from tests folder or launch `hardpy-panel tests` and open page http://localhost:8000/ in browser.
101
+ 5. View the latest test report: http://localhost:5984/_utils
130
102
 
131
- <h1 align="center">
132
- <img src="https://everypinio.github.io/hardpy/img/hardpy_operator_panel_hello_hardpy.png"
133
- alt="hardpy operator panel" style="width:600px;">
134
- </h1>
103
+ Login and password: **dev**, database - **runstore**, document - **current**.
135
104
 
136
- #### Test report
105
+ <h1 align="center">
106
+ <img src="https://everypinio.github.io/hardpy/img/runstore_hello_hardpy.png"
107
+ alt="hardpy runstore" style="width:500px;">
108
+ </h1>
137
109
 
138
- The last test report is stored in **runstore** database, document - **current**.
139
- You can view the CouchDB instance through Fauxton web interface: http://localhost:5984/_utils
110
+ ## Examples
140
111
 
141
- <h1 align="center">
142
- <img src="https://everypinio.github.io/hardpy/img/runstore_hello_hardpy.png"
143
- alt="hardpy runstore" style="width:600px;">
144
- </h1>
112
+ Find more examples of using the **HardPy** in the [examples](https://github.com/everypinio/hardpy/tree/main/examples) folder.
hardpy-0.6.0/README.md ADDED
@@ -0,0 +1,70 @@
1
+ <h1 align="center">
2
+ <img src="https://everypinio.github.io/hardpy/img/logo256.png" alt="HardPy" style="width:200px;">
3
+ </h1>
4
+
5
+ <h1 align="center">
6
+ <b>HardPy</b>
7
+ </h1>
8
+
9
+ <p align="center">
10
+ HardPy is a python library for creating a test bench for devices.
11
+ </p>
12
+
13
+ ---
14
+
15
+ **Documentation**: <a href=https://everypinio.github.io/hardpy/ target="_blank">https://everypinio.github.io/hardpy/</a>
16
+
17
+ **Source Code**: <a href=https://github.com/everypinio/hardpy target="_blank">https://github.com/everypinio/hardpy</a>
18
+
19
+ **PyPi**: <a href=https://pypi.org/project/hardpy/ target="_blank">https://pypi.org/project/hardpy/</a>
20
+
21
+ ---
22
+
23
+ ## Overview
24
+
25
+ HardPy allows you to:
26
+
27
+ * Create test benches for devices using [pytest](https://docs.pytest.org/);
28
+ * Use a browser to view, start, stop, and interact with tests;
29
+ * Store test results in the [CouchDB](https://couchdb.apache.org/) database.
30
+
31
+ ## To Install
32
+
33
+ ```bash
34
+ pip install hardpy
35
+ ```
36
+
37
+ ## Getting Started
38
+
39
+ 1. Create your first test bench.
40
+ ```bash
41
+ hardpy init
42
+ ```
43
+ 2. Launch [CouchDB](https://couchdb.apache.org/) database via [docker compose](https://docs.docker.com/compose/) in the background.
44
+ ```bash
45
+ cd tests
46
+ docker compose up -d
47
+ ```
48
+ 3. Launch HardPy operator panel.
49
+ ```bash
50
+ hardpy run
51
+ ```
52
+ 4. View operator panel in browser: http://localhost:8000/
53
+
54
+ <h1 align="center">
55
+ <img src="https://everypinio.github.io/hardpy/img/hardpy_operator_panel_hello_hardpy.png"
56
+ alt="hardpy operator panel" style="width:600px;">
57
+ </h1>
58
+
59
+ 5. View the latest test report: http://localhost:5984/_utils
60
+
61
+ Login and password: **dev**, database - **runstore**, document - **current**.
62
+
63
+ <h1 align="center">
64
+ <img src="https://everypinio.github.io/hardpy/img/runstore_hello_hardpy.png"
65
+ alt="hardpy runstore" style="width:500px;">
66
+ </h1>
67
+
68
+ ## Examples
69
+
70
+ Find more examples of using the **HardPy** in the [examples](https://github.com/everypinio/hardpy/tree/main/examples) folder.
@@ -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",
@@ -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()
@@ -0,0 +1,210 @@
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
+ """
141
+
142
+ test_1_py = """import pytest
143
+ import hardpy
144
+
145
+
146
+ pytestmark = pytest.mark.module_name("HardPy template")
147
+
148
+
149
+ @pytest.mark.case_name("Test 1")
150
+ def test_one():
151
+ assert True
152
+ """
153
+
154
+ conftest_py = """import pytest
155
+ import hardpy
156
+
157
+
158
+ def finish_executing():
159
+ print("Testing completed")
160
+
161
+
162
+ @pytest.fixture(scope="session", autouse=True)
163
+ def fill_actions_after_test(post_run_functions: list):
164
+ post_run_functions.append(finish_executing)
165
+ yield
166
+ """
167
+
168
+
169
+ class TemplateGenerator:
170
+ """HardPy template files generator."""
171
+
172
+ def __init__(self, config: HardpyConfig):
173
+ self._config = config
174
+
175
+ def create_file(self, file_path: Path, content: str):
176
+ """Create HardPy template file.
177
+
178
+ Args:
179
+ file_path (Path): file path
180
+ content (str): file content
181
+ """
182
+ with open(file_path, "w") as file:
183
+ file.write(content)
184
+
185
+ @property
186
+ def docker_compose_yaml(self) -> str:
187
+ return docker_compose_yaml.format(
188
+ self._config.database.port,
189
+ self._config.database.user,
190
+ self._config.database.password,
191
+ )
192
+
193
+ @property
194
+ def couchdb_ini(self) -> str:
195
+ return couchdb_ini.format(
196
+ self._config.database.port,
197
+ self._config.database.host,
198
+ )
199
+
200
+ @property
201
+ def pytest_ini(self) -> str:
202
+ return pytest_ini
203
+
204
+ @property
205
+ def test_1_py(self) -> str: # noqa: WPS114
206
+ return test_1_py
207
+
208
+ @property
209
+ def conftest_py(self) -> str:
210
+ return conftest_py