vfWorks 0.0.1.dev5__tar.gz → 0.0.2b1__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 (59) hide show
  1. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/PKG-INFO +1 -1
  2. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/pyproject.toml +1 -1
  3. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfWorks.egg-info/PKG-INFO +1 -1
  4. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/metamodels/monitors.py +20 -15
  5. vfworks-0.0.2b1/vfworks/metamodels/process.py +103 -0
  6. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/metamodels/validity_frame.py +181 -3
  7. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/package/PackageManager.py +538 -371
  8. vfworks-0.0.1.dev5/vfworks/metamodels/process.py +0 -26
  9. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/LICENSE +0 -0
  10. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/README.md +0 -0
  11. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/setup.cfg +0 -0
  12. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/setup.py +0 -0
  13. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfWorks.egg-info/SOURCES.txt +0 -0
  14. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfWorks.egg-info/dependency_links.txt +0 -0
  15. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfWorks.egg-info/entry_points.txt +0 -0
  16. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfWorks.egg-info/requires.txt +0 -0
  17. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfWorks.egg-info/top_level.txt +0 -0
  18. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/DSLs/__init__.py +0 -0
  19. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/DSLs/specificationModel/__init__.py +0 -0
  20. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/DSLs/specificationModel/grammar/__init__.py +0 -0
  21. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/DSLs/specificationModel/parser/__init__.py +0 -0
  22. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/DSLs/specificationModel/parser/parser.py +0 -0
  23. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/DSLs/specificationModel/templates/__init__.py +0 -0
  24. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/__init__.py +0 -0
  25. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/__main__.py +0 -0
  26. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/clientLibraries/__init__.py +0 -0
  27. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/clientLibraries/vfclpy/__init__.py +0 -0
  28. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/clientLibraries/vfclpy/data_digest/__init__.py +0 -0
  29. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/clientLibraries/vfclpy/data_digest/digest.py +0 -0
  30. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/clientLibraries/vfclpy/data_forwarders/__init__.py +0 -0
  31. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/clientLibraries/vfclpy/data_forwarders/experiment.py +0 -0
  32. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/clientLibraries/vfclpy/data_platform.py +0 -0
  33. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/clientLibraries/vfclpy/probe.py +0 -0
  34. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/commands/__init__.py +0 -0
  35. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/commands/version.py +0 -0
  36. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/logging/__init__.py +0 -0
  37. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/logging/logger.py +0 -0
  38. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/metamodels/__init__.py +0 -0
  39. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/metamodels/common.py +0 -0
  40. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/metamodels/experiment.py +0 -0
  41. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/metamodels/knowledge_graph.py +0 -0
  42. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/metamodels/model_structure.py +0 -0
  43. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/metamodels/properties.py +0 -0
  44. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/metamodels/specification.py +0 -0
  45. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/metamodels/standard.py +0 -0
  46. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/metamodels/torch_representation.py +0 -0
  47. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/package/__init__.py +0 -0
  48. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/transformations/__init__.py +0 -0
  49. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/transformations/transformations.py +0 -0
  50. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/utils/__init__.py +0 -0
  51. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/utils/auxiliary.py +0 -0
  52. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/utils/constants.py +0 -0
  53. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/utils/data/__init__.py +0 -0
  54. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/utils/data/dataLoader.py +0 -0
  55. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/utils/model/__init__.py +0 -0
  56. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/utils/model/modelLoader.py +0 -0
  57. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/workflows/__init__.py +0 -0
  58. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/workflows/executer.py +0 -0
  59. {vfworks-0.0.1.dev5 → vfworks-0.0.2b1}/vfworks/workflows/tasks.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vfWorks
3
- Version: 0.0.1.dev5
3
+ Version: 0.0.2b1
4
4
  Summary: vfWorks - your gateway to valid model (re-)use.
5
5
  Home-page:
6
6
  Author: Jan Gladiné & Bert Van Acker
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "vfWorks"
7
- version = "0.0.1.dev5"
7
+ version = "0.0.2b1"
8
8
  description = "vfWorks - your gateway to valid model (re-)use."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vfWorks
3
- Version: 0.0.1.dev5
3
+ Version: 0.0.2b1
4
4
  Summary: vfWorks - your gateway to valid model (re-)use.
5
5
  Home-page:
6
6
  Author: Jan Gladiné & Bert Van Acker
