robotframework-dashboard 1.3.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 (79) hide show
  1. robotframework_dashboard/__init__.py +0 -0
  2. robotframework_dashboard/abstractdb.py +60 -0
  3. robotframework_dashboard/arguments.py +459 -0
  4. robotframework_dashboard/css/styling.css +431 -0
  5. robotframework_dashboard/dashboard.py +126 -0
  6. robotframework_dashboard/database.py +371 -0
  7. robotframework_dashboard/dependencies/bootstrap.css +6 -0
  8. robotframework_dashboard/dependencies/bootstrap.js +7 -0
  9. robotframework_dashboard/dependencies/chart.js +20 -0
  10. robotframework_dashboard/dependencies/chartjs-adapter-date-fns.js +7 -0
  11. robotframework_dashboard/dependencies/chartjs-chart-boxplot.js +2 -0
  12. robotframework_dashboard/dependencies/chartjs-chart-matrix.js +8 -0
  13. robotframework_dashboard/dependencies/chartjs-plugin-datalabels.js +7 -0
  14. robotframework_dashboard/dependencies/datatables.css +18 -0
  15. robotframework_dashboard/dependencies/datatables.js +25 -0
  16. robotframework_dashboard/dependencies/gridstack.css +1 -0
  17. robotframework_dashboard/dependencies/gridstack.js +9 -0
  18. robotframework_dashboard/dependencies/pako.js +2 -0
  19. robotframework_dashboard/dependencies.py +222 -0
  20. robotframework_dashboard/js/admin_page/admin_api.js +218 -0
  21. robotframework_dashboard/js/admin_page/admin_common.js +26 -0
  22. robotframework_dashboard/js/admin_page/admin_eventlisteners.js +102 -0
  23. robotframework_dashboard/js/admin_page/admin_information.js +128 -0
  24. robotframework_dashboard/js/admin_page/admin_main.js +20 -0
  25. robotframework_dashboard/js/admin_page/admin_theme.js +129 -0
  26. robotframework_dashboard/js/common.js +169 -0
  27. robotframework_dashboard/js/database.js +18 -0
  28. robotframework_dashboard/js/eventlisteners.js +675 -0
  29. robotframework_dashboard/js/filter.js +662 -0
  30. robotframework_dashboard/js/graph_creation/all.js +107 -0
  31. robotframework_dashboard/js/graph_creation/compare.js +77 -0
  32. robotframework_dashboard/js/graph_creation/keyword.js +360 -0
  33. robotframework_dashboard/js/graph_creation/overview.js +589 -0
  34. robotframework_dashboard/js/graph_creation/run.js +154 -0
  35. robotframework_dashboard/js/graph_creation/suite.js +338 -0
  36. robotframework_dashboard/js/graph_creation/tables.js +188 -0
  37. robotframework_dashboard/js/graph_creation/test.js +475 -0
  38. robotframework_dashboard/js/graph_data/donut.js +289 -0
  39. robotframework_dashboard/js/graph_data/duration.js +188 -0
  40. robotframework_dashboard/js/graph_data/duration_deviation.js +50 -0
  41. robotframework_dashboard/js/graph_data/failed.js +118 -0
  42. robotframework_dashboard/js/graph_data/flaky.js +155 -0
  43. robotframework_dashboard/js/graph_data/graph_config.js +332 -0
  44. robotframework_dashboard/js/graph_data/heatmap.js +62 -0
  45. robotframework_dashboard/js/graph_data/helpers.js +111 -0
  46. robotframework_dashboard/js/graph_data/messages.js +116 -0
  47. robotframework_dashboard/js/graph_data/statistics.js +219 -0
  48. robotframework_dashboard/js/graph_data/stats.js +43 -0
  49. robotframework_dashboard/js/graph_data/time_consuming.js +201 -0
  50. robotframework_dashboard/js/information.js +105 -0
  51. robotframework_dashboard/js/layout.js +451 -0
  52. robotframework_dashboard/js/localstorage.js +221 -0
  53. robotframework_dashboard/js/log.js +122 -0
  54. robotframework_dashboard/js/main.js +26 -0
  55. robotframework_dashboard/js/menu.js +252 -0
  56. robotframework_dashboard/js/theme.js +215 -0
  57. robotframework_dashboard/js/variables/chartconfig.js +88 -0
  58. robotframework_dashboard/js/variables/data.js +35 -0
  59. robotframework_dashboard/js/variables/globals.js +74 -0
  60. robotframework_dashboard/js/variables/graphmetadata.js +940 -0
  61. robotframework_dashboard/js/variables/graphs.js +69 -0
  62. robotframework_dashboard/js/variables/information.js +271 -0
  63. robotframework_dashboard/js/variables/settings.js +85 -0
  64. robotframework_dashboard/js/variables/svg.js +116 -0
  65. robotframework_dashboard/licenses/THIRD_PARTY_LICENSES.txt +250 -0
  66. robotframework_dashboard/main.py +88 -0
  67. robotframework_dashboard/processors.py +304 -0
  68. robotframework_dashboard/queries.py +45 -0
  69. robotframework_dashboard/robotdashboard.py +245 -0
  70. robotframework_dashboard/server.py +593 -0
  71. robotframework_dashboard/templates/admin.html +350 -0
  72. robotframework_dashboard/templates/dashboard.html +713 -0
  73. robotframework_dashboard/version.py +1 -0
  74. robotframework_dashboard-1.3.1.dist-info/METADATA +101 -0
  75. robotframework_dashboard-1.3.1.dist-info/RECORD +79 -0
  76. robotframework_dashboard-1.3.1.dist-info/WHEEL +5 -0
  77. robotframework_dashboard-1.3.1.dist-info/entry_points.txt +2 -0
  78. robotframework_dashboard-1.3.1.dist-info/licenses/LICENSE +21 -0
  79. robotframework_dashboard-1.3.1.dist-info/top_level.txt +1 -0
