hardpy 0.6.1__py3-none-any.whl → 0.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. hardpy/__init__.py +49 -49
  2. hardpy/cli/cli.py +8 -9
  3. hardpy/cli/template.py +6 -6
  4. hardpy/common/config.py +19 -18
  5. hardpy/hardpy_panel/api.py +9 -9
  6. hardpy/hardpy_panel/frontend/dist/asset-manifest.json +3 -3
  7. hardpy/hardpy_panel/frontend/dist/index.html +1 -1
  8. hardpy/hardpy_panel/frontend/dist/logo192.png +0 -0
  9. hardpy/hardpy_panel/frontend/dist/static/css/main.e8a862f1.css.map +1 -1
  10. hardpy/hardpy_panel/frontend/dist/static/js/main.6f09d61a.js +3 -0
  11. hardpy/hardpy_panel/frontend/dist/static/js/{main.7c954faf.js.map → main.6f09d61a.js.map} +1 -1
  12. hardpy/pytest_hardpy/db/__init__.py +4 -5
  13. hardpy/pytest_hardpy/db/base_connector.py +6 -5
  14. hardpy/pytest_hardpy/db/base_server.py +1 -1
  15. hardpy/pytest_hardpy/db/base_store.py +23 -9
  16. hardpy/pytest_hardpy/db/const.py +3 -1
  17. hardpy/pytest_hardpy/db/runstore.py +13 -15
  18. hardpy/pytest_hardpy/db/schema/__init__.py +9 -0
  19. hardpy/pytest_hardpy/db/{schema.py → schema/v1.py} +120 -79
  20. hardpy/pytest_hardpy/db/statestore.py +7 -20
  21. hardpy/pytest_hardpy/plugin.py +128 -85
  22. hardpy/pytest_hardpy/pytest_call.py +80 -32
  23. hardpy/pytest_hardpy/pytest_wrapper.py +8 -8
  24. hardpy/pytest_hardpy/reporter/__init__.py +2 -2
  25. hardpy/pytest_hardpy/reporter/base.py +32 -7
  26. hardpy/pytest_hardpy/reporter/hook_reporter.py +66 -37
  27. hardpy/pytest_hardpy/reporter/runner_reporter.py +6 -8
  28. hardpy/pytest_hardpy/result/__init__.py +2 -2
  29. hardpy/pytest_hardpy/result/couchdb_config.py +20 -16
  30. hardpy/pytest_hardpy/result/report_loader/couchdb_loader.py +2 -2
  31. hardpy/pytest_hardpy/result/report_reader/couchdb_reader.py +36 -20
  32. hardpy/pytest_hardpy/utils/__init__.py +34 -29
  33. hardpy/pytest_hardpy/utils/connection_data.py +6 -8
  34. hardpy/pytest_hardpy/utils/const.py +1 -1
  35. hardpy/pytest_hardpy/utils/dialog_box.py +105 -66
  36. hardpy/pytest_hardpy/utils/exception.py +14 -8
  37. hardpy/pytest_hardpy/utils/machineid.py +15 -0
  38. hardpy/pytest_hardpy/utils/node_info.py +45 -16
  39. hardpy/pytest_hardpy/utils/progress_calculator.py +4 -3
  40. hardpy/pytest_hardpy/utils/singleton.py +23 -16
  41. {hardpy-0.6.1.dist-info → hardpy-0.8.0.dist-info}/METADATA +26 -33
  42. {hardpy-0.6.1.dist-info → hardpy-0.8.0.dist-info}/RECORD +46 -43
  43. hardpy/hardpy_panel/frontend/dist/static/js/main.7c954faf.js +0 -3
  44. /hardpy/hardpy_panel/frontend/dist/static/js/{main.7c954faf.js.LICENSE.txt → main.6f09d61a.js.LICENSE.txt} +0 -0
  45. {hardpy-0.6.1.dist-info → hardpy-0.8.0.dist-info}/WHEEL +0 -0
  46. {hardpy-0.6.1.dist-info → hardpy-0.8.0.dist-info}/entry_points.txt +0 -0
  47. {hardpy-0.6.1.dist-info → hardpy-0.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,8 +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
+ from __future__ import annotations
3
4
 
4
5
  import signal
5
- import subprocess # noqa: S404
6
+ import subprocess
6
7
  import sys
7
8
  from platform import system
8
9
  from socket import socket
@@ -13,7 +14,7 @@ from hardpy.common.config import ConfigManager
13
14
  class PyTestWrapper:
14
15
  """Wrapper for pytest subprocess."""
15
16
 
16
- def __init__(self):
17
+ def __init__(self) -> None:
17
18
  self._proc = None
18
19
  self.python_executable = sys.executable
19
20
 
@@ -65,7 +66,7 @@ class PyTestWrapper:
65
66
  "--hardpy-pt",
66
67
  ],