@@ -6,11 +6,11 @@
6
6
  # * vfWorks can not be copied and/or distributed without the express
7
7
  # * permission of Bert Van Acker
8
8
  # **************************************************************************************
9
- from vfworks.metamodels.common import *
10
- from vfworks.utils.constants import *
11
- import importlib.util
12
- import os
13
- from pathlib import Path
9
+ from vfworks.metamodels.common import *
10
+ from vfworks.utils.constants import *
11
+ import importlib.util
12
+ import os
13
+ from pathlib import Path
14
14
 
15
15
  class Monitor(baseElement):
16
16
 
@@ -46,6 +46,11 @@ class Monitor(baseElement):
46
46
  """Setup the monitor, including loading any custom validation hooks."""
47
47
  self._load_custom_validation_hook(packageLocation=packageLocation)
48
48
 
49
+ def set_valid(self):
50
+ for observe in self.observes:
51
+ self.spec_status[observe.feature] = StatusType.VALID
52
+ self._status = StatusType.VALID
53
+
49
54
  @property
50
55
  def packageName(self):
51
56
  return self._packageName
@@ -169,16 +174,16 @@ class Monitor(baseElement):
169
174
 
170
175
  return global_is_valid
171
176
 
172
- def _load_custom_validation_hook(self, packageLocation=None):
173
- """Private helper to locate and bind custom vector validation scripts."""
174
- package_root = Path(os.getcwd()) if packageLocation is None else Path(packageLocation)
175
- custom_script_path = package_root / "Resources" / "monitors" / f"{self._custom_code_file}"
176
-
177
- # Check if the user wrote a custom plugin matching this monitor type
178
- if custom_script_path.exists():
179
- try:
180
- # Load the file dynamically as a Python module
181
- spec = importlib.util.spec_from_file_location(self.name, custom_script_path)
177
+ def _load_custom_validation_hook(self, packageLocation=None):
178
+ """Private helper to locate and bind custom vector validation scripts."""
179
+ package_root = Path(os.getcwd()) if packageLocation is None else Path(packageLocation)
180
+ custom_script_path = package_root / "Resources" / "monitors" / f"{self._custom_code_file}"
181
+
182
+ # Check if the user wrote a custom plugin matching this monitor type
183
+ if custom_script_path.exists():
184
+ try:
185
+ # Load the file dynamically as a Python module
186
+ spec = importlib.util.spec_from_file_location(self.name, custom_script_path)
182
187
  custom_module = importlib.util.module_from_spec(spec)
183
188
  spec.loader.exec_module(custom_module)
184
189
 
