Source code for envipyengine.config

"""
The config module is used to configure settings for ENVI Py Engine.

The following properties are currently supported:

==================== ========== ==================================================
Property Name        Data Type  Description
==================== ========== ==================================================
engine               string     The full path to the engine executable. Example:
                                "C:\\\\Program Files\\\\Harris\\\\ENVI54\\\\IDL86\\\\bin\\\\bin.x86_64\\\\taskengine.exe"
engine-args          string     Any additional command line arguments that will be
                                passed to the taskengine executable.
Environment Variable string     Any valid environment variable and value pairs.
Names                           All name/value pairs specified in this
                                section will be interpreted as environment variables
                                for use when running the Engine.
==================== ========== ==================================================

Please refer to the following examples of setting configuration values.

Set the Engine Executable path for the current user:
 >>> import envipyengine
 >>> envipyengine.config.set('engine', <executable-path>)

Set the ENVI Engine Executable path for all users.
 >>> import envipyengine
 >>> envipyengine.config.set('engine', <install-dir>, system=True)

Specify additional arguments for the Task Engine:
 >>> import envipyengine
 >>> envipyengine.config.set('engine-args', '--compile')

Specify an environment variable to be used when running the task engine:
 >>> import envipyengine
 >>> envipyengine.config.set_environment(dict('IDL_PATH'=<path-to-idl-code>)

The locations of the configuration files are:

============================== ===================================================================
OS and Configuration Type      Configuration File
============================== ===================================================================
Windows User Configuration     C:\\\\Users\\\\<user>\\\\AppData\\\\Local\\\\envipyengine\\\\settings.cfg
Windows System Configuration   C:\\\\ProgramData\\\\envipyengine\\\\settings.cfg
Mac OS X User Configuration    /Users/<user>/Library/Preferences/envipyengine/settings.cfg
Max OS X System Configuration  /Library/Preferences/envipyengine/settings.cfg
Linux User Configuration       /home/<user>/.envipyengine/settings.cfg
Linux System Configuration     /var/lib/envipyengine/settings.cfg
============================== ===================================================================


"""
import os
import sys

import ctypes

if sys.platform == 'win32':
    from ctypes import wintypes, windll


try:
    from ConfigParser import ConfigParser  # Python 2
    from ConfigParser import NoOptionError
    from ConfigParser import NoSectionError
except ImportError:
    from configparser import ConfigParser  # Python 3
    from configparser import NoOptionError
    from configparser import NoSectionError

from .error import NoConfigOptionError

_APP_DIRNAME = 'envipyengine'
_CONFIG_FILENAME = 'settings.cfg'
_MAIN_SECTION_NAME = 'envipyengine'
_ENVIRONMENT_SECTION_NAME = 'engine-environment'


def _user_config_file():
    """
    Returns the path to the settings.cfg file. On Windows the file is
    located in the AppData/Local/envipyengine directory. On Unix, the file
    will be located in the ~/.envipyengine directory.

    :return: String specifying the full path to the settings.cfg file
    """
    if sys.platform == 'win32':
        if 'LOCALAPPDATA' in os.environ:
            user_dir = os.getenv('LOCALAPPDATA')
        else:
            user_dir = os.path.join(os.path.expanduser('~'), 'AppData', 'Local')
        config_path = os.path.join(user_dir, _APP_DIRNAME, _CONFIG_FILENAME)
    elif sys.platform.startswith('darwin'):
        user_dir = os.path.expanduser('~')
        config_path = os.path.sep.join([user_dir, 'Library', 'Preferences',
                                        _APP_DIRNAME, _CONFIG_FILENAME])
    else:
        user_dir = os.path.expanduser('~')
        config_path = os.path.sep.join([user_dir, '.' + _APP_DIRNAME,
                                        _CONFIG_FILENAME])
    return config_path


def _system_config_file():
    """
    Returns the path to the settings.cfg file. On Windows the file is
    located in the AppData/Local/envipyengine directory. On Unix, the file
    will be located in the ~/.envipyengine directory.

    :return: String specifying the full path to the settings.cfg file
    """
    if sys.platform == 'win32':
        config_path = os.path.sep.join([_windows_system_appdata(),
                                        _APP_DIRNAME,
                                        _CONFIG_FILENAME])
    elif sys.platform.startswith('darwin'):
        config_path = os.path.sep.join([os.path.sep + 'Library', 'Preferences',
                                        _APP_DIRNAME, _CONFIG_FILENAME])
    else:
        config_path = os.path.sep.join(['', 'var', 'lib', _APP_DIRNAME,
                                        _CONFIG_FILENAME])
    return config_path


