"""
This package implements a simple way of dealing with parameters, ofproviding
default parameters and comments, and to keep track of used parameters for
registration runs. See the corresponding note for a brief description on how to use it.
"""
from __future__ import print_function
# from builtins import str
# from builtins import object
import json
[docs]class ParameterDict(object):
def __init__(self, initDict=None, printSettings=True):
if initDict is not None:
if type(initDict)==type(self):
self.ext = initDict.ext
else:
print('WARNING: Cannot initialize from non ParameterDict object. Ignoring initialization.')
self.ext = {}
else:
self.ext = {}
self.int = {}
self.com = {}
self.currentCategoryName = 'root'
self.printSettings = printSettings
def __str__(self):
return 'ext = ' + "\n" + json.dumps(self.ext, indent=4, sort_keys=True) + "\n" + \
'int = ' + "\n" + json.dumps(self.int, indent=4, sort_keys=True) + "\n" + \
'com = ' + "\n" + json.dumps(self.com, indent=4, sort_keys=True) + "\n" + \
'currentCategoryName = ' + str(self.currentCategoryName) + "\n"
[docs] def isempty(self):
return self.int=={}
[docs] def load_JSON(self, fileName):
"""
Loads a JSON configuration file
:param fileName: filename of the configuration to be loaded
"""
try:
with open(fileName) as data_file:
if self.printSettings:
print('Loading parameter file = ' + fileName )
self.ext = json.load(data_file)
except IOError as e:
print('Could not open file = ' + fileName + '; ignoring request.')
[docs] def write_JSON(self, fileName,save_int=True):
"""
Writes the JSON configuration to a file
:param fileName: filename to write the configuration to
"""
with open(fileName, 'w') as outfile:
if self.printSettings:
print('Writing parameter file = ' + fileName )
if save_int:
json.dump(self.int, outfile, indent=4, sort_keys=True)
else:
json.dump(self.ext, outfile, indent=4, sort_keys=True)
[docs] def print_settings_on(self):
"""
Enable screen output as configurations are read and set.
"""
self.printSettings = True
[docs] def print_settings_off(self):
"""
Disable screen output as configurations are read and set.
"""
self.printSettings = False
[docs] def get_print_settings(self):
"""
Current print settings
:return: Returns if screen printing is on (True) or off (False)
"""
return self.printSettings
[docs] def set_print_settings(self,val):
"""
Sets Current print settings
:param val: value to set the print settings to, needs to be boolean
:return: n/a
"""
self.printSettings = val
def _set_value_of_instance(self, ext, int, com, currentCategoryName):
self.ext = ext
self.int = int
self.com = com
self.currentCategoryName = currentCategoryName
def __missing__(self, key):
# if key cannot be found
raise ValueError('Could not find key = ' + str( key ) )
def __getitem__(self, key_or_keyTuple):
# getting an item based on key
# here the key can be three different things
# 1) simply a text key (then returns the current value)
# 2) A 2-tuple (keyname,defaultvalue)
# 3) A 3-tuple (keyname,defaultvalue,comment)
# returns a ParDicts object if we are accessing a category (i.e., a dictionary)
# returns just the value if it is a regular value
if type(key_or_keyTuple)==tuple:
# here, we need to distinguish cases 2) and 3)
lT = len(key_or_keyTuple)
if lT==1:
# treat this as if it would only be the keyword
return self._get_current_key(key_or_keyTuple[0])
elif lT==2:
# treat this as keyword + default value
return self._get_current_key(key_or_keyTuple[0],
key_or_keyTuple[1])
elif lT==3:
# treat this as keyword + default value + comment
return self._get_current_key(key_or_keyTuple[0],
key_or_keyTuple[1],
key_or_keyTuple[2])
else:
raise ValueError('Tuple of incorrect size')
else:
# now we just want to return it (there is no default value or comment)
return self._get_current_key(key_or_keyTuple)
def __setitem__(self, key, valueTuple):
# to set an item
# valueTuple is either a 2-tuple (actual value, comment)
# or it is simply a comment, then this key becomes a category
if type(valueTuple)==tuple:
if len(valueTuple)==2:
value = valueTuple[0]
comment = valueTuple[1]
elif len(valueTuple)==1:
value = {}
comment = valueTuple[0]
else:
raise ValueError('Expected a 2-tuple as input')
else: # not a tuple
value = valueTuple
comment = None
if type(value)==dict:
# only add if this is an empty dictionary
if len(value)==0:
self._set_current_category(key, comment)
else:
raise ValueError('Can only add empty dictionaries')
# we are assigning a category
else:
# now we have to set an actual value (not a category)
if type(value)==type(self):
# Here we are trying to assign a full parameter object
# We want to add the content and not the object itself
self.ext[key]=value.ext
self.int[key]={}
self.com[key]={}
else:
# this is just a normal value
self._set_current_key(key, value, comment)
def _set_current_category(self, key, comment):
currentCategoryName = self.currentCategoryName + '.' + str(key)
if key not in self.ext or (key in self.ext and type(self.ext[key])!=dict):
# we do not want to over-write any settings here
if self.printSettings:
print('Creating new category: ' + currentCategoryName)
self.ext[key] = {}
self.int[key] = {}
self.com[key] = {}
if comment is not None:
if len(comment) > 0:
self.com[key]['__doc__'] = comment
def _set_current_key(self, key, value, comment=None):
if self.printSettings:
if key in self.ext:
print('Overwriting key = ' + str(key) + '; category = ' + self.currentCategoryName + '; value = ' +
str( self.ext[key] ) + ' -> ' + str(value) )
else:
print('Creating key = ' + str(key) + '; category = ' + self.currentCategoryName + '; value = ' + str(value))
self.ext[key] = value
self.int[key] = value
if comment is not None:
if len(comment)>0:
self.com[key] = comment
def _recursive_has_key(self,current_key_list,current_dict):
if len(current_key_list)==1:
if current_key_list[0] in current_dict:
return True
else:
return False
else:
if current_key_list[0] in current_dict:
return self._recursive_has_key(current_key_list[1:],current_dict[current_key_list[0]])
else:
return False
[docs] def has_key(self,key_list):
if len(key_list) < 1:
raise ValueError('At least one key expected in key list')
else:
return self._recursive_has_key(key_list,self.int)
def _get_current_key(self, key, defaultValue=None, comment=None):
# returns a ParDicts object if we are accessing a category (i.e., a dictionary)
# returns just the value if it is a regular value
if key in self.ext:
value = self.ext[key]
if type(value)==dict:
# this is a category, need to create a ParDicts object to return
# if the key already exists in int and com keep it otherwise initialize it to empty
if key not in self.int:
self.int[key]={}
if key not in self.com:
self.com[key]={}
if comment is not None:
if len(comment)>0:
self.com[key]['__doc__'] = comment
newpar = ParameterDict(printSettings=self.printSettings)
currentCategoryName = self.currentCategoryName + '.' + str(key)
newpar._set_value_of_instance(self.ext[key], self.int[key], self.com[key], currentCategoryName)
return newpar
else:
# just a regular value which we can return
self.int[key] = value
if comment is not None:
if len(comment)>0:
self.com[key] = comment
return value
else:
# does not have the key, create it via the default value
if defaultValue is None:
# then make it a dictionary
defaultValue = {}
# if defaultValue is not None:
if type(defaultValue)==dict:
# make sure it is empty and if it is create a category
if len(defaultValue)==0:
self._set_current_category(key, comment)
# and now we need to return it
newpar = ParameterDict(printSettings=self.printSettings)
currentCategoryName = self.currentCategoryName + '.' + str(key)
newpar._set_value_of_instance(self.ext[key], self.int[key], self.com[key], currentCategoryName)
return newpar
else:
raise ValueError('Cannot create a default key of type dict()')
else:
# now we can create it and return it
self.ext[key]=defaultValue
self.int[key]=defaultValue
if comment is not None:
if len(comment)>0:
self.com[key]=comment
if self.printSettings:
print('Using default value = ' + str(defaultValue) + ' for key = ' + str(key) + ' of category = ' + self.currentCategoryName )
return defaultValue
#else:
# raise ValueError('Cannot create key = ' + str(key) + ' without a default value')
# test it
[docs]def test_parameter_dict():
"""
Convenience testing script (to be converted to an actual test)
"""
p = ParameterDict()
# we can directly assign
p['registration_model'] = ({},'general settings for registration models')
p['registration_model']['similarity_measure'] = ({},'settings for the similarity measures')
p['registration_model']['similarity_measure']['type']=('ssd','similarity measure type')
# we can also ask for a parameter and use a default parameter if it does not exist
p['registration_model'][('nrOfIterations',10,'number of iterations')]
# we can also create a new category with default values if it does not exist yet
p[('new_category',{},'this is a new category')]
p[('registration_model',{},'this category already existed')]
# check if a key exists
print(p.has_key(['registration_model']))
print(p.has_key(['registration_model','bla']))
# and we can print everything of course
print(p)
# lastly we can write it all out as json
p.write_JSON('test_pars.json')
p.write_JSON_comments('test_pars_comments.json')