'''Provide an easy way to set things like gadgetron host, port, etc.
The ProfileConfig object will create (if it's not already created) a file
called 'profiles.config' in the top level of the project (same directory as
setup.py). This file contains one or more profiles, one and only one of which
must be set as active. A profile contains ports and hostnames and other
parameters to use for the gadgetron, MATLAB, siemens_to_ismrmrd, etc. clients.
The config files use python's configparser format. See implementation for
details.
Examples
========
A sample `profiles.config` file might look like:
.. code-block:: ini
[default]
gadgetron.host = localhost
gadgetron.port = 9002
[workcomp]
gadgetron.host = 10.8.1.12
gadgetron.port = 9002
matlab.host = 10.8.1.12
matlab.port = 9999
matlab.bufsize = 1024
[config]
active = workcomp
'''
from configparser import ConfigParser, ExtendedInterpolation, NoOptionError
import os
from mr_utils.definitions import ROOT_DIR
[docs]class ProfileConfig(object):
'''ProfileConfig allows object oriented interaction with profiles.config.
'''
def __init__(self, filename=None):
if filename is None:
# Get the profiles.config file that lives in the top level dir
filename = '%s/profiles.config' % ROOT_DIR
# config file stored at top level of project
self.filename = filename
self.defaults = {
'gadgetron.host': 'localhost',
'gadgetron.port': 9002,
'siemens_to_ismrmrd.host': 'localhost',
'siemens_to_ismrmrd.user': 'user',
'siemens_to_ismrmrd.ssh_key':'%s/.ssh/id_rsa' % os.environ['HOME'],
'matlab.host': 'localhost',
'matlab.port': 9999,
'matlab.bufsize': 1024
}
# Make sure there is a section called 'default'
self.parser = ConfigParser(allow_no_value=True,
interpolation=ExtendedInterpolation())
self.parser.read(self.filename)
if 'default' not in self.parser.sections():
self.parser['default'] = self.defaults
self.update_file()
# Make sure there is a section called config, and make sure it has a
# profile
if 'config' not in self.parser.sections():
self.parser['config'] = {'active': 'default'}
self.update_file()
if 'config' in self.parser.sections():
self.active_profile = self.parser.get('config', 'active',
fallback='default')
[docs] def update_file(self):
'''Update profiles.config by overwriting contents.'''
with open(self.filename, 'w') as f:
self.parser.write(f)
[docs] def create_profile(self, profile_name, args=None):
'''Create a new profile.
Parameters
==========
profile_name : str
New profile's label.
args : dict
key, value pairs of profile's attributes.
'''
# Make sure args is a dictionary
if args is None:
args = {}
elif not isinstance(args, dict):
raise ValueError('args should be a dictionary!')
# Also make sure reserved names are not used
if profile_name == 'config':
raise ValueError(
'"config" is a reserved section in the config file.')
# Make sure we're not overwriting a profile
if profile_name in self.parser.sections():
raise RuntimeError('Profile already exists! Not overwritten!')
# If no values are given for any keys, use the defaults
for key, val in self.defaults.items():
if key not in args:
args[key] = val
# Create the section
self.parser[profile_name] = args
self.update_file()
[docs] def activate_profile(self, profile):
'''Assign a profile to be active.
Parameters
==========
profile : str
Profile label to make active.
Notes
=====
All other profiles will still persist, but will not be used. Only one
profile may be active at a time.
'''
if profile not in self.parser.sections() or (profile == 'config'):
raise ValueError('Profile label must be valid!')
self.parser['config']['active'] = profile
self.update_file()
self.active_profile = profile
[docs] def set_config(self, args, profile=None):
'''Update profile configuration files.
Parameters
==========
profile : str
The profile to update.
args : dict
Dictionary of key, value updates.
Notes
=====
.. code-block:: none
Keys -> Values:
'gadgetron.host' -> (string) ip-address/hostname/etc
'gadgetron.port' -> (int) port number
'''
# If no profile provided, use the active profile
if profile is None:
profile = self.active_profile
for key in self.defaults:
if key in args:
self.parser[profile][key] = str(args[key])
self.update_file()
[docs] def get_config_val(self, key):
'''Retrieve a config value.
Parameters
==========
key : str
Key of the (key, value) pair of the value to be looked up.
Returns
=======
value
Value associated with `key`
'''
# parse these out as integers
if key in ['gadgetron.port', 'matlab.port', 'matlab.bufsize']:
return self.parser.getint(self.active_profile, key)
# else...
# as strings
try:
return self.parser.get(self.active_profile, key)
except NoOptionError:
# Create the option
args = dict(self.parser.items(self.active_profile))
args[key] = ''
print(args)
self.parser[self.active_profile] = args
self.update_file()
return self.get_config_val(key)
if __name__ == '__main__':
# Command line interface to be developed...
pass