67
68
  cwd=ConfigManager().get_tests_path(),
68
- creationflags=subprocess.CREATE_NEW_PROCESS_GROUP,
69
+ creationflags=subprocess.CREATE_NEW_PROCESS_GROUP, # type: ignore
69
70
  )
70
71
 
71
72
  return True
@@ -80,11 +81,11 @@ class PyTestWrapper:
80
81
  if system() == "Linux":
81
82
  self._proc.terminate()
82
83
  elif system() == "Windows":
83
- self._proc.send_signal(signal.CTRL_BREAK_EVENT)
84
+ self._proc.send_signal(signal.CTRL_BREAK_EVENT) # type: ignore
84
85
  return True
85
86
  return False
86
87
 
87
- def collect(self, is_clear_database: bool = False) -> bool:
88
+ def collect(self, *, is_clear_database: bool = False) -> bool:
88
89
  """Perform pytest collection.
89
90
 
90
91
  Args:
@@ -115,7 +116,6 @@ class PyTestWrapper:
115
116
 
116
117
  if is_clear_database:
117
118
  args.append("--hardpy-clear-database")
118
- args.append(str(is_clear_database))
119
119
 
120
120
  subprocess.Popen( # noqa: S603
121
121
  [self.python_executable, *args],
@@ -123,7 +123,7 @@ class PyTestWrapper:
123
123
  )
124
124
  return True
125
125
 
126
- def send_data(self, data: str):
126
+ def send_data(self, data: str) -> bool:
127
127
  """Send data to pytest subprocess.
128
128
 
129
129
  Args:
@@ -138,7 +138,7 @@ class PyTestWrapper:
138
138
  client.connect((self.config.socket.host, self.config.socket.port))
139
139
  client.sendall(data.encode("utf-8"))
140
140
  client.close()
141
- except Exception:
141
+ except Exception: # noqa: BLE001
142
142
  return False
143
143
  return True
144
144
 
@@ -1,10 +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
3
 
4
- from hardpy.pytest_hardpy.reporter.runner_reporter import RunnerReporter
5
4
  from hardpy.pytest_hardpy.reporter.hook_reporter import HookReporter
5
+ from hardpy.pytest_hardpy.reporter.runner_reporter import RunnerReporter
6
6
 
7
7
  __all__ = [
8
- "RunnerReporter",
9
8
  "HookReporter",
9
+ "RunnerReporter",
10
10
  ]
@@ -2,21 +2,30 @@
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 logging import getLogger
5
+ from typing import Any
5
6
 
6
- from hardpy.pytest_hardpy.db import StateStore, RunStore
7
+ from hardpy.pytest_hardpy.db import (
8
+ DatabaseField as DF, # noqa: N817
9
+ RunStore,
10
+ StateStore,
11
+ )
7
12
 
8
13
 
9
14
  class BaseReporter:
10
15
  """Base class for test reporter."""
11
16
 
12
- def __init__(self):
17
+ def __init__(self) -> None:
13
18
  self._statestore = StateStore()
14
19
  self._runstore = RunStore()
15
20
  self._log = getLogger(__name__)
16
21
 
17
22
  def set_doc_value(
18
- self, key: str, value, runstore_only=False, statestore_only=False
19
- ):
23
+ self,
24
+ key: str,
25
+ value: Any, # noqa: ANN401
26
+ runstore_only: bool = False,
27
+ statestore_only: bool = False,
28
+ ) -> None:
20
29
  """Set value to the document.
21
30
 
22
31
  Update a document without writing to the database.
@@ -33,7 +42,8 @@ class BaseReporter:
33
42
  ValueError: if both runstore_only and statestore_only are True
34
43
  """
