Skip to content

Commit

Permalink
Refactor config handling code & config handling unit tests
Browse files Browse the repository at this point in the history
Refactor the config handling code for PEP8 & co and unit tests
that cover important config handling operations, such as config file
loading & config file upgrade.
  • Loading branch information
M4rtinK committed Jul 31, 2016
1 parent f4d4581 commit ac5f86a
Show file tree
Hide file tree
Showing 9 changed files with 282 additions and 94 deletions.
170 changes: 93 additions & 77 deletions core/configs.py
Expand Up @@ -24,32 +24,39 @@
import logging
log = logging.getLogger("core.config")

CONFIGS = ["map_config.conf", "user_config.conf"]

MAP_CONFIG_FILE = "map_config.conf"
USER_CONFIG_FILE = "user_config.conf"
CONFIGS = [MAP_CONFIG_FILE, USER_CONFIG_FILE]
DEFAULT_CONFIGS_DIR = "data/default_configuration_files"

class Configs(object):
def __init__(self, modrana):
self.modrana = modrana
self.paths = modrana.paths
def __init__(self, configs_dir, default_configs_dir=DEFAULT_CONFIGS_DIR):
self._configs_dir = configs_dir
self._default_configs_dir = default_configs_dir

self.userConfig = {}
self.mapConfig = {}
self._user_config = {}
self._map_config = {}

# check if config files exist
self.checkConfigFilesExist()
self.check_config_files_exist()

def checkConfigFilesExist(self):
"""
assure that configuration files are available in the profile folder
- provided the default configuration files exist and that the profile folder
exists and is writable
def check_config_files_exist(self):
"""Assure that configuration files are available.
Check that the default configuration files exist and that the profile folder
exists and is writable.
:returns: list of config file names found
:rtype: list
"""
profilePath = self.modrana.paths.getProfilePath()
existing_configs = []
for config in CONFIGS:
configPath = os.path.join(profilePath, config)
if not os.path.exists(configPath):
configPath = os.path.join(self._configs_dir, config)
if os.path.exists(configPath):
existing_configs.append(config)
else:
try:
source = os.path.join("data/default_configuration_files", config)
source = os.path.join(self._default_configs_dir, config)
log.info(" ** copying default configuration file to profile folder")
log.info(" ** from: %s", source)
log.info(" ** to: %s", configPath)
Expand All @@ -58,81 +65,86 @@ def checkConfigFilesExist(self):
except Exception:
log.exception("copying default configuration file to profile folder failed")

def upgradeConfigFiles(self):
"""
upgrade config files, if needed
"""
upgradeCount = 0
profilePath = self.modrana.paths.getProfilePath()
log.info("upgrading modRana configuration files in %s", profilePath)
return existing_configs

def upgrade_config_files(self):
"""Upgrade config files (if needed)."""
upgrade_count = 0
log.info("upgrading modRana configuration files in %s", self._configs_dir)
# first check the configs actually exist
self.checkConfigFilesExist()
self.check_config_files_exist()

for config in CONFIGS:
# load default config
defaultConfigPath = os.path.join("data/default_configuration_files", config)
installedConfigPath = os.path.join(profilePath, config)
# try to upgrade the config
default_config_path = os.path.join(self._default_configs_dir, config)
config_path = os.path.join(self._configs_dir, config)
try:
defaultRev = int(ConfigObj(defaultConfigPath).get("revision", 0))
installedRev = int(ConfigObj(installedConfigPath).get("revision", 0))
default_rev = int(ConfigObj(default_config_path).get("revision", 0))
installed_rev = int(ConfigObj(config_path).get("revision", 0))

if defaultRev > installedRev: # is installed config is outdated ?
if default_rev > installed_rev: # is the installed config outdated ?
log.info('config file %s is outdated, upgrading', config)
# rename installed config as the user might have modified it
newName = "%s_old_revision_%d" % (config, installedRev)
newPath = os.path.join(profilePath, newName)
shutil.move(installedConfigPath, newPath)
log.info('old config file renamed to %s' % newName)
new_name = "%s_old_revision_%d" % (config, installed_rev)
new_path = os.path.join(self._configs_dir, new_name)
shutil.move(config_path, new_path)
log.info('old config file renamed to %s' % new_name)

# install the (newer) default config
shutil.copy(defaultConfigPath, profilePath)
shutil.copy(default_config_path, self._configs_dir)

# update upgrade counter
upgradeCount += 1
upgrade_count += 1
except Exception:
log.exception("upgrading config file: %s failed", config)

if upgradeCount:
log.info("%d configuration files upgraded", upgradeCount)
if upgrade_count:
log.info("%d configuration files upgraded", upgrade_count)
else:
log.info("no configuration files needed upgrade")

def loadAll(self):
"""
load all configuration files
def load_all(self):
""""Load all configuration files.
:returns: True if all configs were loaded successfully, False otherwise
:rtype: bool
"""
self.loadMapConfig()
self.loadUserConfig()