@@ -0,0 +1,103 @@
1
+ #***************************************************************************************
2
+ # * Copyright (C) 2024-present Bert Van Acker (UAntwerpen) <Bert.VanAcker@uantwerpen.be>
3
+ # *
4
+ # * This file is part of the vfWorks project.
5
+ # *
6
+ # * vfWorks can not be copied and/or distributed without the express
7
+ # * permission of Bert Van Acker
8
+ # **************************************************************************************
9
+ from vfworks.metamodels.common import *
10
+ from vfworks.utils.constants import *
11
+ import importlib.util
12
+ import os
13
+ from pathlib import Path
14
+
15
+ class Process(baseElement):
16
+
17
+ def __init__(self, name='tbd', description='tbd', verbose=False):
18
+ super().__init__(name=name, description=description, verbose=verbose)
19
+
20
+ self._tasks = []
21
+
22
+ @property
23
+ def tasks(self):
24
+ return self._tasks
25
+
26
+ @tasks.setter
27
+ def tasks(self, task_list):
28
+ self._tasks = task_list
29
+
30
+
31
+
32
+ class Task(baseElement):
33
+
34
+ def __init__(self, name='tbd', description='tbd',reference="Processes/train.py", verbose=False):
35
+ super().__init__(name=name, description=description, verbose=verbose)
36
+
37
+ self._input_artefacts = []
38
+ self._output_artefacts = []
39
+
40
+ @property
41
+ def input_artefacts(self):
42
+ return self._input_artefacts
43
+
44
+ @input_artefacts.setter
45
+ def input_artefacts(self, artefact_list):
46
+ self._input_artefacts = artefact_list
47
+
48
+ @property
49
+ def output_artefacts(self):
50
+ return self._output_artefacts
51
+
52
+ @output_artefacts.setter
53
+ def output_artefacts(self, artefact_list):
54
+ self._output_artefacts = artefact_list
55
+
56
+ def execute(self):
57
+ # Placeholder for task execution logic
58
+ pass
59
+
60
+ def _load_custom_task_executor(self, reference):
61
+ """Private helper to locate and bind custom vector validation scripts."""
62
+ package_root = Path(os.getcwd()) if packageLocation is None else Path(packageLocation)
63
+ custom_script_path = package_root / "Resources" / "monitors" / f"{self._custom_code_file}"
64
+
65
+ # Check if the user wrote a custom plugin matching this monitor type
66
+ if custom_script_path.exists():
67
+ try:
68
+ # Load the file dynamically as a Python module
69
+ spec = importlib.util.spec_from_file_location(self.name, custom_script_path)
70
+ custom_module = importlib.util.module_from_spec(spec)
71
+ spec.loader.exec_module(custom_module)
72
+
73
+ # Look for our standardized function name contract
74
+ if hasattr(custom_module, self.name):
75
+ self.execute = getattr(custom_module, self.name)
76
+ print(f"Successfully bound custom execution function for '{self.name}'")
77
+ else:
78
+ print(
79
+ f"Found custom script '{self._custom_code_file}.py', but it is missing '{self.name}'. "
80
+ f"Falling back to default built-in validation rules.",
81
+ level="warning"
82
+ )
83
+ except Exception as e:
84
+ print(f"Failed to compile custom monitor plugin '{self.name}': {str(e)}")
85
+ else:
86
+ # No custom script found; perfectly fine, it will use default built-in value.validate_point rules
87
+ print(f"No custom override found for '{self._custom_code_file}'. Running baseline configurations.")
88
+
89
+ class Artefact(baseElement):
90
+
91
+ def __init__(self, name='tbd', description='tbd',type='tbd',reference='tbd', verbose=False):
92
+ super().__init__(name=name, description=description, verbose=verbose)
93
+
94
+ self._type = type
95
+ self._reference = reference
96
+
97
+ @property
98
+ def reference(self):
99
+ return self._reference
100
+
101
+ @reference.setter
102
+ def reference(self,ref):
103
+ self._reference = ref
@@ -9,6 +9,7 @@
9
9
  import os
10
10
  import json
11
11
  import logging
12
+ import re
12
13
  from pathlib import Path
13
14
  from vfworks.package.PackageManager import PackageManager
14
15
  from vfworks.metamodels.knowledge_graph import KnowledgeGraph
@@ -18,7 +19,8 @@ from vfworks.metamodels.specification import *
18
19
  from vfworks.metamodels.experiment import *
19
20
  from vfworks.metamodels.properties import *
20
21
  from vfworks.metamodels.common import *
21
- from vfworks.utils.constants import StatusType
22
+ from vfworks.metamodels.process import *
23
+ from vfworks.utils.constants import StatusType, MonitorTime
22
24
  from vfworks.logging.logger import *
23
25
  from vfworks.utils.model.modelLoader import *
24
26
  import networkx as nx
@@ -26,7 +28,7 @@ import matplotlib.pyplot as plt
26
28
  from termcolor import colored
27
29
 
28
30
  class ValidityFrame(baseElement):
29
- def __init__(self, name='tbd',description='tbd',config=None,loadExistingVF=False,VFPackage=None, location=None,verbose=False):
31
+ def __init__(self, name='tbd',description='tbd',config=None,loadExistingVF=False,VFPackage=None, location=None,verbose=False,unzipDirectory=None):
30
32
  super().__init__(name=name, description=description, verbose=verbose)
31
33
 
32
34
  # VF_BLDC HIGH-LEVEL STRUCTURE
@@ -37,7 +39,12 @@ class ValidityFrame(baseElement):
37
39
  self._model_loader = ModelLoader(name="VF_model_loader", validityFrame=self)
38
40
 
39
41
  # PACKAGE AND LOGGER