35
44
  if runstore_only and statestore_only:
36
- raise ValueError("Both runstore_only and statestore_only cannot be True")
45
+ msg = "Both runstore_only and statestore_only cannot be True"
46
+ raise ValueError(msg)
37
47
  if runstore_only:
38
48
  self._runstore.update_doc(key, value)
39
49
  return
@@ -43,12 +53,12 @@ class BaseReporter:
43
53
  self._runstore.update_doc(key, value)
44
54
  self._statestore.update_doc(key, value)
45
55
 
46
- def update_db_by_doc(self):
56
+ def update_db_by_doc(self) -> None:
47
57
  """Update database by current document."""
48
58
  self._statestore.update_db()
49
59
  self._runstore.update_db()
50
60
 
51
- def generate_key(self, *args) -> str:
61
+ def generate_key(self, *args: Any) -> str: # noqa: ANN401
52
62
  """Generate key for database.
53
63
 
54
64
  Args:
@@ -58,3 +68,18 @@ class BaseReporter:
58
68
  str: database key
59
69
  """
60
70
  return ".".join(args)
71
+
72
+ def get_current_attempt(self, module_id: str, case_id: str) -> int:
73
+ """Get current attempt.
74
+
75
+ Returns:
76
+ int: current attempt
77
+ """
78
+ key = self.generate_key(
79
+ DF.MODULES,
80
+ module_id,
81
+ DF.CASES,
82
+ case_id,
83
+ DF.ATTEMPT,
84
+ )
85
+ return self._statestore.get_field(key)
@@ -1,27 +1,30 @@
1
1
  # Copyright (c) 2024 Everypin
2
2
  # GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
3
+ from __future__ import annotations
3
4
 
4
- from time import time, tzname
5
- from logging import getLogger
6
5
  from copy import deepcopy
6
+ from logging import getLogger
7
+ from time import time
7
8
 
8
9
  from natsort import natsorted
10
+ from tzlocal import get_localzone
9
11
 
10
- from hardpy.pytest_hardpy.db import DatabaseField as DF
12
+ from hardpy.pytest_hardpy.db import DatabaseField as DF # noqa: N817
11
13
  from hardpy.pytest_hardpy.reporter.base import BaseReporter
12
- from hardpy.pytest_hardpy.utils import TestStatus, NodeInfo
14
+ from hardpy.pytest_hardpy.utils import NodeInfo, TestStatus, machine_id
13
15
 
14
16
 
15
17
  class HookReporter(BaseReporter):
16
18
  """Reporter for using in the hook HardPy plugin's hooks."""
17
19
 
18
- def __init__(self, is_clear_database: bool = False): # noqa: WPS612
20
+ def __init__(self, is_clear_database: bool = False) -> None:
19
21
  super().__init__()
20
22
  if is_clear_database:
21
23
  self._statestore.clear()
24
+ self._runstore.clear()
22
25
  self._log = getLogger(__name__)
23
26
 
24
- def init_doc(self, doc_name: str):
27
+ def init_doc(self, doc_name: str) -> None:
25
28
  """Initialize document.
26
29
 
27
30
  Args:
@@ -30,23 +33,26 @@ class HookReporter(BaseReporter):
30
33
  self.set_doc_value(DF.NAME, doc_name)
31
34
  self.set_doc_value(DF.STATUS, TestStatus.READY)
32
35
  self.set_doc_value(DF.START_TIME, None)
33
- self.set_doc_value(DF.TIMEZONE, None)
34
36
  self.set_doc_value(DF.STOP_TIME, None)
35
- self.set_doc_value(DF.PROGRESS, 0)
36
- self.set_doc_value(DF.DRIVERS, {})
37
+ self.set_doc_value(DF.PROGRESS, 0, statestore_only=True)
37
38
  self.set_doc_value(DF.ARTIFACT, {}, runstore_only=True)
38
39
  self.set_doc_value(DF.OPERATOR_MSG, {}, statestore_only=True)
39
40
 
40
- def start(self):
41
+ test_stand_tz = self.generate_key(DF.TEST_STAND, DF.TIMEZONE)
42
+ self.set_doc_value(test_stand_tz, str(get_localzone().key))
43
+
44
+ test_stand_id_key = self.generate_key(DF.TEST_STAND, DF.HW_ID)
45
+ self.set_doc_value(test_stand_id_key, machine_id())
46
+
47
+ def start(self) -> None:
41
48
  """Start test."""
42
49
  self._log.debug("Starting test run.")
43
50
  start_time = int(time())
44
51
  self.set_doc_value(DF.START_TIME, start_time)
45
52
  self.set_doc_value(DF.STATUS, TestStatus.RUN)
46
- self.set_doc_value(DF.TIMEZONE, tzname) # noqa: WPS432
47
- self.set_doc_value(DF.PROGRESS, 0)
53
+ self.set_doc_value(DF.PROGRESS, 0, statestore_only=True)
48
54
 
49
- def finish(self, status: TestStatus):
55
+ def finish(self, status: TestStatus) -> None:
50
56
  """Finish test.