def getUserConfig(self):
return self.userConfig
return all((self.load_map_config(), self.load_user_config()))

@property
def user_config(self):
"""The "raw" user config."""
return self._user_config

def load_user_config(self):
"""Load the user oriented configuration file."""

def loadUserConfig(self):
"""load the user oriented configuration file."""
path = os.path.join(self.modrana.paths.getProfilePath(), "user_config.conf")
config_path = os.path.join(self._configs_dir, USER_CONFIG_FILE)
if not os.path.isfile(config_path):
return False

try:
config = ConfigObj(path)
config = ConfigObj(config_path)
if 'enabled' in config:
if config['enabled'] == 'True':
self.userConfig = config
self._user_config = config
return True
except Exception:
msg = "loading user_config.conf failed, check the syntax\n" \
"and if the config file is present in the modRana profile directory"
log.exception(msg)
log.exception("loading user_config.conf from %s failed, check the syntax\n"
"and if the config file is present in the modRana profile directory.",
self._configs_dir)
return False

def getMapConfig(self):
"""
get the "raw" map config
"""
return self.mapConfig
@property
def map_config(self):
"""The "raw" map config."""
return self._map_config

def loadMapConfig(self):
"""
load the map configuration file
"""
def load_map_config(self):
"""Load the map configuration file."""