40
- self._package_manager = PackageManager(verbose=verbose, packageName=VFPackage, packageLocation=location)
42
+ # VFPackage can be a package directory or a zipped package (.vf), which is unzipped to a working copy
43
+ self._log_handler = None
44
+ self._package_manager = PackageManager(verbose=verbose, packageName=VFPackage, packageLocation=location, unzipDirectory=unzipDirectory)
45
+ archive = self._package_manager.archive
46
+ if loadExistingVF and archive is not None and not archive.is_file():
47
+ raise FileNotFoundError(f"Zipped validity frame package {archive} does not exist!")
41
48
  if config is None:
42
49
  self.config = self._package_manager.init_config()
43
50
  else:
@@ -239,6 +246,7 @@ class ValidityFrame(baseElement):
239
246
  file_handler = logging.FileHandler(Path("..") / log_file) #LOAD FROM FOLDER LEVEL (e.g. in processes)
240
247
  file_handler.setFormatter(formatter)
241
248
  logger.addHandler(file_handler)
249
+ self._log_handler = file_handler
242
250
  else:
243
251
  console_handler = logging.StreamHandler()
244
252
  console_handler.setFormatter(formatter)
@@ -387,6 +395,132 @@ class ValidityFrame(baseElement):
387
395
  with open(file_name, 'w') as f:
388
396
  json.dump(graph_dict, f)
389
397
 
398
+ def architecture_graph(self):
399
+ """
400
+ Build an architecture graph payload from the metadata and operational state.
401
+ """
402
+
403
+ def humanize(name):
404
+ return re.sub(r'(?<!^)(?=[A-Z])', ' ', str(name)).strip()
405
+
406
+ def normalize(value):
407
+ return getattr(value, 'value', value)
408
+
409
+ model_structure = self.activeModelStructure
410
+ if model_structure is None and self.modelStructures:
411
+ model_structure = self.modelStructures[0]
412
+
413
+ if model_structure is None:
414
+ component = {
415
+ "id": self.GUID,
416
+ "name": self.name,
417
+ "inputs": [],
418
+ "outputs": [],
419
+ "ai_architecture": {
420
+ "pattern": "unknown",
421
+ "models": [],
422
+ "flow": []
423
+ }
424
+ }
425
+ else:
426
+ inputs = []
427
+ for inport in model_structure.inports:
428
+ input_entry = {
429
+ "id": f"input_{inport.name}",
430
+ "name": inport.name,
431
+ "datatype": normalize(inport.datatype),
432
+ "dimensions": None,
433
+ "shape": [],
434
+ "unit": None if normalize(inport.unit) in (None, "-", "UNIT_none") else normalize(inport.unit),
435
+ "description": inport.description
436
+ }
437
+ if "image" in inport.name.lower() or "image" in inport.description.lower():
438
+ input_entry["format"] = "image"
439
+ inputs.append(input_entry)
440
+
441
+ outputs = []
442
+ has_confidence_output = False
443
+ for outport in model_structure.outports:
444
+ output_entry = {
445
+ "id": f"output_{outport.name}",
446
+ "name": outport.name,
447
+ "datatype": normalize(outport.datatype),
448
+ "dimensions": None,
449
+ "shape": [],
450
+ "unit": None if normalize(outport.unit) in (None, "-", "UNIT_none") else normalize(outport.unit),
451
+ "description": outport.description
452
+ }
453
+ if outport.min != 0 or outport.max != 0:
454
+ output_entry["value_range"] = {"min": outport.min, "max": outport.max}
455
+ if outport.name.lower() == "confidence":
456
+ has_confidence_output = True
457
+ outputs.append(output_entry)
458
+
459
+ model_entry = {
460
+ "id": f"model_{model_structure.name}",
461
+ "name": humanize(model_structure.name),
462
+ "type": normalize(model_structure.modelType),
463
+ "reference": model_structure.modelRef
464
+ }
465
+
466
+ flow = []
467
+ for input_entry in inputs:
468
+ flow.append({"from": input_entry["id"], "to": model_entry["id"]})
469
+ for output_entry in outputs:
470
+ flow.append({"from": model_entry["id"], "to": output_entry["id"]})
471
+
472
+ component = {
473
+ "id": model_structure.name,
474
+ "name": humanize(model_structure.name),
475
+ "inputs": inputs,
476
+ "outputs": outputs,
477
+ "ai_architecture": {
478
+ "pattern": "single_model_with_confidence_output" if has_confidence_output else "single_model",
479
+ "models": [model_entry],
480
+ "flow": flow
481
+ }
482
+ }
483
+
484
+ monitors = []
485
+ default_target = model_structure.inports[0].name if model_structure and model_structure.inports else "model"
486
+ for monitor in self.runtime_monitors:
487
+ if monitor.type == MonitorTime.DATA_VALIDATION:
488
+ target = "dataset"
489
+ elif monitor.type == MonitorTime.MODEL_VALIDATION:
490
+ target = "model"
491
+ elif monitor.type == MonitorTime.RUN_TIME:
492
+ observed_features = [spec.feature for spec in (monitor.observes or [])]
493
+ if any("odd" in feature.lower() for feature in observed_features) or "odd" in monitor.name.lower() or "odd" in monitor.description.lower():
494
+ target = "environment"
495
+ else:
496
+ target = default_target
497
+ else:
498
+ target = default_target
499
+
500
+ monitors.append({
501
+ "name": monitor.name,
502
+ "target": target,
503
+ "description": monitor.description,
504
+ "observes": [spec.feature for spec in (monitor.observes or [])]
505
+ })
506
+
507
+ return {
508
+ "component": component,
509
+ "monitors": monitors
510
+ }
511
+
512
+ def export_architecture_json(self, file_name="architecture.json"):
513
+ """
514
+ Export the architecture graph payload to a JSON file.
515
+ """
516
+ architecture = self.architecture_graph()
517
+ output_path = Path(file_name)
518
+ if not output_path.is_absolute():
519
+ output_path = self.package_manager.package_root / output_path
520
+
521
+ with open(output_path, 'w', encoding='utf-8') as f:
522
+ json.dump(architecture, f, indent=2)
523
+
390
524
  # ------------------------------------------------------------------------------------------------------------------
