"""
A module to load hardware properties from a json file. This information
is then accessible through class attributes.
The json file contains an object for a corresponding physical device.
Within these objects each property is characterized with an array
containing the information in following order: [value, type, unit,
comment]
Warning:
Make sure that all keys within the json file are 'legal'/valid
variables names in Python! Else the property is going to be assigned
to an attribute name that cannot be accessed with the
instance.attribute syntax.
Example:
A json file containing following information:
.. code-block::
{...
"device1":{
"property1": [15, "int", "mm", "interesting comment and information"]
"subdevice1": {
"subproperty1": [0.6, "float", "hectopascal", "interesting comment and information2"]
"subproperty2": ["foo", "str", "dimensionless", "interesting comment and information3"]
}
}
...}
would be accessible through:
.. code-block::
>>> path = "path/to/hardware_properties.json"
>>> hw = HardwareProperties(path)
>>> hw.device1.property1
>>> hw.device1.subdevice1.subproperty2
"""
# Helper modules
import logging
import typing
import os
# Essential modules
import json
# Set up logger
logger = logging.getLogger(__name__)
# Set up 'path'-like type
Path = typing.Union[str, bytes, os.PathLike]
[docs]class HardwareProperties:
"""
This class has attributes containing attributes to relevant hardware
properties.
Each json-object is instantiated as an Attribute-object. The
properties/attributes of this json–object are then assigned as
attribute to the instance.
Args:
path (Path): Path to json file containing properties of the hardware in the setup.
"""
def __init__(self, path: Path):
with open(path) as json_file:
# Load json file into dictionary
self.hardware_properties = json.load(json_file)
# Create attributes or classes that have attributes that hold
# all properties
create_class_and_attributes(self, self.hardware_properties)
[docs]def create_class_and_attributes(instance, dictionary: dict):
"""
Assigns the 0th entry of the values in dictionary as attributes to
instance. The name of the attribute corresponds to the key of the
value.
If the value itself is a dictionary a new object is instantiated to
which the values of the dictionary within value are assigned.
(recursive algorithm)
Args:
instance (object): Instance of an object to which the values should be assigned
dictionary (dict): Dictionary containing the values that should be assigned as
attributes to the instance. The keys are the names of the attribute.
Warning:
Make sure that all keys are valid python variable names! Spaces in
keys will automatically be replaced with underscores.
"""
# Iterate over entries in dictionary
for key, value in dictionary.items():
key = key.replace(" ", "_") # Replace space character with underscore
if type(value) == dict:
# If value is itself a dictionary create an 'Attribute'
# instance (subinstance) that holds all the entries of
# 'value' as attributes.
sub_instance = Attribute()
create_class_and_attributes(sub_instance, value)
# Assign 'Attribute' instance (subinstance) as attribute to
# the actual instance that is of interest
setattr(instance, key, sub_instance)
elif type(value) == str:
# mainly for the setup name attribute, where the dictionary
# value is _not_ a list. This is more or less the only case
# so far
setattr(instance, key, value)
else:
# If value is not a dictionary, assign the 0th entry of the
# array as attribute to instance with the name key
setattr(instance, key, value[0])
if __name__ == "__main__":
path = "hardware_config_files/i-lab_hardware_properties.json"
hw = HardwareProperties(path)