51
57
 
52
58
  This method must be called at the end of test run.
@@ -56,20 +62,20 @@ class HookReporter(BaseReporter):
56
62
  self.set_doc_value(DF.STOP_TIME, stop_time)
57
63
  self.set_doc_value(DF.STATUS, status)
58
64
 
59
- def compact_all(self):
60
- """Compact all databases"""
65
+ def compact_all(self) -> None:
66
+ """Compact all databases."""
61
67
  self._statestore.compact()
62
68
  self._runstore.compact()
63
69
 
64
- def set_progress(self, progress: int):
70
+ def set_progress(self, progress: int) -> None:
65
71
  """Set test progress.
66
72
 
67
73
  Args:
68
74
  progress (int): test progress
69
75
  """
70
- self.set_doc_value(DF.PROGRESS, progress)
76
+ self.set_doc_value(DF.PROGRESS, progress, statestore_only=True)
71
77
 
72
- def set_assertion_msg(self, module_id: str, case_id: str, msg: str | None):
78
+ def set_assertion_msg(self, module_id: str, case_id: str, msg: str | None) -> None:
73
79
  """Set case assertion message.
74
80
 
75
81
  Args:
@@ -78,11 +84,15 @@ class HookReporter(BaseReporter):
78
84
  msg (str): assertion message
79
85
  """
80
86
  key = self.generate_key(
81
- DF.MODULES, module_id, DF.CASES, case_id, DF.ASSERTION_MSG
87
+ DF.MODULES,
88
+ module_id,
89
+ DF.CASES,
90
+ case_id,
91
+ DF.ASSERTION_MSG,
82
92
  )
83
93
  self.set_doc_value(key, msg)
84
94
 
85
- def add_case(self, node_info: NodeInfo):
95
+ def add_case(self, node_info: NodeInfo) -> None:
86
96
  """Add test case to document.
87
97
 
88
98
  Args:
@@ -99,7 +109,7 @@ class HookReporter(BaseReporter):
99
109
  self.set_doc_value(key, item_statestore, statestore_only=True)
100
110
  self.set_doc_value(key, item_runstore, runstore_only=True)
101
111
 
102
- def set_case_status(self, module_id: str, case_id: str, status: TestStatus):
112
+ def set_case_status(self, module_id: str, case_id: str, status: TestStatus) -> None:
103
113
  """Set test case status.
104
114
 
105
115
  Args:
@@ -110,7 +120,7 @@ class HookReporter(BaseReporter):
110
120
  key = self.generate_key(DF.MODULES, module_id, DF.CASES, case_id, DF.STATUS)
111
121
  self.set_doc_value(key, status)
112
122
 
113
- def set_case_start_time(self, module_id: str, case_id: str):
123
+ def set_case_start_time(self, module_id: str, case_id: str) -> None:
114
124
  """Set test case start_time.
115
125
 
116
126
  Args:
@@ -120,7 +130,7 @@ class HookReporter(BaseReporter):
120
130
  key = self.generate_key(DF.MODULES, module_id, DF.CASES, case_id, DF.START_TIME)
121
131
  self._set_time(key)
122
132
 
123
- def set_case_stop_time(self, module_id: str, case_id: str):
133
+ def set_case_stop_time(self, module_id: str, case_id: str) -> None:
124
134
  """Set test case start_time.
125
135
 
126
136
  Args:
@@ -130,7 +140,7 @@ class HookReporter(BaseReporter):
130
140
  key = self.generate_key(DF.MODULES, module_id, DF.CASES, case_id, DF.STOP_TIME)
131
141
  self._set_time(key)
132
142
 
133
- def set_module_status(self, module_id: str, status: TestStatus):
143
+ def set_module_status(self, module_id: str, status: TestStatus) -> None:
134
144
  """Set test module status.
135
145
 
136
146
  Args:
@@ -140,7 +150,7 @@ class HookReporter(BaseReporter):
140
150
  key = self.generate_key(DF.MODULES, module_id, DF.STATUS)
141
151
  self.set_doc_value(key, status)
142
152
 
143
- def set_module_start_time(self, module_id: str):
153
+ def set_module_start_time(self, module_id: str) -> None:
144
154
  """Set test module status.
145
155
 
146
156
  Args:
@@ -149,7 +159,7 @@ class HookReporter(BaseReporter):
149
159
  key = self.generate_key(DF.MODULES, module_id, DF.START_TIME)
150
160
  self._set_time(key)
151
161
 
152
- def set_module_stop_time(self, module_id: str):
162
+ def set_module_stop_time(self, module_id: str) -> None:
153
163
  """Set test module status.
154
164
 
155
165
  Args:
@@ -158,6 +168,23 @@ class HookReporter(BaseReporter):
158
168
  key = self.generate_key(DF.MODULES, module_id, DF.STOP_TIME)
159
169
  self._set_time(key)
160
170
 
171
+ def set_case_attempt(self, module_id: str, case_id: str, attempt: int) -> None:
172
+ """Set test case current attempt.
173
+
174
+ Args:
175
+ module_id (str): module id
176
+ case_id (str): case id
177
+ attempt (int): test case current attempt
178
+ """
179
+ key = self.generate_key(
180
+ DF.MODULES,
181
+ module_id,
182
+ DF.CASES,
183
+ case_id,
184
+ DF.ATTEMPT,
185
+ )
186
+ self.set_doc_value(key, attempt, statestore_only=True)
187
+
161
188
  def update_node_order(self, nodes: dict) -> None:
162
189
  """Update node order.
163
190
 
@@ -173,7 +200,7 @@ class HookReporter(BaseReporter):
173
200
  updated_module_order = self._update_module_order(updated_case_order)
174
201
  self.set_doc_value(key, updated_module_order, statestore_only=True)
175
202
 
176
- def _set_time(self, key: str):
203
+ def _set_time(self, key: str) -> None:
177
204
  current_time = self._statestore.get_field(key)
178
205
  if current_time is None:
179
206
  self.set_doc_value(key, int(time()))
@@ -184,8 +211,8 @@ class HookReporter(BaseReporter):
184
211
  node_info: NodeInfo,
185
212
  is_only_runstore: bool = False,
186
213
  is_only_statestore: bool = False,
187
- ):
188
- module_default = { # noqa: WPS204
214
+ ) -> None:
215
+ module_default = {
189
216
  DF.STATUS: TestStatus.READY,
190
217
  DF.NAME: self._get_module_name(node_info),
191
218
  DF.START_TIME: None,
@@ -199,13 +226,12 @@ class HookReporter(BaseReporter):
199
226
  DF.STOP_TIME: None,
200
227
  DF.ASSERTION_MSG: None,
201
228
  DF.MSG: None,
202
- DF.ATTEMPT: 0,
203
229
  }
204
230
 
205
- if item.get(node_info.module_id) is None: # noqa: WPS204
231
+ if item.get(node_info.module_id) is None:
206
232
  if is_only_runstore:
207
233
  module_default[DF.ARTIFACT] = {}
208
- item[node_info.module_id] = module_default # noqa: WPS204
234
+ item[node_info.module_id] = module_default
209
235
  else:
210
236
  item[node_info.module_id][DF.STATUS] = TestStatus.READY
211
237
  item[node_info.module_id][DF.NAME] = self._get_module_name(node_info)
@@ -218,10 +244,14 @@ class HookReporter(BaseReporter):
218
244
 
219
245
  if is_only_statestore:
220
246
  case_default[DF.DIALOG_BOX] = {}
247
+ case_default[DF.ATTEMPT] = 0
221
248
  item[node_info.module_id][DF.CASES][node_info.case_id] = case_default
