hardpy 0.2.0__py3-none-any.whl → 0.4.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 (28) hide show
  1. hardpy/__init__.py +9 -1
  2. hardpy/hardpy_panel/api.py +15 -0
  3. hardpy/hardpy_panel/frontend/dist/asset-manifest.json +3 -3
  4. hardpy/hardpy_panel/frontend/dist/index.html +1 -1
  5. hardpy/hardpy_panel/frontend/dist/static/js/main.37744128.js +3 -0
  6. hardpy/hardpy_panel/frontend/dist/static/js/main.37744128.js.map +1 -0
  7. hardpy/hardpy_panel/runner.py +2 -0
  8. hardpy/pytest_hardpy/db/base_store.py +21 -11
  9. hardpy/pytest_hardpy/db/const.py +1 -0
  10. hardpy/pytest_hardpy/db/schema.py +23 -2
  11. hardpy/pytest_hardpy/plugin.py +72 -4
  12. hardpy/pytest_hardpy/pytest_call.py +100 -11
  13. hardpy/pytest_hardpy/pytest_wrapper.py +29 -0
  14. hardpy/pytest_hardpy/reporter/base.py +30 -12
  15. hardpy/pytest_hardpy/reporter/hook_reporter.py +38 -40
  16. hardpy/pytest_hardpy/utils/__init__.py +17 -1
  17. hardpy/pytest_hardpy/utils/config_data.py +5 -1
  18. hardpy/pytest_hardpy/utils/dialog_box.py +100 -0
  19. hardpy/pytest_hardpy/utils/exception.py +7 -0
  20. hardpy/pytest_hardpy/utils/node_info.py +66 -0
  21. {hardpy-0.2.0.dist-info → hardpy-0.4.0.dist-info}/METADATA +9 -2
  22. {hardpy-0.2.0.dist-info → hardpy-0.4.0.dist-info}/RECORD +26 -25
  23. hardpy/hardpy_panel/frontend/dist/static/js/main.8ef63e9b.js +0 -3
  24. hardpy/hardpy_panel/frontend/dist/static/js/main.8ef63e9b.js.map +0 -1
  25. /hardpy/hardpy_panel/frontend/dist/static/js/{main.8ef63e9b.js.LICENSE.txt → main.37744128.js.LICENSE.txt} +0 -0
  26. {hardpy-0.2.0.dist-info → hardpy-0.4.0.dist-info}/WHEEL +0 -0
  27. {hardpy-0.2.0.dist-info → hardpy-0.4.0.dist-info}/entry_points.txt +0 -0
  28. {hardpy-0.2.0.dist-info → hardpy-0.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -21,6 +21,8 @@ def run():
21
21
  parser.add_argument("-dbh", "--db_host", type=str, default=config.db_host, help="database hostname") # noqa: E501
22
22
  parser.add_argument("-wh", "--web_host", type=str, default=config.web_host, help="web operator panel hostname") # noqa: E501
23
23
  parser.add_argument("-wp", "--web_port", type=str, default=config.web_port, help="web operator panel port") # noqa: E501
24
+ parser.add_argument("-sp", "--sck_port", type=int, default=config.socket_port, help="internal socket port") # noqa: E501
25
+ parser.add_argument("-sa", "--sck_addr", type=int, default=config.socket_port, help="internal socket address") # noqa: E501
24
26
  parser.add_argument("path", type=str, nargs='?', help="path to test directory")
25
27
  # fmt: on
26
28
 
@@ -36,19 +36,29 @@ class BaseStore(BaseConnector):
36
36
  """
37
37
  return glom(self._doc, key)
38
38
 
39
- def set_value(self, key: str, value):
40
- """Set a value in the state store."""
41
- assign(self._doc, key, value)
39
+ def update_doc(self, key: str, value):
40
+ """Update document.
41
+
42
+ HardPy collecting uses a simple key without dots.
43
+ Assign is used to update a document.
44
+ Assign is a longer function.
45
+
46
+ Args:
47
+ key (str): document key
48
+ value: document value
49
+ """
50
+ if "." in key:
51
+ assign(self._doc, key, value)
52
+ else:
53
+ self._doc[key] = value
54
+
55
+ def update_db(self):
56
+ """Update database by current document."""
42
57
  try:
43
58
  self._doc = self._db.save(self._doc)
44
- except Conflict as exc:
45
- self._log.error(
46
- f"Error while saving runner document: {exc} "
47
- f"when trying to save key={key}, value={value}. "
48
- "Current document will be changed by "
49
- "document from database."
50
- )
51
- self._doc = self._db.get(self._doc_id)
59
+ except Conflict:
60
+ self._doc["_rev"] = self._db.get(self._doc_id)["_rev"]
61
+ self._doc = self._db.save(self._doc)
52
62
 
53
63
  def get_document(self) -> ModelMetaclass:
54
64
  """Get document by schema.
@@ -23,3 +23,4 @@ class DatabaseField(str, Enum): # noqa: WPS600
23
23
  TEST_STAND = "test_stand"
24
24
  SERIAL_NUMBER = "serial_number"
25
25
  DRIVERS = "drivers"
26
+ DIALOG_BOX = "dialog_box"
@@ -29,12 +29,23 @@ class CaseStateStore(IBaseResult):
29
29
  "start_time": 1695817188,
30
30
  "stop_time": 1695817189,
31
31
  "assertion_msg": null,
32
- "msg": null
32
+ "msg": null,
33
+ "dialog_box": {
34
+ "title_bar": "Example of text input",
35
+ "dialog_text": "Type some text and press the Confirm button",
36
+ "widget": {
37
+ "info": {
38
+ "text": "some text"
39
+ },
40
+ "type": "textinput"
41
+ }
42
+ }
33
43
  }