391
525
  # IMPORT/EXPORT FUNCTIONS
392
526
  # -----------------------------------------------------------------------------------------------------------------
@@ -396,6 +530,30 @@ class ValidityFrame(baseElement):
396
530
  self._processes.object2json(package_root / "Processes" / "Processes.json")
397
531
  self._experiments.object2json(package_root / "Experiments" / "Experiments.json")
398
532
  self._operational.object2json(package_root / "Operational" / "Operational.json")
533
+ # keep the zipped package (.vf) in sync with its unzipped working copy
534
+ if packageName is None and self.package_manager.archive is not None:
535
+ self.package_manager.zip()
536
+
537
+ def zip(self, archive=None):
538
+ """
539
+ Export the validity frame and zip its package into a .vf archive.
540
+ Defaults to the archive the validity frame was loaded from.
541
+ """
542
+ self.export()
543
+ if archive is None and self.package_manager.archive is not None:
544
+ return self.package_manager.archive
545
+ return self.package_manager.zip(archive=archive)
546
+
547
+ def close(self):
548
+ """
549
+ Release the log file and the unzipped working copy of a zipped package (.vf).
550
+ Changes made after the last export()/zip() are not written to the archive.
551
+ """
552
+ if self._log_handler is not None:
553
+ self.logger.removeHandler(self._log_handler)
554
+ self._log_handler.close()
555
+ self._log_handler = None
556
+ self.package_manager.close()
399
557
 
400
558
 
401
559
  class MetaData(baseElement):
@@ -639,6 +797,26 @@ class Processes(baseElement):
639
797
  with open(fileName, 'w', encoding='utf-8') as f:
640
798
  f.write(data)
641
799
 
800
+ def json2object(self, fileName):
801
+ """
802
+ Function to generate object from a json file
803
+ """
804
+ # --- read stored requirements ---
805
+ available = False
806
+ try:
807
+ f = open(fileName)
808
+ data = json.load(f)
809
+ available = True
810
+ except:
811
+ print(colored('ERROR: ', 'red'), colored('Stored operational data cannot be read!', 'black'))
812
+
813
+ if available:
814
+ for process in data["_processes"]:
815
+ _process = Process(name=process["_name"], description=process["_description"], processType=process["_processType"], custom_code_file=process["_custom_code_file"])
816
+ _process.GUID = process["_GUID"]
817
+ _process.timestamp = process["_timestamp"]
818
+ self.addProcess(_process)
819
+
642
820
  class Experiments(baseElement):
643
821
  def __init__(self, name='tbd',description='tbd',experiments=None,verbose=False):
644
822
  super().__init__(name=name, description=description, verbose=verbose)