From fe070163228fba339445483883a05d0178f321cd Mon Sep 17 00:00:00 2001 From: mathieui Date: Sun, 6 Apr 2014 17:17:51 +0200 Subject: Do not instantiate the Config at module load delayed execution is cleaner and less error-prone --- src/config.py | 188 +++++++++++++++++++++++++++++++++++++--------------------- src/poezio.py | 22 +++++-- 2 files changed, 137 insertions(+), 73 deletions(-) diff --git a/src/config.py b/src/config.py index 8362bf94..12710e1e 100644 --- a/src/config.py +++ b/src/config.py @@ -7,12 +7,16 @@ """ Defines the global config instance, used to get or set (and save) values -from/to the config file +from/to the config file. + +This module has the particularity that some imports and global variables +are delayed because it would mean doing an incomplete setup of the python +loggers. """ DEFSECTION = "Poezio" -import logging +import logging.config import os import sys from gettext import gettext as _ @@ -22,6 +26,7 @@ from os import environ, makedirs, path, remove from shutil import copy2 from args import parse_args + class Config(RawConfigParser): """ load/save the config to a file @@ -59,7 +64,7 @@ class Config(RawConfigParser): res = self.getboolean(option, section) else: res = self.getstr(option, section) - except (NoOptionError, NoSectionError, ValueError, AttributeError) as e: + except (NoOptionError, NoSectionError, ValueError, AttributeError): return default if res is None: return default @@ -254,47 +259,107 @@ class Config(RawConfigParser): res[section][option] = self.get(option, "", section) return res -firstrun = False -# creates the configuration directory if it doesn't exist -# and copy the default config in it -CONFIG_HOME = environ.get("XDG_CONFIG_HOME") -if not CONFIG_HOME: - CONFIG_HOME = path.join(environ.get('HOME'), '.config') -CONFIG_PATH = path.join(CONFIG_HOME, 'poezio') - -try: - makedirs(CONFIG_PATH) -except OSError: - pass - -options = parse_args(CONFIG_PATH) - -# Copy a default file if none exists -if not path.isfile(options.filename): - default = path.join(path.dirname(__file__), '../data/default_config.cfg') - other = path.join(path.dirname(__file__), 'default_config.cfg') - if path.isfile(default): - copy2(default, options.filename) - elif path.isfile(other): - copy2(other, options.filename) - firstrun = True - -try: - config = Config(options.filename) -except: - import traceback - sys.stderr.write('Poezio was unable to read or parse the config file.\n') - traceback.print_exc(limit=0) - sys.exit(1) - -LOG_DIR = config.get('log_dir', '') or path.join(environ.get('XDG_DATA_HOME') or path.join(environ.get('HOME'), '.local', 'share'), 'poezio') -LOG_DIR = path.expanduser(LOG_DIR) - -try: - makedirs(LOG_DIR) -except: - pass +def check_create_config_dir(): + """ + create the configuration directory if it doesn't exist + and copy the default config in it + """ + CONFIG_HOME = environ.get("XDG_CONFIG_HOME") + if not CONFIG_HOME: + CONFIG_HOME = path.join(environ.get('HOME'), '.config') + CONFIG_PATH = path.join(CONFIG_HOME, 'poezio') + + try: + makedirs(CONFIG_PATH) + except OSError: + pass + return CONFIG_PATH + +def run_cmdline_args(CONFIG_PATH): + "Parse the command line arguments" + global options + options = parse_args(CONFIG_PATH) + + # Copy a default file if none exists + if not path.isfile(options.filename): + default = path.join(path.dirname(__file__), '../data/default_config.cfg') + other = path.join(path.dirname(__file__), 'default_config.cfg') + if path.isfile(default): + copy2(default, options.filename) + elif path.isfile(other): + copy2(other, options.filename) + global firstrun + firstrun = True + +def create_global_config(): + "Create the global config object, or crash" + try: + global config + config = Config(options.filename) + except: + import traceback + sys.stderr.write('Poezio was unable to read or' + ' parse the config file.\n') + traceback.print_exc(limit=0) + sys.exit(1) + +def check_create_log_dir(): + "Create the poezio logging directory if it doesn’t exist" + global LOG_DIR + LOG_DIR = config.get('log_dir', '') + + if not LOG_DIR: + + data_dir = environ.get('XDG_DATA_HOME') + if not data_dir: + home = environ.get('HOME') + data_dir = path.join(home, '.local', 'share') + + LOG_DIR = path.join(data_dir, 'poezio') + + LOG_DIR = path.expanduser(LOG_DIR) + + try: + makedirs(LOG_DIR) + except: + pass + +def setup_logging(): + "Change the logging config according to the cmdline options and config" + if config.get('log_errors', True): + LOGGING_CONFIG['root']['handlers'].append('error') + LOGGING_CONFIG['handlers']['error'] = { + 'level': 'ERROR', + 'class': 'logging.FileHandler', + 'filename': path.join(LOG_DIR, 'errors.log'), + 'formatter': 'simple', + } + + if options.debug: + LOGGING_CONFIG['root']['handlers'].append('debug') + LOGGING_CONFIG['handlers']['debug'] = { + 'level':'DEBUG', + 'class':'logging.FileHandler', + 'filename': options.debug, + 'formatter': 'simple', + } + + + if LOGGING_CONFIG['root']['handlers']: + logging.config.dictConfig(LOGGING_CONFIG) + else: + logging.basicConfig(level=logging.CRITICAL) + + global log + log = logging.getLogger(__name__) + +def post_logging_setup(): + # common imports sleekxmpp, which creates then its loggers, so + # it needs to be after logger configuration + from common import safeJID as JID + global safeJID + safeJID = JID LOGGING_CONFIG = { 'version': 1, @@ -312,33 +377,22 @@ LOGGING_CONFIG = { 'level': 'DEBUG', } } -if config.get('log_errors', True): - LOGGING_CONFIG['root']['handlers'].append('error') - LOGGING_CONFIG['handlers']['error'] = { - 'level': 'ERROR', - 'class': 'logging.FileHandler', - 'filename': path.join(LOG_DIR, 'errors.log'), - 'formatter': 'simple', - } -if options.debug: - LOGGING_CONFIG['root']['handlers'].append('debug') - LOGGING_CONFIG['handlers']['debug'] = { - 'level':'DEBUG', - 'class':'logging.FileHandler', - 'filename': options.debug, - 'formatter': 'simple', - } +# True if this is the first run, in this case we will display +# some help in the info buffer +firstrun = False +# Global config object. Is setup in poezio.py +config = None -if LOGGING_CONFIG['root']['handlers']: - logging.config.dictConfig(LOGGING_CONFIG) -else: - logging.basicConfig(level=logging.CRITICAL) +# The logger object for this module +log = None -# common import sleekxmpp, which creates then its loggers, so -# it needs to be after logger configuration -from common import safeJID +# The command-line options +options = None -log = logging.getLogger(__name__) +# delayed import from common.py +safeJID = None +# the global log dir +LOG_DIR = '' diff --git a/src/poezio.py b/src/poezio.py index 7218cf13..99831896 100644 --- a/src/poezio.py +++ b/src/poezio.py @@ -12,22 +12,32 @@ Starting point of poezio. Launches both the Connection and Gui import sys import os - import signal -import logging.config +import logging sys.path.append(os.path.dirname(os.path.abspath(__file__))) -from config import options import singleton -import core - -log = logging.getLogger('') def main(): """ Enter point """ + import config + config_path = config.check_create_config_dir() + config.run_cmdline_args(config_path) + config.create_global_config() + config.check_create_log_dir() + config.setup_logging() + config.post_logging_setup() + + from config import options + + + import core + + log = logging.getLogger('') + signal.signal(signal.SIGINT, signal.SIG_IGN) # ignore ctrl-c cocore = singleton.Singleton(core.Core) signal.signal(signal.SIGUSR1, cocore.sigusr_handler) # reload the config -- cgit v1.2.3