34
44
  """
35
45
 
36
46
  assertion_msg: str | None = None
37
47
  msg: dict | None = None
48
+ dialog_box: dict = {}
38
49
 
39
50
 
40
51
  class CaseRunStore(IBaseResult):
@@ -175,7 +186,17 @@ class ResultStateStore(IBaseResult):
175
186
  "start_time": 1695817263,
176
187
  "stop_time": 1695817264,
177
188
  "assertion_msg": null,
178
- "msg": null
189
+ "msg": null,
190
+ "dialog_box": {
191
+ "title_bar": "Example of text input",
192
+ "dialog_text": "Type some text and press the Confirm button",
193
+ "widget": {
194
+ "info": {
195
+ "text": "some text"
196
+ },
197
+ "type": "textinput"
198
+ }
199
+ }
179
200
  },
180
201
  "test_minute_parity": {
181
202
  "status": "failed",
@@ -9,6 +9,7 @@ from platform import system
9
9
 
10
10
  from natsort import natsorted
11
11
  from pytest import (
12
+ skip,
12
13
  exit,
13
14
  TestReport,
14
15
  Item,
@@ -27,6 +28,7 @@ from hardpy.pytest_hardpy.utils import (
27
28
  ProgressCalculator,
28
29
  ConfigData,
29
30
  )
31
+ from hardpy.pytest_hardpy.utils.node_info import TestDependencyInfo
30
32
 
31
33
 
32
34
  def pytest_addoption(parser: Parser):
@@ -38,8 +40,11 @@ def pytest_addoption(parser: Parser):
38
40
  parser.addoption("--hardpy-dbp", action="store", default=config_data.db_port, help="database port number") # noqa: E501
39
41
  parser.addoption("--hardpy-dbh", action="store", default=config_data.db_host, help="database hostname") # noqa: E501
40
42
  parser.addoption("--hardpy-pt", action="store_true", default=False, help="enable pytest-hardpy plugin") # noqa: E501
43
+ parser.addoption("--hardpy-sp", action="store", default=config_data.socket_port, help="internal socket port") # noqa: E501
44
+ parser.addoption("--hardpy-sa", action="store", default=config_data.socket_addr, help="internal socket address") # noqa: E501
41
45
  # fmt: on
42
46
 
47
+
43
48
  # Bootstrapping hooks
44
49
  def pytest_load_initial_conftests(early_config, parser, args):
45
50
  if "--hardpy-pt" in args:
@@ -57,6 +62,7 @@ class HardpyPlugin(object):
57
62
  self._progress = ProgressCalculator()
58
63
  self._results = {}
59
64
  self._post_run_functions: list[Callable] = []
65
+ self._dependencies = {}
60
66
 
61
67
  if system() == "Linux":
62
68
  signal.signal(signal.SIGTERM, self._stop_handler)
@@ -64,7 +70,6 @@ class HardpyPlugin(object):
64
70
  signal.signal(signal.SIGBREAK, self._stop_handler)
65
71
  self._log = getLogger(__name__)
66
72
 
67
-
68
73
  # Initialization hooks
69
74
 
70
75
  def pytest_configure(self, config: Config):
@@ -74,9 +79,12 @@ class HardpyPlugin(object):
74
79
  config_data.db_host = config.getoption("--hardpy-dbh")
75
80
  config_data.db_pswd = config.getoption("--hardpy-dbpw")
76
81
  config_data.db_port = config.getoption("--hardpy-dbp")
82
+ config_data.socket_port = int(config.getoption("--hardpy-sp"))
83
+ config_data.socket_addr = config.getoption("--hardpy-sa")
77
84
 
78
85
  config.addinivalue_line("markers", "case_name")
79
86
  config.addinivalue_line("markers", "module_name")
87
+ config.addinivalue_line("markers", "dependency")
80
88
 
81
89
  # must be init after config data is set
82
90
  self._reporter = HookReporter()
@@ -92,6 +100,8 @@ class HardpyPlugin(object):
92
100
  return
93
101
  status = self._get_run_status(exitstatus)
94
102
  self._reporter.finish(status)
103
+ self._reporter.update_db_by_doc()
104
+ self._reporter.compact_all()
95
105
 
96
106
  # call post run methods
97
107
  if self._post_run_functions:
@@ -107,6 +117,7 @@ class HardpyPlugin(object):
107
117
  self._reporter.init_doc(str(PurePath(config.rootpath).name))
108
118
 
109
119
  nodes = {}
120
+ modules = set()
110
121
 
111
122
  session.items = natsorted(
112
123
  session.items,
@@ -115,18 +126,26 @@ class HardpyPlugin(object):
115
126
  for item in session.items:
116
127
  if item.parent is None:
117
128
  continue
118
- node_info = NodeInfo(item)
129
+ try:
130
+ node_info = NodeInfo(item)
131
+ except ValueError:
132
+ error_msg = f"Error creating NodeInfo for item: {item}\n"
133
+ exit(error_msg, 1)
119
134
 
120
135
  self._init_case_result(node_info.module_id, node_info.case_id)
121
-
122
136
  if node_info.module_id not in nodes:
123
137
  nodes[node_info.module_id] = [node_info.case_id]
124
138
  else:
125
139
  nodes[node_info.module_id].append(node_info.case_id)
126
140
 
127
141
  self._reporter.add_case(node_info)
128
- self._reporter.set_module_status(node_info.module_id, TestStatus.READY)
142
+
143
+ self._add_dependency(node_info, nodes)
144
+ modules.add(node_info.module_id)
145
+ for module_id in modules:
146
+ self._reporter.set_module_status(module_id, TestStatus.READY)
129
147
  self._reporter.update_node_order(nodes)
148
+ self._reporter.update_db_by_doc()
130
149
 
131
150
  # Test running (runtest) hooks
132
151
 
@@ -139,6 +158,7 @@ class HardpyPlugin(object):
139
158
 
140
159
  # testrun entrypoint
141
160
  self._reporter.start()
161
+ self._reporter.update_db_by_doc()
142
162
 
143
163
  def pytest_runtest_setup(self, item: Item):
144
164
  """Call before each test setup phase."""
@@ -148,6 +168,8 @@ class HardpyPlugin(object):
148
168
 
149
169
  node_info = NodeInfo(item)
150
170
 
171
+ self._handle_dependency(node_info)
172
+
151
173
  self._reporter.set_module_status(node_info.module_id, TestStatus.RUN)
152
174
  self._reporter.set_module_start_time(node_info.module_id)
153
175
  self._reporter.set_case_status(
@@ -159,6 +181,7 @@ class HardpyPlugin(object):
159
181
  node_info.module_id,
160
182
  node_info.case_id,
161
183
  )
184
+ self._reporter.update_db_by_doc()
162
185
 
163
186
  # Reporting hooks
164
187
 
@@ -188,6 +211,7 @@ class HardpyPlugin(object):
188
211
 
189
212
  if None not in self._results[module_id].values():
190
213
  self._collect_module_result(module_id)
214
+ self._reporter.update_db_by_doc()
191
215
 
192
216
  # Fixture
193
217
 
@@ -250,3 +274,47 @@ class HardpyPlugin(object):
250
274
  index = report.find("\nE")
251
275
  return report[:index]
252
276
  return None
277
+
278
+ def _handle_dependency(self, node_info: NodeInfo):
279
+ dependency = self._dependencies.get(
280
+ TestDependencyInfo(
281
+ node_info.module_id,
282
+ node_info.case_id,
283
+ )
284
+ )
285
+ if dependency and self._is_dependency_failed(dependency):
286
+ self._log.debug(f"Skipping test due to dependency: {dependency}")
287
+ self._results[node_info.module_id][node_info.case_id] = TestStatus.SKIPPED
288
+ skip(f"Test {node_info.module_id}::{node_info.case_id} is skipped")
289
+
290
+ def _is_dependency_failed(self, dependency) -> bool:
291
+ if isinstance(dependency, TestDependencyInfo):
292
+ incorrect_status = {
293
+ TestStatus.FAILED,
294
+ TestStatus.SKIPPED,
295
+ TestStatus.ERROR,
296
+ }
297
+ module_id, case_id = dependency
298
+ if case_id is not None:
299
+ return self._results[module_id][case_id] in incorrect_status
300
+ return any(
301
+ status in incorrect_status
302
+ for status in set(self._results[module_id].values())
303
+ )
304
+ return False
305
+
306
+ def _add_dependency(self, node_info, nodes):
307
+ dependency = node_info.dependency
308
+ if dependency is None or dependency == "":
309
+ return
310
+ module_id, case_id = dependency
311
+ if module_id not in nodes:
312
+ error_message = f"Error: Module dependency '{dependency}' not found."
313
+ exit(error_message, 1)
314
+ elif case_id not in nodes[module_id] and case_id is not None:
315
+ error_message = f"Error: Case dependency '{dependency}' not found."
316
+ exit(error_message, 1)
317
+
318
+ self._dependencies[
319
+ TestDependencyInfo(node_info.module_id, node_info.case_id)
320
+ ] = dependency
@@ -1,9 +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
+ import socket
4
5
  from os import environ
5
6
  from dataclasses import dataclass
6
- from typing import Optional
7
+ from typing import Optional, Any
7
8
  from uuid import uuid4
8
9
 
9
10
  from pycouchdb.exceptions import NotFound
@@ -14,7 +15,14 @@ from hardpy.pytest_hardpy.db import (
14
15
  ResultRunStore,
15
16
  RunStore,
16
17
  )
17
- from hardpy.pytest_hardpy.utils import DuplicateSerialNumberError
18
+ from hardpy.pytest_hardpy.utils import (
19
+ DuplicateSerialNumberError,
20
+ DuplicateDialogBoxError,
21
+ DialogBox,
22
+ ConfigData,
23
+ generate_dialog_box_dict,
24
+ get_dialog_box_data,
25
+ )
18
26
  from hardpy.pytest_hardpy.reporter import RunnerReporter
19
27
 
20
28
 
@@ -52,7 +60,8 @@ def set_dut_info(info: dict):
52
60
  reporter = RunnerReporter()
53
61
  for dut_key, dut_value in info.items():
54
62
  key = reporter.generate_key(DF.DUT, DF.INFO, dut_key)
55
- reporter.set_db_value(key, dut_value)
63
+ reporter.set_doc_value(key, dut_value)
64
+ reporter.update_db_by_doc()
56
65
 
57
66
 
58
67
  def set_dut_serial_number(serial_number: str):
@@ -68,7 +77,8 @@ def set_dut_serial_number(serial_number: str):
68
77
  key = reporter.generate_key(DF.DUT, DF.SERIAL_NUMBER)
69
78
  if reporter.get_field(key):
70
79
  raise DuplicateSerialNumberError
71
- reporter.set_db_value(key, serial_number)
80
+ reporter.set_doc_value(key, serial_number)
81
+ reporter.update_db_by_doc()
72
82
 
73
83
 
74
84
  def set_stand_info(info: dict):
@@ -80,7 +90,8 @@ def set_stand_info(info: dict):
80
90
  reporter = RunnerReporter()
81
91
  for stand_key, stand_value in info.items():
82
92
  key = reporter.generate_key(DF.TEST_STAND, stand_key)
83
- reporter.set_db_value(key, stand_value)
93
+ reporter.set_doc_value(key, stand_value)
94
+ reporter.update_db_by_doc()
84
95
 
85
96
 
86
97
  def set_message(msg: str, msg_key: Optional[str] = None) -> None:
@@ -111,7 +122,8 @@ def set_message(msg: str, msg_key: Optional[str] = None) -> None:
111
122
 
112
123
  msgs[msg_key] = msg
113
124
 
114
- reporter.set_db_value(key, msgs)
125
+ reporter.set_doc_value(key, msgs)
126
+ reporter.update_db_by_doc()
115
127
 
116
128
 
117
129
  def set_case_artifact(data: dict):
@@ -134,7 +146,8 @@ def set_case_artifact(data: dict):
134
146
  DF.ARTIFACT,
135
147
  stand_key,
136
148
  )
137
- reporter.set_db_value(key, stand_value, is_statestore=False)
149
+ reporter.set_doc_value(key, stand_value, runstore_only=True)
150
+ reporter.update_db_by_doc()
138
151
 
139
152
 
140
153
  def set_module_artifact(data: dict):
@@ -155,7 +168,8 @@ def set_module_artifact(data: dict):
155
168
  DF.ARTIFACT,
156
169
  artifact_key,
157
170
  )
158
- reporter.set_db_value(key, artifact_value, is_statestore=False)
171
+ reporter.set_doc_value(key, artifact_value, runstore_only=True)
172
+ reporter.update_db_by_doc()
159
173
 
160
174
 
161
175
  def set_run_artifact(data: dict):
@@ -173,11 +187,12 @@ def set_run_artifact(data: dict):
173
187
  DF.ARTIFACT,
174
188
  artifact_key,
175
189
  )
176
- reporter.set_db_value(key, artifact_value, is_statestore=False)
190
+ reporter.set_doc_value(key, artifact_value, runstore_only=True)
191
+ reporter.update_db_by_doc()
177
192
 
178
193
 
179
194
  def set_driver_info(drivers: dict) -> None:
180
- """Adds or updates drivers data.
195
+ """Add or update drivers data.
181
196
 
182
197
  Driver data is stored in both StateStore and RunStore databases.
183
198
 
@@ -192,7 +207,58 @@ def set_driver_info(drivers: dict) -> None:
192
207
  DF.DRIVERS,
193
208
  driver_name,
194
209
  )
195
- reporter.set_db_value(key, driver_data)
210
+ reporter.set_doc_value(key, driver_data)
211
+ reporter.update_db_by_doc()
212
+
213
+
214
+ def run_dialog_box(dialog_box_data: DialogBox) -> Any:
215
+ """Display a dialog box.
216
+
217
+ Args:
218
+ dialog_box_data (DialogBox): Data for creating the dialog box.
219
+
220
+ DialogBox attributes:
221
+
222
+ - dialog_text (str): The text of the dialog box.
223
+ - title_bar (str | None): The title bar of the dialog box.
224
+ If the title_bar field is missing, it is the case name.
225
+ - widget (DialogBoxWidget | None): Widget information.
226
+
227
+ Returns:
228
+ Any: An object containing the user's response.
229
+
230
+ The type of the return value depends on the widget type:
231
+
232
+ - Without widget: None.
233
+ - TEXT_INPUT: str.
234
+ - NUMERIC_INPUT: float.
235
+
236
+ Raises:
237
+ ValueError: If the 'message' argument is empty.
238
+ DuplicateDialogBoxError: If the dialog box is already caused.
239
+ """
240
+ if not dialog_box_data.dialog_text:
241
+ raise ValueError("The 'dialog_text' argument cannot be empty.")
242
+
243
+ current_test = _get_current_test()
244
+ reporter = RunnerReporter()
245
+ key = reporter.generate_key(
246
+ DF.MODULES,
247
+ current_test.module_id,
248
+ DF.CASES,
249
+ current_test.case_id,
250
+ DF.DIALOG_BOX,
251
+ )
252
+ if reporter.get_field(key):
253
+ raise DuplicateDialogBoxError
254
+ data_dict = generate_dialog_box_dict(dialog_box_data)
255
+
256
+ reporter.set_doc_value(key, data_dict, statestore_only=True)
257
+ reporter.update_db_by_doc()
258
+
259
+ dialog_raw_data = _get_socket_raw_data()
260
+
261
+ return get_dialog_box_data(dialog_raw_data, dialog_box_data.widget)
196
262
 
197
263
 
198
264
  def _get_current_test() -> CurrentTestInfo:
@@ -216,3 +282,26 @@ def _get_current_test() -> CurrentTestInfo:
216
282
  case_id = case_with_stage[:case_id_end_index]
217
283
 
218
284
  return CurrentTestInfo(module_id=module_id, case_id=case_id)
285
+
286
+
287
+ def _get_socket_raw_data() -> str:
288
+ # create socket connection
289
+ server = socket.socket()
290
+ server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
291
+ config_data = ConfigData()
292
+ try:
293
+ server.bind((config_data.socket_addr, config_data.socket_port))
294
+ except socket.error as exc:
295
+ raise RuntimeError(f"Error creating socket: {exc}")
296
+ server.listen(1)
297
+ client, _ = server.accept()
298
+
299
+ # receive data
300
+ max_input_data_len = 1024
301
+ socket_data = client.recv(max_input_data_len).decode("utf-8")
302
+
303
+ # close connection
304
+ client.close()
305
+ server.close()
306
+
307
+ return socket_data
@@ -4,6 +4,7 @@
4
4
  import sys
5
5
  import signal
6
6
  import subprocess
7
+ from socket import socket
7
8
  from platform import system
8
9
 
9
10
  from hardpy.pytest_hardpy.utils.config_data import ConfigData
@@ -46,6 +47,10 @@ class PyTestWrapper(object):
46
47
  self.config.db_user,
47
48
  "--hardpy-dbpw",
48
49
  self.config.db_pswd,
50
+ "--hardpy-sp",
51
+ str(self.config.socket_port),
52
+ "--hardpy-sa",
53
+ self.config.socket_addr,
49
54
  "--hardpy-pt",
50
55
  ],
51
56
  cwd=self.config.tests_dir.absolute(),
@@ -64,6 +69,10 @@ class PyTestWrapper(object):
64
69
  self.config.db_user,
65
70
  "--hardpy-dbpw",
66
71
  self.config.db_pswd,
72
+ "--hardpy-sp",
73
+ str(self.config.socket_port),
74
+ "--hardpy-sa",
75
+ self.config.socket_addr,
67
76
  "--hardpy-pt",
68
77
  ],
69
78
  cwd=self.config.tests_dir.absolute(),
@@ -115,6 +124,26 @@ class PyTestWrapper(object):
115
124
  )
116
125
  return True
117
126
 
127
+ def confirm_dialog_box(self, dialog_box_output: str):
128
+ """Set dialog box data to pytest subprocess.
129
+
130
+ Args:
131
+ dialog_box_output (str): dialog box output data
132
+
133
+ Returns:
134
+ bool: True if dialog box was confirmed, else False
135
+ """
136
+ config_data = ConfigData()
137
+
138
+ try:
139
+ client = socket()
140
+ client.connect((config_data.socket_addr, config_data.socket_port))
141
+ client.sendall(dialog_box_output.encode("utf-8"))
142
+ client.close()
143
+ except Exception:
144
+ return False
145
+ return True
146
+
118
147
  def is_running(self) -> bool | None:
119
148
  """Check if pytest is running."""
120
149
  return self._proc and self._proc.poll() is None
@@ -14,21 +14,39 @@ class BaseReporter(object):
14
14
  self._runstore = RunStore()
15
15
  self._log = getLogger(__name__)
16
16
 
17
- def set_db_value(self, key: str, value, is_statestore=True, is_runstore=True):
18
- """Set value to database.
17
+ def set_doc_value(
18
+ self, key: str, value, runstore_only=False, statestore_only=False
19
+ ):
20
+ """Set value to the document.
21
+
22
+ Update a document without writing to the database.
19
23
 
20
24
  Args:
21
- key (str): database key
22
- value (_type_): database value
23
- is_statestore (bool, optional): indicates whether data should
24
- be written to StateStore. Defaults to True.
25
- is_runstore (bool, optional): indicates whether data should
26
- be written to RunStore. Defaults to True.
25
+ key (str): document key
26
+ value: document value
27
+ runstore_only (bool, optional): indicates whether data should
28
+ be written to RunStore. Defaults to True.
29
+ statestore_only (bool, optional): indicates whether data should
30
+ be written to StateStore. Defaults to True.
31
+
32
+ Raises:
33
+ ValueError: if both runstore_only and statestore_only are True
27
34
  """
28
- if is_statestore:
29
- self._statestore.set_value(key, value)
30
- if is_runstore:
31
- self._runstore.set_value(key, value)
35
+ if runstore_only and statestore_only:
36
+ raise ValueError("Both runstore_only and statestore_only cannot be True")
37
+ if runstore_only:
38
+ self._runstore.update_doc(key, value)
39
+ return
40
+ if statestore_only:
41
+ self._statestore.update_doc(key, value)
42
+ return
43
+ self._runstore.update_doc(key, value)
44
+ self._statestore.update_doc(key, value)
45
+
46
+ def update_db_by_doc(self):
47
+ """Update database by current document."""
48
+ self._statestore.update_db()
49
+ self._runstore.update_db()
32
50
 
33
51
  def generate_key(self, *args) -> str:
34
52
  """Generate key for database.