configVariables = {
config_variables = {
'label': 'label',
'url': 'tiles',
'max_zoom': 'maxZoom',
Expand All @@ -142,37 +154,41 @@ def loadMapConfig(self):
'coordinates': 'coordinates',
}

def allNeededIn(needed, layerDict):
"""
check if all required values are filled in
"""
def all_needed_in(needed, layer_dict):
"""Check if all required values are filled in."""
# TODO: optimize this ?
for key in needed:
if key in layerDict:
if key in layer_dict:
continue
else:
return False
return True

mapConfigPath = os.path.join(self.modrana.paths.getProfilePath(), 'map_config.conf')
map_config_path = os.path.join(self._configs_dir, MAP_CONFIG_FILE)
# check if the map configuration file is installed
if not os.path.exists(mapConfigPath):
if not os.path.exists(map_config_path):
# nothing in profile folder -> try to use the default config
log.info("no config in profile folder, using default map layer configuration file")
mapConfigPath = os.path.join("data/default_configuration_files", 'map_config.conf')
if not os.path.exists(mapConfigPath):
map_config_path = os.path.join(DEFAULT_CONFIGS_DIR, MAP_CONFIG_FILE)
if not os.path.exists(map_config_path):
# no map layer config available
log.info("map layer configuration file not available")
return False
try:
self.mapConfig = ConfigObj(mapConfigPath)
self._map_config = ConfigObj(map_config_path)
return True
except Exception:
log.exception("loading map_config.conf failed")
return False
return True

def getUserAgent(self):
"""return the default modRana User-Agent"""
@property
def user_agent(self):
"""Returns the default modRana User-Agent.
:returns: default modRana user agent
:rtype: str
"""

#debugging:
# return "Mozilla/5.0 (compatible; MSIE 5.5; Linux)"
#TODO: setting from configuration file, CLI & interface
Expand Down
4 changes: 2 additions & 2 deletions core/paths.py
Expand Up @@ -223,7 +223,7 @@ def getTracklogsFolderPath(self):
"""return path to a folder for storing tracklogs"""
path = None
# first check if the user overrode the tracklog folder path
config = self.modrana.configs.getUserConfig()
config = self.modrana.configs.user_config
if config:
path = config.get("tracklog_folder", None)
if path is None:
Expand All @@ -241,7 +241,7 @@ def getMapFolderPath(self):
"""return a path to folder for map data storage"""
path = None
# first check if the user overrode the map folder path
config = self.modrana.configs.getUserConfig()
config = self.modrana.configs.user_config
if config:
path = config.get("map_folder", None)
if path is None:
Expand Down
6 changes: 3 additions & 3 deletions modrana.py
Expand Up @@ -176,7 +176,7 @@ def __init__(self):
self.paths = paths.Paths(self)

# add the configs handling core module
self.configs = configs.Configs(self)
self.configs = configs.Configs(configs_dir=self.paths.getProfilePath())

# load persistent options
self.optLoadingOK = self._loadOptions()
Expand All @@ -195,7 +195,7 @@ def __init__(self):
self.set('modRanaVersionString', paths.VERSION_STRING)

# load all configuration files
self.configs.loadAll()
self.configs.load_all()

# start loading other modules

Expand All @@ -216,7 +216,7 @@ def _postUpgradeCheck(self):
"""
perform post upgrade checks
"""
self.configs.upgradeConfigFiles()
self.configs.upgrade_config_files()

## MODULE HANDLING ##

Expand Down
8 changes: 4 additions & 4 deletions modules/mod_mapLayers/mod_mapLayers.py
Expand Up @@ -168,7 +168,7 @@ def _parseLayers(self):
"""Parse all map layer definitions"""
# check if there is at least one valid layer

layerDefinitions = self.modrana.configs.mapConfig.get('layers', {})
layerDefinitions = self.modrana.configs.map_config.get('layers', {})
for layerId, layerDefinition in six.iteritems(layerDefinitions):
if self._hasRequiredKeys(layerDefinition, MAP_LAYER_REQUIRED_KEYS):
self._layers[layerId] = MapLayer(layerId, layerDefinition)
Expand All @@ -184,8 +184,8 @@ def _parseGroups(self):
# as groups are not strictly needed for modRana
# to show at least one map layer, we don't check if the
# configuration file has any
if self.modrana.configs.mapConfig:
groupsDict = self.modrana.configs.mapConfig.get('groups', {})
if self.modrana.configs.map_config:
groupsDict = self.modrana.configs.map_config.get('groups', {})
for groupId, groupDefinition in six.iteritems(groupsDict):
if self._hasRequiredKeys(groupDefinition, MAP_LAYER_GROUP_REQUIRED_KEYS):
self._groups[groupId] = MapLayerGroup(self, groupId, groupDefinition)
Expand Down Expand Up @@ -256,4 +256,4 @@ def setOverlayGroup(self, name, overlayList):
except Exception:
self.log.exception("setting overlay group %s failed", name)
self.log.error("current overlay list:")
self.log.error(overlayList)
self.log.error(overlayList)
2 changes: 1 addition & 1 deletion modules/mod_mapTiles/mod_mapTiles.py
Expand Up @@ -275,7 +275,7 @@ def _getConnPool(self, layerId, baseUrl):
return pool
else: # create pool
#headers = { 'User-Agent' : "Mozilla/5.0 (compatible; MSIE 5.5; Linux)" }
userAgent = self.modrana.configs.getUserAgent()
userAgent = self.modrana.configs.user_agent
headers = {'User-Agent': userAgent}
newPool = urllib3.connection_from_url(url=baseUrl, headers=headers, maxsize=10, timeout=10, block=False)
self.connPools[layerId] = newPool
Expand Down
2 changes: 1 addition & 1 deletion modules/mod_menu.py
Expand Up @@ -48,7 +48,7 @@ def __init__(self, *args, **kwargs):
self.setupGeneralMenus()
self.lastActivity = int(time.time())
self.mainScreenCoords = {}
self.userConfig = self.modrana.configs.getUserConfig()
self.userConfig = self.modrana.configs.user_config
self.hideMapScreenButtons = False
self.lastHideCheckTimestamp = time.time()
self.itemMenuGrid = (None, [])
Expand Down
2 changes: 1 addition & 1 deletion modules/mod_onlineServices/mod_onlineServices.py
Expand Up @@ -300,7 +300,7 @@ def _updateProgress(self, progress):
def _elevFromGeonamesBatch(self, latLonList, tracklog):
try:
self._setWorkStatusText("online elevation lookup starting...")
userAgent = self.online.modrana.configs.getUserAgent()
userAgent = self.online.modrana.configs.user_agent
results = geonames.elevBatchSRTM(latLonList, self._geonamesCallback, userAgent)
self._setWorkStatusText("online elevation lookup done ")
return results, tracklog
Expand Down
2 changes: 1 addition & 1 deletion modules/mod_showOSD.py
Expand Up @@ -63,7 +63,7 @@ def colorsChangedCallback(self, colors):

def drawScreenOverlay(self, cr):
""" draw currently active information widgets TODO: just draw object from list"""
config = self.modrana.configs.getUserConfig()
config = self.modrana.configs.user_config

mode = self.get('mode', None)
if mode is None:
Expand Down

0 comments on commit ac5f86a

Please sign in to comment.