vfWorks 0.0.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.
- vfworks/DSLs/__init__.py +0 -0
- vfworks/DSLs/specificationModel/__init__.py +0 -0
- vfworks/DSLs/specificationModel/grammar/__init__.py +0 -0
- vfworks/DSLs/specificationModel/parser/__init__.py +0 -0
- vfworks/DSLs/specificationModel/parser/parser.py +24 -0
- vfworks/DSLs/specificationModel/templates/__init__.py +0 -0
- vfworks/__init__.py +23 -0
- vfworks/__main__.py +19 -0
- vfworks/clientLibraries/__init__.py +0 -0
- vfworks/clientLibraries/vfclpy/__init__.py +0 -0
- vfworks/clientLibraries/vfclpy/data_digest/__init__.py +0 -0
- vfworks/clientLibraries/vfclpy/data_digest/digest.py +152 -0
- vfworks/clientLibraries/vfclpy/data_forwarders/__init__.py +0 -0
- vfworks/clientLibraries/vfclpy/data_forwarders/experiment.py +108 -0
- vfworks/clientLibraries/vfclpy/data_platform.py +110 -0
- vfworks/clientLibraries/vfclpy/probe.py +66 -0
- vfworks/commands/__init__.py +0 -0
- vfworks/commands/version.py +23 -0
- vfworks/logging/__init__.py +0 -0
- vfworks/logging/logger.py +93 -0
- vfworks/metamodels/__init__.py +0 -0
- vfworks/metamodels/common.py +56 -0
- vfworks/metamodels/experiment.py +101 -0
- vfworks/metamodels/knowledge_graph.py +78 -0
- vfworks/metamodels/model_structure.py +185 -0
- vfworks/metamodels/monitors.py +205 -0
- vfworks/metamodels/process.py +26 -0
- vfworks/metamodels/properties.py +114 -0
- vfworks/metamodels/specification.py +239 -0
- vfworks/metamodels/standard.py +172 -0
- vfworks/metamodels/torch_representation.py +33 -0
- vfworks/metamodels/validity_frame.py +859 -0
- vfworks/package/PackageManager.py +538 -0
- vfworks/package/__init__.py +0 -0
- vfworks/transformations/__init__.py +0 -0
- vfworks/transformations/transformations.py +36 -0
- vfworks/utils/__init__.py +0 -0
- vfworks/utils/auxiliary.py +100 -0
- vfworks/utils/constants.py +76 -0
- vfworks/utils/data/__init__.py +0 -0
- vfworks/utils/data/dataLoader.py +136 -0
- vfworks/utils/model/__init__.py +0 -0
- vfworks/utils/model/modelLoader.py +150 -0
- vfworks/workflows/__init__.py +0 -0
- vfworks/workflows/executer.py +139 -0
- vfworks/workflows/tasks.py +52 -0
- vfworks-0.0.1.dist-info/METADATA +59 -0
- vfworks-0.0.1.dist-info/RECORD +52 -0
- vfworks-0.0.1.dist-info/WHEEL +5 -0
- vfworks-0.0.1.dist-info/entry_points.txt +2 -0
- vfworks-0.0.1.dist-info/licenses/LICENSE +201 -0
- vfworks-0.0.1.dist-info/top_level.txt +1 -0
vfworks/DSLs/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
import os
|
|
10
|
+
|
|
11
|
+
from textx import metamodel_from_file
|
|
12
|
+
|
|
13
|
+
class Specification_parser(object):
|
|
14
|
+
def __init__(self, specificationModel):
|
|
15
|
+
self._specificationModel = specificationModel
|
|
16
|
+
|
|
17
|
+
currentDir = os.path.dirname(os.path.abspath(__file__))
|
|
18
|
+
metamodelPath = os.path.join(currentDir,'..','grammar/specificationModel.tx')
|
|
19
|
+
self._specificationModel_metamodel = metamodel_from_file(metamodelPath)
|
|
20
|
+
|
|
21
|
+
def parse(self):
|
|
22
|
+
specificationModel = self._specificationModel_metamodel.model_from_file(self._specificationModel)
|
|
23
|
+
return specificationModel
|
|
24
|
+
|
|
File without changes
|
vfworks/__init__.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
|
|
10
|
+
VERSION = (0, 0, "1")
|
|
11
|
+
__version__ = ".".join([str(s) for s in VERSION])
|
|
12
|
+
|
|
13
|
+
__title__ = "vfWorks"
|
|
14
|
+
__description__ = (
|
|
15
|
+
"vfWorks - your gateway to valid model (re-)use."
|
|
16
|
+
)
|
|
17
|
+
__url__ = "https://vfworks.readthedocs.io/en/latest/index.html"
|
|
18
|
+
|
|
19
|
+
__author__ = "Jan Gladiné & Bert Van Acker"
|
|
20
|
+
__email__ = "Jan.Gladine@uantwerpen.be"
|
|
21
|
+
|
|
22
|
+
__license__ = "Apache License 2.0"
|
|
23
|
+
__copyright__ = "Copyright 2024"
|
vfworks/__main__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
|
|
10
|
+
import click
|
|
11
|
+
|
|
12
|
+
from vfworks.commands.version import versionCmds
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
cli=click.CommandCollection(sources=[versionCmds],help="vfWorks command line tool")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
if __name__ == '__main__':
|
|
19
|
+
cli()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,152 @@
|
|
|
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
|
+
import yaml
|
|
10
|
+
import os
|
|
11
|
+
from os import mkdir
|
|
12
|
+
from os.path import exists, dirname, join, isfile
|
|
13
|
+
import logging
|
|
14
|
+
from vfworks.clientLibraries.vfclpy.data_platform import *
|
|
15
|
+
from vfworks.metamodels.experiment import *
|
|
16
|
+
from vfworks.utils.auxiliary import *
|
|
17
|
+
|
|
18
|
+
class remoteExperiments(object):
|
|
19
|
+
def __init__(self, config,VFName,verbose=False):
|
|
20
|
+
self.config = self.load_config(config)
|
|
21
|
+
self.logger = self.initialize_logger()
|
|
22
|
+
self.data_platform = self._initialize_data_platform() # Initialize knowledge within the component
|
|
23
|
+
|
|
24
|
+
probe_config = VFName
|
|
25
|
+
self.base_key = f"{VFName}:Experiments"
|
|
26
|
+
|
|
27
|
+
#----------------INSTANTIATE EXPERIMENTS---------------------
|
|
28
|
+
self.experiments = []
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def load_config(self, config_file):
|
|
32
|
+
with open(config_file, 'r') as file:
|
|
33
|
+
return yaml.safe_load(file)
|
|
34
|
+
|
|
35
|
+
def initialize_logger(self):
|
|
36
|
+
"""Initialize the logger (same as before)."""
|
|
37
|
+
log_config = self.config.get("logging", {})
|
|
38
|
+
logger = logging.getLogger(self.__class__.__name__)
|
|
39
|
+
log_level = log_config.get("level", "INFO").upper()
|
|
40
|
+
logger.setLevel(getattr(logging, log_level, logging.INFO))
|
|
41
|
+
|
|
42
|
+
log_format = log_config.get("format", "%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
|
43
|
+
log_file = log_config.get("file", None)
|
|
44
|
+
|
|
45
|
+
formatter = logging.Formatter(log_format)
|
|
46
|
+
|
|
47
|
+
if log_file:
|
|
48
|
+
file_handler = logging.FileHandler(log_file)
|
|
49
|
+
file_handler.setFormatter(formatter)
|
|
50
|
+
logger.addHandler(file_handler)
|
|
51
|
+
else:
|
|
52
|
+
console_handler = logging.StreamHandler()
|
|
53
|
+
console_handler.setFormatter(formatter)
|
|
54
|
+
logger.addHandler(console_handler)
|
|
55
|
+
|
|
56
|
+
return logger
|
|
57
|
+
|
|
58
|
+
def _initialize_data_platform(self):
|
|
59
|
+
"""Initialize the data plaform object based on the config."""
|
|
60
|
+
#self.logger.info(f"Initializing the data platform.")
|
|
61
|
+
return DataPlatform(config=self.config['dp_config'])
|
|
62
|
+
|
|
63
|
+
def loadExperiments(self, measerementStorage = "full",timestamped=False): # full => both in the datapoints and csv | csv => store only csv file
|
|
64
|
+
timestamp = None
|
|
65
|
+
experimentIDs = self._getExperimentIDs()
|
|
66
|
+
|
|
67
|
+
for experiment in experimentIDs:
|
|
68
|
+
# instantiate an empty experiment
|
|
69
|
+
label = self.data_platform.read(self.base_key + ":" + experiment + ":label")
|
|
70
|
+
exp = Experiment(name=experiment, description="tbd", label=label)
|
|
71
|
+
# fetch all conditions
|
|
72
|
+
conditionIDs = self._getConditionIDs(experimentID=experiment)
|
|
73
|
+
for condition in conditionIDs:
|
|
74
|
+
key = self.base_key + ":" + experiment + ":Conditions:" + condition
|
|
75
|
+
value = self.data_platform.read(key)
|
|
76
|
+
exp.addCondition(ExperimentCondition(name=condition, value=value))
|
|
77
|
+
measurementIDs = self._getMeasurementIDs(experimentID=experiment)
|
|
78
|
+
for measurement in measurementIDs:
|
|
79
|
+
key = self.base_key + ":" + experiment + ":Measurements:" + measurement
|
|
80
|
+
dataPoints=self.data_platform.read_list(key,all=True)
|
|
81
|
+
if measurement!= "timestamp":
|
|
82
|
+
reference = "Experiments/" + experiment +"/"+ measurement+".csv"
|
|
83
|
+
if measerementStorage=="full":
|
|
84
|
+
exp.addMeasurement(Measurement(name=measurement,dataPoints=dataPoints,reference=reference))
|
|
85
|
+
else:
|
|
86
|
+
exp.addMeasurement(Measurement(name=measurement, dataPoints=[], reference=reference))
|
|
87
|
+
else:
|
|
88
|
+
key = self.base_key + ":" + experiment + ":Measurements:" + measurement
|
|
89
|
+
timestamp = self.data_platform.read_list(key, all=True)
|
|
90
|
+
|
|
91
|
+
for measurement in measurementIDs:
|
|
92
|
+
key = self.base_key + ":" + experiment + ":Measurements:" + measurement
|
|
93
|
+
dataPoints = self.data_platform.read_list(key, all=True)
|
|
94
|
+
#CREATE FOLDER IF NON EXISTING
|
|
95
|
+
path = "Experiments/" + experiment
|
|
96
|
+
if not exists(path):
|
|
97
|
+
mkdir(path)
|
|
98
|
+
|
|
99
|
+
reference = path + "/" + measurement + ".csv"
|
|
100
|
+
if timestamped:
|
|
101
|
+
save_lists_to_csv(reference, timestamp, dataPoints,headers=['timestamp', measurement])
|
|
102
|
+
else:
|
|
103
|
+
save_lists_to_csv(reference, dataPoints, headers=[measurement])
|
|
104
|
+
#TODO: STORE THE MEASUREMENTS AS FILES AND REFERENCE!
|
|
105
|
+
self.experiments.append(exp)
|
|
106
|
+
self.logger.info(msg="experiment added to the VF frame, GUID {"+exp.GUID+"}")
|
|
107
|
+
return self.experiments
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _getExperimentIDs(self):
|
|
111
|
+
"""Get the experiment from the vfWorks backend"""
|
|
112
|
+
unique_values = set()
|
|
113
|
+
keys = self.data_platform.getKeys(self.base_key+":*")
|
|
114
|
+
for key in keys:
|
|
115
|
+
try:
|
|
116
|
+
value = key.split('Experiments:')[1].split(":")[0]
|
|
117
|
+
unique_values.add(value)
|
|
118
|
+
except IndexError:
|
|
119
|
+
print(f"Skipping key due to formatting issue: {key}")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
return list(unique_values)
|
|
123
|
+
|
|
124
|
+
def _getConditionIDs(self, experimentID):
|
|
125
|
+
"""Get the experiment from the vfWorks backend"""
|
|
126
|
+
unique_values = set()
|
|
127
|
+
keys = self.data_platform.getKeys(self.base_key+":"+experimentID+":Conditions:*")
|
|
128
|
+
for key in keys:
|
|
129
|
+
try:
|
|
130
|
+
value = key.split('Conditions:')[1]
|
|
131
|
+
unique_values.add(value)
|
|
132
|
+
except IndexError:
|
|
133
|
+
print(f"Skipping key due to formatting issue: {key}")
|
|
134
|
+
return list(unique_values)
|
|
135
|
+
|
|
136
|
+
def _getMeasurementIDs(self, experimentID):
|
|
137
|
+
"""Get the experiment from the vfWorks backend"""
|
|
138
|
+
unique_values = set()
|
|
139
|
+
keys = self.data_platform.getKeys(self.base_key+":"+experimentID+":Measurements:*")
|
|
140
|
+
for key in keys:
|
|
141
|
+
try:
|
|
142
|
+
value = key.split('Measurements:')[1]
|
|
143
|
+
unique_values.add(value)
|
|
144
|
+
except IndexError:
|
|
145
|
+
print(f"Skipping key due to formatting issue: {key}")
|
|
146
|
+
return list(unique_values)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
File without changes
|
|
@@ -0,0 +1,108 @@
|
|
|
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
|
+
import yaml
|
|
10
|
+
import struct
|
|
11
|
+
import logging
|
|
12
|
+
from vfworks.clientLibraries.vfclpy.data_platform import *
|
|
13
|
+
|
|
14
|
+
class Experiment(object):
|
|
15
|
+
def __init__(self, config, ID="EXP_001", label="nominal", verbose=False):
|
|
16
|
+
self.ID = ID
|
|
17
|
+
self.config = self.load_config(config)
|
|
18
|
+
self.logger = self.initialize_logger()
|
|
19
|
+
self.data_platform = self._initialize_data_platform() # Initialize knowledge within the component
|
|
20
|
+
|
|
21
|
+
probe_config = self.config.get("validityframe", {})
|
|
22
|
+
self.base_key = f"{probe_config.get('name', 'base')}:Experiments"
|
|
23
|
+
self.experiment_key = self.base_key+":"+ID
|
|
24
|
+
self.conditions_key = self.experiment_key+":"+"Conditions"
|
|
25
|
+
self.measurements_key = self.experiment_key + ":" + "Measurements"
|
|
26
|
+
|
|
27
|
+
# set experiment label
|
|
28
|
+
self.addLabel(label=label)
|
|
29
|
+
|
|
30
|
+
def load_config(self, config_file):
|
|
31
|
+
with open(config_file, 'r') as file:
|
|
32
|
+
return yaml.safe_load(file)
|
|
33
|
+
|
|
34
|
+
def initialize_logger(self):
|
|
35
|
+
"""Initialize the logger (same as before)."""
|
|
36
|
+
log_config = self.config.get("logging", {})
|
|
37
|
+
logger = logging.getLogger(self.__class__.__name__)
|
|
38
|
+
log_level = log_config.get("level", "INFO").upper()
|
|
39
|
+
logger.setLevel(getattr(logging, log_level, logging.INFO))
|
|
40
|
+
|
|
41
|
+
log_format = log_config.get("format", "%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
|
42
|
+
log_file = log_config.get("file", None)
|
|
43
|
+
|
|
44
|
+
formatter = logging.Formatter(log_format)
|
|
45
|
+
|
|
46
|
+
if log_file:
|
|
47
|
+
file_handler = logging.FileHandler(log_file)
|
|
48
|
+
file_handler.setFormatter(formatter)
|
|
49
|
+
logger.addHandler(file_handler)
|
|
50
|
+
else:
|
|
51
|
+
console_handler = logging.StreamHandler()
|
|
52
|
+
console_handler.setFormatter(formatter)
|
|
53
|
+
logger.addHandler(console_handler)
|
|
54
|
+
|
|
55
|
+
return logger
|
|
56
|
+
|
|
57
|
+
def _initialize_data_platform(self):
|
|
58
|
+
"""Initialize the data plaform object based on the config."""
|
|
59
|
+
self.logger.info(f"Initializing the data platform.")
|
|
60
|
+
return DataPlatform(config=self.config['dp_config'])
|
|
61
|
+
|
|
62
|
+
#-------------------------EXTERNAL FUNCTIONS-------------------------------------
|
|
63
|
+
def addCondition(self,condition,value):
|
|
64
|
+
"""Add a condition to the experiment description"""
|
|
65
|
+
_condition_key = self.conditions_key + ":" + condition
|
|
66
|
+
try:
|
|
67
|
+
self.data_platform.write(_condition_key, value)
|
|
68
|
+
self.logger.info("Condition <" + condition + "> with value " + str(value) + " written to vfWorks backend!")
|
|
69
|
+
except:
|
|
70
|
+
self.logger.warning("Condition <" + condition + "> with value " + str(value)+ " failed to write to vfWorks backend!")
|
|
71
|
+
|
|
72
|
+
def addLabel(self,label="nominal"):
|
|
73
|
+
_label_key = self.experiment_key + ":" + "label"
|
|
74
|
+
try:
|
|
75
|
+
self.data_platform.write(_label_key, label)
|
|
76
|
+
self.logger.info("Label <" + label + "> written to vfWorks backend!")
|
|
77
|
+
except:
|
|
78
|
+
self.logger.warning("Label <" + label + "> failed to write to vfWorks backend!")
|
|
79
|
+
|
|
80
|
+
def addMeasurement(self,key,value,batch=True,clean=True, vector=False):
|
|
81
|
+
_measurement_key = self.measurements_key + ":" + key
|
|
82
|
+
if clean:
|
|
83
|
+
self.data_platform.delete(_measurement_key)
|
|
84
|
+
if batch:
|
|
85
|
+
if vector:
|
|
86
|
+
self.data_platform.write(_measurement_key, value)
|
|
87
|
+
else:
|
|
88
|
+
value.reverse()
|
|
89
|
+
for point in value:
|
|
90
|
+
self.data_platform.write_storage(_measurement_key, point) #TODO: add batch writer to data_platform!
|
|
91
|
+
else:
|
|
92
|
+
self.data_platform.write_storage(_measurement_key, value)
|
|
93
|
+
|
|
94
|
+
def getMeasurement(self,key):
|
|
95
|
+
_measurement_key = self.measurements_key + ":" + key
|
|
96
|
+
try:
|
|
97
|
+
values = self.data_platform.read_list(key=_measurement_key,all=True)
|
|
98
|
+
# TODO: HACKED byte to float - THIS NEEDS TO BE MORE GENERIC!
|
|
99
|
+
for i in range(0,len(values),1):
|
|
100
|
+
values[i] = float(values[i])
|
|
101
|
+
|
|
102
|
+
self.logger.info("Reading values for measurement <" + key + "> from vfWorks backend!")
|
|
103
|
+
return values
|
|
104
|
+
except:
|
|
105
|
+
self.logger.warning("Failed to read values for measurement <" + key + "> from vfWorks backend!")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import redis
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
class DataPlatform(object):
|
|
5
|
+
def __init__(self, config):
|
|
6
|
+
"""
|
|
7
|
+
Initialize the data platform object.
|
|
8
|
+
:param config: Configuration for data platform storage (local or global)
|
|
9
|
+
"""
|
|
10
|
+
self.config = config
|
|
11
|
+
self.storage_type = config.get('storage_type', 'local') # 'local' or 'global'
|
|
12
|
+
|
|
13
|
+
if self.storage_type == 'global':
|
|
14
|
+
self.redis_client = redis.StrictRedis(
|
|
15
|
+
host=config['redis_host'],
|
|
16
|
+
port=config['redis_port'],
|
|
17
|
+
charset="utf-8",
|
|
18
|
+
decode_responses = True,
|
|
19
|
+
db=config.get('redis_db', 0)
|
|
20
|
+
)
|
|
21
|
+
else:
|
|
22
|
+
self.local_store = {}
|
|
23
|
+
|
|
24
|
+
def write(self, key, value):
|
|
25
|
+
"""
|
|
26
|
+
Store a key-value pair in the data platform. If the value is a dictionary, it will be serialized.
|
|
27
|
+
:param key: The key for storing the data
|
|
28
|
+
:param value: The value to store (can be a dict, str, int, etc.)
|
|
29
|
+
"""
|
|
30
|
+
if isinstance(value, dict):
|
|
31
|
+
value = json.dumps(value) # Serialize the dictionary to a JSON string
|
|
32
|
+
else:
|
|
33
|
+
value = str(value)
|
|
34
|
+
if self.storage_type == 'global':
|
|
35
|
+
self.redis_client.set(key, value)
|
|
36
|
+
# signal new data
|
|
37
|
+
self.redis_client.publish('MONITOR_NEW_DATA', key)
|
|
38
|
+
else:
|
|
39
|
+
self.local_store[key] = value
|
|
40
|
+
|
|
41
|
+
def write_storage(self, key, value):
|
|
42
|
+
"""
|
|
43
|
+
Store a key-value pair in the data platform. If the value is a dictionary, it will be serialized.
|
|
44
|
+
:param key: The key for storing the data
|
|
45
|
+
:param value: The value to store (can be a dict, str, int, etc.)
|
|
46
|
+
"""
|
|
47
|
+
if isinstance(value, list):
|
|
48
|
+
value = json.dumps(value)
|
|
49
|
+
if isinstance(value, dict):
|
|
50
|
+
value = json.dumps(value) # Serialize the dictionary to a JSON string
|
|
51
|
+
if self.storage_type == 'global':
|
|
52
|
+
self.redis_client.lpush(key,value)
|
|
53
|
+
#signal new data
|
|
54
|
+
self.redis_client.publish('MONITOR_NEW_DATA',key)
|
|
55
|
+
else:
|
|
56
|
+
self.local_store[key] = value
|
|
57
|
+
def read(self, key, queueSize = 1):
|
|
58
|
+
"""
|
|
59
|
+
Retrieve a value from the data platform. If the value is JSON, it will be deserialized to a Python object.
|
|
60
|
+
:param key: The key for retrieving the data
|
|
61
|
+
:return: The value associated with the key or None if not found
|
|
62
|
+
"""
|
|
63
|
+
if self.storage_type == 'global':
|
|
64
|
+
value = self.redis_client.get(key)
|
|
65
|
+
if value is not None:
|
|
66
|
+
#value = value.decode('utf-8') # Convert bytes to string #TODO: CHECK IF WE CAN ALWAYS USE AUTO-DECODE OR WE NEED TO MANUALLY DECODE
|
|
67
|
+
try:
|
|
68
|
+
value = json.loads(value) # Try to deserialize the value if it's a JSON string
|
|
69
|
+
except json.JSONDecodeError:
|
|
70
|
+
pass # If it's not JSON, return it as a string
|
|
71
|
+
return value
|
|
72
|
+
else:
|
|
73
|
+
return self.local_store.get(key, None)
|
|
74
|
+
|
|
75
|
+
def read_list(self, key, queueSize = 1, all=False):
|
|
76
|
+
if self.storage_type == 'global':
|
|
77
|
+
if all:
|
|
78
|
+
list = self.redis_client.lrange(key, 0, -1)
|
|
79
|
+
else:
|
|
80
|
+
list = self.redis_client.lrange(key, 0, queueSize)
|
|
81
|
+
|
|
82
|
+
return list
|
|
83
|
+
else:
|
|
84
|
+
return self.local_store.get(key, None)
|
|
85
|
+
|
|
86
|
+
def delete(self, key):
|
|
87
|
+
"""
|
|
88
|
+
Delete a key-value pair from the data platform.
|
|
89
|
+
:param key: The key to delete
|
|
90
|
+
"""
|
|
91
|
+
if self.storage_type == 'global':
|
|
92
|
+
self.redis_client.delete(key)
|
|
93
|
+
else:
|
|
94
|
+
if key in self.local_store:
|
|
95
|
+
del self.local_store[key]
|
|
96
|
+
|
|
97
|
+
def exists(self, key):
|
|
98
|
+
"""
|
|
99
|
+
Check if a key exists in the data platform.
|
|
100
|
+
:param key: The key to check
|
|
101
|
+
:return: True if the key exists, False otherwise
|
|
102
|
+
"""
|
|
103
|
+
if self.storage_type == 'global':
|
|
104
|
+
return self.redis_client.exists(key)
|
|
105
|
+
else:
|
|
106
|
+
return key in self.local_store
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def getKeys(self,pattern):
|
|
110
|
+
return self.redis_client.keys(pattern)
|
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
import yaml
|
|
10
|
+
import logging
|
|
11
|
+
from vfworks.clientLibraries.vfclpy.data_platform import *
|
|
12
|
+
class Probe(object):
|
|
13
|
+
def __init__(self, config, storage=False, verbose=False):
|
|
14
|
+
self.config = self.load_config(config)
|
|
15
|
+
self.logger = self.initialize_logger()
|
|
16
|
+
self.data_platform = self.initialize_data_platform() # Initialize knowledge within the component
|
|
17
|
+
|
|
18
|
+
probe_config = self.config.get("validityframe", {})
|
|
19
|
+
self.probe_key = f"{probe_config.get('name', 'base')}:properties"
|
|
20
|
+
self._storage = storage
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def load_config(self, config_file):
|
|
24
|
+
with open(config_file, 'r') as file:
|
|
25
|
+
return yaml.safe_load(file)
|
|
26
|
+
|
|
27
|
+
def initialize_logger(self):
|
|
28
|
+
"""Initialize the logger (same as before)."""
|
|
29
|
+
log_config = self.config.get("logging", {})
|
|
30
|
+
logger = logging.getLogger(self.__class__.__name__)
|
|
31
|
+
log_level = log_config.get("level", "INFO").upper()
|
|
32
|
+
logger.setLevel(getattr(logging, log_level, logging.INFO))
|
|
33
|
+
|
|
34
|
+
log_format = log_config.get("format", "%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
|
35
|
+
log_file = log_config.get("file", None)
|
|
36
|
+
|
|
37
|
+
formatter = logging.Formatter(log_format)
|
|
38
|
+
|
|
39
|
+
if log_file:
|
|
40
|
+
file_handler = logging.FileHandler(log_file)
|
|
41
|
+
file_handler.setFormatter(formatter)
|
|
42
|
+
logger.addHandler(file_handler)
|
|
43
|
+
else:
|
|
44
|
+
console_handler = logging.StreamHandler()
|
|
45
|
+
console_handler.setFormatter(formatter)
|
|
46
|
+
logger.addHandler(console_handler)
|
|
47
|
+
|
|
48
|
+
return logger
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def initialize_data_platform(self):
|
|
52
|
+
"""Initialize the data plaform object based on the config."""
|
|
53
|
+
self.logger.info(f"Initializing the data platform.")
|
|
54
|
+
return DataPlatform(config=self.config['dp_config'])
|
|
55
|
+
|
|
56
|
+
def write(self, key, message = True):
|
|
57
|
+
"""Write data on the data platform."""
|
|
58
|
+
if self.data_platform:
|
|
59
|
+
_probe_key = self.probe_key+":"+key
|
|
60
|
+
self.logger.info("Probing property (ID:"+key+") with value "+ str(message))
|
|
61
|
+
if not self._storage:
|
|
62
|
+
self.data_platform.write(_probe_key, message)
|
|
63
|
+
else:
|
|
64
|
+
self.data_platform.write_storage(_probe_key, message)
|
|
65
|
+
else:
|
|
66
|
+
self.logger.warning("Probe is not set for writing")
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
|
|
10
|
+
import click
|
|
11
|
+
from vfworks import __version__
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.group()
|
|
15
|
+
@click.pass_context
|
|
16
|
+
def versionCmds():
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
@versionCmds.command()
|
|
20
|
+
def version():
|
|
21
|
+
"""Display the current version."""
|
|
22
|
+
version = __version__
|
|
23
|
+
click.echo("vfWorks v"+version)
|
|
File without changes
|
|
@@ -0,0 +1,93 @@
|
|
|
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
|
+
import os
|
|
10
|
+
import logging
|
|
11
|
+
|
|
12
|
+
def setup_logger(name, log_file, level=logging.INFO):
|
|
13
|
+
"""Setup of multiple loggers"""
|
|
14
|
+
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
|
|
15
|
+
handler = logging.FileHandler(log_file)
|
|
16
|
+
handler.setFormatter(formatter)
|
|
17
|
+
logger = logging.getLogger(name)
|
|
18
|
+
logger.setLevel(level)
|
|
19
|
+
logger.addHandler(handler)
|
|
20
|
+
|
|
21
|
+
return logger
|
|
22
|
+
|
|
23
|
+
class Logger(object):
|
|
24
|
+
def __init__(self,name="customLogger",path=None,verbose=False):
|
|
25
|
+
"""Initialize a Logger component.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
name : string
|
|
30
|
+
name of the property components
|
|
31
|
+
|
|
32
|
+
verbose : bool
|
|
33
|
+
component verbose execution
|
|
34
|
+
|
|
35
|
+
See Also
|
|
36
|
+
--------
|
|
37
|
+
..
|
|
38
|
+
|
|
39
|
+
Examples
|
|
40
|
+
--------
|
|
41
|
+
>> logger = Logger(verbose=False)
|
|
42
|
+
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
# --- logger configuration ---
|
|
46
|
+
self._name = name
|
|
47
|
+
self._verbose = verbose
|
|
48
|
+
|
|
49
|
+
#set logging file
|
|
50
|
+
if path is None:
|
|
51
|
+
systemLog = os.getcwd()+"/Resources/sys.log"
|
|
52
|
+
else:
|
|
53
|
+
systemLog = path+"/Resources/sys.log"
|
|
54
|
+
|
|
55
|
+
#setup logger
|
|
56
|
+
self._syslogger=setup_logger(name="systemLog",log_file=systemLog,level=logging.INFO)
|
|
57
|
+
#self.syslog(msg="Logger configured", level="INFO")
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def name(self):
|
|
61
|
+
"""The name property (read-only)."""
|
|
62
|
+
return self._name
|
|
63
|
+
|
|
64
|
+
def syslog(self,msg="tbd",level="INFO"):
|
|
65
|
+
"""Perform a system log entry.
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
msg : string
|
|
70
|
+
message to be logged
|
|
71
|
+
|
|
72
|
+
type : string
|
|
73
|
+
Level of the logging
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
See Also
|
|
77
|
+
--------
|
|
78
|
+
..
|
|
79
|
+
|
|
80
|
+
Examples
|
|
81
|
+
--------
|
|
82
|
+
>> logger.syslog(msg="this is a examples log message",level="INFO")
|
|
83
|
+
|
|
84
|
+
"""
|
|
85
|
+
# verbose printing
|
|
86
|
+
if self._verbose: print(msg)
|
|
87
|
+
# logging
|
|
88
|
+
if level == 'INFO':
|
|
89
|
+
self._syslogger.info(msg)
|
|
90
|
+
elif level == 'DEBUG':
|
|
91
|
+
self._syslogger.debug(msg)
|
|
92
|
+
elif level == 'ERROR':
|
|
93
|
+
self._syslogger.error(msg)
|
|
File without changes
|