File without changes
@@ -0,0 +1,60 @@
1
+ from abc import ABC, abstractmethod
2
+ from pathlib import Path
3
+
4
+ class AbstractDatabaseProcessor(ABC):
5
+
6
+ def __init_subclass__(cls, **kwargs):
7
+ """Function to validate that the custom dabataseclass is named 'DatabaseProcessor' correctly"""
8
+ super().__init_subclass__(**kwargs)
9
+ if cls.__name__ != "DatabaseProcessor":
10
+ raise TypeError(f"The custom databaseclass classname must be 'DatabaseProcessor', not '{cls.__name__}'")
11
+
12
+ @abstractmethod
13
+ def __init__(self, database_path: Path) -> None:
14
+ """Mandatory: This function should handle the creation of the tables if required
15
+ The use of the database_path variable might not be required but you should still keep it as an argument!
16
+ """
17
+ pass
18
+
19
+ @abstractmethod
20
+ def open_database(self) -> None:
21
+ """Mandatory: This function should handle the connection to the database and set it for other functions to use"""
22
+ pass
23
+
24
+ @abstractmethod
25
+ def close_database(self) -> None:
26
+ """Mandatory: This function is called to close the connection to the database"""
27
+ pass
28
+
29
+ @abstractmethod
30
+ def run_start_exists(self, run_start: str) -> bool:
31
+ """Mandatory: This function is called to check if the output is already present in the database, this is done to save time on needless reprocessing.
32
+ If you want a very simple implementation without complex logic you can simply "return False". This will work but will reprocess needlessly.
33
+ """
34
+ pass
35
+
36
+ @abstractmethod
37
+ def insert_output_data(
38
+ self, output_data: dict, tags: list, run_alias: str, path: Path, project_version: str
39
+ ) -> None:
40
+ """Mandatory: This function inserts the data of an output file into the database"""
41
+ pass
42
+
43
+ @abstractmethod
44
+ def get_data(self) -> dict:
45
+ """Mandatory: This function gets all the data in the database"""
46
+ pass
47
+
48
+ @abstractmethod
49
+ def list_runs(self) -> None:
50
+ """Mandatory: This function gets all available runs and prints them to the console"""
51
+ pass
52
+
53
+ @abstractmethod
54
+ def remove_runs(self, remove_runs: list) -> None:
55
+ """Mandatory: This function removes all provided runs and all their corresponding data"""
56
+ pass
57
+
58
+ def update_output_path(self, log_path: str) -> None:
59
+ """Optional: Function to update the output_path using the log path that the server has used"""
60
+ raise NotImplementedError("update_output_path is not implemented in the custom databaseclass, but is only required when using the server!")
@@ -0,0 +1,459 @@
1
+ import argparse
2
+ from datetime import datetime
3
+ from sys import exit
4
+ from re import split
5
+ from os import getcwd
6
+ from os.path import join, exists
7
+ from .version import __version__
8
+
9
+
10
+ class dotdict(dict):
11
+ """dot.notation access to dictionary attributes"""
12
+
13
+ __getattr__ = dict.get
14
+ __setattr__ = dict.__setitem__
15
+ __delattr__ = dict.__delitem__
16
+
17
+
18
+ class ArgumentParser:
19
+ """Parse the input arguments that can be provided to robotdashboard
20
+ Only get_arguments is called, all other functions are helper functions"""
21
+
22
+ def get_arguments(self):
23
+ """The function that handles the complete parsing process"""
24
+ try:
25
+ arguments = self._parse_arguments()
26
+ arguments = self._process_arguments(arguments)
27
+ except Exception as error:
28
+ print(
29
+ f" ERROR: There was an issue during the parsing of the provided arguments"
30
+ )
31
+ print(f" {error}")
32
+ exit(0)
33
+ return arguments
34
+
35
+ def _normalize_bool(self, value, arg_name):
36
+ """
37
+ Checks the boolean value and returns the correct boolean or exits with error
38
+ """
39
+ v = str(value).lower()
40
+ if v == "true":
41
+ return True
42
+ elif v == "false":
43
+ return False
44
+ else:
45
+ print(
46
+ f" ERROR: The provided value: '{value}' for --{arg_name} is invalid\n"
47
+ f" Please provide True, False, or leave empty for the reverse boolean of the default\n"
48
+ f" See the --h / --help for more information and usage examples"
49
+ )
50
+ exit(0)
51
+
52
+ def _parse_arguments(self):
53
+ """Parses the actual arguments"""
54
+ parser = argparse.ArgumentParser(
55
+ add_help=False,
56
+ formatter_class=argparse.RawTextHelpFormatter,
57
+ epilog="For full documentation, visit: https://timdegroot1996.github.io/robotframework-dashboard/",
58
+ )
59
+ parser.add_argument(
60
+ "-v",
61
+ "--version",
62
+ action="store_true",
63
+ dest="version",
64
+ help="Display application version information.\n",
65
+ )
66
+ parser.add_argument(
67
+ "-h",
68
+ "--help",
69
+ help="Provide additional information.\n",
70
+ action="help",
71
+ default=argparse.SUPPRESS,
72
+ )
73
+ parser.add_argument(
74
+ "-o",
75
+ "--outputpath",
76
+ help=(
77
+ "`path` Specifies one or more paths to output.xml.\n"
78
+ "Usage behavior:\n"
79
+ " • Multiple XML files: repeat '-o' for each file\n"
80
+ " • Accepts files or paths to files\n"
81
+ " • Optional tags can be provided by appending ':tag1:tag2' to the path\n"
82
+ "Examples:\n"
83
+ " • '-o path/to/output1.xml' -> add one output\n"
84
+ " • '-o output2.xml:dev:nightly -o output3.xml:prod' -> add two outputs with tags\n"
85
+ ),
86
+ action="append",
87
+ nargs="*",
88
+ default=None,
89
+ )
90
+ parser.add_argument(
91
+ "-f",
92
+ "--outputfolderpath",
93
+ help=(
94
+ "`path` Specifies a directory path scanned recursively for *output*.xml files.\n"
95
+ "Usage behavior:\n"
96
+ " • Provide a folder path\n"
97
+ " • All matching *output*.xml files in all subfolders will be included\n"
98
+ " • Optional tags can be provided by appending ':tag1:tag2' to the path\n"
99
+ "Examples:\n"
100
+ " • '-f results/' -> scan folder for output files\n"
101
+ " • '-f results/' -f path/to/more_results/:prod:regression -> multiple folders with tags\n"
102
+ ),
103
+ action="append",
104
+ nargs="*",
105
+ default=None,
106
+ )
107
+ parser.add_argument(
108
+ "--projectversion",
109
+ help=(
110
+ "`string` specifies project version associated with runs\n"
111
+ "Usage behaviour:\n"
112
+ " • Provide text to set a project version for the supplied runs\n"
113
+ "Examples:\n"
114
+ " . '--projectversion=1.1'\n"
115
+ " . '--projectversion=1.1'\n"
116
+ ),
117
+ dest="project_version",
118
+ type=str,
119
+ default=None,
120
+ )
121
+ parser.add_argument(
122
+ "-r",
123
+ "--removeruns",
124
+ help=(
125
+ "`string` Specifies indexes, run_starts, aliases or tags to remove from the database.\n"
126
+ "Usage behavior:\n"
127
+ " • Multiple values separated by commas (,)\n"
128
+ " • Must specify data types: index, run_start, alias or tag\n"
129
+ " • Ranges supported using ':' and lists using ';'\n"
130
+ "Examples:\n"
131
+ " • '-r index=0,index=1:4;9,index=10' -> remove index 0, 1, 2, 3, 9, 10\n"
132
+ " • '-r run_start=2024-07-30 15:27:20.184407,index=20' -> remove specified run and index 20\n"
133
+ " • '-r alias=some_alias,tag=prod,tag=dev' -> remove all runs with alias some_alias or tag prod or dev\n"
134
+ ),
135
+ action="append",
136
+ nargs="*",
137
+ default=None,
138
+ )
139
+ parser.add_argument(
140
+ "-d",
141
+ "--databasepath",
142
+ help=(
143
+ "`path` Specifies the path to the database file.\n"
144
+ "Usage behavior:\n"
145
+ " • Default value: robot_results.db\n"
146
+ " • Provide a custom .db file to use instead of the default\n"
147
+ "Examples:\n"
148
+ " • '-d path/to/myresults.db'\n"
149
+ ),
150
+ default="robot_results.db",
151
+ )
152
+ parser.add_argument(
153
+ "-n",
154
+ "--namedashboard",
155
+ help=(
156
+ "`string` Specifies a custom HTML dashboard file name.\n"
157
+ "Usage behavior:\n"
158
+ " • Default value: robot_dashboard_yyyymmdd-hhssmm.html\n"
159
+ " • Provide a filename to override\n"
160
+ "Examples:\n"
161
+ " • '-n dashboard.html'\n"
162
+ ),
163
+ default="",
164
+ )
165
+ parser.add_argument(
166
+ "-j",
167
+ "--jsonconfig",
168
+ help=(
169
+ "`path` Specifies a path to a dashboard JSON configuration.\n"
170
+ "Usage behavior:\n"
171
+ " • Default value: None\n"
172
+ " • File is used as the initial configuration if no config exists yet in user localstorage\n"
173
+ "Examples:\n"
174
+ " • '-j settings.json'\n"
175
+ ),
176
+ default=None,
177
+ )
178
+ parser.add_argument(
179
+ "-t",
180
+ "--dashboardtitle",
181
+ help=(
182
+ "`string` Specifies the dashboard HTML title.\n"
183
+ "Usage behavior:\n"
184
+ " • Default value: Robot Framework Dashboard - yyyy-mm-dd hh:mm:ss\n"
185
+ " • Provide text to set a custom title\n"
186
+ "Examples:\n"
187
+ " • '-t My_Test_Dashboard'\n"
188
+ ),
189
+ default="",
190
+ )
191
+ parser.add_argument(
192
+ "-m",
193
+ "--messageconfig",
194
+ help=(
195
+ "`path` Specifies a config file containing message templates.\n"
196
+ "Usage behavior:\n"
197
+ " • Default value: None\n"
198
+ " • File should contain lines with placeholders like ${value}\n"
199
+ "Examples:\n"
200
+ " • 'The test has failed on date: ${date}' -> example line in messages.txt\n"
201
+ " • 'Expected ${x} but received: ${y}' -> example line in messages.txt\n"
202
+ " • '-m messages.txt'\n"
203
+ ),
204
+ default=None,
205
+ )
206
+ parser.add_argument(
207
+ "-q",
208
+ "--quantity",
209
+ help=(
210
+ "`integer` Specifies the number of runs shown on initial dashboard load.\n"
211
+ "Usage behavior:\n"
212
+ " • Default value: 20\n"
213
+ " • Provide an integer to override, the higher this number the slower initial load\n"
214
+ "Examples:\n"
215
+ " • '-q 25'\n"
216
+ ),
217
+ default=None,
218
+ )
219
+ parser.add_argument(
220
+ "-u",
221
+ "--uselogs",
222
+ help=(
223
+ "`boolean` Enables clickable graphs linking to log.html.\n"
224
+ "Usage behavior:\n"
225
+ " • Default value: False\n"
226
+ " • Using '--uselogs' with no value -> True (reverse default)\n"
227
+ " • Using '--uselogs true' -> True\n"
228
+ " • Using '--uselogs false' -> False\n"
229
+ ),
230
+ nargs="?",
231
+ const=True,
232
+ default=False,
233
+ )
234
+
235
+ parser.add_argument(
236
+ "-g",
237
+ "--generatedashboard",
238
+ help=(
239
+ "`boolean` Whether to generate the HTML dashboard.\n"
240
+ "Usage behavior:\n"
241
+ " • Default value: True\n"
242
+ " • Using '--generatedashboard' with no value -> False (reverse default)\n"
243
+ " • Using '--generatedashboard true' -> True\n"
244
+ " • Using '--generatedashboard false' -> False\n"
245
+ ),
246
+ nargs="?",
247
+ const=False,
248
+ default=True,
249
+ )
250
+
251
+ parser.add_argument(
252
+ "-l",
253
+ "--listruns",
254
+ help=(
255
+ "`boolean` Whether runs should be listed in the dashboard.\n"
256
+ "Usage behavior:\n"
257
+ " • Default value: True\n"
258
+ " • Using '--listruns' with no value -> False (reverse default)\n"
259
+ " • Using '--listruns true' -> True\n"
260
+ " • Using '--listruns false' -> False\n"
261
+ ),
262
+ nargs="?",
263
+ const=False,
264
+ default=True,
265
+ )
266
+
267
+ parser.add_argument(
268
+ "--offlinedependencies",
269
+ help=(
270
+ "`boolean` Use locally embedded JS/CSS instead of CDN.\n"
271
+ "Usage behavior:\n"
272
+ " • Default value: False\n"
273
+ " • Using '--offlinedependencies' with no value -> True (reverse default)\n"
274
+ " • Using '--offlinedependencies true' -> True\n"
275
+ " • Using '--offlinedependencies false' -> False\n"
276
+ ),
277
+ nargs="?",
278
+ const=True,
279
+ default=False,
280
+ )
281
+
282
+ parser.add_argument(
283
+ "-c",
284
+ "--databaseclass",
285
+ help=(
286
+ "`path` Specifies a custom database class to override SQLite.\n"
287
+ "Usage behavior:\n"
288
+ " • Default value: None (built-in SQLite engine)\n"
289
+ " • Provide a .py file implementing a compatible database handler\n"
290
+ " • Detailed instructions can be found in the docs (url at the bottom of the help)\n"
291
+ "Examples:\n"
292
+ " • '-c customdb.py'\n"
293
+ ),
294
+ default=None,
295
+ )
296
+
297
+ parser.add_argument(
298
+ "-s",
299
+ "--server",
300
+ nargs="?", # Makes the argument optional
301
+ const="default", # Value to use if the flag is given without an argument
302
+ help=(
303
+ "Starts the dashboard webserver.\n"
304
+ "Usage behavior:\n"
305
+ " • Default value: None (no webserver)\n"
306
+ " • Provide 'default[:username:password]'\n"
307
+ " • Or provide 'host:port[:username:password]'\n"
308
+ " • Detailed instructions can be found in the docs (url at the bottom of the help)\n"
309
+ "Examples:\n"
310
+ " • '--server' -> results in default behavior\n"
311
+ " • '--server default' -> default behaviour\n"
312
+ " • '--server 0.0.0.0:8080' -> custom host/port\n"
313
+ " • '--server 0.0.0.0:8080:admin:secret' -> custom host/port and admin username/password\n"
314
+ ),
315
+ )
316
+ return parser.parse_args()
317
+
318
+ def _process_arguments(self, arguments):
319
+ """handles the version execution"""
320
+ if arguments.version:
321
+ print(__version__)
322
+ exit(0)
323
+
324
+ # handles possible tags on all provided --outputpath
325
+ outputs = None
326
+ if arguments.outputpath:
327
+ outputs = []
328
+ for output in arguments.outputpath:
329
+ splitted = split(r":(?!(\/|\\))", output[0])
330
+ while None in splitted:
331
+ splitted.remove(
332
+ None
333
+ ) # None values are found by re.split because of the 2 conditions
334
+ path = splitted[0]
335
+ tags = splitted[1:]
336
+ outputs.append([path, tags])
337
+
338
+ # handles possible tags on all provided --outputfolderpath
339
+ outputfolderpaths = None
340
+ if arguments.outputfolderpath:
341
+ outputfolderpaths = []
342
+ for folder in arguments.outputfolderpath:
343
+ splitted = split(r":(?!(\/|\\))", folder[0])
344
+ while None in splitted:
345
+ splitted.remove(
346
+ None
347
+ ) # None values are found by re.split because of the 2 conditions
348
+ path = splitted[0]
349
+ tags = splitted[1:]
350
+ outputfolderpaths.append([path, tags])
351
+
352
+ # handles the processing of --removeruns
353
+ remove_runs = None
354
+ if arguments.removeruns:
355
+ remove_runs = []
356
+ for runs in arguments.removeruns:
357
+ parts = str(runs[0]).split(",")
358
+ for part in parts:
359
+ remove_runs.append(part)
360
+
361
+ # handles the boolean handling of relevant arguments
362
+ generate_dashboard = self._normalize_bool(arguments.generatedashboard, "generatedashboard")
363
+ list_runs = self._normalize_bool(arguments.listruns, "listruns")
364
+ offline_dependencies = self._normalize_bool(arguments.offlinedependencies, "offlinedependencies")
365
+ use_logs = self._normalize_bool(arguments.uselogs, "uselogs")
366
+
367
+ # generates the datetime used in the file dashboard name and the html title
368
+ generation_datetime = datetime.now()
369
+
370
+ # handles the custom test message handling
371
+ message_config = []
372
+ if arguments.messageconfig:
373
+ with open(arguments.messageconfig) as file:
374
+ for line in file:
375
+ message_config.append(line.strip())
376
+
377
+ # handles the json config
378
+ json_config = []
379
+ if arguments.jsonconfig:
380
+ with open(arguments.jsonconfig) as file:
381
+ json_config = file.read()
382
+
383
+ # handles the custom dashboard name
384
+ if arguments.namedashboard == "":
385
+ dashboard_name = (
386
+ f"robot_dashboard_{generation_datetime.strftime('%Y%m%d-%H%M%S')}.html"
387
+ )
388
+ elif not arguments.namedashboard.endswith(".html"):
389
+ dashboard_name = f"{arguments.namedashboard}.html"
390
+ else:
391
+ dashboard_name = arguments.namedashboard
392
+
393
+ # handles the databaseclass implementation and provides the complete path to the module
394
+ database_class = None
395
+ if arguments.databaseclass:
396
+ database_class = join(getcwd(), arguments.databaseclass).replace(
397
+ "\\.\\", "\\"
398
+ )
399
+ if not exists(database_class):
400
+ raise Exception(
401
+ f" ERROR: the provided database class did not exist in the expected path: {database_class}"
402
+ )
403
+
404
+ # handles the server argument
405
+ server_host = "127.0.0.1"
406
+ server_port = 8543
407
+ server_user = ""
408
+ server_pass = ""
409
+ if arguments.server:
410
+ start_server = True
411
+ parts = arguments.server.split(":")
412
+
413
+ if parts[0] == "default":
414
+ # e.g. default[:username:password]
415
+ if len(parts) == 3:
416
+ server_user = parts[1]
417
+ server_pass = parts[2]
418
+ else:
419
+ # e.g. host:port or host:port:username:password
420
+ server_host = parts[0]
421
+ server_port = int(parts[1])
422
+ if len(parts) == 4:
423
+ server_user = parts[2]
424
+ server_pass = parts[3]
425
+ else:
426
+ start_server = False
427
+
428
+ # handles the quantity argument
429
+ quantity = arguments.quantity
430
+ if quantity == None:
431
+ quantity = 20
432
+ else:
433
+ int(quantity)
434
+
435
+ # return all provided arguments
436
+ provided_args = {
437
+ "outputs": outputs,
438
+ "output_folder_paths": outputfolderpaths,
439
+ "database_path": arguments.databasepath,
440
+ "generate_dashboard": generate_dashboard,
441
+ "dashboard_name": dashboard_name,
442
+ "generation_datetime": generation_datetime,
443
+ "list_runs": list_runs,
444
+ "remove_runs": remove_runs,
445
+ "dashboard_title": arguments.dashboardtitle,
446
+ "database_class": database_class,
447
+ "start_server": start_server,
448
+ "server_host": server_host,
449
+ "server_port": server_port,
450
+ "server_user": server_user,
451
+ "server_pass": server_pass,
452
+ "json_config": json_config,
453
+ "message_config": message_config,
454
+ "quantity": quantity,
455
+ "use_logs": use_logs,
456
+ "offline_dependencies": offline_dependencies,
457
+ "project_version": arguments.project_version,
458
+ }
459
+ return dotdict(provided_args)