222
249
 
223
250
  def _remove_outdate_node(
224
- self, old_modules: dict, new_modules: dict, nodes: dict
251
+ self,
252
+ old_modules: dict,
253
+ new_modules: dict,
254
+ nodes: dict,
225
255
  ) -> dict:
226
256
  """Remove outdated nodes from StateStore database.
227
257
 
@@ -277,16 +307,15 @@ class HookReporter(BaseReporter):
277
307
  Returns:
278
308
  dict: list of modules and cases.
279
309
  """
280
-
281
310
  sorted_modules = natsorted(modules.items(), key=lambda item: item[0])
282
311
 
283
312
  new_modules = {}
284
313
  for module_id, module in sorted_modules:
285
- new_modules[module_id] = module
314
+ new_modules[module_id] = module # noqa: PERF403
286
315
 
287
316
  return new_modules
288
317
 
289
- def _get_module_name(self, node_info) -> str:
318
+ def _get_module_name(self, node_info: NodeInfo) -> str:
290
319
  """Get module name from markers or use default.
291
320
 
292
321
  Args:
@@ -297,7 +326,7 @@ class HookReporter(BaseReporter):
297
326
  """
298
327
  return node_info.module_name if node_info.module_name else node_info.module_id
299
328
 
300
- def _get_case_name(self, node_info) -> str:
329
+ def _get_case_name(self, node_info: NodeInfo) -> str:
301
330
  """Get case name from markers or use default.
302
331
 
303
332
  Args:
@@ -5,19 +5,17 @@ from logging import getLogger
5
5
  from typing import Any
6
6
 
7
7
  from hardpy.pytest_hardpy.reporter.base import BaseReporter
8
- from hardpy.pytest_hardpy.utils import Singleton
8
+ from hardpy.pytest_hardpy.utils import SingletonMeta
9
9
 
10
10
 
11
- class RunnerReporter(Singleton, BaseReporter):
11
+ class RunnerReporter(BaseReporter, metaclass=SingletonMeta):
12
12
  """Reporter for using in direct call from test runner with HardPy plugin."""
13
13
 
14
- def __init__(self):
15
- if not self._initialized:
16
- super().__init__()
17
- self._log = getLogger(__name__)
18
- self._initialized = True
14
+ def __init__(self) -> None:
15
+ super().__init__()
16
+ self._log = getLogger(__name__)
19
17
 
20
- def get_field(self, key: str) -> Any:
18
+ def get_field(self, key: str) -> Any: # noqa: ANN401
21
19
  """Get field from the statestore.
22
20
 
23
21
  Args:
@@ -1,10 +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
3
 
4
- from hardpy.pytest_hardpy.result.report_reader.couchdb_reader import CouchdbReader
5
4
  from hardpy.pytest_hardpy.result.report_loader.couchdb_loader import CouchdbLoader
5
+ from hardpy.pytest_hardpy.result.report_reader.couchdb_reader import CouchdbReader
6
6
 
7
7
  __all__ = [
8
- "CouchdbReader",
9
8
  "CouchdbLoader",
9
+ "CouchdbReader",
10
10
  ]
@@ -1,16 +1,17 @@
1
1
  # Copyright (c) 2024 Everypin
2
2
  # GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
3
+ from __future__ import annotations
3
4
 
4
5
  import ast
5
- import requests
6
6
  import socket
7
-
8
7
  from dataclasses import dataclass
8
+
9
+ import requests
9
10
  from urllib3 import disable_warnings
10
11
 
11
12
 
12
13
  @dataclass
13
- class CouchdbConfig: # noqa: WPS306
14
+ class CouchdbConfig:
14
15
  """CouchDB loader config.
15
16
 
16
17
  If `connection_str` arg is not set, it will be created from other args.
@@ -23,7 +24,7 @@ class CouchdbConfig: # noqa: WPS306
23
24
  port: int = 5984
24
25
  connection_str: str | None = None
25
26
 
26
- def __post_init__(self):
27
+ def __post_init__(self) -> None:
27
28
  """Disable urllib3 warnings.
28
29
 
29
30
  More info: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings
@@ -43,14 +44,14 @@ class CouchdbConfig: # noqa: WPS306
43
44
  if self.connection_str:
44
45
  return self.connection_str
45
46
 
46
- # TODO: Modify connection string creating based on protocol.
47
+ # TODO(xorialexandrov): Modify connection string creating based on protocol.
47
48
  # Some problems with http and https, different ports, local
48
49
  # and cloud databases.
49
50
  protocol = self._get_protocol()
50
51
 
51
52
  if protocol == "http":
52
53
  host_url = f"http://{self.host}:{self.port}"
53
- uri = f"{self.host}:{str(self.port)}" # noqa: WPS237
54
+ uri = f"{self.host}:{self.port!s}"
54
55
  elif protocol == "https":
55
56
  host_url = f"https://{self.host}"
56
57
  uri = f"{self.host}"
@@ -58,20 +59,22 @@ class CouchdbConfig: # noqa: WPS306
58
59
  try:
59
60
  response = requests.get(host_url, timeout=5)
60
61
  except requests.exceptions.RequestException:
61
- raise RuntimeError(f"Error CouchDB connecting to {host_url}.")
62
+ msg = f"Error CouchDB connecting to {host_url}."
63
+ raise RuntimeError(msg) # noqa: B904
62
64
 
63
65
  # fmt: off
64
66
  try:
65
- couchdb_dict = ast.literal_eval(response._content.decode("utf-8")) # noqa: WPS437,E501
67
+ couchdb_dict = ast.literal_eval(response._content.decode("utf-8")) # type: ignore # noqa: SLF001
66
68
  couchdb_dict.get("couchdb", False)
67
- except Exception:
68
- raise RuntimeError(f"Address {host_url} does not provide CouchDB attributes.")
69
+ except Exception: # noqa: BLE001
70
+ msg = f"Address {host_url} does not provide CouchDB attributes."
71
+ raise RuntimeError(msg) # noqa: B904
69
72
  # fmt: on
70
73
 
71
74
  credentials = f"{self.user}:{self.password}"
72
75
  return f"{protocol}://{credentials}@{uri}/"
73
76
 
74
- def _get_protocol(self) -> str: # noqa: WPS231
77
+ def _get_protocol(self) -> str:
75
78
  success = 200
76
79
  try:
77
80
  # HTTPS attempt
@@ -80,17 +83,18 @@ class CouchdbConfig: # noqa: WPS306
80
83
  request = f"https://{self.host}"
81
84
  if requests.get(request, timeout=5).status_code == success:
82
85
  return "https"
83
- raise OSError
86
+ raise OSError # noqa: TRY301
84
87
  except OSError:
85
- try: # noqa: WPS505
88
+ try:
86
89
  # HTTP attempt
87
90
  sock = socket.create_connection((self.host, self.port))
88
91
  sock.close()
89
92
  request = f"http://{self.host}:{self.port}"
90
93
  if requests.get(request, timeout=5).status_code == success:
91
94
  return "http"
92
- raise OSError
95
+ raise OSError # noqa: TRY301
93
96
  except OSError:
94
- raise RuntimeError(
95
- f"Error connecting to couchdb server {self.host}:{self.port}."
97
+ msg = f"Error connecting to couchdb server {self.host}:{self.port}."
98
+ raise RuntimeError( # noqa: B904
99
+ msg,
96
100
  )
@@ -5,8 +5,8 @@ from logging import getLogger
5
5
  from uuid import uuid4
6
6
 
7
7
  from pycouchdb import Server as DbServer
8
- from pycouchdb.exceptions import Conflict
9
8
  from pycouchdb.client import Database
9
+ from pycouchdb.exceptions import Conflict
10
10
 
11
11
  from hardpy.pytest_hardpy.db.schema import ResultRunStore
12
12
  from hardpy.pytest_hardpy.result.couchdb_config import CouchdbConfig
@@ -15,7 +15,7 @@ from hardpy.pytest_hardpy.result.couchdb_config import CouchdbConfig
15
15
  class CouchdbLoader:
16
16
  """CouchDB report generator."""
17
17
 
18
- def __init__(self, config: CouchdbConfig):
18
+ def __init__(self, config: CouchdbConfig) -> None:
19
19
  self._log = getLogger(__name__)
20
20
  self._config: CouchdbConfig = config
21
21
  self._db_srv = DbServer(config.connection_string)