def _windows_system_appdata():
    """
    Return the path to the Windows Common App Data folder.
    On Windows 7, for example, this is C:\\ProgramData

    :return: String reprsentation the path to the Windows Common
             App Data folder
    """
    # Could also use os.environ['ALLUSERSPROFILE'] - maybe?
    csidl_common_appdata = 35
    sh_get_folder_path = windll.shell32.SHGetFolderPathW
    sh_get_folder_path.argtypes = [wintypes.HWND,
                                   ctypes.c_int,
                                   wintypes.HANDLE,
                                   wintypes.DWORD,
                                   wintypes.LPCWSTR]
    path_buf = ctypes.create_unicode_buffer(wintypes.MAX_PATH)
    result = sh_get_folder_path(0, csidl_common_appdata, 0, 0, path_buf)
    return str(path_buf.value)


def _read_config(cfg_file):
    """
    Return a ConfigParser object populated from the settings.cfg file.

    :return: A Config Parser object.
    """
    config = ConfigParser()
    # maintain case of options
    config.optionxform = lambda option: option
    if not os.path.exists(cfg_file):
        # Create an empty config
        config.add_section(_MAIN_SECTION_NAME)
        config.add_section(_ENVIRONMENT_SECTION_NAME)
    else:
        config.read(cfg_file)
    return config


def _write_config(config, cfg_file):
    """
    Write a config object to the settings.cfg file.

    :param config: A ConfigParser object to write to the settings.cfg file.
    """
    directory = os.path.dirname(cfg_file)
    if not os.path.exists(directory):
        os.makedirs(directory)
    with open(cfg_file, "w+") as output_file:
        config.write(output_file)


[docs]def get_environment(): """ Return all environment values from the config files. Values stored in the user configuration file will take precedence over values stored in the system configuration file. :return: A dictionary containing the name/value pairs of all environment settings in the config file. """ section = _ENVIRONMENT_SECTION_NAME # Read system sys_cfg = _read_config(_SYSTEM_CONFIG_FILE) sys_env = \ dict(sys_cfg.items(section)) if sys_cfg.has_section(section) else {} # Read user usr_cfg = _read_config(_USER_CONFIG_FILE) usr_env = \ dict(usr_cfg.items(section)) if usr_cfg.has_section(section) else {} # Merge user into system for k in usr_env.keys(): sys_env[k] = usr_env[k] return sys_env
[docs]def set_environment(environment, system=False): """ Set engine environment values in the config file. :param environment: A dictionary containing the environment variable settings as key/value pairs. :keyword system: Set to True to modify the system configuration file. If not set, the user config file will be modified. """ config_filename = \ _SYSTEM_CONFIG_FILE if system is True else _USER_CONFIG_FILE config = _read_config(config_filename) section = _ENVIRONMENT_SECTION_NAME for key in environment.keys(): config.set(section, key, environment[key]) _write_config(config, config_filename)
[docs]def remove_environment(environment_var_name, system=False): """ Remove the specified environment setting from the appropriate config file. :param environment_var_name: The name of the environment setting to remove. :keyword system: Set to True to modify the system configuration file. If not set, the user config file will be modified. """ config_filename = \ _SYSTEM_CONFIG_FILE if system is True else _USER_CONFIG_FILE config = _read_config(config_filename) section = _ENVIRONMENT_SECTION_NAME config.remove_option(section, environment_var_name) _write_config(config, config_filename)
[docs]def get(property_name): """ Returns the value of the specified configuration property. Property values stored in the user configuration file take precedence over values stored in the system configuration file. :param property_name: The name of the property to retrieve. :return: The value of the property. """ config = _read_config(_USER_CONFIG_FILE) section = _MAIN_SECTION_NAME try: property_value = config.get(section, property_name) except (NoOptionError, NoSectionError) as error: # Try the system config file try: config = _read_config(_SYSTEM_CONFIG_FILE) property_value = config.get(section, property_name) except (NoOptionError, NoSectionError) as error: raise NoConfigOptionError(error) return property_value
[docs]def set(property_name, value, system=False): """ Sets the configuration property to the specified value. :param property_name: The name of the property to set. :param value: The value for the property. :keyword system: Set to True to modify the system configuration file. If not set, the user config file will be modified. """ config_filename = \ _SYSTEM_CONFIG_FILE if system is True else _USER_CONFIG_FILE config = _read_config(config_filename) section = _MAIN_SECTION_NAME config.set(section, property_name, value) _write_config(config, config_filename)
[docs]def remove(property_name, system=False): """ Remove a configuration property/value setting from the config file. :param property_name: The name of the property to remove. :keyword system: Set to True to modify the system configuration file. If not set, the user config file will be modified. """ config_filename = \ _SYSTEM_CONFIG_FILE if system is True else _USER_CONFIG_FILE config = _read_config(config_filename) section = _MAIN_SECTION_NAME config.remove_option(section, property_name) _write_config(config, config_filename)
# Set up some module globals so they only need to be # calculated once _USER_CONFIG_FILE = _user_config_file() _SYSTEM_CONFIG_FILE = _system_config_file()